API: Списки, поля, элементы, вложения
Требуется авторизация. Права наследуются от узла-родителя (nodeId).
Чтение и обновление значений полей (примеры REST, JS, WebPart, Event Receiver, Timer Job): Значения полей списков.
Списки — /api/v1/lists
Заголовок раздела «Списки — /api/v1/lists»| Метод | Путь | Право на узел | Описание |
|---|---|---|---|
| GET | /lists?nodeId={uuid} | view | Списки узла |
| POST | /lists | edit | Создать список |
| GET | /lists/{id} | view | Список с полями |
| PATCH | /lists/{id} | edit | Обновить |
| DELETE | /lists/{id} | delete | Удалить в корзину узла (снимок списка целиком) |
| POST | /lists/{id}/recycle-content | delete | Переместить все элементы списка в корзину (список остаётся) |
DELETE /lists/{id} — мягкое удаление: одна запись корзины с полями, представлениями и текущим содержимым. Элементы этого списка, уже лежавшие в корзине, purge. Восстановление — POST /nodes/{nodeId}/recycle-bin/{entryId}/restore. См. Корзина.
Тело создания:
{ "nodeId": "uuid", "title": "Задачи", "slug": "zadachi", "description": ""}Кастомизация форм (form_config)
Заголовок раздела «Кастомизация форм (form_config)»В ответе GET /lists/{id} и после PATCH /lists/{id} поле form_config (JSONB) описывает формы создания / просмотра / редактирования элементов:
{ "edit": { "script": "context.setFieldDisabled('Status', true);", "showStandardForm": true, "webParts": [ { "instanceId": "uuid", "definitionKey": "portal.hero", "title": "Баннер", "properties": {}, "placement": "before" } ] }}| Поле | Описание |
|---|---|
new / view / edit | Конфиг соответствующей формы |
script | Пользовательский JS (до 65 536 символов). На клиенте: $, context, $container. Хелперы: setFieldDisabled, hideField, showField, getFormValues, setFieldValue. Можно вернуть dispose. |
showStandardForm | true (по умолчанию) — показать стандартные поля; false — скрыть, тело страницы занимают веб-части |
webParts[].placement | before или after относительно стандартной формы (при showStandardForm: false порядок в массиве = тело страницы) |
Обновление через PATCH /lists/{id}:
{ "formConfig": { "edit": { "script": "...", "showStandardForm": true, "webParts": [] } } }Права: как у обычного обновления списка (edit). UI: Настройки списка → Формы. Блокировка полей скриптом — только UI; серверная защита по-прежнему через event receivers.
Подробный гайд: Кастомизация форм элементов.
Поля — /api/v1/lists/{listId}/fields
Заголовок раздела «Поля — /api/v1/lists/{listId}/fields»| Метод | Путь | Право | Описание |
|---|---|---|---|
| GET | /lists/{listId}/fields | view | Поля списка |
| POST | /lists/{listId}/fields | edit | Добавить поле |
| PATCH | /lists/{listId}/fields/{fieldId} | edit | Обновить |
| DELETE | /lists/{listId}/fields/{fieldId} | edit | Удалить |
При создании и обновлении поля в теле запроса доступны title, fieldType, isRequired, sortOrder, settings. Флаг isRequired (is_required в ответе) помечает поле обязательным: при создании и редактировании элементов (форма, быстрое редактирование, API) сервер отклоняет пустые значения с ошибкой Поле «…» обязательно.
В UI настроек списка (вкладка Поля, portal_admin) признак Обяз. переключается для каждого поля; при добавлении поля — чекбокс в строке формы. Системные поля created_by и item_number не редактируются; для title можно менять только обязательность.
Типы полей: text, multiline_text, html_text, choice, number, date, datetime, boolean, lookup, person, link.
| Тип | settings | Значение в fieldValues |
|---|---|---|
text | — | строка |
multiline_text | — | строка |
html_text | — | HTML (санитизация на сервере) |
choice | { choices: ["A","B"] } | одна из choices |
number | — | число |
date | — | YYYY-MM-DD |
datetime | — | ISO 8601 |
boolean | — | true / false |
lookup | { lookupNodeId?, lookupListId, lookupFieldId?, allowMultiple? } — allowMultiple по умолчанию false | { itemId, display } или массив при allowMultiple: true |
person | { allowUsers?, allowGroups?, allowMultiple? } — по умолчанию все true | массив { principalType, id, display } (или один объект при allowMultiple: false) |
link | — | { url, description? } |
Для choice укажите settings.choices — массив строк.
Для lookup укажите settings.lookupListId (обязательно), опционально settings.lookupNodeId (узел списка-источника, для UI настроек) и settings.lookupFieldId — поле отображения в целевом списке.
Для person (principalType: user или group):
allowUsers/allowGroups— ограничить типы субъектов (по умолчанию обаtrue);allowMultiple— множественный выбор (по умолчаниюtrue→ значение хранится как массив объектов; явныйfalse— один объект).
При создании поля без settings API подставляет { allowUsers: true, allowGroups: true, allowMultiple: true }.
Системное поле created_by («Кем создано») — person с allowUsers: true, allowGroups: false, allowMultiple: false; в UI настроек списка не редактируется (шестерёнки нет).
Настройки существующего поля person можно изменить через PATCH /lists/{listId}/fields/{fieldId} с телом { "settings": { "allowUsers", "allowGroups", "allowMultiple" } }. При ужесточении правил сервер нормализует значения в элементах (лишние субъекты и недопустимые типы удаляются; при allowMultiple: false остаётся первый субъект).
В UI редактирования элемента поле выглядит как чип-пикер: можно выбрать несколько пользователей и групп сразу (если allowMultiple не выключен). На вкладке Поля у обычного person — значок шестерёнки («Настроить»): пользователи / группы / множественный выбор.
Поиск для person
Заголовок раздела «Поиск для person»GET /lists/{listId}/person-options?fieldId={uuid}&q=текст&excludeIds=id1,id2
Поиск пользователей по ФИО (display_name), логину и email. Группы — по имени и описанию.
excludeIds — уже выбранные субъекты (для множественного выбора).
Возвращает до 15 субъектов: [{ principalType, id, display, subtitle?, email? }].
Поиск для lookup
Заголовок раздела «Поиск для lookup»GET /lists/{listId}/lookup-options?targetListId={uuid}&q=текст&lookupFieldId={uuid}
Возвращает объект:
{ "options": [{ "itemId": "uuid", "display": "Текст" }], "accessDenied": false, "message": null}При отсутствии доступа к целевому списку HTTP 200, accessDenied: true, options: [] и понятное message (без 403/500).
Элементы — /api/v1/lists/{listId}/items
Заголовок раздела «Элементы — /api/v1/lists/{listId}/items»| Метод | Путь | Право | Описание |
|---|---|---|---|
| GET | /lists/{listId}/items | view | Элементы (пагинация, фильтр, сортировка) |
| POST | /lists/{listId}/items | add | Создать |
| GET | /lists/{listId}/items/{itemId} | view | Один элемент |
| GET | /lists/{listId}/items/{itemRef}/versions | view | История версий (снимки fieldValues) |
| PATCH | /lists/{listId}/items/{itemId} | edit | Обновить (merge: только переданные поля) |
| DELETE | /lists/{listId}/items/{itemId} | delete | Удалить |
| POST | /lists/{listId}/items/quick-edit | edit/add | Пакетное быстрое редактирование |
| GET | /lists/{listId}/items/sync-state?ids=1,2,3 | view | Снимок элементов для fallback-синхронизации |
| GET | /lists/{listId}/items/live?ids=1,2,3 | view | SSE-поток изменений элементов (live-синхронизация UI) |
| GET | /lists/{listId}/items/{itemRef}/permission-settings | view | Настройки наследования прав (inheritsPermissions, parentLabel) |
| PATCH | /lists/{listId}/items/{itemRef}/permission-settings | admin | Включить/отключить наследование: { "inheritFromParent": true|false } |
Выборка элементов (GET)
Заголовок раздела «Выборка элементов (GET)»GET /api/v1/lists/{listId}/items?page=1&limit=50&viewId={uuid}&sort=...&orderBy=...&filter=...&q=...| Параметр | Описание |
|---|---|
page | Номер страницы (по умолчанию 1) |
limit | Размер страницы (1–500; иначе из pageSize представления) |
viewId | UUID представления (иначе — default view) |
sort | Override сортировки: JSON-массив или column:asc,column2:desc |
orderBy | То же, что sort (приоритет у orderBy, если указаны оба) |
filter | Override фильтра (JSON, см. ниже); объединяется с фильтром представления через AND |
q | Текстовый поиск (OR по полям, без учёта регистра) |
Ответ meta: page, limit, total, totalPages, totalInView, fields, groups, view.
Фильтрация и сортировка по поддерживаемым условиям выполняются на уровне PostgreSQL (push-down в list_items.field_values), без загрузки всего списка в память. Сложные сценарии (groupBy, часть операторов по lookup/person) используют in-memory fallback.
Формат фильтра
Заголовок раздела «Формат фильтра»Тот же JSON, что в конфиге представления (list_views.config.filter):
{ "logic": "and", "conditions": [ { "column": "title", "operator": "eq", "value": "GlobalSettings" } ]}| Поле условия | Описание |
|---|---|
column | UUID поля, internal_name ("title") или meta-колонка (__created_at, __updated_at) |
operator / op | eq, ne, contains, startsWith, gt, gte, lt, lte, isEmpty, isNotEmpty, in |
value | Значение для сравнения |
Плейсхолдеры (как в UI представлений): [Я] (person), [Сегодня], [Сегодня]+7, [Сегодня]-3 (date/datetime).
Пример — найти элемент по заголовку (аналог SharePoint CAML Eq по Title):
GET /api/v1/lists/{listId}/items?filter={"logic":"and","conditions":[{"column":"title","operator":"eq","value":"GlobalSettings"}]}&limit=1В ответе элемента (GET/PATCH) дополнительно возвращаются updated_by, updated_by_user, updated_at — автор и время последнего изменения; inherits_permissions (по умолчанию true); permissions — { canEdit, canDelete, canManagePermissions }.
Для itemRef допускается числовой id или guid. Управление наследованием — только администратор портала. Явные права на элемент — через /api/v1/permissions с resourceType=list_item и query-параметром listId.
Совместное редактирование (live sync)
Заголовок раздела «Совместное редактирование (live sync)»Пока у пользователя открыта форма редактирования или режим «Быстрое редактирование», UI подписывается на изменения через Server-Sent Events:
GET /api/v1/lists/{listId}/items/live?ids=12,13Accept: text/event-stream- Требуется cookie
portal_token(как для остального API). - Параметр
ids— публичные номера элементов (до 100 за запрос), с проверкой правlist→ view иlist_item→ view. - Событие
item_updatedсодержит актуальныеfield_values,updated_at,updated_by_user. - Heartbeat (
: ping) каждые 30 с. - Требуется Redis (Valkey) на стороне API; без Redis endpoint возвращает
503, клиент переходит на редкий polling.
При сохранении элемента (PATCH, quick-edit) API публикует обновление в Redis (portal:list-item:updated) и рассылает подписчикам на всех инстансах API.
Fallback: GET /lists/{listId}/items/sync-state?ids=... — компактный снимок для polling (интервал ~30 с), если SSE недоступен.
Ответ sync-state:
{ "items": [ { "id": 12, "updated_at": "2026-07-07T12:00:00Z", "updated_by": "uuid", "updated_by_user": { "display_name": "Иван Иванов" }, "field_values": { "field-uuid": "значение" } } ]}Формат SSE-события item_updated:
{ "listId": "uuid", "item": { "id": 12, "updated_at": "...", "updated_by": "uuid", "updated_by_user": { "display_name": "..." }, "field_values": {} }}При одновременном редактировании сохранение по-прежнему last-write-wins (без optimistic locking); открытые формы получают чужие изменения и показывают уведомление.
Версии элементов
Заголовок раздела «Версии элементов»Если у списка включено версионирование (versioning_enabled), при создании и обновлении элемента сервер сохраняет полный снимок fieldValues в журнале версий.
Включение — администратор портала: Настройки списка → Общие, либо:
PATCH /api/v1/lists/{listId}Content-Type: application/json
{ "versioningEnabled": true }Изменение versioningEnabled доступно только администратору портала.
Участие в глобальном поиске
Заголовок раздела «Участие в глобальном поиске»Поле search_enabled (по умолчанию true). Если выключено, список и его элементы не попадают в GET /api/v1/search и удаляются из индекса сразу.
Настройки списка → Общие → Участвует в поиске, либо:
PATCH /api/v1/lists/{listId}Content-Type: application/json
{ "searchEnabled": false }Изменение searchEnabled — только администратор портала. Локальный поиск над таблицей списка (?q=) не зависит от этого флага. См. Поиск.
История версий:
GET /api/v1/lists/{listId}/items/{itemRef}/versionsitemRef — публичный номер элемента или GUID. Право: view на элемент.
Ответ (data):
{ "versioningEnabled": true, "versions": [ { "id": "uuid-версии", "versionNumber": 2, "changeType": "updated", "fieldValues": { "uuid-поля-title": "Заголовок после правки", "uuid-поля-status": "Готово" }, "changes": { "uuid-поля-status": { "title": "Статус", "old": "Новая", "new": "Готово" } }, "changedBy": { "id": "uuid-пользователя", "displayName": "Иван Иванов" }, "createdAt": "2026-07-18T12:00:00Z" }, { "id": "uuid-версии-1", "versionNumber": 1, "changeType": "created", "fieldValues": { "uuid-поля-title": "Исходный заголовок" }, "changes": null, "changedBy": { "id": "uuid-пользователя", "displayName": "Иван Иванов" }, "createdAt": "2026-07-17T09:00:00Z" } ], "fields": [ /* схема полей списка */ ]}| Поле | Описание |
|---|---|
versioningEnabled | false — версионирование выключено, versions пустой |
versions[].versionNumber | Номер версии (1 = создание, далее по порядку) |
versions[].changeType | created или updated |
versions[].fieldValues | Полный снимок значений на момент версии (ключи — UUID полей) |
versions[].changes | Diff относительно предыдущей версии (null для created) |
fields | Схема полей (для подписей в UI) |
В SDK: GetItemVersionsAsync / GetItemVersionAsync (WebPart, Event Receiver, Timer Job). Примеры чтения полей из версии: Значения полей списков.
PATCH merge
Заголовок раздела «PATCH merge»PATCH принимает частичный объект fieldValues: сервер объединяет переданные ключи с существующими field_values элемента, затем валидирует полный набор по схеме списка (включая обязательные поля). Непереданные поля не обнуляются. POST при создании элемента также проверяет все поля с is_required.
Quick Edit batch
Заголовок раздела «Quick Edit batch»POST /lists/{listId}/items/quick-edit — сохранение изменений из режима быстрого редактирования UI.
Тело запроса:
{ "updates": [ { "id": "uuid", "fieldValues": { "field-uuid": "новое значение" } } ], "creates": [ { "clientRowId": "tmp-1", "fieldValues": { "title-field-uuid": "Новая задача" } } ]}Ответ:
{ "updated": [{ "id": "...", "field_values": {} }], "created": [{ "clientRowId": "tmp-1", "id": "...", "field_values": {} }], "errors": [{ "itemId": "...", "clientRowId": "...", "fieldId": "...", "message": "..." }]}Операции выполняются независимо: успешные строки сохраняются, ошибки возвращаются по ячейкам без отката остальных.
При сохранении проверяются обязательные поля (is_required): для новых строк — все обязательные поля схемы; для изменений — полный набор значений строки после merge с существующими данными. Клиент валидирует видимые колонки до отправки; сервер повторяет проверку по всей схеме.
Значения полей — объект fieldValues, ключи — UUID полей:
{ "fieldValues": { "field-uuid-1": "Текст", "field-uuid-2": 42 }}Вложения
Заголовок раздела «Вложения»| Метод | Путь | Право | Описание |
|---|---|---|---|
| GET | /lists/{listId}/items/{itemId}/attachments | view | Список файлов |
| POST | /lists/{listId}/items/{itemId}/attachments | add | Загрузить (multipart, поле file) |
| GET | /attachments/{id}/download | view | Скачать файл |
| DELETE | /lists/{listId}/items/{itemId}/attachments/{id} | delete | Удалить |
Файлы хранятся в SeaweedFS (S3), клиент получает их только через API.
События и Event Receivers
Заголовок раздела «События и Event Receivers»При создании/изменении/удалении элементов диспетчер отправляет:
listItem.createdlistItem.updatedlistItem.deleted
Обработчики для конкретного списка настраиваются на вкладке Обработчики в UI списка (требуется portal_admin + право edit на список) или через API с config.listId.
Подробнее: Event Receivers.
Представления — /api/v1/lists/{listId}/views
Заголовок раздела «Представления — /api/v1/lists/{listId}/views»| Метод | Путь | Право | Описание |
|---|---|---|---|
| GET | /lists/{listId}/views | view | Список представлений |
| POST | /lists/{listId}/views | admin | Создать |
| GET | /lists/{listId}/views/{viewId} | view | Одно представление |
| PATCH | /lists/{listId}/views/{viewId} | admin | Обновить |
| DELETE | /lists/{listId}/views/{viewId} | admin | Удалить (не default) |
Поле config (JSONB):
| Ключ | Описание |
|---|---|
columns | UUID/meta-колонки в порядке отображения; пустой массив — все поля по умолчанию |
sort | [{ "column", "direction": "asc"|"desc" }] |
groupBy | { "column" } или null |
filter | { "logic": "and"|"or", "conditions": [...] } |
pageSize | 1–500 (по умолчанию 50) |
selectionMode | none | single | multiple — чекбоксы и массовое удаление |
showActionsColumn | true | false — колонка контекстного меню (⋮) в таблице (по умолчанию true) |
hideFromSelector | Скрыть в выпадающем списке представлений для не-администраторов |
Дефолтный config представления списка:
{ "columns": [], "sort": [{ "column": "__created_at", "direction": "desc" }], "groupBy": null, "filter": { "logic": "and", "conditions": [] }, "pageSize": 50, "selectionMode": "multiple", "showActionsColumn": true}В таблице порядок колонок: при включённом выборе — чекбокс → действия (⋮) → поля; без выбора — действия → поля. Контекстное меню открывается вправо, если слева не хватает места.