diff --git a/.claude/skills/cf-edit/SKILL.md b/.claude/skills/cf-edit/SKILL.md index e2c0e395..fd4f1141 100644 --- a/.claude/skills/cf-edit/SKILL.md +++ b/.claude/skills/cf-edit/SKILL.md @@ -1,6 +1,6 @@ --- name: cf-edit -description: Точечное редактирование конфигурации 1С. Используй когда нужно изменить свойства конфигурации, добавить или удалить объект из состава, настроить роли по умолчанию +description: Точечное редактирование конфигурации 1С. Используй когда нужно изменить свойства конфигурации, добавить или удалить объект из состава, настроить роли по умолчанию, поменять раскладку панелей argument-hint: -ConfigPath -Operation -Value allowed-tools: - Bash @@ -37,6 +37,7 @@ powershell.exe -NoProfile -File .claude/skills/cf-edit/scripts/cf-edit.ps1 -Conf | `add-defaultRole` | `Role.Name` или `Name` | Добавить роль по умолчанию | | `remove-defaultRole` | `Role.Name` или `Name` | Удалить роль по умолчанию | | `set-defaultRoles` | Имена через `;;` | Заменить список ролей по умолчанию | +| `set-panels` | JSON-объект (см. [reference.md](reference.md)) | Перезаписать `Ext/ClientApplicationInterface.xml` (раскладка панелей) | Допустимые значения свойств, формат DefinitionFile (JSON), каноничный порядок: [reference.md](reference.md) diff --git a/.claude/skills/cf-edit/reference.md b/.claude/skills/cf-edit/reference.md index 57a8c0f9..f394237f 100644 --- a/.claude/skills/cf-edit/reference.md +++ b/.claude/skills/cf-edit/reference.md @@ -52,6 +52,52 @@ Batch: `"Catalog.Товары ;; Document.Заказ ;; Enum.ВидыОплат" `set-defaultRoles` полностью заменяет список ролей. +## set-panels + +Перезаписывает `Ext/ClientApplicationInterface.xml` — раскладку панелей рабочего пространства Taxi. Файл создаётся с нуля; то, что не упомянуто в `value`, отсутствует на экране. + +`value` — объект с ключами `top`, `left`, `right`, `bottom`. Каждый ключ — массив записей. Ключ можно опустить (= пустая сторона). + +**Запись** — одна из: +- Строка-алиас (одна панель в этом слоте) +- Объект `{"group": [...]}` (стек: панели/подгруппы внутри располагаются друг под другом) + +**Алиасы панелей:** + +| Алиас | Панель | +|-------|--------| +| `sections` | Панель разделов | +| `open` | Панель открытых | +| `favorites` | Панель избранного | +| `history` | Панель истории | +| `functions` | Панель функций текущего раздела | + +**Семантика:** +- Несколько записей в одной стороне → отдельные слоты «рядом» (несколько тегов ``/...) +- `{"group":[...]}` → один тег с ``-обёрткой, элементы внутри идут стеком + +**Пример** (DefinitionFile): +```json +[ + { + "operation": "set-panels", + "value": { + "top": ["open"], + "left": ["sections"], + "right": [{ "group": ["favorites", "history"] }], + "bottom": ["functions"] + } + } +] +``` + +**Через `-Value`** (CLI): передавай тот же объект как JSON-строку: +```powershell +... -Operation set-panels -Value '{"top":["open"],"left":["sections"]}' +``` + +`` для всех 5 панелей пишется автоматически — они всегда доступны пользователю через «Вид → Настройка панелей», даже если не размещены по умолчанию. + ## DefinitionFile (JSON) ```json diff --git a/.claude/skills/cf-edit/scripts/cf-edit.ps1 b/.claude/skills/cf-edit/scripts/cf-edit.ps1 index 72e48a24..45faa035 100644 --- a/.claude/skills/cf-edit/scripts/cf-edit.ps1 +++ b/.claude/skills/cf-edit/scripts/cf-edit.ps1 @@ -1,9 +1,9 @@ -# cf-edit v1.1 — Edit 1C configuration root (Configuration.xml) +# cf-edit v1.3 — Edit 1C configuration root (Configuration.xml) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory)][Alias('Path')][string]$ConfigPath, [string]$DefinitionFile, - [ValidateSet("modify-property","add-childObject","remove-childObject","add-defaultRole","remove-defaultRole","set-defaultRoles")] + [ValidateSet("modify-property","add-childObject","remove-childObject","add-defaultRole","remove-defaultRole","set-defaultRoles","set-panels")] [string]$Operation, [string]$Value, [switch]$NoValidate @@ -444,6 +444,120 @@ function Do-RemoveDefaultRole([string]$batchVal) { } } +# --- Operation: set-panels --- +# Canonical English aliases — preferred form, used in docs and error messages. +$script:panelUuids = @{ + "sections" = "b553047f-c9aa-4157-978d-448ecad24248" + "open" = "cbab57f2-a0f3-4f0a-89ea-4cb19570ab75" + "favorites" = "13322b22-3960-4d68-93a6-fe2dd7f28ca3" + "history" = "c933ac92-92cd-459d-81cc-e0c8a83ced99" + "functions" = "b2735bd3-d822-4430-ba59-c9e869693b24" +} +# Russian synonyms — silently accepted (cf-info displays Russian names; users +# may copy them straight into cf-edit value). +$script:panelSynonyms = @{ + "разделов" = "sections"; "разделы" = "sections" + "открытых" = "open"; "открытые" = "open" + "избранного" = "favorites";"избранное" = "favorites" + "истории" = "history"; "история" = "history" + "функций" = "functions";"функции" = "functions" +} + +function Build-PanelEntryXml($entry, [string]$indent) { + # String alias -> ... + if ($entry -is [string]) { + $key = $entry.ToLowerInvariant() + if ($script:panelSynonyms.ContainsKey($key)) { $key = $script:panelSynonyms[$key] } + if (-not $script:panelUuids.ContainsKey($key)) { + Write-Error "Unknown panel alias '$entry'. Allowed: $(($script:panelUuids.Keys | Sort-Object) -join ', ')" + exit 1 + } + $u = $script:panelUuids[$key] + $instId = [guid]::NewGuid().ToString() + return "$indent`r`n$indent`t$u`r`n$indent" + } + # Object {group: [...]} -> ... (stack) + if ($entry.PSObject.Properties['group']) { + $children = $entry.group + if (-not $children -or $children.Count -eq 0) { + Write-Error "group must contain at least one entry" + exit 1 + } + $gid = [guid]::NewGuid().ToString() + $inner = "" + foreach ($child in $children) { + $childXml = Build-PanelEntryXml $child "$indent`t`t" + $inner += "$indent`t`r`n$childXml`r`n$indent`t`r`n" + } + return "$indent`r`n$inner$indent" + } + Write-Error "Panel entry must be a string alias or object {group:[...]}, got: $($entry | ConvertTo-Json -Compress)" + exit 1 +} + +function Do-SetPanels($valArg) { + # Accept string (JSON), PSCustomObject, or hashtable + $layout = $valArg + if ($layout -is [string]) { + try { $layout = $layout | ConvertFrom-Json } catch { + Write-Error "set-panels value must be valid JSON object, got: $valArg" + exit 1 + } + } + if (-not $layout) { + Write-Error "set-panels value is empty" + exit 1 + } + + $sides = @("top","left","right","bottom") + $bodyParts = @() + foreach ($side in $sides) { + $entries = $null + if ($layout.PSObject.Properties[$side]) { $entries = $layout.$side } + if ($null -eq $entries) { continue } + # Normalize to array + if ($entries -isnot [System.Array] -and $entries -isnot [System.Collections.IList]) { + $entries = @($entries) + } + foreach ($entry in $entries) { + $entryXml = Build-PanelEntryXml $entry "`t`t" + $bodyParts += "`t<$side>`r`n$entryXml`r`n`t" + } + } + + # Reject unknown side keys (catches typos like "Top" vs "top") + foreach ($prop in $layout.PSObject.Properties) { + if ($sides -notcontains $prop.Name) { + Write-Error "Unknown side '$($prop.Name)'. Allowed: $($sides -join ', ')" + exit 1 + } + } + + $body = $bodyParts -join "`r`n" + $declarations = @" + + + + + +"@ + $bodyBlock = if ($body) { "$body`r`n" } else { "" } + $caiXml = @" + + +$bodyBlock$declarations + +"@ + + $extDir = Join-Path $script:configDir "Ext" + if (-not (Test-Path $extDir)) { New-Item -ItemType Directory -Path $extDir -Force | Out-Null } + $caiPath = Join-Path $extDir "ClientApplicationInterface.xml" + $utf8Bom = New-Object System.Text.UTF8Encoding($true) + [System.IO.File]::WriteAllText($caiPath, $caiXml, $utf8Bom) + $script:modifyCount++ + Info "Wrote panel layout: $caiPath" +} + # --- Operation: set-defaultRoles --- function Do-SetDefaultRoles([string]$batchVal) { $items = Parse-BatchValue $batchVal @@ -508,15 +622,18 @@ if ($DefinitionFile) { foreach ($op in $operations) { $opName = if ($op.operation) { "$($op.operation)" } else { "$Operation" } - $opValue = if ($op.value) { "$($op.value)" } else { "$Value" } + # Pass value through as-is (object or string); set-panels needs object form + $opValue = if ($null -ne $op.value) { $op.value } else { $Value } + $opValueStr = if ($opValue -is [string]) { $opValue } else { "$opValue" } switch ($opName) { - "modify-property" { Do-ModifyProperty $opValue } - "add-childObject" { Do-AddChildObject $opValue } - "remove-childObject" { Do-RemoveChildObject $opValue } - "add-defaultRole" { Do-AddDefaultRole $opValue } - "remove-defaultRole" { Do-RemoveDefaultRole $opValue } - "set-defaultRoles" { Do-SetDefaultRoles $opValue } + "modify-property" { Do-ModifyProperty $opValueStr } + "add-childObject" { Do-AddChildObject $opValueStr } + "remove-childObject" { Do-RemoveChildObject $opValueStr } + "add-defaultRole" { Do-AddDefaultRole $opValueStr } + "remove-defaultRole" { Do-RemoveDefaultRole $opValueStr } + "set-defaultRoles" { Do-SetDefaultRoles $opValueStr } + "set-panels" { Do-SetPanels $opValue } default { Write-Error "Unknown operation: $opName"; exit 1 } } } diff --git a/.claude/skills/cf-edit/scripts/cf-edit.py b/.claude/skills/cf-edit/scripts/cf-edit.py index 614902e8..ca679bb8 100644 --- a/.claude/skills/cf-edit/scripts/cf-edit.py +++ b/.claude/skills/cf-edit/scripts/cf-edit.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# cf-edit v1.1 — Edit 1C configuration root (Configuration.xml) +# cf-edit v1.3 — Edit 1C configuration root (Configuration.xml) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -7,6 +7,7 @@ import json import os import subprocess import sys +import uuid as _uuid from html import escape as html_escape from lxml import etree @@ -161,7 +162,7 @@ def main(): parser = argparse.ArgumentParser(description="Edit 1C configuration root (Configuration.xml)", allow_abbrev=False) parser.add_argument("-ConfigPath", "-Path", required=True) parser.add_argument("-DefinitionFile", default=None) - parser.add_argument("-Operation", default=None, choices=["modify-property", "add-childObject", "remove-childObject", "add-defaultRole", "remove-defaultRole", "set-defaultRoles"]) + parser.add_argument("-Operation", default=None, choices=["modify-property", "add-childObject", "remove-childObject", "add-defaultRole", "remove-defaultRole", "set-defaultRoles", "set-panels"]) parser.add_argument("-Value", default=None) parser.add_argument("-NoValidate", action="store_true") args = parser.parse_args() @@ -493,6 +494,105 @@ def main(): modify_count += 1 info(f"Set DefaultRoles: {len(items)} roles") + # --- set-panels (writes Ext/ClientApplicationInterface.xml from scratch) --- + # Canonical English aliases — preferred form, used in docs and error messages. + PANEL_UUIDS = { + "sections": "b553047f-c9aa-4157-978d-448ecad24248", + "open": "cbab57f2-a0f3-4f0a-89ea-4cb19570ab75", + "favorites": "13322b22-3960-4d68-93a6-fe2dd7f28ca3", + "history": "c933ac92-92cd-459d-81cc-e0c8a83ced99", + "functions": "b2735bd3-d822-4430-ba59-c9e869693b24", + } + # Russian synonyms — silently accepted (cf-info displays Russian names; + # users may copy them straight into cf-edit value). + PANEL_SYNONYMS = { + "разделов": "sections", "разделы": "sections", + "открытых": "open", "открытые": "open", + "избранного": "favorites","избранное": "favorites", + "истории": "history", "история": "history", + "функций": "functions", "функции": "functions", + } + + def build_panel_entry_xml(entry, indent): + if isinstance(entry, str): + key = entry.lower() + key = PANEL_SYNONYMS.get(key, key) + if key not in PANEL_UUIDS: + allowed = ", ".join(sorted(PANEL_UUIDS.keys())) + print(f"Unknown panel alias '{entry}'. Allowed: {allowed}", file=sys.stderr) + sys.exit(1) + inst = str(_uuid.uuid4()) + return f'{indent}\r\n{indent}\t{PANEL_UUIDS[key]}\r\n{indent}' + if isinstance(entry, dict) and "group" in entry: + children = entry["group"] + if not children: + print("group must contain at least one entry", file=sys.stderr) + sys.exit(1) + gid = str(_uuid.uuid4()) + inner = "" + for child in children: + child_xml = build_panel_entry_xml(child, indent + "\t\t") + inner += f"{indent}\t\r\n{child_xml}\r\n{indent}\t\r\n" + return f'{indent}\r\n{inner}{indent}' + print(f"Panel entry must be string alias or {{group:[...]}}, got: {entry!r}", file=sys.stderr) + sys.exit(1) + + def do_set_panels(value): + nonlocal modify_count + layout = value + if isinstance(layout, str): + try: + layout = json.loads(layout) + except json.JSONDecodeError: + print(f"set-panels value must be valid JSON object", file=sys.stderr) + sys.exit(1) + if not isinstance(layout, dict) or not layout: + print("set-panels value must be non-empty object", file=sys.stderr) + sys.exit(1) + + sides = ("top", "left", "right", "bottom") + # Reject unknown side keys + for k in layout.keys(): + if k not in sides: + print(f"Unknown side '{k}'. Allowed: {', '.join(sides)}", file=sys.stderr) + sys.exit(1) + + body_parts = [] + for side in sides: + entries = layout.get(side) + if entries is None: + continue + if not isinstance(entries, list): + entries = [entries] + for entry in entries: + entry_xml = build_panel_entry_xml(entry, "\t\t") + body_parts.append(f"\t<{side}>\r\n{entry_xml}\r\n\t") + body = "\r\n".join(body_parts) + body_block = body + "\r\n" if body else "" + declarations = ( + '\t\r\n' + '\t\r\n' + '\t\r\n' + '\t\r\n' + '\t' + ) + cai_xml = ( + '\r\n' + '\r\n' + f'{body_block}{declarations}\r\n' + '' + ) + ext_dir = os.path.join(config_dir, "Ext") + os.makedirs(ext_dir, exist_ok=True) + cai_path = os.path.join(ext_dir, "ClientApplicationInterface.xml") + with open(cai_path, "w", encoding="utf-8-sig", newline="") as fh: + fh.write(cai_xml) + modify_count += 1 + info(f"Wrote panel layout: {cai_path}") + # --- Execute operations --- operations = [] if args.DefinitionFile: @@ -513,17 +613,19 @@ def main(): op_value = op.get("value", args.Value or "") if op_name == "modify-property": - do_modify_property(op_value) + do_modify_property(op_value if isinstance(op_value, str) else str(op_value)) elif op_name == "add-childObject": - do_add_child_object(op_value) + do_add_child_object(op_value if isinstance(op_value, str) else str(op_value)) elif op_name == "remove-childObject": - do_remove_child_object(op_value) + do_remove_child_object(op_value if isinstance(op_value, str) else str(op_value)) elif op_name == "add-defaultRole": - do_add_default_role(op_value) + do_add_default_role(op_value if isinstance(op_value, str) else str(op_value)) elif op_name == "remove-defaultRole": - do_remove_default_role(op_value) + do_remove_default_role(op_value if isinstance(op_value, str) else str(op_value)) elif op_name == "set-defaultRoles": - do_set_default_roles(op_value) + do_set_default_roles(op_value if isinstance(op_value, str) else str(op_value)) + elif op_name == "set-panels": + do_set_panels(op_value) else: print(f"Unknown operation: {op_name}", file=sys.stderr) sys.exit(1) diff --git a/.claude/skills/cf-info/scripts/cf-info.ps1 b/.claude/skills/cf-info/scripts/cf-info.ps1 index adf18ec3..bd9479c1 100644 --- a/.claude/skills/cf-info/scripts/cf-info.ps1 +++ b/.claude/skills/cf-info/scripts/cf-info.ps1 @@ -1,4 +1,4 @@ -# cf-info v1.0 — Compact summary of 1C configuration root +# cf-info v1.1 — Compact summary of 1C configuration root # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [Parameter(Mandatory=$true)][Alias('Path')][string]$ConfigPath, @@ -118,6 +118,59 @@ $typeRuNames = @{ "Task"="Задачи"; "IntegrationService"="Сервисы интеграции" } +# --- Read panel layout (Ext/ClientApplicationInterface.xml) --- +$script:panelNames = @{ + "cbab57f2-a0f3-4f0a-89ea-4cb19570ab75" = "Открытых" + "b553047f-c9aa-4157-978d-448ecad24248" = "Разделов" + "13322b22-3960-4d68-93a6-fe2dd7f28ca3" = "Избранного" + "c933ac92-92cd-459d-81cc-e0c8a83ced99" = "История" + "b2735bd3-d822-4430-ba59-c9e869693b24" = "Функций" +} + +function Get-PanelsLayout { + $configDir = [System.IO.Path]::GetDirectoryName($ConfigPath) + $caiPath = Join-Path (Join-Path $configDir "Ext") "ClientApplicationInterface.xml" + if (-not (Test-Path $caiPath)) { return $null } + try { [xml]$caiDoc = Get-Content -Path $caiPath -Encoding UTF8 } catch { return $null } + if (-not $caiDoc.DocumentElement) { return $null } + $caiNs = New-Object System.Xml.XmlNamespaceManager($caiDoc.NameTable) + $caiNs.AddNamespace("ca", "http://v8.1c.ru/8.2/managed-application/core") + $layout = [ordered]@{ top=@(); left=@(); right=@(); bottom=@(); declared=@() } + foreach ($side in @("top","left","right","bottom")) { + foreach ($sideEl in $caiDoc.DocumentElement.SelectNodes("ca:$side", $caiNs)) { + $slot = @() + foreach ($u in $sideEl.SelectNodes(".//ca:panel/ca:uuid", $caiNs)) { + $key = $u.InnerText.Trim() + $nm = if ($script:panelNames.Contains($key)) { $script:panelNames[$key] } else { "?$key" } + $slot += $nm + } + if ($slot.Count -gt 0) { $layout[$side] += ,$slot } + } + } + foreach ($pd in $caiDoc.DocumentElement.SelectNodes("ca:panelDef", $caiNs)) { + $key = $pd.GetAttribute("id") + $nm = if ($script:panelNames.Contains($key)) { $script:panelNames[$key] } else { "?$key" } + $layout.declared += $nm + } + return $layout +} + +function Format-LayoutSlots($slots) { + # slots is array of arrays (each inner array = one side-tag's panels, may be 1+) + # Single inner array, single panel -> just name + # Single inner array, multiple panels -> "Стек(a, b)" + # Multiple inner arrays -> separate entries joined by " | " + if (-not $slots -or $slots.Count -eq 0) { return "" } + $parts = @() + foreach ($slot in $slots) { + if ($slot.Count -eq 1) { $parts += $slot[0] } + else { $parts += ("Стек(" + ($slot -join ", ") + ")") } + } + return ($parts -join " | ") +} + +$script:panelLayout = Get-PanelsLayout + # --- Count objects in ChildObjects --- $objectCounts = [ordered]@{} $totalObjects = 0 @@ -181,6 +234,23 @@ if ($Mode -eq "overview") { Out "Интерфейс: $cfgIntfCompat" Out "" + # Panel layout (if file exists) + if ($script:panelLayout) { + $hasPlaced = $false + foreach ($s in @("top","left","right","bottom")) { + if ($script:panelLayout[$s].Count -gt 0) { $hasPlaced = $true; break } + } + if ($hasPlaced) { + Out "--- Раскладка панелей ---" + foreach ($s in @("top","left","right","bottom")) { + if ($script:panelLayout[$s].Count -gt 0) { + Out " $($s.PadRight(7)) $(Format-LayoutSlots $script:panelLayout[$s])" + } + } + Out "" + } + } + # Object counts table Out "--- Состав ($totalObjects объектов) ---" Out "" @@ -275,6 +345,23 @@ if ($Mode -eq "full") { Out "Обычн.формы в управл.: $useOF" Out "" + # --- Section: Panel layout --- + if ($script:panelLayout) { + Out "--- Раскладка панелей ---" + foreach ($s in @("top","left","right","bottom")) { + $slots = $script:panelLayout[$s] + if ($slots.Count -gt 0) { + Out " $($s.PadRight(7)) $(Format-LayoutSlots $slots)" + } else { + Out " $($s.PadRight(7)) —" + } + } + if ($script:panelLayout.declared.Count -gt 0) { + Out " объявлено: $($script:panelLayout.declared -join ', ')" + } + Out "" + } + # --- Section: Storages & default forms --- Out "--- Хранилища и формы по умолчанию ---" $storageProps = @("CommonSettingsStorage","ReportsUserSettingsStorage","ReportsVariantsStorage","FormDataSettingsStorage","DynamicListsUserSettingsStorage","URLExternalDataStorage") diff --git a/.claude/skills/cf-info/scripts/cf-info.py b/.claude/skills/cf-info/scripts/cf-info.py index 0677436a..64e87381 100644 --- a/.claude/skills/cf-info/scripts/cf-info.py +++ b/.claude/skills/cf-info/scripts/cf-info.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# cf-info v1.0 — Compact summary of 1C configuration root +# cf-info v1.1 — Compact summary of 1C configuration root # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse @@ -125,6 +125,53 @@ type_ru_names = { "Task": "Задачи", "IntegrationService": "Сервисы интеграции", } +# --- Read panel layout (Ext/ClientApplicationInterface.xml) --- +PANEL_NAMES = { + "cbab57f2-a0f3-4f0a-89ea-4cb19570ab75": "Открытых", + "b553047f-c9aa-4157-978d-448ecad24248": "Разделов", + "13322b22-3960-4d68-93a6-fe2dd7f28ca3": "Избранного", + "c933ac92-92cd-459d-81cc-e0c8a83ced99": "История", + "b2735bd3-d822-4430-ba59-c9e869693b24": "Функций", +} +CAI_NS = "http://v8.1c.ru/8.2/managed-application/core" + +def get_panels_layout(): + cfg_dir = os.path.dirname(config_path) + cai_path = os.path.join(cfg_dir, "Ext", "ClientApplicationInterface.xml") + if not os.path.isfile(cai_path): + return None + try: + cai_tree = etree.parse(cai_path) + except Exception: + return None + cai_root = cai_tree.getroot() + layout = {"top": [], "left": [], "right": [], "bottom": [], "declared": []} + for side in ("top", "left", "right", "bottom"): + for side_el in cai_root.findall(f"{{{CAI_NS}}}{side}"): + slot = [] + for u in side_el.iter(f"{{{CAI_NS}}}uuid"): + key = (u.text or "").strip() + slot.append(PANEL_NAMES.get(key, f"?{key}")) + if slot: + layout[side].append(slot) + for pd in cai_root.findall(f"{{{CAI_NS}}}panelDef"): + key = pd.get("id", "") + layout["declared"].append(PANEL_NAMES.get(key, f"?{key}")) + return layout + +def format_layout_slots(slots): + if not slots: + return "" + parts = [] + for slot in slots: + if len(slot) == 1: + parts.append(slot[0]) + else: + parts.append("Стек(" + ", ".join(slot) + ")") + return " | ".join(parts) + +panel_layout = get_panels_layout() + # --- Count objects in ChildObjects --- object_counts = OrderedDict() total_objects = 0 @@ -187,6 +234,13 @@ if args.Mode == "overview": out(f"Интерфейс: {cfg_intf_compat}") out() + if panel_layout and any(panel_layout[s] for s in ("top", "left", "right", "bottom")): + out("--- Раскладка панелей ---") + for s in ("top", "left", "right", "bottom"): + if panel_layout[s]: + out(f" {s.ljust(7)} {format_layout_slots(panel_layout[s])}") + out() + # Object counts table out(f"--- Состав ({total_objects} объектов) ---") out() @@ -283,6 +337,19 @@ if args.Mode == "full": out(f"Обычн.формы в управл.: {use_of}") out() + # --- Section: Panel layout --- + if panel_layout: + out("--- Раскладка панелей ---") + for s in ("top", "left", "right", "bottom"): + slots = panel_layout[s] + if slots: + out(f" {s.ljust(7)} {format_layout_slots(slots)}") + else: + out(f" {s.ljust(7)} —") + if panel_layout["declared"]: + out(f" объявлено: {', '.join(panel_layout['declared'])}") + out() + # --- Section: Storages & default forms --- out("--- Хранилища и формы по умолчанию ---") storage_props = [ diff --git a/tests/skills/cases/cf-edit/set-panels.json b/tests/skills/cases/cf-edit/set-panels.json new file mode 100644 index 00000000..c3fba247 --- /dev/null +++ b/tests/skills/cases/cf-edit/set-panels.json @@ -0,0 +1,14 @@ +{ + "name": "Установить раскладку панелей (top/left/right стек/bottom)", + "input": [ + { + "operation": "set-panels", + "value": { + "top": ["open"], + "left": ["sections"], + "right": [{ "group": ["favorites", "history"] }], + "bottom": ["functions"] + } + } + ] +} diff --git a/tests/skills/cases/cf-edit/snapshots/set-panels/Configuration.xml b/tests/skills/cases/cf-edit/snapshots/set-panels/Configuration.xml new file mode 100644 index 00000000..ae8620a1 --- /dev/null +++ b/tests/skills/cases/cf-edit/snapshots/set-panels/Configuration.xml @@ -0,0 +1,251 @@ + + + + + + UUID-002 + UUID-003 + + + UUID-004 + UUID-005 + + + UUID-006 + UUID-007 + + + UUID-008 + UUID-009 + + + UUID-010 + UUID-011 + + + UUID-012 + UUID-013 + + + UUID-014 + UUID-015 + + + + TestConfig + + + ru + TestConfig + + + + + Version8_3_24 + ManagedApplication + + PlatformApplication + + Russian + + + + + false + false + false + + + + + + + + + + + + + + + + + + + + + + Biometrics + true + + + Location + false + + + BackgroundLocation + false + + + BluetoothPrinters + false + + + WiFiPrinters + false + + + Contacts + false + + + Calendars + false + + + PushNotifications + false + + + LocalNotifications + false + + + InAppPurchases + false + + + PersonalComputerFileExchange + false + + + Ads + false + + + NumberDialing + false + + + CallProcessing + false + + + CallLog + false + + + AutoSendSMS + false + + + ReceiveSMS + false + + + SMSLog + false + + + Camera + false + + + Microphone + false + + + MusicLibrary + false + + + PictureAndVideoLibraries + false + + + AudioPlaybackAndVibration + false + + + BackgroundAudioPlaybackAndVibration + false + + + InstallPackages + false + + + OSBackup + true + + + ApplicationUsageStatistics + false + + + BarcodeScanning + false + + + BackgroundAudioRecording + false + + + AllFilesAccess + false + + + Videoconferences + false + + + NFC + false + + + DocumentScanning + false + + + SpeechToText + false + + + Geofences + false + + + IncomingShareRequests + false + + + AllIncomingShareRequestsTypesProcessing + false + + + + + + Normal + + + Language.Русский + + + + + + Managed + NotAutoFree + DontUse + DontUse + TaxiEnableVersion8_2 + DontUse + Version8_3_24 + + + + Русский + + + \ No newline at end of file diff --git a/tests/skills/cases/cf-edit/snapshots/set-panels/Ext/ClientApplicationInterface.xml b/tests/skills/cases/cf-edit/snapshots/set-panels/Ext/ClientApplicationInterface.xml new file mode 100644 index 00000000..ec0cb324 --- /dev/null +++ b/tests/skills/cases/cf-edit/snapshots/set-panels/Ext/ClientApplicationInterface.xml @@ -0,0 +1,37 @@ + + + + + UUID-002 + + + + + UUID-004 + + + + + + + UUID-007 + + + + + UUID-009 + + + + + + + UUID-011 + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/cf-edit/snapshots/set-panels/Languages/Русский.xml b/tests/skills/cases/cf-edit/snapshots/set-panels/Languages/Русский.xml new file mode 100644 index 00000000..37c60d78 --- /dev/null +++ b/tests/skills/cases/cf-edit/snapshots/set-panels/Languages/Русский.xml @@ -0,0 +1,16 @@ + + + + + Русский + + + ru + Русский + + + + ru + + + \ No newline at end of file