Перейти к содержимому

API: Списки, поля, элементы, вложения

Требуется авторизация. Права наследуются от узла-родителя (nodeId).

Чтение и обновление значений полей (примеры REST, JS, WebPart, Event Receiver, Timer Job): Значения полей списков.

МетодПутьПраво на узелОписание
GET/lists?nodeId={uuid}viewСписки узла
POST/listseditСоздать список
GET/lists/{id}viewСписок с полями
PATCH/lists/{id}editОбновить
DELETE/lists/{id}deleteУдалить в корзину узла (снимок списка целиком)
POST/lists/{id}/recycle-contentdeleteПереместить все элементы списка в корзину (список остаётся)

DELETE /lists/{id} — мягкое удаление: одна запись корзины с полями, представлениями и текущим содержимым. Элементы этого списка, уже лежавшие в корзине, purge. Восстановление — POST /nodes/{nodeId}/recycle-bin/{entryId}/restore. См. Корзина.

Тело создания:

{
"nodeId": "uuid",
"title": "Задачи",
"slug": "zadachi",
"description": ""
}

В ответе 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.
showStandardFormtrue (по умолчанию) — показать стандартные поля; false — скрыть, тело страницы занимают веб-части
webParts[].placementbefore или after относительно стандартной формы (при showStandardForm: false порядок в массиве = тело страницы)

Обновление через PATCH /lists/{id}:

{ "formConfig": { "edit": { "script": "...", "showStandardForm": true, "webParts": [] } } }

Права: как у обычного обновления списка (edit). UI: Настройки списка → Формы. Блокировка полей скриптом — только UI; серверная защита по-прежнему через event receivers.

Подробный гайд: Кастомизация форм элементов.

МетодПутьПравоОписание
GET/lists/{listId}/fieldsviewПоля списка
POST/lists/{listId}/fieldseditДобавить поле
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_textHTML (санитизация на сервере)
choice{ choices: ["A","B"] }одна из choices
numberчисло
dateYYYY-MM-DD
datetimeISO 8601
booleantrue / 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 — значок шестерёнки («Настроить»): пользователи / группы / множественный выбор.

GET /lists/{listId}/person-options?fieldId={uuid}&q=текст&excludeIds=id1,id2

Поиск пользователей по ФИО (display_name), логину и email. Группы — по имени и описанию.
excludeIds — уже выбранные субъекты (для множественного выбора).

Возвращает до 15 субъектов: [{ principalType, id, display, subtitle?, email? }].

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).

МетодПутьПравоОписание
GET/lists/{listId}/itemsviewЭлементы (пагинация, фильтр, сортировка)
POST/lists/{listId}/itemsaddСоздать
GET/lists/{listId}/items/{itemId}viewОдин элемент
GET/lists/{listId}/items/{itemRef}/versionsviewИстория версий (снимки fieldValues)
PATCH/lists/{listId}/items/{itemId}editОбновить (merge: только переданные поля)
DELETE/lists/{listId}/items/{itemId}deleteУдалить
POST/lists/{listId}/items/quick-editedit/addПакетное быстрое редактирование
GET/lists/{listId}/items/sync-state?ids=1,2,3viewСнимок элементов для fallback-синхронизации
GET/lists/{listId}/items/live?ids=1,2,3viewSSE-поток изменений элементов (live-синхронизация UI)
GET/lists/{listId}/items/{itemRef}/permission-settingsviewНастройки наследования прав (inheritsPermissions, parentLabel)
PATCH/lists/{listId}/items/{itemRef}/permission-settingsadminВключить/отключить наследование: { "inheritFromParent": true|false }
GET /api/v1/lists/{listId}/items?page=1&limit=50&viewId={uuid}&sort=...&orderBy=...&filter=...&q=...
ПараметрОписание
pageНомер страницы (по умолчанию 1)
limitРазмер страницы (1500; иначе из pageSize представления)
viewIdUUID представления (иначе — default view)
sortOverride сортировки: JSON-массив или column:asc,column2:desc
orderByТо же, что sort (приоритет у orderBy, если указаны оба)
filterOverride фильтра (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" }
]
}
Поле условияОписание
columnUUID поля, internal_name ("title") или meta-колонка (__created_at, __updated_at)
operator / opeq, 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.

Пока у пользователя открыта форма редактирования или режим «Быстрое редактирование», UI подписывается на изменения через Server-Sent Events:

GET /api/v1/lists/{listId}/items/live?ids=12,13
Accept: 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}/versions

itemRef — публичный номер элемента или 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": [ /* схема полей списка */ ]
}
ПолеОписание
versioningEnabledfalse — версионирование выключено, versions пустой
versions[].versionNumberНомер версии (1 = создание, далее по порядку)
versions[].changeTypecreated или updated
versions[].fieldValuesПолный снимок значений на момент версии (ключи — UUID полей)
versions[].changesDiff относительно предыдущей версии (null для created)
fieldsСхема полей (для подписей в UI)

В SDK: GetItemVersionsAsync / GetItemVersionAsync (WebPart, Event Receiver, Timer Job). Примеры чтения полей из версии: Значения полей списков.

PATCH принимает частичный объект fieldValues: сервер объединяет переданные ключи с существующими field_values элемента, затем валидирует полный набор по схеме списка (включая обязательные поля). Непереданные поля не обнуляются. POST при создании элемента также проверяет все поля с is_required.

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}/attachmentsviewСписок файлов
POST/lists/{listId}/items/{itemId}/attachmentsaddЗагрузить (multipart, поле file)
GET/attachments/{id}/downloadviewСкачать файл
DELETE/lists/{listId}/items/{itemId}/attachments/{id}deleteУдалить

Файлы хранятся в SeaweedFS (S3), клиент получает их только через API.

При создании/изменении/удалении элементов диспетчер отправляет:

  • listItem.created
  • listItem.updated
  • listItem.deleted

Обработчики для конкретного списка настраиваются на вкладке Обработчики в UI списка (требуется portal_admin + право edit на список) или через API с config.listId.

Подробнее: Event Receivers.

МетодПутьПравоОписание
GET/lists/{listId}/viewsviewСписок представлений
POST/lists/{listId}/viewsadminСоздать
GET/lists/{listId}/views/{viewId}viewОдно представление
PATCH/lists/{listId}/views/{viewId}adminОбновить
DELETE/lists/{listId}/views/{viewId}adminУдалить (не default)

Поле config (JSONB):

КлючОписание
columnsUUID/meta-колонки в порядке отображения; пустой массив — все поля по умолчанию
sort[{ "column", "direction": "asc"|"desc" }]
groupBy{ "column" } или null
filter{ "logic": "and"|"or", "conditions": [...] }
pageSize1500 (по умолчанию 50)
selectionModenone | single | multiple — чекбоксы и массовое удаление
showActionsColumntrue | false — колонка контекстного меню (⋮) в таблице (по умолчанию true)
hideFromSelectorСкрыть в выпадающем списке представлений для не-администраторов

Дефолтный config представления списка:

{
"columns": [],
"sort": [{ "column": "__created_at", "direction": "desc" }],
"groupBy": null,
"filter": { "logic": "and", "conditions": [] },
"pageSize": 50,
"selectionMode": "multiple",
"showActionsColumn": true
}

В таблице порядок колонок: при включённом выборе — чекбокс → действия (⋮) → поля; без выбора — действия → поля. Контекстное меню открывается вправо, если слева не хватает места.