1
0
mirror of https://github.com/zerobig/vscode-1c-metadata-viewer.git synced 2024-11-28 08:58:41 +02:00

Merge branch 'main' into templates

This commit is contained in:
Ilya Bushin 2022-11-06 11:28:44 +03:00
commit f1df1f2a47
17 changed files with 697 additions and 185 deletions

29
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,29 @@
name: Publish package to VSCode Marketplace
on:
release:
types: [published]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: '16'
- run: npm install
- run: npm install -g vsce
- name: Build package
run: npx vsce package
- name: Upload vsix to release
uses: AButler/upload-release-assets@v1.0
with:
files: '*.vsix'
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: lannonbr/vsce-action@master
if: github.event.release.prerelease == false
with:
args: "publish -p $VSCE_TOKEN"
env:
VSCE_TOKEN: ${{ secrets.VSCE_TOKEN }}

View File

@ -1,6 +1,23 @@
# Changelog
### 0.0.4
## 0.0.6
* [new] Поиск конфигураций 1С во вложенных каталогах и возможность работы с несколькими конфигурациями одновременно
## 0.0.5
* [new] Просмотр предопределенных элементов
* [new] Закончил метаданные верхнего уровня
* Планы счетов
* Планы видов расчета
* Регистры бухгалтерии
* Регистры расчета
* Бизнес-процессы
* Задачи
* Внешние источники данных
* [fix] Не открывается модуль формы
## 0.0.4
* [new] Открытие XML
* [new] Параметры сеанса, Роли, Общие реквизиты и Планы видов характеристик
@ -10,11 +27,11 @@
* [new] Модуль менеджера для перечислений
* [new] Модуль менеджера значения
### 0.0.3
## 0.0.3
* Добавил регистры сведений и накопления
### 0.0.2
## 0.0.2
* Добавил реквизиты табличных частей [#1](https://github.com/zerobig/vscode-1c-metadata-viewer/pull/1)
* Добавил иконок в дерево метаданных

View File

@ -1,11 +1,13 @@
# Вывод дерева метаданных конфигурации 1С и открытие модулей в VSC
Расширение анализирует файл ConfigDumpInfo.xml выгруженной конфигурации 1С и строит дерево метаданных в панели VS Code.
## Возможности расширения
* Расширение ищет в открытой папке пары файлов ConfigDumpInfo.xml и Configuration.xml выгруженных конфигураций 1С и для каждой пары строит дерево метаданных в панели VS Code. Для задания глубины просмотра подкаталогов существует настройка "Search Depth". По умолчанию значение настройки равно трём.
* Открывает текстовые модули 1С (*.bsl) через контекстное меню у соответствующих элементов.
* У метаданных для которых есть возможность создания предопределенных элементов можно открыть панель существующих в конфигурации элементов.
![Скриншот дерева метаданных](/resources/screenshot.png)
Открывает текстовые модули 1С (*.bsl) через контекстное меню у соответствующих элементов.
## Метаданные и модули
### Типы метаданных
@ -22,8 +24,15 @@
* Отчеты
* Обработки
* Планы видов характеристик
* Планы счетов
* Планы видов расчета
* Регистры сведений
* Регистры накопления
* Регистры бухгалтерии
* Регистры расчета
* Бизнес-процессы
* Задачи
* Внешние источники данных
### Модули
@ -41,4 +50,4 @@
* Расширение количества обрабатываемых типов метаданных
* Открытие модуля без контекстного меню по двойному щелчку когда модуль у элемента конфигурации один
* Редактирование свойств метаданных в отдельной панели
* Редактирование свойств метаданных в отдельной панели

View File

@ -2,7 +2,7 @@
"name": "vscode-1c-metadata-viewer",
"displayName": "1C Metadata Viewer",
"description": "Explore 1C:Enterprise 8 configuration in the usual way",
"version": "0.0.4",
"version": "0.0.6",
"publisher": "zerobig",
"license": "MIT",
"engines": {
@ -77,6 +77,10 @@
{
"command": "metadataViewer.openXml",
"title": "%1c-metadata-viewer.openXml.title%"
},
{
"command": "metadataViewer.openPredefinedData",
"title": "%1c-metadata-viewer.openPredefinedData.title%"
}
],
"menus": {
@ -135,10 +139,26 @@
"command": "metadataViewer.openXml",
"group": "xml",
"when": "viewItem"
},
{
"command": "metadataViewer.openPredefinedData",
"group": "bsl",
"when": "viewItem =~ /predefined/"
}
]
},
"configuration": []
"configuration": [
{
"title": "1C Metadata Viewer",
"properties": {
"metadataViewer.searchDepth": {
"type": "integer",
"default": 3,
"description": "%1c-metadata-viewer.searchDepth.title%"
}
}
}
]
},
"scripts": {
"vscode:prepublish": "npm run compile",
@ -156,6 +176,7 @@
"typescript": "^4.8.4"
},
"dependencies": {
"fast-glob": "^3.2.12",
"xml2js": "^0.4.23"
}
}

View File

@ -9,5 +9,7 @@
"1c-metadata-viewer.openCommandModule.title": "Open command module",
"1c-metadata-viewer.openRecordSetModule.title": "Open record set module",
"1c-metadata-viewer.openValueManagerModule.title": "Open value manager module",
"1c-metadata-viewer.openXml.title": "Open XML"
"1c-metadata-viewer.openXml.title": "Open XML",
"1c-metadata-viewer.openPredefinedData.title": "Open predefined data",
"1c-metadata-viewer.searchDepth.title": "The number of nesting levels of directories in which 1C:Enterprise configurations are searched"
}

View File

