From 7c765137dbb586804526433636a67b3b5c216e51 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sat, 6 Jun 2026 21:30:08 +0300 Subject: [PATCH] =?UTF-8?q?feat(form-decompile,form-compile):=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=D1=82=D0=B5=D0=BD=D1=82=20=D0=BA=D0=BE=D0=BC=D0=B0?= =?UTF-8?q?=D0=BD=D0=B4=D0=BD=D1=8B=D1=85=20=D0=BF=D0=B0=D0=BD=D0=B5=D0=BB?= =?UTF-8?q?=D0=B5=D0=B9=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=86=D1=8B=20?= =?UTF-8?q?=E2=80=94=20commandBar/contextMenu=20(companion=20tier=202)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Крупнейший левередж-кластер. Companion-панели элемента (AutoCommandBar/ContextMenu) теперь несут контент как СВОЙСТВА: - commandBar → (командная панель) - contextMenu → (контекстное меню) Значение: массив = shorthand для { children }; объект { autofill?, horizontalAlign?, children[] }. children — обычная грамматика button/buttonGroup/popup. Forgiving-синонимы (commandBar ← autoCommandBar/AutoCommandBar/autoCmdBar/cmdBar/ КоманднаяПанель; contextMenu ← ContextMenu/КонтекстноеМеню). Разведение «тип-элемент vs панель-свойство» — по ТИПУ значения: строка = элемент-тип в дереве (cmdBar:"Имя"), объект/массив = companion-панель этого элемента. Тип-синонимы применяются только к строковому значению. Механизм общий (любой элемент), декомпилятор захватывает в Decompile-Element, компилятор — Emit-CompanionPanel. Новый ключ кнопки commandName — глобальная команда «как есть» (CommonCommand.X, Catalog.X.Command.Y) без обёртки Form. (раньше попадала в command и ошибочно оборачивалась в Form.Command.). stdCommand/command без изменений. Декомпилятор: для дин-список-таблицы пустой AutoCommandBar(autofill=false) не пишет commandBar (восстановит heuristic) — без шума. tableAutofill остаётся shorthand, commandBar имеет приоритет. TOTAL diff lines выборки 2.17: 7560 → 5293 (-2267), match 11 → 13, cascade LOST 3414 → 1805. Table>ContextMenu/Table>AutoCommandBar ушли из топа impact. Снапшот table сертифицирован в 1С (8.3.24); регресс form-compile 33/33 зелёный на ps + python. decompile v0.29, compile v1.48. Co-Authored-By: Claude Opus 4.8 --- .../form-compile/scripts/form-compile.ps1 | 123 +++++++++++++++--- .../form-compile/scripts/form-compile.py | 106 +++++++++++++-- .../form-decompile/scripts/form-decompile.ps1 | 34 ++++- docs/form-dsl-spec.md | 36 ++++- .../Таблица/Forms/Форма/Ext/Form.xml | 85 ++++++++---- tests/skills/cases/form-compile/table.json | 14 +- 6 files changed, 336 insertions(+), 62 deletions(-) diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1 index 384a6a52..3b929986 100644 --- a/.claude/skills/form-compile/scripts/form-compile.ps1 +++ b/.claude/skills/form-compile/scripts/form-compile.ps1 @@ -1,4 +1,4 @@ -# form-compile v1.47 — Compile 1C managed form from JSON or object metadata +# form-compile v1.48 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$JsonPath, @@ -2264,6 +2264,38 @@ function Emit-Companion { X "$indent" } +# Companion-командная-панель (ContextMenu/AutoCommandBar) с контентом: { autofill?, children?[] } +# или массив = shorthand для { children }. Пусто/нет → self-closing companion (как Emit-Companion). +# Дети — обычная грамматика button/buttonGroup/popup (Emit-Element, inCmdBar). +function Emit-CompanionPanel { + param([string]$tag, [string]$name, [string]$indent, $panel) + $id = New-Id + $autofill = $null + $children = $null + $halign = $null + if ($panel -is [array]) { + $children = $panel + } elseif ($null -ne $panel) { + if ($null -ne $panel.PSObject.Properties['autofill'] -and $null -ne $panel.autofill) { $autofill = [bool]$panel.autofill } + if ($null -ne $panel.PSObject.Properties['horizontalAlign'] -and "$($panel.horizontalAlign)" -ne '') { $halign = "$($panel.horizontalAlign)" } + $children = $panel.children + } + $hasChildren = $children -and @($children).Count -gt 0 + if ($null -eq $autofill -and -not $hasChildren -and -not $halign) { + X "$indent<$tag name=`"$name`" id=`"$id`"/>" + return + } + X "$indent<$tag name=`"$name`" id=`"$id`">" + if ($halign) { X "$indent`t$halign" } + if ($null -ne $autofill) { X "$indent`t$(if ($autofill){'true'}else{'false'})" } + if ($hasChildren) { + X "$indent`t" + foreach ($c in @($children)) { Emit-Element -el $c -indent "$indent`t`t" -inCmdBar $true } + X "$indent`t" + } + X "$indent" +} + # Табличный addition (СтрокаПоиска/СостояниеПросмотра/УправлениеПоиском) с AdditionSource. # Item = имя таблицы, Type фиксирован по виду; внутри — companion ContextMenu/ExtendedTooltip. function Emit-TableAddition { @@ -2283,8 +2315,14 @@ function Emit-TableAddition { function Emit-Element { param($el, [string]$indent, [bool]$inCmdBar = $false) + # Companion-панели (объект/массив-значение) → commandBar/contextMenu, до тип-синонимов. + Normalize-PanelSynonyms $el + # Silent synonyms: model often writes XML name or Russian (ПолеПереключателя/RadioButtonField → radio). # Maps any synonym to canonical short DSL key. + # commandBar/autoCommandBar/КоманднаяПанель → тип-элемент ТОЛЬКО при строковом значении (имя); + # объект/массив уже отнесён к панель-свойству выше. + $strOnlyKeys = @('commandBar','autoCommandBar','КоманднаяПанель') $synonyms = @{ "commandBar" = "cmdBar" "autoCommandBar" = "autoCmdBar" @@ -2324,6 +2362,7 @@ function Emit-Element { } foreach ($pair in $synonyms.GetEnumerator()) { if ($null -ne $el.PSObject.Properties[$pair.Key] -and $null -eq $el.PSObject.Properties[$pair.Value]) { + if ($strOnlyKeys -contains $pair.Key -and -not ($el.($pair.Key) -is [string])) { continue } $val = $el.($pair.Key) $el.PSObject.Properties.Remove($pair.Key) | Out-Null $el | Add-Member -NotePropertyName $pair.Value -NotePropertyValue $val -Force @@ -2357,6 +2396,8 @@ function Emit-Element { "radioButtonType"=1;"choiceList"=1;"columnsCount"=1;"checkBoxType"=1;"editMode"=1 # naming & binding "name"=1;"path"=1;"title"=1;"tooltip"=1;"tooltipRepresentation"=1;"extendedTooltip"=1 + # companion-панели (свойства): командная панель + контекстное меню + "commandBar"=1;"contextMenu"=1 # visibility & state "visible"=1;"hidden"=1;"enabled"=1;"disabled"=1;"readOnly"=1;"userVisible"=1 # events ("events" — основной формат; on/handlers — legacy, принимаются ради совместимости) @@ -2393,7 +2434,7 @@ function Emit-Element { # pages-specific "pagesRepresentation"=1 # button-specific - "type"=1;"command"=1;"stdCommand"=1;"defaultButton"=1;"locationInCommandBar"=1 + "type"=1;"command"=1;"commandName"=1;"stdCommand"=1;"defaultButton"=1;"locationInCommandBar"=1 # picture/decoration "src"=1;"valuesPicture"=1;"loadTransparent"=1 # cmdBar-specific @@ -2709,7 +2750,7 @@ function Emit-Input { } # Companions - Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner + Emit-CompanionPanel -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner -panel $el.contextMenu Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip Emit-Events -el $el -elementName $name -indent $inner -typeKey "input" @@ -2742,7 +2783,7 @@ function Emit-Check { Emit-Layout -el $el -indent $inner # Companions - Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner + Emit-CompanionPanel -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner -panel $el.contextMenu Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip Emit-Events -el $el -elementName $name -indent $inner -typeKey "check" @@ -2967,7 +3008,7 @@ function Emit-Radio { Emit-Layout -el $el -indent $inner # Companions - Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner + Emit-CompanionPanel -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner -panel $el.contextMenu Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip Emit-Events -el $el -elementName $name -indent $inner -typeKey "radio" @@ -3007,7 +3048,7 @@ function Emit-Label { Emit-Layout -el $el -indent $inner # Companions - Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner + Emit-CompanionPanel -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner -panel $el.contextMenu Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip Emit-Events -el $el -elementName $name -indent $inner -typeKey "label" @@ -3033,7 +3074,7 @@ function Emit-LabelField { Emit-Layout -el $el -indent $inner # Companions - Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner + Emit-CompanionPanel -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner -panel $el.contextMenu Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip Emit-Events -el $el -elementName $name -indent $inner -typeKey "labelField" @@ -3136,9 +3177,11 @@ function Emit-Table { } # Companions - Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner - # AutoCommandBar — with optional Autofill control - if ($null -ne $el.tableAutofill) { + Emit-CompanionPanel -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner -panel $el.contextMenu + # AutoCommandBar: приоритет commandBar-свойства (контент); иначе tableAutofill-shorthand; иначе пусто. + if ($null -ne $el.commandBar) { + Emit-CompanionPanel -tag "AutoCommandBar" -name "${name}КоманднаяПанель" -indent $inner -panel $el.commandBar + } elseif ($null -ne $el.tableAutofill) { $acbId = New-Id X "$inner" $afVal = if ($el.tableAutofill) { "true" } else { "false" } @@ -3285,6 +3328,10 @@ function Emit-Button { if ($el.command) { X "$innerForm.Command.$($el.command)" } + # commandName — глобальная команда «как есть» (CommonCommand.X, Catalog.X.Command.Y …), без обёртки Form. + if ($el.commandName -and -not $el.command) { + X "$inner$($el.commandName)" + } if ($el.stdCommand) { $sc = "$($el.stdCommand)" if ($sc -match '^(.+)\.(.+)$') { @@ -3294,7 +3341,7 @@ function Emit-Button { } } - $btnAuto = -not ($el.command -or $el.stdCommand) + $btnAuto = -not ($el.command -or $el.commandName -or $el.stdCommand) Emit-Title -el $el -name $name -indent $inner -auto:$btnAuto Emit-CommonFlags -el $el -indent $inner @@ -3347,7 +3394,7 @@ function Emit-PictureDecoration { Emit-Layout -el $el -indent $inner # Companions - Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner + Emit-CompanionPanel -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner -panel $el.contextMenu Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip Emit-Events -el $el -elementName $name -indent $inner -typeKey "picture" @@ -3381,7 +3428,7 @@ function Emit-PictureField { Emit-Layout -el $el -indent $inner # Companions - Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner + Emit-CompanionPanel -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner -panel $el.contextMenu Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip Emit-Events -el $el -elementName $name -indent $inner -typeKey "picField" @@ -3423,7 +3470,7 @@ function Emit-Calendar { if ($null -ne $el.showMonthsPanel) { $v = if ($el.showMonthsPanel) { "true" } else { "false" }; X "$inner$v" } # Companions - Emit-Companion -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner + Emit-CompanionPanel -tag "ContextMenu" -name "${name}КонтекстноеМеню" -indent $inner -panel $el.contextMenu Emit-Companion -tag "ExtendedTooltip" -name "${name}РасширеннаяПодсказка" -indent $inner -content $el.extendedTooltip Emit-Events -el $el -elementName $name -indent $inner -typeKey "calendar" @@ -3755,17 +3802,59 @@ function Emit-Properties { # --- 11b. Pre-pass: synonyms, main attribute inference, heuristics, autoCmdBar extraction --- +# Companion-панели как СВОЙСТВА элемента (значение объект/массив): любой знакомый +# синоним → каноника commandBar / contextMenu. Разводим с одноимёнными ТИПАМИ-элементами +# по типу значения: строка = элемент-тип (имя), объект/массив = панель-свойство. +function Normalize-PanelSynonyms { + param($el) + if ($null -eq $el) { return } + $panelSyns = @{ + 'commandBar' = @('commandBar','autoCommandBar','AutoCommandBar','autoCmdBar','cmdBar','КоманднаяПанель') + 'contextMenu' = @('contextMenu','ContextMenu','КонтекстноеМеню') + } + foreach ($canon in $panelSyns.Keys) { + foreach ($syn in $panelSyns[$canon]) { + $p = $el.PSObject.Properties[$syn] + if ($null -ne $p -and ($p.Value -is [array] -or $p.Value -is [System.Management.Automation.PSCustomObject])) { + if ($syn -ne $canon -and $null -eq $el.PSObject.Properties[$canon]) { + $v = $p.Value + $el.PSObject.Properties.Remove($syn) | Out-Null + $el | Add-Member -NotePropertyName $canon -NotePropertyValue $v -Force + } + break + } + } + } +} + function Normalize-ElementSynonyms { param($el) if ($null -eq $el) { return } - $synonyms = @{ "commandBar" = "cmdBar"; "autoCommandBar" = "autoCmdBar"; "extTooltip" = "extendedTooltip" } - foreach ($pair in $synonyms.GetEnumerator()) { - if ($null -ne $el.PSObject.Properties[$pair.Key] -and $null -eq $el.PSObject.Properties[$pair.Value]) { + Normalize-PanelSynonyms $el + # Тип-синонимы (commandBar/autoCommandBar → элемент-тип) применяем ТОЛЬКО к строковому + # значению (имя элемента); объект/массив уже отнесён к панель-свойству выше. + $typeSyn = @{ "commandBar" = "cmdBar"; "autoCommandBar" = "autoCmdBar" } + foreach ($pair in $typeSyn.GetEnumerator()) { + $src = $el.PSObject.Properties[$pair.Key] + if ($null -ne $src -and ($src.Value -is [string]) -and $null -eq $el.PSObject.Properties[$pair.Value]) { $val = $el.($pair.Key) $el.PSObject.Properties.Remove($pair.Key) | Out-Null $el | Add-Member -NotePropertyName $pair.Value -NotePropertyValue $val -Force } } + if ($el.PSObject.Properties["extTooltip"] -and $null -eq $el.PSObject.Properties["extendedTooltip"]) { + $val = $el.extTooltip + $el.PSObject.Properties.Remove("extTooltip") | Out-Null + $el | Add-Member -NotePropertyName "extendedTooltip" -NotePropertyValue $val -Force + } + # Рекурсия в детей панелей (commandBar/contextMenu) — нормализуем кнопки/группы внутри + foreach ($pk in @('commandBar','contextMenu')) { + $pp = $el.PSObject.Properties[$pk] + if ($null -ne $pp) { + $kids = if ($pp.Value -is [array]) { $pp.Value } elseif ($null -ne $pp.Value) { $pp.Value.children } else { $null } + if ($kids) { foreach ($child in $kids) { Normalize-ElementSynonyms $child } } + } + } if ($el.PSObject.Properties["children"] -and $el.children) { foreach ($child in $el.children) { Normalize-ElementSynonyms $child } } diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py index 68274fc2..b2870381 100644 --- a/.claude/skills/form-compile/scripts/form-compile.py +++ b/.claude/skills/form-compile/scripts/form-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# form-compile v1.47 — Compile 1C managed form from JSON or object metadata +# form-compile v1.48 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import copy @@ -1779,7 +1779,8 @@ KNOWN_KEYS = { "commandBarLocation", "searchStringLocation", "viewStatusLocation", "searchControlLocation", "excludedCommands", "pagesRepresentation", - "type", "command", "stdCommand", "defaultButton", "locationInCommandBar", + "type", "command", "commandName", "stdCommand", "defaultButton", "locationInCommandBar", + "commandBar", "contextMenu", "src", "valuesPicture", "loadTransparent", "autofill", "choiceMode", "initialTreeView", "enableDrag", "enableStartDrag", @@ -1834,6 +1835,28 @@ ELEMENT_TYPE_SYNONYMS = { "ВсплывающееМеню": "popup", } +# Тип-синонимы, применяемые ТОЛЬКО к строковому значению (имя элемента); объект/массив +# у того же слова — companion-панель (свойство), см. normalize_panel_synonyms. +STR_ONLY_TYPE_SYNONYMS = {"commandBar", "autoCommandBar", "КоманднаяПанель"} + +# Companion-панели как СВОЙСТВА (значение объект/массив): синоним → каноника. +PANEL_SYNONYMS = { + 'commandBar': ['commandBar', 'autoCommandBar', 'AutoCommandBar', 'autoCmdBar', 'cmdBar', 'КоманднаяПанель'], + 'contextMenu': ['contextMenu', 'ContextMenu', 'КонтекстноеМеню'], +} + + +def normalize_panel_synonyms(el): + if not isinstance(el, dict): + return + for canon, syns in PANEL_SYNONYMS.items(): + for syn in syns: + if syn in el and isinstance(el[syn], (list, dict)): + if syn != canon and canon not in el: + el[canon] = el.pop(syn) + break + + # Maps Russian/English root of typed reference path to canonical English root REF_ROOT_SYNONYMS = { "Перечисление": "Enum", @@ -2045,6 +2068,38 @@ def emit_companion(lines, tag, name, indent, content=None): lines.append(f'{indent}') +def emit_companion_panel(lines, tag, name, indent, panel): + # Companion-командная-панель (ContextMenu/AutoCommandBar) с контентом: { autofill?, horizontalAlign?, children?[] } + # или массив = shorthand для { children }. Пусто/нет → self-closing. + cid = new_id() + autofill = None + halign = None + children = None + if isinstance(panel, list): + children = panel + elif panel is not None: + if panel.get('autofill') is not None: + autofill = bool(panel.get('autofill')) + if panel.get('horizontalAlign'): + halign = str(panel.get('horizontalAlign')) + children = panel.get('children') + has_children = bool(children) and len(children) > 0 + if autofill is None and not has_children and not halign: + lines.append(f'{indent}<{tag} name="{name}" id="{cid}"/>') + return + lines.append(f'{indent}<{tag} name="{name}" id="{cid}">') + if halign: + lines.append(f'{indent}\t{halign}') + if autofill is not None: + lines.append(f'{indent}\t{"true" if autofill else "false"}') + if has_children: + lines.append(f'{indent}\t') + for c in children: + emit_element(lines, c, f'{indent}\t\t', in_cmd_bar=True) + lines.append(f'{indent}\t') + lines.append(f'{indent}') + + def emit_table_addition(lines, tag, table_name, name_suffix, src_type, indent): # Табличный addition с AdditionSource (Item = имя таблицы, Type фиксирован). add_name = f'{table_name}{name_suffix}' @@ -2372,9 +2427,15 @@ def emit_type(lines, type_str, indent): # --- Element emitters --- def emit_element(lines, el, indent, in_cmd_bar=False): - # Silent synonyms: model often writes XML name or Russian (ПолеПереключателя/RadioButtonField → radio) + # Companion-панели (объект/массив-значение) → commandBar/contextMenu, до тип-синонимов. + normalize_panel_synonyms(el) + + # Silent synonyms: model often writes XML name or Russian (ПолеПереключателя/RadioButtonField → radio). + # commandBar/autoCommandBar/КоманднаяПанель → тип-элемент ТОЛЬКО при строковом значении (имя). for src, dst in ELEMENT_TYPE_SYNONYMS.items(): if src in el and dst not in el: + if src in STR_ONLY_TYPE_SYNONYMS and not isinstance(el[src], str): + continue el[dst] = el.pop(src) type_key = None @@ -2562,7 +2623,7 @@ def emit_input(lines, el, name, eid, indent): emit_mltext(lines, inner, 'InputHint', el['inputHint']) # Companions - emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner) + emit_companion_panel(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner, el.get('contextMenu')) emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip')) emit_events(lines, el, name, inner, 'input') @@ -2595,7 +2656,7 @@ def emit_check(lines, el, name, eid, indent): emit_layout(lines, el, inner) # Companions - emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner) + emit_companion_panel(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner, el.get('contextMenu')) emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip')) emit_events(lines, el, name, inner, 'check') @@ -2654,7 +2715,7 @@ def emit_radio_button_field(lines, el, name, eid, indent): emit_layout(lines, el, inner) - emit_companion(lines, 'ContextMenu', f'{name}КонтекстноеМеню', inner) + emit_companion_panel(lines, 'ContextMenu', f'{name}КонтекстноеМеню', inner, el.get('contextMenu')) emit_companion(lines, 'ExtendedTooltip', f'{name}РасширеннаяПодсказка', inner, el.get('extendedTooltip')) emit_events(lines, el, name, inner, 'radio') @@ -2693,7 +2754,7 @@ def emit_label(lines, el, name, eid, indent): emit_layout(lines, el, inner) # Companions - emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner) + emit_companion_panel(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner, el.get('contextMenu')) emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip')) emit_events(lines, el, name, inner, 'label') @@ -2721,7 +2782,7 @@ def emit_label_field(lines, el, name, eid, indent): emit_layout(lines, el, inner) # Companions - emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner) + emit_companion_panel(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner, el.get('contextMenu')) emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip')) emit_events(lines, el, name, inner, 'labelField') @@ -2834,9 +2895,11 @@ def emit_table(lines, el, name, eid, indent): lines.append(f'{inner}') # Companions - emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner) + emit_companion_panel(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner, el.get('contextMenu')) # AutoCommandBar — with optional Autofill control - if el.get('tableAutofill') is not None: + if el.get('commandBar') is not None: + emit_companion_panel(lines, 'AutoCommandBar', f'{name}\u041a\u043e\u043c\u0430\u043d\u0434\u043d\u0430\u044f\u041f\u0430\u043d\u0435\u043b\u044c', inner, el.get('commandBar')) + elif el.get('tableAutofill') is not None: acb_id = new_id() acb_name = f'{name}\u041a\u043e\u043c\u0430\u043d\u0434\u043d\u0430\u044f\u041f\u0430\u043d\u0435\u043b\u044c' af_val = 'true' if el['tableAutofill'] else 'false' @@ -2963,6 +3026,9 @@ def emit_button(lines, el, name, eid, indent, in_cmd_bar=False): # CommandName if el.get('command'): lines.append(f'{inner}Form.Command.{el["command"]}') + # commandName — глобальная команда «как есть» (CommonCommand.X, Catalog.X.Command.Y …), без обёртки Form. + if el.get('commandName') and not el.get('command'): + lines.append(f'{inner}{el["commandName"]}') if el.get('stdCommand'): sc = str(el['stdCommand']) m = re.match(r'^(.+)\.(.+)$', sc) @@ -2971,7 +3037,7 @@ def emit_button(lines, el, name, eid, indent, in_cmd_bar=False): else: lines.append(f'{inner}Form.StandardCommand.{sc}') - emit_title(lines, el, name, inner, auto=not (el.get('command') or el.get('stdCommand'))) + emit_title(lines, el, name, inner, auto=not (el.get('command') or el.get('commandName') or el.get('stdCommand'))) emit_common_flags(lines, el, inner) if el.get('defaultButton') is True: @@ -3019,7 +3085,7 @@ def emit_picture_decoration(lines, el, name, eid, indent): emit_layout(lines, el, inner) # Companions - emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner) + emit_companion_panel(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner, el.get('contextMenu')) emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip')) emit_events(lines, el, name, inner, 'picture') @@ -3053,7 +3119,7 @@ def emit_picture_field(lines, el, name, eid, indent): emit_layout(lines, el, inner) # Companions - emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner) + emit_companion_panel(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner, el.get('contextMenu')) emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip')) emit_events(lines, el, name, inner, 'picField') @@ -3091,7 +3157,7 @@ def emit_calendar(lines, el, name, eid, indent): lines.append(f'{inner}{"true" if el["showMonthsPanel"] else "false"}') # Companions - emit_companion(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner) + emit_companion_panel(lines, 'ContextMenu', f'{name}\u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435\u041c\u0435\u043d\u044e', inner, el.get('contextMenu')) emit_companion(lines, 'ExtendedTooltip', f'{name}\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u0430\u044f\u041f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430', inner, el.get('extendedTooltip')) emit_events(lines, el, name, inner, 'calendar') @@ -3646,10 +3712,22 @@ def main(): def _normalize_synonyms(el): if not isinstance(el, dict): return + # Companion-панели (объект/массив-значение) → commandBar/contextMenu + normalize_panel_synonyms(el) + # Тип-синонимы: commandBar/autoCommandBar → элемент-тип ТОЛЬКО при строковом значении synonyms = {'commandBar': 'cmdBar', 'autoCommandBar': 'autoCmdBar', 'extTooltip': 'extendedTooltip'} for src, dst in synonyms.items(): if src in el and dst not in el: + if src in STR_ONLY_TYPE_SYNONYMS and not isinstance(el[src], str): + continue el[dst] = el.pop(src) + # Рекурсия в детей панелей (commandBar/contextMenu) + for pk in ('commandBar', 'contextMenu'): + pv = el.get(pk) + kids = pv if isinstance(pv, list) else (pv.get('children') if isinstance(pv, dict) else None) + if isinstance(kids, list): + for child in kids: + _normalize_synonyms(child) if isinstance(el.get('children'), list): for child in el['children']: _normalize_synonyms(child) diff --git a/.claude/skills/form-decompile/scripts/form-decompile.ps1 b/.claude/skills/form-decompile/scripts/form-decompile.ps1 index c5dd842c..03b3d8b6 100644 --- a/.claude/skills/form-decompile/scripts/form-decompile.ps1 +++ b/.claude/skills/form-decompile/scripts/form-decompile.ps1 @@ -1,4 +1,4 @@ -# form-decompile v0.28 — Decompile 1C managed Form.xml to JSON DSL (draft) +# form-decompile v0.29 — Decompile 1C managed Form.xml to JSON DSL (draft) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью. param( @@ -883,6 +883,28 @@ function Decompile-Children { return ,@($list) } +# Инверсия Emit-CompanionPanel: companion-командная-панель (ContextMenu/AutoCommandBar) с контентом +# → { autofill?, horizontalAlign?, children?[] } либо $null, если companion пустой (self-closing). +# $isDynListTable: для дин-список-таблицы пустой AutoCommandBar с autofill=false восстановит +# эвристика компилятора — молчим (как с tableAutofill), чтобы не плодить ключ. +function Decompile-CompanionPanel { + param($node, [string]$tag, [bool]$isDynListTable = $false) + $p = $node.SelectSingleNode("lf:$tag", $ns) + if (-not $p) { return $null } + $autofillRaw = Get-Child $p 'Autofill' + $halign = Get-Child $p 'HorizontalAlign' + $kids = Decompile-Children $p + $hasKids = $kids -and @($kids).Count -gt 0 + if (-not $hasKids -and $null -eq $autofillRaw -and -not $halign) { return $null } + if ($isDynListTable -and $tag -eq 'AutoCommandBar' -and -not $hasKids -and -not $halign -and $autofillRaw -eq 'false') { return $null } + $o = [ordered]@{} + if ($halign) { $o['horizontalAlign'] = $halign } + if ($autofillRaw -eq 'false') { $o['autofill'] = $false } + elseif ($autofillRaw -eq 'true') { $o['autofill'] = $true } + if ($hasKids) { $o['children'] = $kids } + return $o +} + function Decompile-Element { param($node) $tag = $node.LocalName @@ -1091,7 +1113,7 @@ function Decompile-Element { if ($cmd -match '^Form\.Command\.(.+)$') { $obj['command'] = $matches[1] } elseif ($cmd -match '^Form\.StandardCommand\.(.+)$') { $obj['stdCommand'] = $matches[1] } elseif ($cmd -match '^Form\.Item\.(.+)\.StandardCommand\.(.+)$') { $obj['stdCommand'] = "$($matches[1]).$($matches[2])" } - else { $obj['command'] = $cmd } + else { $obj['commandName'] = $cmd } } Add-CommonProps $obj $node $name $type = Get-Child $node 'Type' @@ -1129,7 +1151,7 @@ function Decompile-Element { if (-not $obj.Contains('title')) { $autoTitle = $false if ($tag -in @('LabelDecoration','Page','Popup')) { $autoTitle = $true } - elseif ($tag -eq 'Button') { $autoTitle = -not ($obj.Contains('command') -or $obj.Contains('stdCommand')) } + elseif ($tag -eq 'Button') { $autoTitle = -not ($obj.Contains('command') -or $obj.Contains('commandName') -or $obj.Contains('stdCommand')) } elseif ($tag -in @('InputField','CheckBoxField','RadioButtonField','LabelField','Table','CalendarField')) { $autoTitle = -not $obj.Contains('path') } if ($autoTitle) { $obj['title'] = '' } } @@ -1137,6 +1159,12 @@ function Decompile-Element { # extendedTooltip: контент companion (любой элемент) $etTitle = $node.SelectSingleNode("lf:ExtendedTooltip/lf:Title", $ns) if ($etTitle) { $et = Get-MLFormattedValue $etTitle; if ($null -ne $et) { $obj['extendedTooltip'] = $et } } + # companion-панели с контентом: AutoCommandBar → commandBar, ContextMenu → contextMenu (любой элемент) + $isDynListTable = ($tag -eq 'Table') -and (Has-Child $node 'UpdateOnDataChange') + $cb = Decompile-CompanionPanel $node 'AutoCommandBar' $isDynListTable + if ($null -ne $cb) { $obj['commandBar'] = $cb } + $cm = Decompile-CompanionPanel $node 'ContextMenu' + if ($null -ne $cm) { $obj['contextMenu'] = $cm } return $obj } diff --git a/docs/form-dsl-spec.md b/docs/form-dsl-spec.md index ddce04e7..d39f5855 100644 --- a/docs/form-dsl-spec.md +++ b/docs/form-dsl-spec.md @@ -115,6 +115,8 @@ | `disabled` | bool | `true` → `<Enabled>false</Enabled>` | | `readOnly` | bool | `true` → `<ReadOnly>true</ReadOnly>` | | `userVisible` | bool/object | Пользовательская видимость по ролям (`<UserVisible>`). См. §4.1c. Отсутствие = виден всем | +| `commandBar` | object/array | Командная панель элемента (companion `<AutoCommandBar>`) с контентом. См. §4.1d | +| `contextMenu` | object/array | Контекстное меню элемента (companion `<ContextMenu>`) с контентом. См. §4.1d | | `events` | object | Обработчики событий: `{ "ИмяСобытия": "ИмяОбработчика" }` — тот же формат, что у событий формы (§3). Значение `null` → имя по конвенции (§4.2). См. §4.2 | | `titleLocation` | string | Расположение заголовка: `none`/`left`/`right`/`top`/`bottom`/`auto`. Эмитится при наличии (input, labelField, picField, table, calendar). У `check`/`radio` — особая семантика с умным дефолтом (см. их разделы) | | `tooltip` | string/object | Всплывающая подсказка элемента (`<ToolTip>`). Строка → ru, объект `{ "ru": …, "en": … }` → мультиязычный (как `title`). Эмитится сразу после `title` | @@ -161,6 +163,37 @@ { "name": "Команда", "use": { "common": false, "roles": { "Роль.Бухгалтер": true } } } ``` +### 4.1d. Companion-панели элемента (`commandBar` / `contextMenu`) + +Командная панель (`<AutoCommandBar>`) и контекстное меню (`<ContextMenu>`) элемента — это +companion-панели с собственным контентом. Оба несут одну грамматику. + +| Ключ | XML companion | Forgiving-синонимы (при объект/массив-значении) | +|------|---------------|--------------------------------------------------| +| `commandBar` | `<AutoCommandBar>` | `autoCommandBar`, `AutoCommandBar`, `autoCmdBar`, `cmdBar`, `КоманднаяПанель` | +| `contextMenu` | `<ContextMenu>` | `ContextMenu`, `КонтекстноеМеню` | + +**Значение** (обе формы): +- массив `[ … ]` → shorthand для `{ "children": [ … ] }`; +- объект `{ "autofill"?: bool, "children": [ … ] }` (+ `horizontalAlign` у `commandBar`). + +`children` — обычная грамматика кнопок: `button` (с `command`/`commandName`/`stdCommand`), `buttonGroup`, `popup`. + +- `autofill`: отсутствует → дефолт платформы (тег не эмитим); `false` → подавить автозаполнение панели. +- Отсутствие свойства целиком → пустой companion (как обычно). + +**Разведение тип-элемента и панель-свойства — по типу значения:** `cmdBar: "Имя"` (строка) — это +отдельный элемент-панель в дереве (§4.3); `commandBar: { … }` (объект/массив) — companion-панель *данного* +элемента. Поэтому модель может писать панель таблицы любым знакомым словом. + +```jsonc +{ "table": "Список", "path": "Список", + "commandBar": { "autofill": false, "children": [ + { "button": "Создать", "command": "СоздатьЭлемент" } ] }, + "contextMenu": { "children": [ + { "button": "Карта", "commandName": "CommonCommand.КартаМаршрута" } ] } } +``` + ### 4.1a. Общие layout-свойства Применимы к любому элементу (размеры, растягивание, выравнивание внутри родителя). Эмитятся только при указании. @@ -447,7 +480,8 @@ Pages поддерживает `pagesRepresentation`: `None`, `TabsOnTop`, `Tabs | Свойство | Тип | Описание | |----------|-----|----------| | `command` | string | Имя команды формы (→ `Form.Command.<name>`) | -| `stdCommand` | string | Стандартная команда (→ `Form.StandardCommand.<name>`) | +| `commandName` | string | Глобальная команда «как есть» (`CommonCommand.X`, `Catalog.X.Command.Y` …) — без обёртки `Form.` | +| `stdCommand` | string | Стандартная команда (→ `Form.StandardCommand.<name>`; `X.Y` → `Form.Item.X.StandardCommand.Y`) | | `type` | string | `usual`, `hyperlink`, `commandBar` | | `defaultButton` | bool | Кнопка по умолчанию | | `picture` | string | Ссылка на картинку (`StdPicture.Name`) | diff --git a/tests/skills/cases/form-compile/snapshots/table/DataProcessors/Таблица/Forms/Форма/Ext/Form.xml b/tests/skills/cases/form-compile/snapshots/table/DataProcessors/Таблица/Forms/Форма/Ext/Form.xml index 547ff475..2ae76856 100644 --- a/tests/skills/cases/form-compile/snapshots/table/DataProcessors/Таблица/Forms/Форма/Ext/Form.xml +++ b/tests/skills/cases/form-compile/snapshots/table/DataProcessors/Таблица/Forms/Форма/Ext/Form.xml @@ -21,60 +21,82 @@ <ExcludedCommand>MoveUp</ExcludedCommand> <ExcludedCommand>MoveDown</ExcludedCommand> </CommandSet> - <ContextMenu name="ДанныеКонтекстноеМеню" id="2"/> - <AutoCommandBar name="ДанныеКоманднаяПанель" id="3"/> - <ExtendedTooltip name="ДанныеРасширеннаяПодсказка" id="4"/> - <SearchStringAddition name="ДанныеСтрокаПоиска" id="5"> + <ContextMenu name="ДанныеКонтекстноеМеню" id="2"> + <ChildItems> + <ButtonGroup name="МенюГруппа" id="3"> + <ExtendedTooltip name="МенюГруппаРасширеннаяПодсказка" id="4"/> + <ChildItems> + <Button name="МенюОбновить" id="5"> + <Type>CommandBarButton</Type> + <CommandName>Form.Command.Обновить</CommandName> + <ExtendedTooltip name="МенюОбновитьРасширеннаяПодсказка" id="6"/> + </Button> + </ChildItems> + </ButtonGroup> + </ChildItems> + </ContextMenu> + <AutoCommandBar name="ДанныеКоманднаяПанель" id="7"> + <Autofill>false</Autofill> + <ChildItems> + <Button name="ПанельОбновить" id="8"> + <Type>CommandBarButton</Type> + <CommandName>Form.Command.Обновить</CommandName> + <ExtendedTooltip name="ПанельОбновитьРасширеннаяПодсказка" id="9"/> + </Button> + </ChildItems> + </AutoCommandBar> + <ExtendedTooltip name="ДанныеРасширеннаяПодсказка" id="10"/> + <SearchStringAddition name="ДанныеСтрокаПоиска" id="11"> <AdditionSource> <Item>Данные</Item> <Type>SearchStringRepresentation</Type> </AdditionSource> - <ContextMenu name="ДанныеСтрокаПоискаКонтекстноеМеню" id="6"/> - <ExtendedTooltip name="ДанныеСтрокаПоискаРасширеннаяПодсказка" id="7"/> + <ContextMenu name="ДанныеСтрокаПоискаКонтекстноеМеню" id="12"/> + <ExtendedTooltip name="ДанныеСтрокаПоискаРасширеннаяПодсказка" id="13"/> </SearchStringAddition> - <ViewStatusAddition name="ДанныеСостояниеПросмотра" id="8"> + <ViewStatusAddition name="ДанныеСостояниеПросмотра" id="14"> <AdditionSource> <Item>Данные</Item> <Type>ViewStatusRepresentation</Type> </AdditionSource> - <ContextMenu name="ДанныеСостояниеПросмотраКонтекстноеМеню" id="9"/> - <ExtendedTooltip name="ДанныеСостояниеПросмотраРасширеннаяПодсказка" id="10"/> + <ContextMenu name="ДанныеСостояниеПросмотраКонтекстноеМеню" id="15"/> + <ExtendedTooltip name="ДанныеСостояниеПросмотраРасширеннаяПодсказка" id="16"/> </ViewStatusAddition> - <SearchControlAddition name="ДанныеУправлениеПоиском" id="11"> + <SearchControlAddition name="ДанныеУправлениеПоиском" id="17"> <AdditionSource> <Item>Данные</Item> <Type>SearchControl</Type> </AdditionSource> - <ContextMenu name="ДанныеУправлениеПоискомКонтекстноеМеню" id="12"/> - <ExtendedTooltip name="ДанныеУправлениеПоискомРасширеннаяПодсказка" id="13"/> + <ContextMenu name="ДанныеУправлениеПоискомКонтекстноеМеню" id="18"/> + <ExtendedTooltip name="ДанныеУправлениеПоискомРасширеннаяПодсказка" id="19"/> </SearchControlAddition> <ChildItems> - <InputField name="Дата" id="14"> + <InputField name="Дата" id="20"> <DataPath>Данные.Дата</DataPath> - <ContextMenu name="ДатаКонтекстноеМеню" id="15"/> - <ExtendedTooltip name="ДатаРасширеннаяПодсказка" id="16"/> + <ContextMenu name="ДатаКонтекстноеМеню" id="21"/> + <ExtendedTooltip name="ДатаРасширеннаяПодсказка" id="22"/> </InputField> - <InputField name="Сумма" id="17"> + <InputField name="Сумма" id="23"> <DataPath>Данные.Сумма</DataPath> - <ContextMenu name="СуммаКонтекстноеМеню" id="18"/> - <ExtendedTooltip name="СуммаРасширеннаяПодсказка" id="19"/> + <ContextMenu name="СуммаКонтекстноеМеню" id="24"/> + <ExtendedTooltip name="СуммаРасширеннаяПодсказка" id="25"/> </InputField> - <InputField name="Комментарий" id="20"> + <InputField name="Комментарий" id="26"> <DataPath>Данные.Комментарий</DataPath> - <ContextMenu name="КомментарийКонтекстноеМеню" id="21"/> - <ExtendedTooltip name="КомментарийРасширеннаяПодсказка" id="22"/> + <ContextMenu name="КомментарийКонтекстноеМеню" id="27"/> + <ExtendedTooltip name="КомментарийРасширеннаяПодсказка" id="28"/> </InputField> </ChildItems> </Table> </ChildItems> <Attributes> - <Attribute name="Объект" id="23"> + <Attribute name="Объект" id="29"> <Type> <v8:Type>cfg:DataProcessorObject.Таблица</v8:Type> </Type> <MainAttribute>true</MainAttribute> </Attribute> - <Attribute name="Данные" id="24"> + <Attribute name="Данные" id="30"> <Title> <v8:item> <v8:lang>ru</v8:lang> @@ -85,7 +107,7 @@ <v8:Type>v8:ValueTable</v8:Type> </Type> <Columns> - <Column name="Дата" id="25"> + <Column name="Дата" id="31"> <Type> <v8:Type>xs:dateTime</v8:Type> <v8:DateQualifiers> @@ -93,7 +115,7 @@ </v8:DateQualifiers> </Type> </Column> - <Column name="Сумма" id="26"> + <Column name="Сумма" id="32"> <Type> <v8:Type>xs:decimal</v8:Type> <v8:NumberQualifiers> @@ -103,7 +125,7 @@ </v8:NumberQualifiers> </Type> </Column> - <Column name="Комментарий" id="27"> + <Column name="Комментарий" id="33"> <Type> <v8:Type>xs:string</v8:Type> <v8:StringQualifiers> @@ -115,4 +137,15 @@ </Columns> </Attribute> </Attributes> + <Commands> + <Command name="Обновить" id="34"> + <Title> + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Обновить</v8:content> + </v8:item> + + ОбновитьОбработка + + diff --git a/tests/skills/cases/form-compile/table.json b/tests/skills/cases/form-compile/table.json index 311d81f7..b6eb0e0c 100644 --- a/tests/skills/cases/form-compile/table.json +++ b/tests/skills/cases/form-compile/table.json @@ -18,7 +18,16 @@ "elements": [ { "table": "Данные", "path": "Данные", "changeRowSet": true, "titleLocation": "top", "viewStatusLocation": "None", "searchControlLocation": "None", - "excludedCommands": ["Add", "Delete", "MoveUp", "MoveDown"], "columns": [ + "excludedCommands": ["Add", "Delete", "MoveUp", "MoveDown"], + "commandBar": { "autofill": false, "children": [ + { "button": "ПанельОбновить", "command": "Обновить" } + ]}, + "contextMenu": { "children": [ + { "buttonGroup": "МенюГруппа", "children": [ + { "button": "МенюОбновить", "command": "Обновить" } + ]} + ]}, + "columns": [ { "input": "Дата", "path": "Данные.Дата" }, { "input": "Сумма", "path": "Данные.Сумма" }, { "input": "Комментарий", "path": "Данные.Комментарий" } @@ -31,6 +40,9 @@ { "name": "Сумма", "type": "decimal(15,2)" }, { "name": "Комментарий", "type": "string(200)" } ]} + ], + "commands": [ + { "name": "Обновить", "action": "ОбновитьОбработка" } ] } }