Skip to content
Back to skills

Form Edit

ASecurity

Добавление и удаление элементов, реквизитов и команд в существующей управляемой форме 1С. Используй когда нужно точечно модифицировать готовую форму

  • 213 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added June 11, 2026
toolsbashnode

Works with

  • cursor
  • cli
  • mcp

Security analysis

A100/100

Scanned October 4, 2026

npx -y skills add IngvarConsulting/unica --skill form-edit --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Form Edit?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Form Edit
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/ingvarconsulting-form-edit/badge)](https://www.skillsdirectory.com/skills/ingvarconsulting-form-edit)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: form-edit
description: Добавление и удаление элементов, реквизитов и команд в существующей управляемой форме 1С. Используй когда нужно точечно модифицировать готовую форму
allowed-tools:
  - Bash
  - Read
  - Write
  - Glob
---

# /form-edit — Редактирование формы

## MCP routing

- Preferred path: use MCP `unica` tool `unica.apply` с операциями формы; адрес
  цели — логический, файлового селектора у поверхности нет.
- Не зови внутренние адаптеры напрямую: они спрятаны за MCP `unica`.
- Сначала вызови `unica.apply` с `at` и `ops`: это план без записи.
  Когда пользователь поручил внести эту правку, вызови `unica.apply` только
  с `executionToken` из `data.executionToken` успешного плана.
- Словарь операций узла даёт `unica.view {at}` в секции `can`: что не названо
  там, того поверхность не пишет.
- Поддержку объекта проверяет сама операция; заблокированный поставщиком
  объект правится через расширение, а не правкой метаданных поддержки.

Добавляет и удаляет элементы, реквизиты и команды существующей управляемой
формы. Идентификаторы, companion-элементы (`ContextMenu`, `ExtendedTooltip` и
прочие) и привязки событий собирает сама операция.

## Адрес и операции

Цель — узел формы: `<набор>:<Вид>.<Имя>.Form.<Форма>`. Имя набора даёт
`unica.view {}`, адрес по имени объекта — `unica.search {corpus: "names"}`.

| Операция | Что делает |
|---|---|
| `element.add` | добавляет элементы; `items[]` несёт то же описание, что раздел «JSON формат» ниже |
| `element.remove` | удаляет элемент, названный адресом (`…Form.Ф.Item.X`) или списком `items` |
| `formAttribute.add` | добавляет реквизит формы |
| `formCommand.add` | добавляет команду формы |
| `event.bind` | привязывает обработчик к событию формы или элемента |
| `form.add`, `form.set`, `form.remove` | состав форм объекта и их свойства |

## MCP вызов

```json
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "unica.apply",
    "arguments": {
      "at": "main:Catalog.Номенклатура.Form.ФормаЭлемента",
      "ops": [
        {
          "op": "element.add",
          "args": {
            "items": [
              {"name": "Артикул", "type": "InputField", "path": "Объект.Артикул", "into": "ГруппаШапка"}
            ]
          }
        }
      ]
    }
  }
}
```

Применение — вызов только с `executionToken` из `data.executionToken` успешного плана.

## JSON формат

```json
{
  "into": "ГруппаШапка",
  "after": "Контрагент",
  "elements": [
    { "input": "Склад", "path": "Объект.Склад", "on": ["OnChange"] }
  ],
  "attributes": [
    { "name": "СуммаИтого", "type": "decimal(15,2)" }
  ],
  "commands": [
    { "name": "Рассчитать", "action": "РассчитатьОбработка" }
  ]
}
```

### Расширения (extension-формы)

Для заимствованных форм (с `<BaseForm>`) автоматически активируется extension-режим: ID начинаются с 1000000+. Доступны дополнительные секции:

```json
{
  "formEvents": [
    { "name": "OnCreateAtServer", "handler": "Расш1_ПриСозданииПосле", "callType": "After" },
    { "name": "OnOpen", "handler": "Расш1_ПриОткрытии", "callType": "Before" }
  ],
  "elementEvents": [
    { "element": "Банк", "name": "OnChange", "handler": "Расш1_БанкПриИзменении", "callType": "Before" }
  ],
  "commands": [
    { "name": "Подбор", "action": "Расш1_ПодборПосле", "callType": "After" },
    { "name": "Запрос", "actions": [
      { "callType": "Before", "handler": "Расш1_ЗапросПеред" },
      { "callType": "After", "handler": "Расш1_ЗапросПосле" }
    ]}
  ],
  "elements": [
    { "input": "Поле", "path": "Объект.Поле", "on": [{ "event": "OnChange", "callType": "After" }] }
  ]
}
```

### Позиционирование элементов

| Ключ | По умолчанию | Описание |
|------|-------------|----------|
| `into` | корневой ChildItems | Имя группы/таблицы/страницы, куда вставлять |
| `after` | в конец | Имя элемента, после которого вставлять |

### Удаление элементов

`element.remove` называет цель адресом — `…Form.<Форма>.Item.<Имя>` — либо
списком имён в `items`:

```json
{
  "op": "element.remove",
  "args": {"items": [{"name": "Товары"}]}
}
```

Ключ `removeElements` — внутренняя форма описания, в которую операция
разворачивает эти имена; аргументом `element.remove` он не является и в вызове
отклоняется как неизвестное поле. Гарантии ниже описаны для обеих форм.

- Элемент сопоставляется с атрибутом XML `name` точно, с учётом регистра и пробелов. Поиск по префиксу и нормализация имени не выполняются.
- В записи разрешено только строковое непустое поле `name`. Параметров `includeCompanions` и `ifMissing` нет: они отклоняются как неизвестные поля.
- Удаляется всё структурное XML-поддерево элемента. Вложенные элементы и contained companions (`ContextMenu`, `ExtendedTooltip`, `AutoCommandBar` и другие узлы внутри поддерева) удаляются вместе с владельцем и перечисляются в результате с `reason: "contained"`.
- По умолчанию отсутствующая цель завершает весь вызов ошибкой `FORM_ELEMENT_NOT_FOUND`; повторное удаление отсутствующего элемента не является idempotent no-op.
- Удалять можно только публичный элемент рабочего дерева формы, непосредственно принадлежащий контейнеру `ChildItems`. Корневой `AutoCommandBar`, отдельный companion внутри владельца, baseline внутри `BaseForm` и другие именованные узлы вне рабочего дерева защищены; неоднозначные и перекрывающиеся цели также отклоняются.
- До публикации проверяются конфликты с тем же `definition` (`elements`, вложенные `children`/`columns`, `into`, `after`, `elementEvents`) и поддерживаемые ссылки в остающемся рабочем XML: binding paths вида `Items.<name>.CurrentData...` (включая имена с точками), `Form.Item.<name>.StandardCommand.*` и `AdditionSource/Item`.
- Если сохраняемый элемент ссылается на удаляемый contained companion, весь вызов завершается атомарной ошибкой `FORM_EDIT_REMOVE_SURVIVING_REFERENCE`: companion не отделяется от владельца и не удаляется частично. Ссылки из baseline `BaseForm` не блокируют изменение рабочего дерева, а сам baseline не редактируется.
- Проверка ссылок намеренно не анализирует BSL и не переписывает обращения к элементу в `Module.bsl`. Такие ссылки нужно найти и изменить отдельно до удаления.
- Весь batch атомарен: планирование, проверки ссылок и полная валидация спроецированного XML завершаются до фиксации транзакции. Apply дополнительно повторяет проверку формы (`unica.check` на узле формы) после записи внутри транзакции; при любой ошибке Form.xml не меняется.

Preview и apply возвращают одинаковую типизированную форму `data`:

```json
{
  "changed": true,
  "removed": [
    { "name": "Товары", "kind": "Table", "reason": "requested" },
    { "name": "ТоварыКонтекстноеМеню", "kind": "ContextMenu", "reason": "contained" }
  ],
  "validation": "passed"
}
```

При планировании (`at` и `ops`) файл и cache events не меняются. Preview, apply и no-op проходят одну полную валидацию спроецированного XML до возврата `validation: "passed"`. Apply (`executionToken`) публикует только успешно проверенный результат и инвалидирует кэш событием `FormChanged`, только если `changed: true`. Валидный idempotent no-op без удаления сохраняет исходные байты, возвращает `changed: false`, пустой `removed` и не создаёт cache event; невалидный исходный XML завершается ошибкой.

### Типы элементов

В `element.add` каждый `items[]` задаёт `name` и `type` (платформенный XML-тег
из таблицы). Короткие ключи ниже относятся к внутреннему описанию элементов.
Словарь создаёт одиннадцать видов:

| Ключ | XML тег | Companions |
|------|---------|------------|
| `input` | InputField | ContextMenu, ExtendedTooltip |
| `html` | HTMLDocumentField | ContextMenu, ExtendedTooltip |
| `check` | CheckBoxField | ContextMenu, ExtendedTooltip |
| `label` | LabelDecoration | ContextMenu, ExtendedTooltip |
| `labelField` | LabelField | ContextMenu, ExtendedTooltip |
| `group` | UsualGroup | ExtendedTooltip |
| `table` | Table | ContextMenu, AutoCommandBar, Search*, ViewStatus* |
| `pages` | Pages | ExtendedTooltip |
| `page` | Page | ExtendedTooltip |
| `button` | Button | ExtendedTooltip |
| `commandBar` | CommandBar | — |

Группы и таблицы поддерживают `children`/`columns` для вложенных элементов.

### Поле HTML-документа

HTML-поле привязывается через `path` к строковому реквизиту формы.
Публичный `items[]` задаёт `name` и `type: "HTMLDocumentField"`;
внутренний ключ `html` здесь отклоняется, в том числе вместе с `type`.
Сначала создайте его через `formAttribute.add`, если реквизита ещё нет.
Затем запросите план добавления поля и примените его отдельным вызовом
`unica.apply` только с `executionToken` из `data.executionToken` ответа:

```json
{
  "at": "main:Catalog.ТехническиеПроекты.Form.ФормаЭлемента",
  "ops": [{"op": "element.add", "args": {"items": [{
    "name": "ПолеОписания", "type": "HTMLDocumentField",
    "path": "СтраницаРедактораОписания", "titleLocation": "none",
    "width": 1, "height": 1, "autoMaxWidth": false, "skipOnInput": true,
    "on": ["OnClick", "DocumentComplete"]
  }]}}]
}
```

Поддержаны `path`, `title`, `tooltip`, `titleLocation`, `width`/`height`
(целые `0..4294967295`), `autoMaxWidth`/`autoMaxHeight`, `skipOnInput`,
`visible`, `userVisible`, `enabled`, `readOnly` и синонимы `hidden`/`disabled`.
Булевы параметры принимают JSON boolean. События — только `OnClick` и
`DocumentComplete`; имена обработчиков можно задать в `handlers` вместе с `on`.
Для существующего поля используйте `event.bind` по адресу `…Form.ФормаЭлемента.Item.ПолеОписания`.
DOM-свойство `Document` относится к выполнению 1С и не записывается в XML.

Для помещения HTML-поля в группу задайте `into` в отдельном `items[]`;
`after` задаёт соседний элемент. Вложенный typed-объект с
`type: "HTMLDocumentField"` в `children`/`columns` отклоняется с подсказкой
использовать отдельный item. Полученную форму прочитайте через `unica.view`
и проверьте через `unica.check`.

### Чего словарь не пишет

Остальные виды платформенных полей и декораций **поверхность не создаёт**:
поля картинки, текстового, табличного и форматированного документа,
диаграммы и сводной диаграммы, диаграммы Ганта, календаря, периода,
индикатора, ползунка, географической схемы, дендрограммы, планировщика,
радиокнопки, а также декоративную картинку и поле поиска.

Существующий элемент такого вида **читается** `unica.view` на узле формы и
переживает правку соседей; создать или переписать его этой операцией нельзя.
Если задача требует именно такого элемента — сообщи об этом как о пробеле
контракта Unica MCP и не подменяй его другим видом.

### Кнопки: command и stdCommand

- `"command": "ИмяКоманды"` → `Form.Command.ИмяКоманды`
- `"stdCommand": "Close"` → `Form.StandardCommand.Close`
- `"stdCommand": "Товары.Add"` → `Form.Item.Товары.StandardCommand.Add` (стандартная команда элемента)

### Доступность команд формы

Если пользователь просит заблокировать, отключить или сделать недоступной
команду формы, управляй UI-элементами, связанными с командой, а не объектом
команды. Не генерируй и не советуй `Команды[ИмяКоманды].Доступность`: у команды
формы не используется свойство `Доступность` для управления кнопками и пунктами
меню.

Перед написанием BSL-кода прочитай узел формы через `unica.view` по
квалифицированному адресу `at` (CTR.SOURCE.LOGICAL-NODE-VIEW-SHAPE). Например,
аргументы вызовов чтения формы и её коллекции элементов:

```json
{"name": "unica.view", "arguments": {"at": "main:Catalog.Номенклатура.Form.ФормаЭлемента"}}
```

```json
{"name": "unica.view", "arguments": {"at": "main:Catalog.Номенклатура.Form.ФормаЭлемента.Item"}}
```

Ответ узла содержит `props` и `branches`, страница коллекции — `items` с
адресами `at`. Обойди все вложенные ветви `Item` по адресам из `branches` и
все страницы по возвращённому `cursor`, сохраняя адрес и параметры чтения.
У элемента нынешний view публикует в `props` только `tag`, `title`, `visible`,
`enabled`, `readOnly` (`title` равен `null`, если отдельный заголовок не задан).

Для установления связи требуется `CommandName`, например
`Form.Command.<ИмяКоманды>`, либо соответствующая ссылка стандартной команды.
Однако нынешний view не публикует ни `CommandName`, ни `binding`: по одному
дереву элементов нельзя доказать связь с командой и полноту связанных элементов.
Не угадывай связь по имени или заголовку. Для недостающих данных используй
аварийный мост к исходникам, разрешённый для чтения файла вне Unica:

```json
{"name": "unica.resolve", "arguments": {"at": "main:Catalog.Номенклатура.Form.ФормаЭлемента"}}
```

Возвращённый `path` относится к корню выбранного набора исходников, а не
обязательно к корню рабочего пространства. Сверь корень и формат набора
с конфигурацией проекта. В выгрузке Designer это может быть дескриптор
`Catalogs/Номенклатура/Forms/ФормаЭлемента.xml`: дерево элементов находится
рядом, в `ФормаЭлемента/Ext/Form.xml`. Проверь существование файла и его
корень `Form` в пространстве имён `http://v8.1c.ru/8.3/xcf/logform`;
дескриптор `MetaDataObject` не содержит полного дерева формы. Не переноси
эту раскладку на EDT и другие форматы без подтверждения.

Прочитай содержимое формы через `Read` и найди все элементы с точным
`CommandName` нужной команды, учитывая пространство имён XML. Обойди весь XML, включая `AutoCommandBar`,
`ContextMenu`, командные панели таблиц и вложенные группы, а не только
`ChildItems` корня: проекция `Item` не показывает все эти контейнеры.
Зафиксируй имена элементов и их привязки. Это только чтение; изменения
исходников по-прежнему выполняются через `unica.apply` с preview и `executionToken`.

Проверь также автозаполнение командных панелей и создание элементов в модуле
формы: статический XML не доказывает состав динамического интерфейса.
Если файл недоступен, формат не подтверждён или полнота связей остаётся
неизвестной, назови конкретное ограничение и найденных кандидатов; не генерируй
BSL с неподтверждёнными именами. Пробел чтения MCP обозначай как
**Unica MCP contract gap**, а динамический состав формы — как требующий
проверки кода или открытой формы. Отсутствие `binding` в `view` само по себе
не завершает исследование.

Когда связи подтверждены, меняй все связанные элементы через
`Элементы[ИмяЭлемента].Доступность`: кнопку основной командной панели, кнопку
командной панели таблицы, пункт контекстного меню, кнопку группы или подменю.
Одна найденная кнопка не доказывает, что других элементов этой команды нет.

```bsl
Элементы[ИмяЭлемента].Доступность = Ложь;
```

Например, если в проверенной форме кнопки `ЗаполнитьВПанели` и
`ЗаполнитьВМеню` обе связаны с `Form.Command.Заполнить`, отключи обе:

```bsl
Для Каждого ИмяЭлемента Из СтрРазделить("ЗаполнитьВПанели,ЗаполнитьВМеню", ",") Цикл
    Элементы[ИмяЭлемента].Доступность = Ложь;
КонецЦикла;
```

Если связанный элемент нельзя определить однозначно, сначала проанализируй форму
и назови найденные кандидаты. Для стандартных команд табличной части отдельно
проверь свойство таблицы `ТолькоПросмотр` (`readOnly` в `props` узла таблицы):
когда таблица уже только для просмотра, платформа обычно сама блокирует стандартные команды добавления,
копирования, удаления и перемещения строк. Ручная блокировка нужна прежде всего
для пользовательских элементов, запускающих изменение табличной части: подбор,
заполнение, загрузку, пересчёт, удаление строк, сортировку, изменение цен,
скидок, НДС и аналогичные действия.

### Допустимые события (`on`)

Editor до записи проверяет событие по единой платформенной матрице. Недопустимое сочетание возвращает `ok=false` и код `FORM_EVENT_*`, не меняя файл. Основные сочетания:

- **input**: `OnChange`, `StartChoice`, `ChoiceProcessing`, `Clearing`, `AutoComplete`, `TextEditEnd`, `Opening`, `Creating`, `EditTextChange`
- **check**: `OnChange`
- **table**: `OnStartEdit`, `OnEditEnd`, `OnChange`, `Selection`, `BeforeAddRow`, `BeforeDeleteRow`, `OnActivateRow`
- **label**: `Click`, `URLProcessing`
- **picture**: `Click`, `Drag`, `DragCheck`
- **pages**: `OnCurrentPageChange`
- **page/button/group/command bar**: события не поддерживаются

События `table` требуют непустой привязки: `path` для нового элемента или прямого `DataPath` у существующего `Table`. Платформа удаляет обработчики событий у несвязанной таблицы при загрузке/выгрузке конфигурации.

`OnReadAtServer`, `BeforeWrite`, `BeforeWriteAtServer`, `OnWriteAtServer`, `AfterWriteAtServer` и `AfterWrite` разрешены только при подтверждённом persistent object/record типе главного реквизита. Для `DataProcessorObject`, `ReportObject`, `DynamicList` и неизвестного контекста они отклоняются. `NewWriteProcessing` и `FillCheckProcessingAtServer` являются общими событиями формы и этим ограничением не связаны.

### Система типов (для attributes)

`string`, `string(100)`, `decimal(15,2)`, `boolean`, `date`, `dateTime`, `CatalogRef.XXX`, `DocumentObject.XXX`, `ValueTable`, `DynamicList`, `Type1 | Type2` (составной).

### Секции расширений

| Секция | Назначение |
|--------|-----------|
| `formEvents` | События уровня формы; `callType` только для расширения |
| `elementEvents` | События существующих элементов; `callType` только для расширения |
| `callType` на `commands` | callType на Action команды |
| `callType` на `on` | callType на событиях новых элементов (объектный формат) |

Все extension-секции опциональны — без них навык работает как с обычными формами.

Повтор идентичного binding является явным idempotent no-op. Конфликт обработчика/`callType`, duplicate, отсутствующий элемент и любой недопустимый event отклоняют весь batch до мутации; планирование использует тот же planner.

## Workflow

1. `unica.view` на узле формы — текущая структура и секция `can`
2. Собрать `ops` по описанию ниже
3. `unica.apply` с `at` и `ops` — план и `data.executionToken`
4. `unica.apply` только с `executionToken` — применение
5. `unica.check` на узле формы — проверка, затем `unica.view` — убедиться, что структура изменилась правильно

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…