@ -9,5 +9,7 @@
"1c-metadata-viewer.openCommandModule.title": "Открыть модуль команды",
"1c-metadata-viewer.openRecordSetModule.title": "Открыть модуль набора записей",
"1c-metadata-viewer.openValueManagerModule.title": "Открыть модуль менеджера значения",
"1c-metadata-viewer.openXml.title": "Открыть XML"
"1c-metadata-viewer.openXml.title": "Открыть XML",
"1c-metadata-viewer.openPredefinedData.title": "Открыть предопределенные данные",
"1c-metadata-viewer.searchDepth.title": "Количество уровней вложенности каталогов в которых осуществляется поиск конфигураций 1С:Предприятия"
}

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{opacity:0;fill:#F6F6F6;} .icon-vs-bg{fill:#656565;} .icon-vs-fg{fill:#F0EFF1;}</style>
<path class="icon-vs-fg" d="M20.95 31.95 35.4 17.5l-2.15-2.15-12.3 12.3L15 21.7l-2.15 2.15ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 473 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{opacity:0;fill:#F6F6F6;} .icon-vs-bg{fill:#656565;} .icon-vs-fg{fill:#F0EFF1;}</style>
<path class="icon-vs-fg" d="m24.5 28.85 11.4-11.4-2.1-2.05-9.25 9.3-4.85-4.85-2.1 2.1ZM13 38q-1.2 0-2.1-.9-.9-.9-.9-2.1V7q0-1.2.9-2.1.9-.9 2.1-.9h28q1.2 0 2.1.9.9.9.9 2.1v28q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h28V7H13v28Zm-6 9q-1.2 0-2.1-.9Q4 42.2 4 41V10h3v31h31v3Zm6-37v28V7Z"/>
</svg>

After

Width:  |  Height:  |  Size: 519 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{opacity:0;fill:#F6F6F6;} .icon-vs-bg{fill:#656565;} .icon-vs-fg{fill:#F0EFF1;}</style>
<path class="icon-vs-fg" d="M7.05 40q-1.2 0-2.1-.925-.9-.925-.9-2.075V11q0-1.15.9-2.075Q5.85 8 7.05 8h14l3 3h17q1.15 0 2.075.925.925.925.925 2.075v23q0 1.15-.925 2.075Q42.2 40 41.05 40Zm0-29v26h34V14H22.8l-3-3H7.05Zm0 0v26Z"/>
</svg>

After

Width:  |  Height:  |  Size: 472 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M20.95 31.95 35.4 17.5l-2.15-2.15-12.3 12.3L15 21.7l-2.15 2.15ZM9 42q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h30q1.2 0 2.1.9.9.9.9 2.1v30q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h30V9H9v30ZM9 9v30V9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 440 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="m24.5 28.85 11.4-11.4-2.1-2.05-9.25 9.3-4.85-4.85-2.1 2.1ZM13 38q-1.2 0-2.1-.9-.9-.9-.9-2.1V7q0-1.2.9-2.1.9-.9 2.1-.9h28q1.2 0 2.1.9.9.9.9 2.1v28q0 1.2-.9 2.1-.9.9-2.1.9Zm0-3h28V7H13v28Zm-6 9q-1.2 0-2.1-.9Q4 42.2 4 41V10h3v31h31v3Zm6-37v28V7Z"/>
</svg>

After

Width:  |  Height:  |  Size: 486 B

View File

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48">
<style>.icon-canvas-transparent{opacity:0;fill:#2d2d30}.icon-vs-out{fill:#2d2d30}.icon-vs-bg{fill:#c5c5c5}.icon-vs-fg{fill:#2b282e}</style>
<path class="icon-vs-fg" d="M7.05 40q-1.2 0-2.1-.925-.9-.925-.9-2.075V11q0-1.15.9-2.075Q5.85 8 7.05 8h14l3 3h17q1.15 0 2.075.925.925.925.925 2.075v23q0 1.15-.925 2.075Q42.2 40 41.05 40Zm0-29v26h34V14H22.8l-3-3H7.05Zm0 0v26Z"/>
</svg>

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -5,52 +5,49 @@ import { MetadataView, TreeItem } from './metadataView';
import * as fs from 'fs';
export function activate(context: vscode.ExtensionContext) {
const rootPath = (vscode.workspace.workspaceFolders && (vscode.workspace.workspaceFolders.length > 0))
? vscode.workspace.workspaceFolders[0].uri.fsPath : undefined;
vscode.commands.registerCommand('metadataViewer.openAppModule', (node: TreeItem) => {
const filePath = rootPath + '/Ext/ManagedApplicationModule.bsl';
const filePath = node.path + '/Ext/ManagedApplicationModule.bsl';
OpenFile(filePath);
});
vscode.commands.registerCommand('metadataViewer.openSessionModule', (node: TreeItem) => {
const filePath = rootPath + '/Ext/SessionModule.bsl';
const filePath = node.path + '/Ext/SessionModule.bsl';
OpenFile(filePath);
});
vscode.commands.registerCommand('metadataViewer.openExternalConnectionModule', (node: TreeItem) => {
// TODO: Имя модуля проверить. Может быть не верным.
const filePath = rootPath + '/Ext/ExternalConnectionModule.bsl';
const filePath = node.path + '/Ext/ExternalConnectionModule.bsl';
OpenFile(filePath);
});
vscode.commands.registerCommand('metadataViewer.openObjectModule', (node: TreeItem) => {
const filePath = rootPath + '/' + node.path + '/Ext/ObjectModule.bsl';
const filePath = node.path + '/Ext/ObjectModule.bsl';
OpenFile(filePath);
});
vscode.commands.registerCommand('metadataViewer.openManagerModule', (node: TreeItem) => {
const filePath = rootPath + '/' + node.path + '/Ext/ManagerModule.bsl';
const filePath = node.path + '/Ext/ManagerModule.bsl';
OpenFile(filePath);
});
vscode.commands.registerCommand('metadataViewer.openForm', (node: TreeItem) => {
const filePath = rootPath + '/' + node.path + '/Forms/' + node.label + '/Ext/Form/Module.bsl';
const filePath = node.path + '/Ext/Form/Module.bsl';
OpenFile(filePath);
});
vscode.commands.registerCommand('metadataViewer.openModule', (node: TreeItem) => {
const filePath = rootPath + '/CommonModules/' + node.label + '/Ext/Module.bsl';
const filePath = node.path + '/Ext/Module.bsl';
OpenFile(filePath);
});
vscode.commands.registerCommand('metadataViewer.openCommandModule', (node: TreeItem) => {
const filePath = rootPath + '/' + node.path + '/Commands/' + node.label + '/Ext/CommandModule.bsl';
const filePath = node.path + '/Ext/CommandModule.bsl';
OpenFile(filePath);
});
vscode.commands.registerCommand('metadataViewer.openRecordSetModule', (node: TreeItem) => {
const filePath = rootPath + '/' + node.path + '/Ext/RecordSetModule.bsl';
const filePath = node.path + '/Ext/RecordSetModule.bsl';
OpenFile(filePath);
});
vscode.commands.registerCommand('metadataViewer.openValueManagerModule', (node: TreeItem) => {
const filePath = rootPath + '/Constants/' + node.label + '/Ext/ValueManagerModule.bsl';
const filePath = node.path + '/Ext/ValueManagerModule.bsl';
OpenFile(filePath);
});
vscode.commands.registerCommand('metadataViewer.openXml', (node: TreeItem) => {
const filePath = rootPath + '/' + node.path + '.xml';
const filePath = node.path + '.xml';
OpenFile(filePath);
});

View File

@ -1,4 +1,5 @@
import * as fs from 'fs';
import * as glob from 'fast-glob';
import * as vscode from 'vscode';
import * as xml2js from 'xml2js';
import { posix } from 'path';
@ -6,6 +7,8 @@ import * as path from 'path';
import { MetadataFile, ObjectMetadata, ObjectParams, VersionMetadata } from './metadataInterfaces';
import { TemplatePanel } from './templatePanel';
import { TemplateFile } from './templatInterfaces';
import { PredefinedDataFile } from './predefinedDataInterfaces';
import { PredefinedDataPanel } from './predefinedDataPanel';
interface MetadataDictionaries {
form: { [key: string]: TreeItem[] },
@ -26,8 +29,15 @@ interface MetadataObjects {
report: TreeItem[],
dataProcessor: TreeItem[],
сhartOfCharacteristicTypes: TreeItem[],
chartOfAccounts: TreeItem[],
chartOfCalculationTypes: TreeItem[],
informationRegister: TreeItem[],
accumulationRegister: TreeItem[],
accountingRegister: TreeItem[],
calculationRegister: TreeItem[],
businessProcess: TreeItem[],
task: TreeItem[],
externalDataSource: TreeItem[],
}
type IconType = 'common' | 'subsystem' | 'commonModule' | 'sessionParameter' | 'role' | 'attribute' |
@ -35,7 +45,8 @@ type IconType = 'common' | 'subsystem' | 'commonModule' | 'sessionParameter' | '
'dataProcessor' | 'chartsOfCharacteristicType' | 'chartsOfAccount' | 'chartsOfCalculationType' |
'informationRegister' | 'accumulationRegister' | 'tabularSection' | 'form' | 'command' |
'template' | 'dimension' | 'resource' | 'column' | 'task' | 'businessProcess' | 'externalDataSource' |
'accountingRegister' | 'calculationRegister' | 'filterCriteria' | 'eventSubscription' | 'scheduledJob';
'accountingRegister' | 'calculationRegister' | 'filterCriteria' | 'eventSubscription' | 'scheduledJob' |
'accountingFlag' | 'extDimensionAccountingFlag';
interface TreeItemParams {
icon?: IconType,
@ -51,14 +62,19 @@ export class TreeItem extends vscode.TreeItem {
id: string;
children: TreeItem[] | undefined;
path?: string;
parentId = '';
isConfiguration = false;
constructor(id: string, label: string, children?: TreeItem[]) {
super(
label,
children === undefined ?
vscode.TreeItemCollapsibleState.None :
vscode.TreeItemCollapsibleState.Collapsed);
id === 'configurations' ?
vscode.TreeItemCollapsibleState.Expanded :
vscode.TreeItemCollapsibleState.Collapsed);
this.id = id;
children?.forEach(ch => ch.parentId = id);
this.children = children;
}
}
@ -68,12 +84,18 @@ export class MetadataView {
const view = vscode.window.createTreeView('metadataView', { treeDataProvider: NodeWithIdTreeDataProvider(), showCollapseAll: true });
context.subscriptions.push(view);
view.onDidExpandElement(e => {
this.expand(e.element);
});
vscode.workspace.workspaceFolders?.map(folder => {
const folderUri = folder.uri;
LoadAndParseConfigurationXml(folderUri);
view.reveal(tree[0]);
});
vscode.commands.registerCommand('metadataViewer.showTemplate', (template) => this.openTemplate(context, template));
vscode.commands.registerCommand('metadataViewer.openPredefinedData', (item) => this.openPredefinedData(context, item));
}
private openTemplate(context: vscode.ExtensionContext, template: ObjectParams): void {
@ -98,75 +120,116 @@ export class MetadataView {
});
}
}
private openPredefinedData(context: vscode.ExtensionContext, item: TreeItem): void {
const rootPath = (vscode.workspace.workspaceFolders && (vscode.workspace.workspaceFolders.length > 0))
? vscode.workspace.workspaceFolders[0].uri : undefined;
if (rootPath) {
const fileName = posix.join(rootPath.fsPath, item.path!, 'Ext/Predefined.xml');
if (!fs.existsSync(fileName)) {
PredefinedDataPanel.show(context.extensionUri, { Item: [] });
} else {
vscode.workspace.fs.readFile(rootPath.with({ path: fileName }))
.then(configXml => {
xml2js.parseString(configXml, (err, result) => {
if (err) {
console.error(err);
return;
}
const typedResult = result as PredefinedDataFile;
PredefinedDataPanel.show(context.extensionUri, typedResult.PredefinedData);
});
});
}
}
}
private expand(element: TreeItem) {
if (!element.isConfiguration) {
return;
}
const rootPath = (vscode.workspace.workspaceFolders && (vscode.workspace.workspaceFolders.length > 0))
? vscode.workspace.workspaceFolders[0].uri : undefined;
if (rootPath) {
vscode.workspace.fs.readFile(rootPath.with({ path: posix.join(element.id, 'ConfigDumpInfo.xml') }))
.then(configXml => {
xml2js.parseString(configXml, (err, result) => {
if (err) {
console.error(err);
return;
}
const typedResult = result as MetadataFile;
CreateTreeElements(element, typedResult);
});
});
}
}
}
const tree: TreeItem[] = [
GetTreeItem({ $: { id: 'configuration', name: 'Конфигурация' } }, { path: 'Configuration', context: 'main', children: [
GetTreeItem({ $: { id: 'common', name: 'Общие' } }, { icon: 'common', children: [
GetTreeItem({ $: { id: 'subsystems', name: 'Подсистемы' } }, { icon: 'subsystem', children: [] }),
GetTreeItem({ $: { id: 'commonModules', name: 'Общие модули' } }, { icon: 'commonModule', children: [] }),
GetTreeItem({ $: { id: 'sessionParameters', name: 'Параметры сеанса' } }, { icon: 'sessionParameter', children: [] }),
GetTreeItem({ $: { id: 'roles', name: 'Роли' } }, { icon: 'role', children: [] }),
GetTreeItem({ $: { id: 'commonAttributes', name: 'Общие реквизиты' } }, { icon: 'attribute', children: [] }),
GetTreeItem({ $: { id: 'exchangePlans', name: 'Планы обмена' } }, { icon: 'exchangePlan', children: [] }),
GetTreeItem({ $: { id: 'filterCriteria', name: 'Критерии отбора' } }, { icon: 'filterCriteria', children: [] }),
GetTreeItem({ $: { id: 'eventSubscriptions', name: 'Подписки на события' } }, { icon: 'eventSubscription', children: [] }),
GetTreeItem({ $: { id: 'scheduledJobs', name: 'Регламентные задания' } }, { icon: 'scheduledJob', children: [] }),
//GetTreeItem({ $: { id: '', name: 'Боты' } }, { children: [] }),
GetTreeItem({ $: { id: 'functionalOptions', name: 'Функциональные опции' } }, { children: [] }),
GetTreeItem({ $: { id: 'functionalOptionsParameters', name: 'Параметры функциональных опций' } }, { children: [] }),
GetTreeItem({ $: { id: 'definedTypes', name: 'Определяемые типы' } }, { children: [] }),
GetTreeItem({ $: { id: 'settingsStorages', name: 'Хранилища настроек' } }, { children: [] }),
GetTreeItem({ $: { id: 'commonCommands', name: 'Общие команды' } }, { children: [] }),
GetTreeItem({ $: { id: 'commandGroups', name: 'Группы команд' } }, { children: [] }),
GetTreeItem({ $: { id: 'commonForms', name: 'Общие формы' } }, { children: [] }),
GetTreeItem({ $: { id: 'commonTemplates', name: 'Общие макеты' } }, { children: [] }),
GetTreeItem({ $: { id: 'commonPictures', name: 'Общие картинки' } }, { children: [] }),
GetTreeItem({ $: { id: 'xdtoPackages', name: 'XDTO-пакеты' } }, { children: [] }),
GetTreeItem({ $: { id: 'webServices', name: 'Web-сервисы' } }, { children: [] }),
GetTreeItem({ $: { id: 'httpServices', name: 'HTTP-сервисы' } }, { children: [] }),
GetTreeItem({ $: { id: 'wsReferences', name: 'WS-ссылки' } }, { children: [] }),
//GetTreeItem({ $: { id: '', name: 'Сервисы интеграции' } }, { children: [] }),
GetTreeItem({ $: { id: 'styleItems', name: 'Элементы стиля' } }, { children: [] }),
//GetTreeItem({ $: { id: '', name: 'Стили' } }, { children: [] }),
GetTreeItem({ $: { id: 'languages', name: 'Языки' } }, { children: [] }),
]}),
GetTreeItem({ $: { id: 'constants', name: 'Константы' } }, { icon: 'constant', children: [] }),
GetTreeItem({ $: { id: 'catalogs', name: 'Справочники' } }, { icon: 'catalog', children: [] }),
GetTreeItem({ $: { id: 'documents', name: 'Документы' } }, { icon: 'document', children: [
GetTreeItem({ $: { id: 'documentNumerators', name: 'Нумераторы' } }, { children: [] }),
GetTreeItem({ $: { id: 'sequences', name: 'Последовательности' } }, { children: [] }),
]}),
GetTreeItem({ $: { id: 'documentJournals', name: 'Журналы документов' } }, { icon: 'documentJournal', children: [] }),
GetTreeItem({ $: { id: 'enums', name: 'Перечисления' } }, { icon: 'enum', children: [] }),
GetTreeItem({ $: { id: 'reports', name: 'Отчеты' } }, { icon: 'report', children: [] }),
GetTreeItem({ $: { id: 'dataProcessors', name: 'Обработки' } }, { icon: 'dataProcessor', children: [] }),
GetTreeItem({ $: { id: 'chartsOfCharacteristicTypes', name: 'Планы видов характеристик' } }, { icon: 'chartsOfCharacteristicType', children: [] }),
GetTreeItem({ $: { id: 'chartsOfAccounts', name: 'Планы счетов' } }, { icon: 'chartsOfAccount', children: [] }),
GetTreeItem({ $: { id: 'chartsOfCalculationTypes', name: 'Планы видов расчета' } }, { icon: 'chartsOfCalculationType', children: [] }),
GetTreeItem({ $: { id: 'informationRegisters', name: 'Регистры сведений' } }, { icon: 'informationRegister', children: [] }),
GetTreeItem({ $: { id: 'accumulationRegisters', name: 'Регистры накопления' } }, { icon: 'accumulationRegister', children: [] }),
GetTreeItem({ $: { id: 'accountingRegisters', name: 'Регистры бухгалтерии', } }, { icon: 'accountingRegister', children: [] }),
GetTreeItem({ $: { id: 'calculationRegisters', name: 'Регистры расчета', } }, { icon: 'calculationRegister', children: [] }),
GetTreeItem({ $: { id: 'businessProcesses', name: 'Бизнес-процессы', } }, { icon: 'businessProcess', children: [] }),
GetTreeItem({ $: { id: 'tasks', name: 'Задачи', } }, { icon: 'task', children: [] }),
GetTreeItem({ $: { id: 'externalDataSources', name: 'Внешние источники данных', } }, { icon: 'externalDataSource', children: [] }),
]}),
GetTreeItem('configurations', 'Конфигурации', { children: [] })
];
function LoadAndParseConfigurationXml(uri: vscode.Uri) {
vscode.workspace.fs.readFile(uri.with({ path: posix.join(uri.path, 'ConfigDumpInfo.xml') }))
.then(configXml => {
xml2js.parseString(configXml, (err, result) => {
const typedResult = result as MetadataFile;
CreateTreeElements(typedResult);
});
});
console.time('glob');
const files = glob.sync([ '**/ConfigDumpInfo.xml', '**/Configuration.xml' ], {
dot: true,
cwd: uri.fsPath,
absolute: true,
deep: vscode.workspace.getConfiguration().get('metadataViewer.searchDepth'),
});
console.timeEnd('glob');
const configurations = files.reduce<{ [key: string]: string[] }>((previous, current) => {
const key = current.split('/').slice(0, -1).join('/');
if (!previous[key]) {
previous[key] = [];
}
previous[key].push(current);
return previous;
}, {});
const filtered = Object
.keys(configurations)
.filter(f => configurations[f].length === 2);
filtered.forEach(fc => {
vscode.workspace.fs.readFile(uri.with({ path: posix.join(fc, 'Configuration.xml') }))
.then(configXml => {
xml2js.parseString(configXml, (err, result) => {
if (err) {
console.error(err);
return;
}
let synonym = result.MetaDataObject.Configuration[0].Properties[0].Synonym[0]["v8:item"][0]["v8:content"][0];
if (!synonym) {
synonym = result.MetaDataObject.Configuration[0].Properties[0].Name[0];
}
console.log(`Конфигурация ${synonym} найдена`);
const treeItem = new TreeItem(fc, `${synonym} (${fc})`, CreateMetadata(fc));
treeItem.contextValue = 'main';
treeItem.path = fc;
treeItem.isConfiguration = true;
tree[0].children?.push(treeItem);
});
});
});
}
function CreateTreeElements(metadataFile: MetadataFile) {
function CreateTreeElements(element: TreeItem, metadataFile: MetadataFile) {
const versionMetadata = metadataFile.ConfigDumpInfo.ConfigVersions[0].Metadata;
const treeItemIdSlash = element.id + '/';
console.time('reduce');
const attributeReduceResult = versionMetadata.reduce<MetadataDictionaries>((previous, current) => {
const objectName = current.$.name.split('.').slice(0,2).join('.');
@ -174,17 +237,28 @@ function CreateTreeElements(metadataFile: MetadataFile) {
if (!previous.form[objectName]) {
previous.form[objectName] = [];
}
previous.form[objectName].push(GetTreeItem(current, {
icon: 'form', path: `${CreatePath(objectName)}/Forms/${current.$.name.split('.').pop()}`, context: 'form' }));
previous.form[objectName].push(GetTreeItem(
treeItemIdSlash + current.$.id,
current.$.name,
{
icon: 'form',
context: 'form',
path: `${element.id}/${CreatePath(objectName)}/Forms/${current.$.name.split('.').pop()}`,
}));
} else if (current.$.name.includes('.Template.') && !current.$.name.endsWith('.Template')) {
if (!previous.template[objectName]) {
previous.template[objectName] = [];
}
previous.template[objectName].push(GetTreeItem(current, {
icon: 'template',
command: 'metadataViewer.showTemplate',
commandTitle: 'Show template',
commandArguments: [ current.$ ] }));
previous.template[objectName].push(GetTreeItem(
treeItemIdSlash + current.$.id,
current.$.name,
{
icon: 'template',
command: 'metadataViewer.showTemplate',
commandTitle: 'Show template',
commandArguments: [ current.$ ],
path: `${element.id}/${CreatePath(objectName)}/Templates/${current.$.name.split('.').pop()}`,
}));
}
return previous;
}, { form: {}, template: {} });
@ -193,47 +267,152 @@ function CreateTreeElements(metadataFile: MetadataFile) {
if (current.$.name.split('.').length !== 2) {
return previous;
}
if (current.$.name.startsWith('CommonModule.')) {
previous.commonModule.push(GetTreeItem(current, { icon: 'commonModule', context: 'module' }));
} else if (current.$.name.startsWith('SessionParameter.')) {
previous.sessionParameter.push(GetTreeItem(current, { icon: 'sessionParameter' }));
} else if (current.$.name.startsWith('Role.')) {
previous.role.push(GetTreeItem(current, { icon: 'role' }));
} else if (current.$.name.startsWith('CommonAttribute.')) {
previous.commonAttribute.push(GetTreeItem(current, { icon: 'attribute' }));
} else if (current.$.name.startsWith('ExchangePlan.')) {
previous.exchangePlan.push(GetTreeItem(current,
{ icon: 'exchangePlan', context: 'object_and_manager', children: FillObjectItemsByMetadata(current, attributeReduceResult) }));
} if (current.$.name.startsWith('Constant.')) {
previous.constant.push(GetTreeItem(current, { icon: 'constant', context: 'valueManager_and_manager' }));
} if (current.$.name.startsWith('Catalog.')) {
previous.catalog.push(GetTreeItem(current, {
icon: 'catalog', context: 'object_and_manager', children: FillObjectItemsByMetadata(current, attributeReduceResult ) }));
} else if (current.$.name.startsWith('Document.')) {
previous.document.push(GetTreeItem(current, {
icon: 'document', context: 'object_and_manager', children: FillObjectItemsByMetadata(current, attributeReduceResult ) }));
} else if (current.$.name.startsWith('DocumentJournal.')) {
previous.documentJournal.push(GetTreeItem(current, {
icon: 'documentJournal', context: 'manager', children: FillDocumentJournalItemsByMetadata(current, attributeReduceResult ) }));
} if (current.$.name.startsWith('Enum.')) {
previous.enum.push(GetTreeItem(current, {
icon: 'enum', context: 'manager', children: FillEnumItemsByMetadata(current, attributeReduceResult) }));
} else if (current.$.name.startsWith('Report.')) {
previous.report.push(GetTreeItem(current, {
icon: 'report', context: 'object_and_manager', children: FillObjectItemsByMetadata(current, attributeReduceResult) }));
} else if (current.$.name.startsWith('DataProcessor.')) {
previous.dataProcessor.push(GetTreeItem(current, {
icon: 'dataProcessor', context: 'object_and_manager', children: FillObjectItemsByMetadata(current, attributeReduceResult) }));
} else if (current.$.name.startsWith('ChartOfCharacteristicTypes.')) {
previous.сhartOfCharacteristicTypes.push(GetTreeItem(current, {
icon: 'chartsOfCharacteristicType', context: 'object_and_manager', children: FillObjectItemsByMetadata(current, attributeReduceResult) }));
} else if (current.$.name.startsWith('InformationRegister')) {
previous.informationRegister.push(GetTreeItem(current, {
icon: 'informationRegister', context: 'recordset_and_manager', children: FillRegisterItemsByMetadata(current, attributeReduceResult ) }));
} else if (current.$.name.startsWith('AccumulationRegister')) {
previous.accumulationRegister.push(GetTreeItem(current, {
icon: 'accumulationRegister', context: 'recordset_and_manager', children: FillRegisterItemsByMetadata(current, attributeReduceResult ) }));
}
const treeItemId = treeItemIdSlash + current.$.id;
const treeItemPath = `${treeItemIdSlash}${CreatePath(current.$.name)}`;
switch (true) {
case current.$.name.startsWith('CommonModule.'):
previous.commonModule.push(GetTreeItem(
treeItemId, current.$.name,
{ icon: 'commonModule', context: 'module', path: treeItemPath, }));
break;
case current.$.name.startsWith('SessionParameter.'):
previous.sessionParameter.push(GetTreeItem(treeItemId, current.$.name, { icon: 'sessionParameter' }));
break;
case current.$.name.startsWith('Role.'):
previous.role.push(GetTreeItem(treeItemId, current.$.name, { icon: 'role' }));
break;
case current.$.name.startsWith('CommonAttribute.'):
previous.commonAttribute.push(GetTreeItem(treeItemId, current.$.name, { icon: 'attribute' }));
break;
case current.$.name.startsWith('ExchangePlan.'):
previous.exchangePlan.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'exchangePlan', context: 'object_and_manager', path: treeItemPath,
children: FillObjectItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('Constant.'):
previous.constant.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'constant', context: 'valueManager_and_manager', path: treeItemPath, }));
break;
case current.$.name.startsWith('Catalog.'):
previous.catalog.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'catalog', context: 'object_and_manager_and_predefined', path: treeItemPath,
children: FillObjectItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('Document.'):
previous.document.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'document', context: 'object_and_manager', path: treeItemPath,
children: FillObjectItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('DocumentJournal.'):
previous.documentJournal.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'documentJournal', context: 'manager', path: treeItemPath,
children: FillDocumentJournalItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('Enum.'):
previous.enum.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'enum', context: 'manager', path: treeItemPath,
children: FillEnumItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('Report.'):
previous.report.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'report', context: 'object_and_manager', path: treeItemPath,
children: FillObjectItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('DataProcessor.'):
previous.dataProcessor.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'dataProcessor', context: 'object_and_manager', path: treeItemPath,
children: FillObjectItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('ChartOfCharacteristicTypes.'):
previous.сhartOfCharacteristicTypes.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'chartsOfCharacteristicType', context: 'object_and_manager_and_predefined', path: treeItemPath,
children: FillObjectItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('ChartOfAccounts.'):
previous.chartOfAccounts.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'chartsOfAccount', context: 'object_and_manager_and_predefined', path: treeItemPath,
children: FillChartOfAccountsItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('ChartOfCalculationTypes.'):
previous.chartOfCalculationTypes.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'chartsOfCalculationType', context: 'object_and_manager_and_predefined', path: treeItemPath,
children: FillObjectItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('InformationRegister.'):
previous.informationRegister.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'informationRegister', context: 'recordset_and_manager', path: treeItemPath,
children: FillRegisterItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('AccumulationRegister.'):
previous.accumulationRegister.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'accumulationRegister', context: 'recordset_and_manager', path: treeItemPath,
children: FillRegisterItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('AccountingRegister.'):
previous.accountingRegister.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'accountingRegister', context: 'recordset_and_manager', path: treeItemPath,
children: FillRegisterItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('CalculationRegister.'):
previous.calculationRegister.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'calculationRegister', context: 'recordset_and_manager', path: treeItemPath,
children: FillCalculationRegisterItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('BusinessProcess.'):
previous.businessProcess.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'businessProcess', context: 'object_and_manager', path: treeItemPath,
children: FillObjectItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('Task.'):
previous.task.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'task', context: 'object_and_manager', path: treeItemPath,
children: FillTaskItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
case current.$.name.startsWith('ExternalDataSource.'):
previous.externalDataSource.push(GetTreeItem(
treeItemId, current.$.name, {
icon: 'externalDataSource',
children: FillExternalDataSourceItemsByMetadata(treeItemIdSlash, current, attributeReduceResult) }));
break;
}
return previous;
}, {
@ -250,129 +429,201 @@ function CreateTreeElements(metadataFile: MetadataFile) {
report: [],
dataProcessor: [],
сhartOfCharacteristicTypes: [],
chartOfAccounts: [],
chartOfCalculationTypes: [],
informationRegister: [],
accumulationRegister: []
accumulationRegister: [],
accountingRegister: [],
calculationRegister: [],
businessProcess: [],
task: [],
externalDataSource: [],
});
SearchTree(tree[0], 'commonModules')!.children = reduceResult.commonModule;
SearchTree(tree[0], 'sessionParameters')!.children = reduceResult.sessionParameter;
SearchTree(tree[0], 'roles')!.children = reduceResult.role;
SearchTree(tree[0], 'commonAttributes')!.children = reduceResult.commonAttribute;
SearchTree(tree[0], 'exchangePlans')!.children = reduceResult.exchangePlan;
SearchTree(tree[0], 'constants')!.children = reduceResult.constant;
SearchTree(tree[0], 'catalogs')!.children = reduceResult.catalog;
SearchTree(element, element.id + '/commonModules')!.children = reduceResult.commonModule;
SearchTree(element, element.id + '/sessionParameters')!.children = reduceResult.sessionParameter;
SearchTree(element, element.id + '/roles')!.children = reduceResult.role;
SearchTree(element, element.id + '/commonAttributes')!.children = reduceResult.commonAttribute;
SearchTree(element, element.id + '/exchangePlans')!.children = reduceResult.exchangePlan;
SearchTree(element, element.id + '/constants')!.children = reduceResult.constant;
SearchTree(element, element.id + '/catalogs')!.children = reduceResult.catalog;
const documents = SearchTree(tree[0], 'documents');
const documents = SearchTree(element, element.id + '/documents');
documents!.children = [ ...documents!.children ?? [], ...reduceResult.document];
SearchTree(tree[0], 'documentJournals')!.children = reduceResult.documentJournal;
SearchTree(tree[0], 'enums')!.children = reduceResult.enum;
SearchTree(tree[0], 'reports')!.children = reduceResult.report;
SearchTree(tree[0], 'dataProcessors')!.children = reduceResult.dataProcessor;
SearchTree(tree[0], 'chartsOfCharacteristicTypes')!.children = reduceResult.сhartOfCharacteristicTypes;
SearchTree(tree[0], 'informationRegisters')!.children = reduceResult.informationRegister;
SearchTree(tree[0], 'accumulationRegisters')!.children = reduceResult.accumulationRegister;
SearchTree(element, element.id + '/documentJournals')!.children = reduceResult.documentJournal;
SearchTree(element, element.id + '/enums')!.children = reduceResult.enum;
SearchTree(element, element.id + '/reports')!.children = reduceResult.report;
SearchTree(element, element.id + '/dataProcessors')!.children = reduceResult.dataProcessor;
SearchTree(element, element.id + '/chartsOfCharacteristicTypes')!.children = reduceResult.сhartOfCharacteristicTypes;
SearchTree(element, element.id + '/chartsOfAccounts')!.children = reduceResult.chartOfAccounts;
SearchTree(element, element.id + '/chartsOfCalculationTypes')!.children = reduceResult.chartOfCalculationTypes;
SearchTree(element, element.id + '/informationRegisters')!.children = reduceResult.informationRegister;
SearchTree(element, element.id + '/accumulationRegisters')!.children = reduceResult.accumulationRegister;
SearchTree(element, element.id + '/accountingRegisters')!.children = reduceResult.accountingRegister;
SearchTree(element, element.id + '/calculationRegisters')!.children = reduceResult.calculationRegister;
SearchTree(element, element.id + '/businessProcesses')!.children = reduceResult.businessProcess;
SearchTree(element, element.id + '/tasks')!.children = reduceResult.task;
SearchTree(element, element.id + '/externalDataSources')!.children = reduceResult.externalDataSource;
console.timeEnd('reduce');
}
function FillObjectItemsByMetadata(versionMetadata: VersionMetadata, objectData: MetadataDictionaries): TreeItem[] {
function FillObjectItemsByMetadata(idPrefix: string, versionMetadata: VersionMetadata, objectData: MetadataDictionaries): TreeItem[] {
const attributes = (versionMetadata
.Metadata ?? [])
.filter(m => m.$.name.startsWith(versionMetadata.$.name + '.Attribute.'))
.map(m => GetTreeItem(m, { icon: 'attribute' }));
.map(m => GetTreeItem(idPrefix + m.$.id, m.$.name, { icon: 'attribute' }));
const tabularSection = (versionMetadata.Metadata ?? [])
.filter(m => m.$.name.startsWith(versionMetadata.$.name + '.TabularSection.') && !m.$.name.includes('.Attribute.'))
.map(m => GetTreeItem(m, {
.map(m => GetTreeItem(idPrefix + m.$.id, m.$.name, {
icon: 'tabularSection',
// TODO: undefined for children if length eq zero
children: (versionMetadata.Metadata ?? [])
.filter(f => f.$.name.startsWith(versionMetadata.$.name + '.TabularSection.' + m.$.name.split('.').pop()) && f.$.name.includes('.Attribute.'))
.map(f => GetTreeItem(f, { icon: 'attribute' })) }));
.map(f => GetTreeItem(idPrefix + f.$.id, f.$.name, { icon: 'attribute' })) }));
const items = [
GetTreeItem({ $: { id: '', name: 'Реквизиты'}}, { icon: 'attribute', children: attributes.length === 0 ? undefined : attributes }),
GetTreeItem({ $: { id: '', name: 'Табличные части'}}, { icon: 'tabularSection', children: tabularSection }),
GetTreeItem('', 'Реквизиты', { icon: 'attribute', children: attributes.length === 0 ? undefined : attributes }),
GetTreeItem('', 'Табличные части', { icon: 'tabularSection', children: tabularSection }),
];
return [ ...items, ...FillCommonItems(versionMetadata, objectData) ];
return [ ...items, ...FillCommonItems(idPrefix , versionMetadata, objectData) ];
}
function FillDocumentJournalItemsByMetadata(versionMetadata: VersionMetadata, objectData: MetadataDictionaries): TreeItem[] {
function FillDocumentJournalItemsByMetadata(idPrefix: string, versionMetadata: VersionMetadata, objectData: MetadataDictionaries): TreeItem[] {
const columns = (versionMetadata
.Metadata ?? [])
.filter(m => m.$.name.startsWith(versionMetadata.$.name + '.Column.'))
.map(m => GetTreeItem(m, { icon: 'column' }));
.map(m => GetTreeItem(idPrefix + m.$.id, m.$.name, { icon: 'column' }));
const items = [
GetTreeItem({ $: { id: '', name: 'Графы'}}, { icon: 'column', children: columns.length === 0 ? undefined : columns }),
GetTreeItem('', 'Графы', { icon: 'column', children: columns.length === 0 ? undefined : columns }),
];
return [ ...items, ...FillCommonItems(versionMetadata, objectData) ];
return [ ...items, ...FillCommonItems(idPrefix, versionMetadata, objectData) ];
}
function FillEnumItemsByMetadata(versionMetadata: VersionMetadata, objectData: MetadataDictionaries): TreeItem[] {
function FillEnumItemsByMetadata(idPrefix: string, versionMetadata: VersionMetadata, objectData: MetadataDictionaries): TreeItem[] {
const values = (versionMetadata
.Metadata ?? [])
.filter(m => m.$.name.startsWith('Enum.'))
.map(m => GetTreeItem(m, { icon: 'attribute' }));
.map(m => GetTreeItem(idPrefix + m.$.id, m.$.name, { icon: 'attribute' }));
const items = [
GetTreeItem({ $: { id: '', name: 'Значения'}}, { icon: 'attribute', children: values.length === 0 ? undefined : values }),
GetTreeItem('', 'Значения', { icon: 'attribute', children: values.length === 0 ? undefined : values }),
];
return [ ...items, ...FillCommonItems(versionMetadata, objectData) ];
return [ ...items, ...FillCommonItems(idPrefix, versionMetadata, objectData) ];
}
function FillRegisterItemsByMetadata(versionMetadata: VersionMetadata, objectData: MetadataDictionaries): TreeItem[] {
function FillChartOfAccountsItemsByMetadata(idPrefix: string, versionMetadata: VersionMetadata, objectData: MetadataDictionaries): TreeItem[] {
const accountingFlags = (versionMetadata
.Metadata ?? [])
.filter(m => m.$.name.startsWith(versionMetadata.$.name + '.AccountingFlag.'))
.map(m => GetTreeItem(idPrefix + m.$.id, m.$.name, { icon: 'accountingFlag' }));
const extDimensionAccountingFlag = (versionMetadata
.Metadata ?? [])
.filter(m => m.$.name.startsWith(versionMetadata.$.name + '.ExtDimensionAccountingFlag.'))
.map(m => GetTreeItem(idPrefix + m.$.id, m.$.name, { icon: 'extDimensionAccountingFlag' }));
const items = [
GetTreeItem('', 'Признаки учета', { icon: 'accountingFlag', children: accountingFlags.length === 0 ? undefined : accountingFlags }),
GetTreeItem('', 'Признаки учета субконто', {
icon: 'extDimensionAccountingFlag', children: extDimensionAccountingFlag.length === 0 ? undefined : extDimensionAccountingFlag }),
];
return [ ...items, ...FillObjectItemsByMetadata(idPrefix, versionMetadata, objectData) ]
.sort((x, y) => { return x.label == "Реквизиты" ? -1 : y.label == "Реквизиты" ? 1 : 0; });
}
function FillRegisterItemsByMetadata(idPrefix: string, versionMetadata: VersionMetadata, objectData: MetadataDictionaries): TreeItem[] {
const dimensions = (versionMetadata
.Metadata ?? [])
.filter(m => m.$.name.startsWith(versionMetadata.$.name + '.Dimension.'))
.map(m => GetTreeItem(m, { icon: 'dimension' }));
.map(m => GetTreeItem(idPrefix + m.$.id, m.$.name, { icon: 'dimension' }));
const resources = (versionMetadata
.Metadata ?? [])
.filter(m => m.$.name.startsWith(versionMetadata.$.name + '.Resource.'))
.map(m => GetTreeItem(m, { icon: 'resource' }));
.map(m => GetTreeItem(idPrefix + m.$.id, m.$.name, { icon: 'resource' }));
const attributes = (versionMetadata
.Metadata ?? [])
.filter(m => m.$.name.startsWith(versionMetadata.$.name + '.Attribute.'))
.map(m => GetTreeItem(m, { icon: 'attribute' }));
.map(m => GetTreeItem(idPrefix + m.$.id, m.$.name, { icon: 'attribute' }));
const items = [
GetTreeItem({ $: { id: '', name: 'Измерения'}}, { icon: 'dimension', children: dimensions.length === 0 ? undefined : dimensions }),
GetTreeItem({ $: { id: '', name: 'Ресурсы'}}, { icon: 'resource', children: resources.length === 0 ? undefined : resources }),
GetTreeItem({ $: { id: '', name: 'Реквизиты'}}, { icon: 'attribute', children: attributes.length === 0 ? undefined : attributes }),
GetTreeItem('', 'Измерения', { icon: 'dimension', children: dimensions.length === 0 ? undefined : dimensions }),
GetTreeItem('', 'Ресурсы', { icon: 'resource', children: resources.length === 0 ? undefined : resources }),
GetTreeItem('', 'Реквизиты', { icon: 'attribute', children: attributes.length === 0 ? undefined : attributes }),
];
return [ ...items, ...FillCommonItems(versionMetadata, objectData) ];
return [ ...items, ...FillCommonItems(idPrefix, versionMetadata, objectData) ];
}
function FillCommonItems(versionMetadata: VersionMetadata, objectData: MetadataDictionaries): TreeItem[] {
function FillCalculationRegisterItemsByMetadata(idPrefix: string, versionMetadata: VersionMetadata, objectData: MetadataDictionaries): TreeItem[] {
const items: TreeItem[] = [
// TODO: Перерасчеты
];
return [ ...items, ...FillRegisterItemsByMetadata(idPrefix, versionMetadata, objectData) ];
}
function FillTaskItemsByMetadata(idPrefix: string, versionMetadata: VersionMetadata, objectData: MetadataDictionaries): TreeItem[] {
const attributes = (versionMetadata
.Metadata ?? [])
.filter(m => m.$.name.startsWith(versionMetadata.$.name + '.AddressingAttribute.'))
.map(m => GetTreeItem(idPrefix + m.$.id, m.$.name, { icon: 'attribute' }));
const items = [
GetTreeItem('', 'Реквизиты адресации', { icon: 'attribute', children: attributes.length === 0 ? undefined : attributes }),
];
return [ ...items, ...FillObjectItemsByMetadata(idPrefix, versionMetadata, objectData) ]
.sort((x, y) => { return x.label == "Реквизиты" ? -1 : y.label == "Реквизиты" ? 1 : 0; });
}
function FillExternalDataSourceItemsByMetadata(idPrefix: string, versionMetadata: VersionMetadata, objectData: MetadataDictionaries): TreeItem[] {
const items: TreeItem[] = [
// TODO:
];
return items;
}
function FillCommonItems(idPrefix: string, versionMetadata: VersionMetadata, objectData: MetadataDictionaries): TreeItem[] {
const commands = (versionMetadata
.Metadata ?? [])
.filter(m => m.$.name.includes('.Command.'))
.map(m => GetTreeItem(m, { icon: 'command', context: 'command' }));
.map(m => GetTreeItem(
idPrefix + m.$.id,
m.$.name,
{
icon: 'command',
context: 'command',
path: `${idPrefix}${CreatePath(m.$.name)}/Commands/${m.$.name.split('.').pop()}`,
}));
return [
GetTreeItem({ $: { id: '', name: 'Формы'}}, { icon: 'form', children: objectData.form[versionMetadata.$.name] }),
GetTreeItem({ $: { id: '', name: 'Команды'}}, { icon: 'command', children: commands.length === 0 ? undefined : commands }),
GetTreeItem({ $: { id: '', name: 'Макеты'}}, { icon: 'template', children: objectData.template[versionMetadata.$.name] }),
GetTreeItem('', 'Формы', { icon: 'form', children: objectData.form[versionMetadata.$.name] }),
GetTreeItem('', 'Команды', { icon: 'command', children: commands.length === 0 ? undefined : commands }),
GetTreeItem('', 'Макеты', { icon: 'template', children: objectData.template[versionMetadata.$.name] }),
];
}
function GetTreeItem(element: ObjectMetadata, params?: TreeItemParams ): TreeItem {
const treeItem = new TreeItem(element.$.id, element.$.name.split('.').pop() ?? '', params?.children);
function GetTreeItem(id: string, name: string, params: TreeItemParams ): TreeItem {
const treeItem = new TreeItem(id, name.split('.').pop() ?? '', params?.children);
if (params?.icon) {
if (params.icon) {
treeItem.iconPath = getIconPath(params.icon);
}
if (params?.context) {
if (params.context) {
treeItem.contextValue = params.context;
}
treeItem.path = params?.path ?? CreatePath(element.$.name.split('.').slice(0,2).join('.'));
if (params?.command && params.commandTitle) {
treeItem.path = params.path;
if (params.command && params.commandTitle) {
treeItem.command = { command: params.command, title: params.commandTitle, arguments: params.commandArguments };
}
@ -392,6 +643,7 @@ function SearchTree(element: TreeItem, matchingId: string): TreeItem | null {
return null;
}
// TODO: Ужасная функция!!!1 Первая очередь на рефакторинг!
function CreatePath(name: string): string {
return name
.replace('CommonModule.', 'CommonModules/')
@ -403,10 +655,18 @@ function CreatePath(name: string): string {
.replace('Enum.', 'Enums/')
.replace('Report.', 'Reports/')
.replace('DataProcessor.', 'DataProcessors/')
.replace('ChartOfCharacteristicTypes.', 'ChartsOfCharacteristicTypes/')
.replace('ChartOfAccounts.', 'ChartsOfAccounts/')
.replace('ChartOfCalculationTypes.', 'ChartsOfCalculationTypes/')
.replace('InformationRegister.', 'InformationRegisters/')
.replace('AccumulationRegister.', 'AccumulationRegisters/')
.replace('AccountingRegister.', 'AccountingRegisters/')
.replace('CalculationRegister.', 'CalculationRegisters/')
.replace('BusinessProcess.', 'BusinessProcesses/')
.replace('Task.', 'Tasks/')
.replace('ExternalDataSource.', 'ExternalDataSources/')
.replace('.Template.', '/Templates/');
}
}
function NodeWithIdTreeDataProvider(): vscode.TreeDataProvider<TreeItem> {
return {
@ -419,10 +679,67 @@ function NodeWithIdTreeDataProvider(): vscode.TreeDataProvider<TreeItem> {
getTreeItem: (element: TreeItem): vscode.TreeItem | Thenable<vscode.TreeItem> => {
return element;
},
getParent(element: TreeItem): TreeItem | undefined{
return SearchTree(tree[0], element.parentId) ?? undefined;
},
};
}
function getIconPath(icon: string): string {
const isDark = vscode.window.activeColorTheme.kind === vscode.ColorThemeKind.Dark;
return path.join(__filename, '..', '..', 'resources', isDark ? 'dark' : 'light', icon + '.svg');
}
function CreateMetadata(idPrefix: string) {
return [
GetTreeItem(idPrefix + '/common', 'Общие', { icon: 'common', children: [
GetTreeItem(idPrefix + '/subsystems', 'Подсистемы', { icon: 'subsystem', children: [] }),
GetTreeItem(idPrefix + '/commonModules', 'Общие модули', { icon: 'commonModule', children: [] }),
GetTreeItem(idPrefix + '/sessionParameters', 'Параметры сеанса', { icon: 'sessionParameter', children: [] }),
GetTreeItem(idPrefix + '/roles', 'Роли', { icon: 'role', children: [] }),
GetTreeItem(idPrefix + '/commonAttributes', 'Общие реквизиты', { icon: 'attribute', children: [] }),
GetTreeItem(idPrefix + '/exchangePlans', 'Планы обмена', { icon: 'exchangePlan', children: [] }),
GetTreeItem(idPrefix + '/filterCriteria', 'Критерии отбора', { icon: 'filterCriteria', children: [] }),
GetTreeItem(idPrefix + '/eventSubscriptions', 'Подписки на события', { icon: 'eventSubscription', children: [] }),
GetTreeItem(idPrefix + '/scheduledJobs', 'Регламентные задания', { icon: 'scheduledJob', children: [] }),
//GetTreeItem(idPrefix + '', 'Боты', { children: [] }),
GetTreeItem(idPrefix + '/functionalOptions', 'Функциональные опции', { children: [] }),
GetTreeItem(idPrefix + '/functionalOptionsParameters', 'Параметры функциональных опций', { children: [] }),
GetTreeItem(idPrefix + '/definedTypes', 'Определяемые типы', { children: [] }),
GetTreeItem(idPrefix + '/settingsStorages', 'Хранилища настроек', { children: [] }),
GetTreeItem(idPrefix + '/commonCommands', 'Общие команды', { children: [] }),
GetTreeItem(idPrefix + '/commandGroups', 'Группы команд', { children: [] }),
GetTreeItem(idPrefix + '/commonForms', 'Общие формы', { children: [] }),
GetTreeItem(idPrefix + '/commonTemplates', 'Общие макеты', { children: [] }),
GetTreeItem(idPrefix + '/commonPictures', 'Общие картинки', { children: [] }),
GetTreeItem(idPrefix + '/xdtoPackages', 'XDTO-пакеты', { children: [] }),
GetTreeItem(idPrefix + '/webServices', 'Web-сервисы', { children: [] }),
GetTreeItem(idPrefix + '/httpServices', 'HTTP-сервисы', { children: [] }),
GetTreeItem(idPrefix + '/wsReferences', 'WS-ссылки', { children: [] }),
//GetTreeItem(idPrefix + '/', 'Сервисы интеграции', { children: [] }),
GetTreeItem(idPrefix + '/styleItems', 'Элементы стиля', { children: [] }),
//GetTreeItem(idPrefix + '/', 'Стили', { children: [] }),
GetTreeItem(idPrefix + '/languages', 'Языки', { children: [] }),
]}),
GetTreeItem(idPrefix + '/constants', 'Константы', { icon: 'constant', children: [] }),
GetTreeItem(idPrefix + '/catalogs', 'Справочники', { icon: 'catalog', children: [] }),
GetTreeItem(idPrefix + '/documents', 'Документы', { icon: 'document', children: [
GetTreeItem(idPrefix + '/documentNumerators', 'Нумераторы', { children: [] }),
GetTreeItem(idPrefix + '/sequences', 'Последовательности', { children: [] }),
]}),
GetTreeItem(idPrefix + '/documentJournals', 'Журналы документов', { icon: 'documentJournal', children: [] }),
GetTreeItem(idPrefix + '/enums', 'Перечисления', { icon: 'enum', children: [] }),
GetTreeItem(idPrefix + '/reports', 'Отчеты', { icon: 'report', children: [] }),
GetTreeItem(idPrefix + '/dataProcessors', 'Обработки', { icon: 'dataProcessor', children: [] }),
GetTreeItem(idPrefix + '/chartsOfCharacteristicTypes', 'Планы видов характеристик', { icon: 'chartsOfCharacteristicType', children: [] }),
GetTreeItem(idPrefix + '/chartsOfAccounts', 'Планы счетов', { icon: 'chartsOfAccount', children: [] }),
GetTreeItem(idPrefix + '/chartsOfCalculationTypes', 'Планы видов расчета', { icon: 'chartsOfCalculationType', children: [] }),
GetTreeItem(idPrefix + '/informationRegisters', 'Регистры сведений', { icon: 'informationRegister', children: [] }),
GetTreeItem(idPrefix + '/accumulationRegisters', 'Регистры накопления', { icon: 'accumulationRegister', children: [] }),
GetTreeItem(idPrefix + '/accountingRegisters', 'Регистры бухгалтерии', { icon: 'accountingRegister', children: [] }),
GetTreeItem(idPrefix + '/calculationRegisters', 'Регистры расчета', { icon: 'calculationRegister', children: [] }),
GetTreeItem(idPrefix + '/businessProcesses', 'Бизнес-процессы', { icon: 'businessProcess', children: [] }),
GetTreeItem(idPrefix + '/tasks', 'Задачи', { icon: 'task', children: [] }),
GetTreeItem(idPrefix + '/externalDataSources', 'Внешние источники данных', { icon: 'externalDataSource', children: [] }),
];
}

View File

@ -0,0 +1,15 @@
export interface PredefinedDataFile {
PredefinedData: PredefinedData;
}
export interface PredefinedData {
Item: PredefinedDataItem[];
}
export interface PredefinedDataItem {
ChildItems: PredefinedData[];
Code: string[];
Description: string[];
IsFolder: string[];
Name: string[];
}

View File

@ -0,0 +1,79 @@
import * as vscode from 'vscode';
import { PredefinedData, PredefinedDataItem } from './predefinedDataInterfaces';
export class PredefinedDataPanel {
public static readonly viewType = 'metadataViewer.predefinedPanel';
public static show(extensionUri: vscode.Uri, data: PredefinedData) {
const column = vscode.window.activeTextEditor
? vscode.window.activeTextEditor.viewColumn
: undefined;
const panel = vscode.window.createWebviewPanel(
PredefinedDataPanel.viewType,
"Предопределенные элементы",
column || vscode.ViewColumn.One
);
panel.webview.html = this._getHtmlForWebview(panel.webview, extensionUri, data);
}
private static _getHtmlForWebview(webview: vscode.Webview, extensionUri: vscode.Uri, data: PredefinedData) {
const styleUri = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, 'media', 'predefined', 'styles.css'));
// TODO: иконка catalog.svg для других предопределенных элементов должна быть другой
const isDark = vscode.window.activeColorTheme.kind === vscode.ColorThemeKind.Dark;
const rootImagePath = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, 'resources', isDark ? 'dark' : 'light', 'catalog.svg'));
const folderImagePath = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, 'resources', isDark ? 'dark' : 'light', 'folder.svg'));
const elementImagePath = webview.asWebviewUri(vscode.Uri.joinPath(extensionUri, 'resources', isDark ? 'dark' : 'light', 'attribute.svg'));
// TODO: разобраться с безопасностью ресурсов и переделать
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<link href="${styleUri}" rel="stylesheet" />
</style>
</head>
<body>
<table rules="all">
<thead>
<tr>
<th>Имя</th>
<th>Код</th>
<th>Наименование</th>
</tr>
</thead>
<tbody>
<tr><td colspan="3"><img src="${rootImagePath}" width="16px" height="16px" style="margin-bottom: 3px; vertical-align: middle;" />&nbsp;Элементы</td></tr>
${data.Item.map(i => CreateItem(i, [ folderImagePath, elementImagePath ], 1)).join('')}
</tbody>
</table>
</body>
</html>`;
}
}
function CreateItem(item: PredefinedDataItem, imageUri: vscode.Uri[], level: number): string {
return `<tr>
<td>${(() => {
if (item.IsFolder[0] === 'true') {
return `<img src="${imageUri[0]}" width="16px" height="16px" style="margin-left: ${16 * level}px; margin-bottom: 3px; vertical-align: middle;" />`;
} else {
return `<img src="${imageUri[1]}" width="16px" height="16px" style="margin-left: ${16 * level}px; margin-bottom: 3px; vertical-align: middle;" />`;
}
})()}&nbsp;${item.Name}</td>
<td>${item.Code}</td>
<td>${item.Description}</td>
</tr>
${(() => {
if (item.ChildItems) {
return item.ChildItems[0].Item.map(i => CreateItem(i, imageUri, level + 1)).join('');
}
return '';
})()}`;
}