К содержанию

Навигация

Представление данных

<sf-table> показывает серверную коллекцию записей: поиск, фильтры, таблицу, выбор строк, действия, настройки колонок и пагинацию. Данные, права и выполнение действий остаются за приложением: компонент показывает то, что ему передали, и сообщает о намерениях пользователя событиями. <sf-data-view> оборачивает таблицу и связывает её с приложением через порт хоста. Оба элемента входят в пакет компонентов larena.

Пример

Применение

Подключение пакета

Элементы <sf-table> и <sf-data-view> поставляет Larena, а не выпуск Framework: пакет компонентов Loader с именем larena из репозитория simai/larena-ui (лицензия Apache-2.0). В пакет входят ещё <sf-property-view> и <sf-admin-menu>. Объявите пакет до подключения Core: window.SF_BOOT_CONFIG = {packages: {larena: {base: '/assets/larena/<коммит пакета>/smart'}}}. Сборка пакета публикуется выпуском репозитория simai/larena-ui (см. Пакет larena для проекта без Larena). Подробнее — в разделе Подключение Smart-компонентов.

Имя и ключ настроек

aria-label называет область таблицы; доступное имя у неё обязательно. table-settings-key выбирает, под каким ключом хранятся настройки колонок пользователя. Без него ключом служит id элемента, а без id — номер экземпляра на странице, поэтому у таблицы, которая живёт на нескольких страницах, ключ задавайте явно.

Колонки и строки

Данные передаются методами, а не атрибутами. setColumns(columns) задаёт разрешённые приложением колонки, setRows(rows) — текущие записи, setTableData(patch) обновляет несколько частей сразу, addRows(rows) добавляет следующую страницу в режиме «Показать ещё». У колонки нужен стабильный key, у строки — стабильный id.

Колонка с sortable: true получает сортировку по нажатию на заголовок. Таблица строки не переставляет: она отправляет sf-table-sort-change с {key, direction} (asc, desc или null), приложение загружает отсортированные данные и показывает текущую сортировку через setSort(key, direction).

Состояние данных

data-state или setDataState(state) показывает, в каком состоянии данные: loading, populated, empty, error. По умолчанию auto: есть строки — таблица заполнена, нет — пуста. Повторная загрузка поверх уже показанных строк оставляет их на месте притушенными. В состоянии error таблица показывает кнопку повтора; нажатие отправляет sf-table-retry. Тексты состояний задают loading-text, empty-text, error-text и retry-text; без них компонент берёт тексты на языке страницы. loading-text на экране не виден: пока стоит скелетон, его объявляет экранный диктор.

Части оболочки

Логические атрибуты включают и выключают части представления: toolbar — панель инструментов, selectable — выбор строк и массовые действия, settings — настройки колонок, actions — действия строки и кнопку «Создать», row-actions — только колонку действий строки (кнопка «Создать» остаётся). Встроенную пагинацию включает pagin; pagination-total, pagination-page-size и page-sizes задают общее число записей, размер страницы и выбор размеров. Её события sf-page-change, sf-page-size-change и sf-show-more приходят от Pagination. vertical-scroll="page" отдаёт прокрутку странице вместо самой таблицы, context-menu-columns (от 1 до 4) делит меню настроек на колонки.

У <sf-data-view> свои части перечисляет атрибут chrome: toolbar, pagination, select, settings; без атрибута включены все. Часть toolbar — запасная строка поиска самого представления. Если в слот content вставлена своя <sf-table> со своей панелью инструментов, запасная строка не показывается. Без toolbar в chrome представление ставит таблице layout="table"; список на узком экране сохраняет layout="auto", записанный на самой таблице.

Область представления называет aria-label самого <sf-data-view>; без него — общее «Представление данных». Строка страниц с «Всего» появляется после первого ответа приложения и скрыта, пока список не загрузился, при ошибке и при отказе в доступе.

Поиск и фильтр

Поиск отправляет sf-table-search-change со строкой запроса в event.detail после паузы ввода. setFilterFields(fields) передаёт разрешённые поля и операторы фильтра; применение фильтра отправляет sf-table-filter-change, в event.detail — шаблон (templateKey, templateLabel), значения values и метки tags. getFilterPayload() возвращает тот же объект в любой момент.

Варианты полей multi-select и single-select можно показать цветными метками, как в ячейках: filter.optionRenderer: 'badge', цвет — в option.color (схема Framework или hex), иконка — в option.icon.

Фильтр поля-файла предлагает виды файлов — изображения, документы, архивы, другие, — а фильтр поля-цвета показывает палитру поля образцами; оба отправляют выбранные значения с оператором in, а что входит в каждый вид, решает приложение. Цвет без палитры ищется как текст. Текстовый фильтр подписан «Содержит…».

Ячейки колонок и элементы фильтра по типу свойства рисует общий набор, описанный в главе Поля по типу свойства.

Действия и создание

Действие над строкой или над выбранными строками отправляет sf-table-action-intent с {action_id, record_ids}. setBulkActions(actions) задаёт массовые действия; пока ничего не выбрано, они выключены. getSelectedRecordIds() возвращает выбранные идентификаторы.

Кнопка «Создать» отправляет sf-table-create-intent с {item: null}; setCreateItems([{id, name}]) добавляет ей меню, и выбор пункта приходит как {item: id}. setToolbarActions(items) добавляет собственные действия в меню панели инструментов; выбор отправляет отменяемое sf-table-toolbar-action с {action, href}, и без preventDefault() компонент переходит по href того же сайта.

В <sf-data-view> кнопку «Создать» показывает возможность create-record адаптера. Отдельного права на создание у человека порт не передаёт: хост объявляет create-record в адаптере, который строит для этого человека, а на view.create_record без права отвечает refused.

Таблица или список

layout выбирает, как рисуются записи: table — таблицей (по умолчанию), list — компактным списком, auto — таблицей, пока контейнер таблицы не уже порога list-below, и списком, когда уже. Решает ширина контейнера, а не окна: таблица рядом с открытой панелью тоже становится списком. <sf-data-view> с панелью инструментов задаёт своей таблице auto; встроенный список без панели остаётся таблицей, а layout, который приложение написало на <sf-table> само, сохраняется.

В компактном списке каждая запись — блок: флажок выбора (при selectable), заголовок, под ним несколько полей с подписями и меню строки. Заголовок — колонка с role: 'title', а без неё — первая колонка данных. Поля выбираются по priority колонок: меньшее значение важнее, колонки без priority идут после остальных в своём порядке. list-fields задаёт число полей (по умолчанию три). Остальное о записи показывает её открытие, как у строки таблицы.

Панель инструментов списка занимает одну строку: поле поиска и рядом кнопки-иконки фильтра, сортировки (если есть колонки с сортировкой) и создания. Кнопка фильтра показывает число активных условий; сами условия идут ниже строкой меток, которая прокручивается вбок, и каждую можно снять. Фильтр открывается листом на весь экран.

Дерево

Адаптер с возможностью tree отвечает деревом, и <sf-data-view> показывает записи по уровням. Ответ на запрос несёт tree: {mode: 'tree', parent: null} и записи одного уровня — корни; каждая запись сообщает has_children. Открытие узла поднимает намерение tree.expand с id узла, и адаптер отвечает его детьми с tree.parent, равным этому id. Длинный уровень приходит страницами: tree.has_next и tree.cursor добавляют в конец уровня строку «Показать ещё», которая запрашивает следующую страницу того же уровня. У дерева нет обычной пагинации. Режим flat — обычный список, а flattened — результат поиска или фильтра по дереву: каждая запись несёт path, путь от корня, и компактный список показывает его под заголовком записи.

Дерево растёт из колонки заголовка (role: 'title') или из первой колонки данных. В ней строка получает отступ по уровню, кнопку открытия, если у узла есть дети, и иконку: icon и icon_expanded записи, а без них — папку для узла с детьми и документ для листа. Поля icon и icon_expanded входят в порт версии 1.9.0.

Перенос узла включает возможность tree-move. Действие move из actions записи открывает выбор места: представление спрашивает адаптер намерением node.targets, какие родители допустимы, показывает только их (и корень, если адаптер его разрешает) и отправляет node.move с новым parent, позицией index, если адаптер разрешает менять порядок, и ревизией записи. Действие create создаёт запись внутри узла: view.create_record уходит с parent. Оба действия появляются только у записей, которые перечисляют их в actions.

<sf-table> дерево только рисует: строки с __tree пишет <sf-data-view>. Нажатие на кнопку узла отправляет sf-table-tree-toggle с {id, expanded}, строка «Показать ещё» — sf-table-tree-more с {parent, cursor}; на оба отвечает представление. Намерения дерева, которые оно поднимает, приходят событием sf-table-tree-intent с {intent, payload}. Своими методами expandNode(id), collapseNode(id), loadMoreNodes(parent, cursor) и openMoveDialog(record) представление делает то же из кода.

Ширина и порядок колонок

Ширина. Ширину колонки тянут за линию между заголовками: вокруг неё невидимая полоса захвата, курсор меняется на col-resize, а при наведении и во время перетаскивания по строкам видна линия края колонки. Полоса — это кнопка с доступным именем «Изменить ширину столбца: …»: с клавиатуры на неё переходят по Tab и меняют ширину клавишами ArrowLeft и ArrowRight. Пределы задают minWidth и maxWidth колонки.

Порядок. Колонку переставляют, перетаскивая её заголовок. Пока колонку тянут, она приглушена во всех строках, а на месте, куда она встанет, стоит пунктирный контур во всю высоту таблицы. Закреплённая колонка переставляется только среди закреплённых, остальные — среди остальных. Отпускание не срабатывает как клик по заголовку, поэтому сортировка от него не включается. С клавиатуры порядок меняют в списке колонок в настройках таблицы. Колонка действий — системная: её не растягивают и не переносят.

Перетаскивание заголовков устроено на SF.Sortable.attach (см. Колонки таблицы): скрипт sf-sortable таблица подгружает сама при первом перетаскивании. Каждое изменение ширины или порядка приходит приложению событием sf-table-column-settings-change, как описано ниже.

Перетаскивание строк и файлов

  • drag-rows — строки можно вытащить из таблицы как записи: запись строки или все выбранные, если строка среди них. Начало перетаскивания сообщает sf-table-rows-drag с {ids, source}. Принимает их, например, дерево с accept-records — так записи раскладывают по папкам.
  • row-reorder — строки можно переставить, перетаскивая их внутри списка. Во время перетаскивания отмечено место, куда встанет строка; после отпускания приходит sf-table-rows-reorder с {ids, before, order}: перемещённые идентификаторы, строка, перед которой они встали (null — в конце), и весь новый порядок. Если порядок не изменился, события нет. Порядок сохраняет приложение; в <sf-data-view> — через порт хоста (Перестановка строк и запись в ячейке).
  • accept-files на <sf-data-view> — на представление можно перетащить файлы с компьютера: пока они над ним, видна зона сброса, после отпускания приходит sf-data-view-files-drop с {files}. Загружает файлы приложение.

Флажки в ячейках

С атрибутом inline-edit логическая ячейка — ячейка колонки с type: 'boolean' — становится флажком, если запись называет поле этой колонки в своём списке editable. Так приложение решает по каждой записи, что человек может менять:

JavaScript
table.setColumns([
  {key: 'title', label: 'Название'},
  {key: 'published', label: 'Опубликовано', type: 'boolean'}
]);
table.setRows([
  {id: 7, title: 'Отчёт за квартал', published: true, editable: ['published'], revision: 'r12'},
  {id: 8, title: 'Черновик', published: false, editable: []}
]);

Нажатие флажка отправляет sf-table-cell-set с {id, key, value, revision}; пока приложение отвечает, флажок выключен. Таблица сама значение не сохраняет: строку перерисовывает то, что ответило приложение. В <sf-data-view> запись в ячейке идёт через порт хоста (Перестановка строк и запись в ячейке).

Кнопки действий строки по умолчанию видны в строке под указателем, в фокусе или текущей (row-actions-visible="hover"); always показывает их во всех строках.

Пустые состояния

Когда ответ пришёл, а строк нет, таблица показывает внутри себя пустое состояние своего размера и сама выбирает причину: нет прав (refused), ошибка с «Повторить», «Ничего не найдено» с кнопкой сброса того, что включено — поиска, фильтров или обоих, — или «нет записей» с «Создать», если создание разрешено. Пока идёт запрос, остаётся скелетон. empty-text и error-text становятся заголовками состояний «нет записей» и ошибки. Слот empty заменяет блок при любой причине, включая ошибку: «Повторить» и встроенные слова тогда не показываются.

Уже при первой отрисовке таблица вынимает элемент слота из документа, и поиск по id после этого вернёт null — в том числе после customElements.whenDefined('sf-data-view'). Поэтому ссылку на блок берите на верхнем уровне скрипта в конце body, до того как придёт код пакета, и меняйте блок по событию sf-data-view-state. Таблица записывает причину в свойство emptyContext до того, как представление отправляет событие:

detail.state Что в table.emptyContext
empty {kind, reset}: kind — no-access, nothing-found или no-data; reset у nothing-found — search, filters или both
error {caused}: true, если ошибку вызвал поиск или фильтр человека

Действия с id retry, create и reset-query в блоке слота таблица выполняет сама: повторяет запрос, отправляет намерение создания (оно, как кнопка на панели инструментов, проходит проверку возможности create-record) или очищает то, что назвал reset. Второй запрос из кода страницы не нужен.

HTML
<sf-data-view id="solutions" preferences-key="cms.solutions" aria-label="Решения">
  <sf-table slot="content" aria-label="Решения">
    <sf-empty-state slot="empty" id="solutions-empty" heading-level="2"></sf-empty-state>
  </sf-table>
</sf-data-view>
<script>
  const view = document.getElementById('solutions');
  const empty = document.getElementById('solutions-empty'); // сразу, до прихода кода
  const words = {
    'no-data': ['Решений пока нет', [{id: 'create', text: 'Создать'}]],
    'nothing-found': ['Решения не найдены', [{id: 'reset-query', text: 'Очистить поиск', appearance: 'outline'}]],
    'no-access': ['Нет доступа к решениям', []],
    error: ['Не удалось загрузить решения', [{id: 'retry', text: 'Повторить', appearance: 'outline'}]],
  };
  view.addEventListener('sf-data-view-state', ({detail}) => {
    if (detail.state !== 'empty' && detail.state !== 'error') return;
    const context = view.querySelector('sf-table').emptyContext ?? {};
    const kind = detail.state === 'error' ? 'error' : context.kind;
    const [heading, actions] = words[kind] ?? words['no-data'];
    empty.setAttribute('kind', kind);
    empty.setAttribute('title', heading);
    empty.setAttribute('live', context.caused ? 'alert' : 'auto');
    empty.actions = actions;
  });
</script>

Отдельная таблица без <sf-data-view> показывает только «нет записей» и ошибку. Подробнее — в Пустые состояния.

Прокрутка на странице списка

vertical-scroll у <sf-table> выбирает, что прокручивается вверх и вниз: self — таблица внутри своей рамки, page — сама страница. Представление данных по умолчанию ставит своей таблице page, если приложение не выбрало иное. Тогда таблица растёт на высоту своих строк, и на странице списка прокручивается одно — сама страница. По горизонтали таблица прокручивается внутри себя: её полосу заменяет направляющая, закреплённая у нижнего края окна. Панель инструментов держится у верхнего края, а шапка таблицы встаёт под ней. В настройках таблицы на вкладке «Вид» это переключает «Закреплять фильтр и шапку»; по умолчанию закрепление включено.

Персональный вид

С атрибутом preferences-key на <sf-data-view> (обычно это имя коллекции) раскладка таблицы, сортировка и размер страницы хранятся как персональный вид под ключом sf-table/<preferences-key> и применяются до первого запроса: первый запрос несёт сортировку и размер страницы человека, а первый кадр с колонками данных уже стоит в его раскладке. Скелетон до ответа колонок данных не показывает. Без ключа ничего не запоминается. Поля значения — columnSettings, widths, view, sort и pageSize — таблица объявляет в манифесте (persistence.view_preference); все пять сервер может положить в страницу для первой отрисовки. Их описание — в справочнике <sf-table> ниже и в Персональный вид → Поля значения.

Шаблоны и настройки колонок

Ширина, порядок, видимость и закрепление колонок — настройки представления. Их изменение отправляет sf-table-column-settings-change с reason, tableSettingsKey и полными настройками columnSettings; отдельная таблица отдаёт их приложению, и оно при следующей загрузке применяет их через setTableSettings(settings). В <sf-data-view> то же изменение всегда уходит в личный слой человека — намерением settings.save_personal с base_revision — ревизией слоя data.column_settings.layers.personal, а если хост этого слоя ещё не прислал, — ревизией из data.column_settings.target. Если нет ни того, ни другого, представление само отвечает unavailable и намерение до хоста не отправляет; поэтому присылайте в ответе на запрос личный слой с ревизией или target с ней.

Ответ conflict несёт рядом с answer текущую ревизию слоя current_revision и колонки слоя, какими они стали, — columns. Представление показывает message уведомлением и обновляет ревизию, по которой пишет: берёт настройки колонок из data.column_settings, если хост их прислал, иначе current_revision и columns, а без них перечитывает список — ответ на запрос приносит слой с текущей ревизией. Поэтому следующая запись колонок с этого устройства идёт уже против новой ревизии.

saveColumnSettings(columnSettings, {shared, base_revision}) записывает раскладку из кода: shared: true — в общий слой намерением settings.save_shared (возможность shared-column-settings), без него — в личный. Выбора слоя таблица человеку не предлагает, поэтому общий слой записывает только код страницы этим вызовом; base_revision заменяет ревизию, которую представление взяло бы из слоя. resetColumnSettings() делает то же, что «Сбросить» в настройках таблицы: записывает пустую раскладку {} в личный слой против его ревизии; значения по умолчанию определяет хост. Где при этом хранится раскладка — в Персональный вид → Раскладка таблицы. Сохранённые представления передаёт setTemplates(templates); изменения на вкладке «Шаблоны» приходят событиями sf-table-template-save, sf-table-template-select ({key}) и sf-table-template-delete ({key}, по одному на шаблон). sf-table-template-save несёт один шаблон из формы или массив шаблонов, если «Применить» на вкладке «Шаблоны» изменило несколько (порядок, закрепление, выбор по умолчанию); <sf-data-view> сохраняет каждый шаблон с key отдельным намерением view.save.

Общее сохранённое представление записывает код страницы: он отправляет на <sf-data-view> событие sf-data-view-saved-view-intent с {key, label, revision, roles} (revision и roles необязательны), и представление отправляет хосту view.save_shared с текущим запросом, колонками и настройками. Нужна возможность shared-saved-views и порт версии 1.1.0 или новее; на порте 1.0.0 представление само отвечает unavailable. То же делает saveView({key, label, level: 'shared'}).

JavaScript
view.dispatchEvent(new CustomEvent('sf-data-view-saved-view-intent', {
  detail: {key: 'overdue', label: 'Просроченные'},
}));

Порт хоста

<sf-table> получает данные методами и сообщает о намерениях событиями; метода setHostPort() у него нет. Адаптер приложения подключается к <sf-data-view>: setHostPort(host) принимает объект с полями version и capabilities и методом raise(intent, payload, {signal}), который отвечает {answer: 'applied' | 'conflict' | 'refused' | 'unavailable', …}. <sf-data-view> говорит на порте simai.dataview-port версии 1.12.0 и принимает адаптеры версий от 1.0.0 до 1.12.0; манифест <sf-table> записывает версию порта 1.0.0. Если адаптер не передан, <sf-data-view> один раз запрашивает его событием sf-host-port-request.

Возможности хост объявляет в capabilities: представление предлагает только то, что хост объявил. Создание записи (create-record) и личные настройки колонок (personal-column-settings) — тоже возможности: хосту на порте 1.10.0, который их не объявил, представление не показывает кнопку создания и шестерёнку настроек колонок. Хост на более ранней версии порта получает обе, не объявляя их. Запись логического поля в ячейке (inline-edit) и перестановка строк (row-reorder) — возможности порта 1.11.0; их получает только хост, который их объявил. Порт 1.12.0 новых намерений и возможностей не добавляет: он точнее описывает ответ — sequence, что несёт конфликт, известные причины — и требует column_settings только от хоста, который объявил personal-column-settings или shared-column-settings. Хост без них может не присылать column_settings, и представление рисует колонки как есть. У самой таблицы те же части включают и выключают атрибуты creatable, settings-menu и filter-templates.

Ответ адаптера — конверт, а данные лежат в его поле data; порт описывает и конверт (answer), и данные ответа на каждое намерение (answer_data). Адаптер передаёт намерение серверу и возвращает его конверт как есть: сервер сам решает, ответить applied, conflict или refused. Ошибку HTTP адаптер превращает в unavailable, а намерение, которого приложение не поддерживает, сервер отклоняет ответом unavailable с причиной capability-not-provided:

JavaScript
const host = {
  version: '1.12.0',
  capabilities: ['row-actions', 'create-record'],
  async raise(intent, payload, {signal}) {
    const response = await fetch('/api/projects/port', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({intent, payload}),
      signal,
    });
    if (!response.ok) {
      return {answer: 'unavailable', reason: `http-${response.status}`, sequence: payload.sequence};
    }
    return response.json();   // {answer, reason?, message?, sequence?, data?}
  },
};
document.querySelector('sf-data-view').setHostPort(host);

Транспорт, сессия и защита от подделки запроса (CSRF) — дело приложения: порт описывает только намерение, его payload и конверт ответа.

  • answer — applied, conflict, refused или unavailable; message — текст для человека.

  • reason — машинная причина отказа или недоступности, свободная строка, которую хост может дополнять своими. Если хост не прислал message, представление показывает для причин из порта свои слова на языке страницы; message хоста важнее них:

    reason Слова представления
    capability-not-provided Хост не поддерживает это действие.
    confirm_required Действие нужно сначала подтвердить.
    not-confirmed Действие отменено.
    port-not-connected Источник данных не подключён.
    no-base-revision Настройки пока нельзя сохранить: у представления нет их текущей версии. Обновите представление.
    record_invalid Запись не найдена.
    forbidden Недостаточно прав для этого действия.
    stale-revision Данные успели изменить. Обновите представление и повторите действие.

    Для другой причины представление показывает общий текст по виду ответа, например «Действие отклонено.» у refused.

  • sequence в ответе на query.change и query.count повторяет номер запроса: ответ на устаревший запрос представление отбрасывает. Это проверяет случай набора query-answer-names-its-sequence.

  • Конфликт несёт рядом с answer, а не в data, current_revision — ревизию, против которой нужно было писать. Конфликт записи настроек колонок несёт ещё columns — колонки слоя, какими они стали, а конфликт пакетного действия — conflicts, по записи {id, current_revision} на каждую устаревшую запись. Без current_revision представление перечитывает список.

  • data — данные порта: columns, records, total, has_next, echo, column_settings (обязательны только у хоста с личными или общими настройками колонок) и другие из его описания. Ответ на запрос (query.change) без data представление считает ошибкой. В каждом ответе на запрос обязательны records и echo. columns нужны в первом ответе: представление рисует колонки по ним и держит их, пока следующий ответ не пришлёт новые. total нужен, если хост не объявил count-on-request; хост с этой возможностью может не считать записи и вместо total присылает has_next. Ответ на изменение записи может вернуть в data.records только изменённые записи или не вернуть data вовсе — тогда представление перезапросит список.

  • Отказ с причиной confirm_required несёт data.confirm с digest и summary: представление спрашивает человека и повторяет намерение с подтверждением.

Первый запрос query.change уходит сам, как только адаптер передан в setHostPort(), с reason: 'host-connected'. Его payload — {sequence, query, reason}, а query от представления всегда содержит пять полей. Случаи набора проверок присылают только нужные им поля (например, page и per_page), поэтому хост подставляет недостающим значения по умолчанию из таблицы:

Поле query Что в нём
search строка поиска, по умолчанию пустая
filters объект значений фильтра, по умолчанию {}
sort массив [{key, direction}] или пустой массив без сортировки
page номер страницы с 1
per_page размер страницы, по умолчанию 25

Пагинация предлагает размеры из своего page-sizes, по умолчанию 10, 20, 30 и 40; действующий размер страницы представление добавляет в этот список, поэтому 25 тоже есть в выборе. Свои размеры задаёт своя пагинация в слоте: <sf-pagination slot="pagination" page-sizes="25,50,100">; page-sizes на <sf-table> внутри представления не действует.

Поиск, фильтр и сортировка возвращают page к 1. reason называет причину запроса: search, filter, sort, page-change, page-size-change, show-more, retry, after-write (перезапрос после изменения записи).

Действие над строкой превращается в намерение так:

Что выбрал человек Намерение
действие view у одной записи record.open
другое действие у одной записи record.mutate с ревизией записи в revisions — объекте, где ключ — идентификатор записи строкой: {"1": "r1"}
действие над выбранными записями — из панели выбора или над несколькими сразу bulk.apply_selected
кнопка создания view.create_record
флажок в ячейке (возможность inline-edit) record.set
перетаскивание строк внутри плоского списка (возможность row-reorder) record.reorder

Действие, которого нет в списке actions записи, до хоста не доходит: представление отвечает себе отказом action-not-allowed. Подписи есть только у действий view, edit и delete; подпись и значок своего действия приложение передаёт каталогом data.row_actions: [{id, label, icon}] в ответе на запрос. Действие без записи в каталоге подписано «Действие», а в консоли появляется предупреждение с его идентификатором. Переход после record.open и view.create_record делает само приложение.

Поля фильтра порт не передаёт. Кнопку «Фильтр» таблица показывает, только когда есть по чему фильтровать: страница передала поля фильтра, есть сохранённые шаблоны или фильтр уже применён. Поля задаёт страница: она вставляет свою <sf-table> в слот content представления и вызывает у неё setFilterFields(fields) (см. Поиск и фильтр); применённый фильтр представление отправляет хосту в query.filters.

Повторный вызов setHostPort() заменяет адаптер и заново запрашивает список. Если raise выбросил ошибку или запрос прерван через signal, представление показывает ошибку; ответ на устаревший запрос отбрасывается. Отказ refused на query.change означает «нет доступа»: строки прежнего ответа и строка страниц убираются, вместе с ними прячутся панель инструментов (поиск, фильтр, «Создать») и выбор строк, а текст message приходит уведомлением и в блок «Нет доступа» не попадает. Следующий ответ applied возвращает панель и выбор такими, какими их задал автор; при unavailable представление показывает свою ошибку и message не читает. Ответ на запрос называет свой sequence и тогда, когда он refused или unavailable; ответ без него представление считает ответом на текущий запрос.

У порта карточки записи (<sf-property-view>) свой формат: запись приходит в самом ответе, без data.

Порт описывает стык отдельно от компонента:

Часть порта Что в ней
Данные колонки, записи с ревизией, разрешёнными действиями и полями для записи на месте (editable), общее число, эхо запроса и настройки колонок по слоям
Эхо запроса что человек выбрал, что приложение применило, что отклонило, поиск, сортировка, окно и что потерялось при смене представления
Намерения запрос, действия над записью, запись поля в ячейке, перестановка записей, пакет по выбору и по фильтру, сохранение настроек лично и для всех, шаблоны, создание
Возможности сохранённые представления, общие настройки колонок, пакет по фильтру, действия над записью, создание, личные настройки колонок, запись в ячейке, перестановка строк — приложение объявляет, что даёт
Настройки слои package, shared, personal; запись всегда против ревизии слоя, сброс — запись пустой раскладки {} против ревизии
Словарь колонки видимость, порядок, ширина, минимальная ширина, приоритет при нехватке места, закрепление

Права приходят вместе с данными: каждая запись несёт список действий, которые приложение разрешает именно для неё, и представление предлагает только их. Текущая версия — порт 1.12.0 и его набор проверок; прежние версии опубликованы рядом. Приложение заявляет поддержку версии порта, когда прошло все проверки её набора. Правила стыка — в стандарте порта хоста.

Запрос и события для кода страницы

changeQuery(patch, reason) сливает patch с текущим запросом и запрашивает список. В patch — поля query: search, filters, sort, page, per_page. reason уходит хосту в payload.reason; по умолчанию это query-change. Только причины page-change, page-size-change и show-more сохраняют page, при любой другой она становится 1. Причины search и filter отмечают запрос как действие человека: ошибка в ответ на него объявляется сразу. Поле поиска на панели показывает строку поиска запроса, кто бы её ни задал: после changeQuery({search: 'договор'}) в нём стоит «договор». refresh(reason) повторяет текущий запрос.

Событие detail
sf-data-view-state {state, message, instance_id}: state — loading, populated, empty или error; message — текст для экранного диктора: о загрузке, ошибке или уведомлении хоста
sf-data-view-answer ответ хоста на любое намерение: {intent, answer, reason, message, data, sequence, effects, instance_id} — поля, которых не было в ответе, отсутствуют
sf-table-column-settings-reset {target: 'personal', tableSettingsKey}; представление отвечает на него resetColumnSettings()

Пример: связь с приложением

Пример подключает <sf-data-view> к приложению через порт хоста. Приложение здесь — несколько строк JavaScript с массивом записей и задержкой ответа; на своей странице raise() отправляет те же намерения на сервер и возвращает его ответ в том же конверте. Переключатель над таблицей меняет ответ приложения: данные, отказ в доступе или сбой сервера. При отказе представление убирает строки, строку страниц и панель инструментов, показывает блок «Нет доступа», а текст message приходит уведомлением. При сбое оно показывает ошибку с «Повторить».

Что делает адаптер в примере:

  • объявляет версию порта 1.12.0 и возможности row-actions и personal-column-settings; без объявленной возможности намерение до приложения не доходит, а её часть интерфейса не показывается;
  • на намерение, которого приложение не поддерживает, отвечает unavailable с причиной capability-not-provided, а ответы на запрос, в том числе отказ и сбой, называют sequence запроса;
  • на query.change отвечает applied с data: колонки, записи страницы, total, эхо запроса, каталог действий row_actions и настройки колонок с личным слоем;
  • кладёт значения записи прямо под ключи колонок: {id, revision, actions, name, owner, status, updated_at};
  • на record.mutate возвращает только изменённые записи — представление перерисовывает ровно эти строки;
  • на settings.save_personal сверяет base_revision с ревизией личного слоя и при расхождении отвечает conflict;
  • даты в ячейках пишет методом formatFieldValue(field, value) того же объекта (см. Поля по типу свойства); без него в ячейке остаётся исходное значение 2026-10-01T09:00:00Z.

Поля записи и эха:

Поле Что в нём
id, revision идентификатор записи и её ревизия; ревизия уходит в revisions намерения record.mutate
actions действия, которые приложение разрешает для этой записи
<ключ колонки> значение ячейки; тип задаёт property_type колонки
echo.search, echo.sort, echo.page, echo.per_page что приложение применило из запроса
echo.filters_chosen, echo.filters, echo.filters_rejected выбранный фильтр, применённый фильтр и отклонённые поля

Перестановка строк и запись в ячейке

Обе возможности описывает порт 1.11.0 — младшая версия, которая только добавляет: хост, объявивший 1.10.0, продолжает работать, и представление не предлагает ему ни одну из них. Хост на 1.11.0 получает их, только если объявил в capabilities.

Запись в ячейке (inline-edit). Запись может назвать в списке editable ключи полей, которые этот человек вправе менять на месте; без списка таких полей нет. Представление ставит своей таблице inline-edit, и логическое поле из editable становится флажком. Нажатие поднимает намерение record.set:

Поле Что в нём
record_id идентификатор записи, строка или целое число
key ключ поля
value новое значение, только true или false
revision последняя увиденная ревизия записи
confirm дайджест подтверждения, если хост его просил

Хост перечитывает хранимое значение и сравнивает ревизию. Ответ applied может нести в data.records запись в её нынешнем виде — представление перерисует только эту строку; без неё список перезапрашивается. Запись, которая меняет другие записи (например, делает поле обязательным), хост может сначала отклонить с причиной confirm_required и data.confirm — представление спросит человека и повторит намерение с confirm. Любой ответ, кроме applied (conflict, refused, unavailable), оставляет в ячейке значение, которое запись хранит.

Перестановка строк (row-reorder). Только для плоского списка: в режиме дерева перенос остаётся за node.move. Представление ставит таблице row-reorder, сразу показывает новый порядок и поднимает record.reorder:

Поле Что в нём
record_ids перетащенные записи в порядке перетаскивания, не меньше одной, без повторов
before запись, перед которой они встают, или null — в конец
revision ревизия первой перемещённой записи
confirm дайджест подтверждения, если хост его просил

Ответ applied может нести перемещённые записи в data.records, иначе список перезапрашивается. На любой другой ответ, например conflict с текущей ревизией, представление возвращает прежний порядок.

Набор проверок порта 1.12.0 — 44 случая; три из них проверяют запись в ячейке с ответом записью, запись с подтверждением и перестановку против устаревшей ревизии, а query-answer-names-its-sequence — что ответ на запрос называет его sequence.

Проверка на сервере

Идентификатор записи, действие, сортировку, фильтр и лимиты нельзя считать доверенными только потому, что их отправил компонент: приложение повторно проверяет их на сервере.

JavaScript
const table = document.querySelector('sf-table');
table.setDataState('loading');
const page = await api.listProjects({sort: table.getSort()});
table.setTableData({columns: page.columns, rows: page.rows});
table.setDataState('auto');

table.addEventListener('sf-table-action-intent', async (event) => {
  const {action_id, record_ids} = event.detail;
  await api.runAction(action_id, record_ids);
});

Доступность

  • Таблица — именованная область (role="region"): задайте aria-label, который называет коллекцию. У <sf-data-view> своё обязательное имя.
  • Все действия только с иконкой и все меню имеют доступные имена. Меню, фильтры и окна настроек закрываются по Escape и возвращают фокус на кнопку, которая их открыла.
  • Ширину колонки с клавиатуры меняют ArrowLeft и ArrowRight на её кнопке изменения ширины; фокус при этом остаётся на кнопке.
  • Дерево — таблица с ролью treegrid: строки сообщают уровень, позицию среди соседей и открыты ли они. ArrowRight на строке открывает закрытый узел, ArrowLeft закрывает открытый. Кнопка узла называет действие: «Развернуть» или «Свернуть».
  • Компактный список — список с именем таблицы; кнопки-иконки его панели имеют доступные имена, кнопка фильтра называет и число активных условий.
  • Обновление данных не переносит фокус. Состояние загрузки объявляется как статус, ошибка — как срочное сообщение.
  • Для узких экранов настраивайте видимость и приоритет колонок, а не уменьшайте текст и интерактивные цели.

Справочник API

Раздел собран из манифеста компонентов выпуска ui-106d5901f8c3 и обновляется вместе с выпуском. Чтобы исправить описание, исправьте манифест.

Каждому атрибуту соответствует свойство элемента с тем же именем в camelCase: search-placeholder — searchPlaceholder. Свойство атрибута template называется templateName.

<sf-data-view>

Тег <sf-data-view>
Назначение Представление данных под управлением элемента: панель инструментов, содержимое и пагинация вокруг отдельного порта данных.
Контракт smart.data-view-composite, версия 1.0.0
Поставка пакет larena (SF_BOOT_CONFIG.packages.larena)
Жизненный цикл экспериментальный: API может меняться между выпусками
Готовность host-required
Заготовка до прихода кода сервер пишет data-sf-skeleton="rows"; пока ждёт данные, рисует свой скелетон (Заготовка до прихода кода)

Атрибуты

  • aria-label — string, по умолчанию Представление данных.
  • chrome — string, по умолчанию toolbar pagination select settings. Какие элементы оформления отображает список, через пробел. toolbar и pagination — собственные части этого элемента; select и settings — два служебных столбца таблицы, они указаны здесь, потому что относятся к той же категории: столбец флажков нужен для панели групповых действий, столбец с шестерёнкой — для доступа к настройкам столбцов, а во встроенном списке нет ни того, ни другого. Пустое значение не отображает ничего из этого — для списка внутри блока, у которого уже есть заголовок. Значения задаются явно, а не выводятся из панели инструментов, чтобы потребитель мог запросить во встроенном списке только выделение. status не входит в список и не отключается: список, который не может сообщить об ошибке загрузки, выглядел бы пустым при сбое.
  • row-cap — integer, по умолчанию 0, значения: от 0. Максимальное число строк во встроенном списке; если часть скрыта, под ним отображается действие «показать все». Ноль — без ограничения, как в списке на странице. Отделено от page-size — постраничного вывода хоста, — потому что ограничение определяет, сколько элемент показывает из уже имеющейся страницы.
  • port-owner — string, по умолчанию пусто. Составной компонент, в который встроен этот список; передаётся с запросом к порту хоста, чтобы хост знал, на какой обмен отвечает. Указывает составной компонент, а не элемент, поэтому списку, встроенному в другое место, не нужно новое значение.
  • port-record — string, по умолчанию пусто. Запись, которую показывает встраивающий составной компонент; передаётся с запросом к порту хоста.
  • port-group — string, по умолчанию пусто. Группа внутри составного компонента, которую представляет этот список; передаётся с запросом к порту хоста.
  • size — string, по умолчанию 1, значения: 1/2, 1. Ступень лестницы размеров для элементов управления представления; её получают таблица, строка страниц и полоса выбора: 1 или плотная 1/2, как в админке.
  • column-search-placeholder — string. Передаётся как column-search-placeholder в таблицу, которую рисует представление; без него действует собственная подпись таблицы на языке страницы.
  • column-search-empty-text — string. Передаётся как column-search-empty-text в таблицу, которую рисует представление; без него действует собственная подпись таблицы на языке страницы.
  • column-move-label — string. Передаётся как column-move-label в таблицу, которую рисует представление; без него действует собственная подпись таблицы на языке страницы.
  • filter-apply-text — string. Передаётся как filter-apply-text в таблицу, которую рисует представление; без него действует собственная подпись таблицы на языке страницы.
  • show-more-text — string. Передаётся как show-more-text в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • selected-label — string. Передаётся как selected-label в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • total-label — string. Передаётся как total-label в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • pages-label — string. Передаётся как pages-label в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • first-label — string. Передаётся как first-label в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • previous-label — string. Передаётся как previous-label в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • page-label — string. Передаётся как page-label в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • next-label — string. Передаётся как next-label в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • last-label — string. Передаётся как last-label в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • page-field-label — string. Передаётся как page-field-label в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • action-choose-label — string. Передаётся как action-choose-label в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • actions-label — string. Передаётся как actions-label в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • actions-region-label — string. Передаётся как actions-region-label в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • clear-selection-label — string. Передаётся как clear-selection-label в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • page-size-label — string. Передаётся как page-size-label в пагинацию, которую рисует представление; без него действует собственная подпись пагинации на языке страницы.
  • pagination-aria-label — string. Передаётся как aria-label в пагинацию, которую рисует представление (собственный aria-label представления называет само представление).
  • preferences-key — string, по умолчанию пусто. Ключ, под которым хранится персональный вид этого списка (SF.Preferences, sf-table/<key>): раскладка таблицы, сортировка и размер страницы; применяется до первой отрисовки и первого запроса. Обычно это коллекция.
  • accept-files — boolean, по умолчанию false. Файлы, перетащенные с компьютера на представление, загружает хост: пока файлы над ним, видна зона сброса, а sf-data-view-files-drop {files} сообщает, что их отпустили.

Свойства в документе макета

Узел типа smart.data-view-composite в документе макета (simai.composition.document.v1) принимает:

  • свойства: aria-label.

Значения свойств те же, что у одноимённых атрибутов, и того же типа, что в списке атрибутов: строковое значение пишется строкой ("size": "1", а не 1 — число отклоняется с диагностикой schema_enum или schema_type), логическое — true или false.

Методы

  • applyProjection(data: object) — возвращает null. Отображает ответ хоста во всех трёх слотах.
  • applyUnderFilter(actionId: string, confirmedTotal: integer) — возвращает object. Выполняет подтверждённое действие над всем фильтром (bulk.apply_under_filter) по текущим фильтрам. Бросает TypeError, если confirmedTotal не равен текущему общему числу.
  • changeQuery(patch: object, reason?: string) — возвращает object. Изменяет поиск, фильтры, сортировку или окно.
  • deleteView(key: string) — возвращает object. Удаляет сохранённое представление.
  • notify(text: string, options?: object) — возвращает object. Показывает одно уведомление поверх карточки или убирает его при пустом тексте. Отказ, конфликт и недоступность хоста выводят его сами.
  • openView(key: string) — возвращает object. Открывает сохранённое представление.
  • refresh(reason?: string) — возвращает object. Запрашивает текущую выборку с новым номером последовательности.
  • resetColumnSettings() — возвращает object. Сбрасывает раскладку колонок человека: пустой личный слой, записанный против его ревизии, — это сброс по порту (запись, а не удаление). Значения по умолчанию даёт хост.
  • saveColumnSettings(columnSettings: object, options?: object) — возвращает object. Записывает слой настроек колонок, личный или общий, против его ревизии: settings.save_personal или settings.save_shared. Базовая ревизия — переданная, иначе ревизия слоя, иначе ревизия цели порта. После конфликта представление берёт current_revision (и колонки слоя), которые ответ несёт рядом с answer, как требует simai.dataview-port 1.12.0; data.current_revision и data.column_settings оно тоже читает — для хоста, который следовал словам версии 1.10.0, — а если конфликт не называет ревизию, перечитывает список.
  • saveView(view: object) — возвращает object. Сохраняет личное или общее представление: view.save или view.save_shared на порте 1.1.0 и новее. Бросает TypeError без key и label или для другого уровня.
  • setHostPort(host: object) — возвращает object. Привязывает конкретный адаптер хоста.
  • updateRecord(id: string|integer, patch?: object) — возвращает boolean. Записывает одну запись на месте: строка перезаписывается, и у хоста ничего не запрашивается. Запись, на которую получен ответ только с записями, проходит этот путь сама.
  • expandNode(id: string|integer) — возвращает object. Открывает узел, у которого по словам хоста есть потомки: из того, что уже есть у представления, или запросом к хосту через tree.expand.
  • collapseNode(id: string|integer) — возвращает null. Закрывает открытый узел. Это дело самого представления, хост не спрашивается.
  • loadMoreNodes(parent: string|integer|null, cursor?: string|null) — возвращает object. Следующая страница одного уровня: корни — через запрос, потомки узла — через tree.expand с его курсором.
  • openMoveDialog(record: object) — возвращает object. Спрашивает хост, куда можно перенести запись (node.targets), даёт выбрать ровно из этих мест и переносит её туда (node.move).

События

Все события приходят на сам элемент и всплывают. Общие события базового элемента перечислены в главе Жизненный цикл → Этапы.

  • sf-count-request — detail: { component: object, tagName: string, template: string, reason: string, current: integer, pageSize: integer }. Отправляет пагинация представления, когда человек просит общее число, последнюю страницу или действие над фильтром, пока число неизвестно. Представление отвечает на него намерением query.count; хосту слушать его не нужно.
  • sf-data-view-answer — detail: { intent: string, answer: string, reason?: string, data?: object, sequence?: integer, effects?: array, instance_id: string }. Приходит после каждого ответа порта, по которому действует представление, включая ответы, которые оно даёт себе само (порт не подключён, возможность не объявлена, действие не разрешено), — чтобы страница видела результаты, не оборачивая порт.
  • sf-data-view-saved-view-intent — detail: { key: string, label: string, revision?: string|integer, roles?: object }. Событие, которое страница отправляет на представление, чтобы сохранить общее сохранённое представление (порт 1.1.0 и новее): представление отправляет view.save_shared с key и label из detail.
  • sf-data-view-state — detail: { state: string, message: string, instance_id: string }. Приходит при каждой смене состояния данных представления (loading, populated, empty, error) вместе со строкой, которую оно объявляет в своей живой области; для страницы, которая показывает состояние где-то ещё.
  • sf-table-action-intent — detail: { action_id: string, record_ids: array }. Событие таблицы, которое слушает представление: в его таблице выбрано действие над строкой или групповое действие. Представление проверяет, что строка его разрешает, и отправляет record.open (view), record.mutate (одна строка) или bulk.apply_selected с ревизиями записей; перенос и создание в дереве открывают окно переноса или view.create_record.
  • sf-table-column-settings-change — detail: { reason: string, columnSettings: object, tableSettingsKey: string, target?: string, base_revision?: string|number }. Событие таблицы, которое слушает представление: человек изменил ширину колонки, переставил, закрепил или скрыл её. Представление записывает это в личный слой человека (settings.save_personal): выбора слоя таблица не предлагает, и таблица, которую оно рисует, не передаёт target. Общий слой записывает код страницы через saveColumnSettings(settings, {shared: true}).
  • sf-table-column-settings-reset — detail: { target: string, tableSettingsKey: string|null }. Событие таблицы, которое слушает представление: человек попросил вернуть колонки по умолчанию. Представление вызывает resetColumnSettings — пустой личный слой, записанный против его ревизии; значения по умолчанию даёт хост.
  • sf-table-create-intent — detail: { item: string|null }. Событие таблицы, которое слушает представление: нажата кнопка создания или пункт её меню. Представление отправляет view.create_record с detail в том виде, в каком он пришёл.
  • sf-table-query-intent — detail: { reason: any, context: object, sequence: integer }. Событие таблицы, которое слушает представление: изменился входной порт контекста его таблицы. Представление не берёт номер последовательности таблицы и перечитывает список своим query.change.
  • sf-table-template-delete — detail: { key: string }. Событие таблицы, которое слушает представление: на вкладке «Шаблоны» удалён сохранённый шаблон, по одному событию на шаблон. Представление отправляет view.delete с ключом.
  • sf-table-template-save — detail не описан. Событие таблицы, которое слушает представление: сохранён шаблон фильтра. Представление превращает его в saveView (view.save) с key, label, revision, level, roles, layout и settings; массив в detail сохраняется по одному шаблону, каждый своим view.save, записи без key пропускаются.
  • sf-table-template-select — detail: { key: string }. Событие таблицы, которое слушает представление: на вкладке «Шаблоны» применён другой сохранённый шаблон. Представление отправляет view.open с ключом и восстанавливает поля фильтра, с которыми представление было сохранено.
  • sf-host-port-request — detail: { component?: object, context?: object }. Запрашивает у страницы порт хоста — один раз за подключение и только пока у элемента его нет. Общее соглашение для всех компонентов, принимающих setHostPort: потребителю, встраивающему такой компонент в другой, не нужно искать элемент и вызывать у него метод. Ответ — вызов setHostPort на цели события, сразу или позже.
  • sf-data-view-list-open — detail: { reason: any, query: object }. Пользователь запросил весь список, часть которого показана из-за ограничения числа строк. Передаёт запрос, чтобы хост открыл полное представление с теми же записями; компонент не строит собственный адрес.
  • sf-table-tree-intent — detail: { intent: string, payload: object }. Намерение дерева порта simai.dataview-port 1.8.0 — tree.expand, node.targets или node.move, — которое представление объявляет, когда его поднимает. Хост отвечает через порт.
  • sf-data-view-files-drop — detail: { files: array }. На представление с accept-files отпустили файлы с компьютера. Представление ничего не загружает, и файлы не идут через порт; их загружает хост.
  • sf-table-cell-set — detail: { id: string|integer, key: string, value: any, revision: string|integer|null }. Событие таблицы, которое слушает представление: нажат флажок в ячейке. Представление отправляет record.set порта simai.dataview-port 1.11.0 (возможность inline-edit) с record_id, key, value и revision и возвращает флажок, если ответ не applied.
  • sf-table-rows-reorder — detail: { ids: array, before: string|null, order: array }. Событие таблицы, которое слушает представление: строки перетащили в другой порядок. Представление сразу показывает новый порядок и отправляет record.reorder порта simai.dataview-port 1.11.0 (возможность row-reorder); отказ или конфликт возвращает прежний порядок.

Доступность

  • Роль: область (region).
  • Доступное имя: обязательно.
  • Клавиши: Нативные элементы управления и дочерние Smart-компоненты.
  • Фокус: Фокус не перемещается при обновлении данных

Минимальная разметка

HTML
<sf-data-view aria-label="Записи"><sf-table slot="content" aria-label="Записи"></sf-table><sf-pagination slot="pagination"></sf-pagination></sf-data-view>

Источник

  • simai/larena-ui@5f33ba576aebde377d5195ec71836eb4430aa84d:components/src/smart/data-view
  • simai/larena-ui@5f33ba576aebde377d5195ec71836eb4430aa84d:components/src/smart/data-view/rule.js#name=cl-data-view

<sf-table>

Тег <sf-table>
Назначение Полное представление коллекции с серверными данными: поиск, фильтры, настройки таблицы, действия над строками и массовые действия, пагинация.
Контракт smart.data-view, версия 1.9.0
Поставка пакет larena (SF_BOOT_CONFIG.packages.larena)
Жизненный цикл экспериментальный: API может меняться между выпусками
Готовность host-required
Заготовка до прихода кода сервер пишет data-sf-skeleton="rows"; пока ждёт данные, рисует свой скелетон (Заготовка до прихода кода)

Атрибуты

  • template — string, по умолчанию default, значения: default.
  • aria-label — string, по умолчанию Data table, значения: не короче 1. Доступное имя таблицы. Читайте его из контекста props, а не из элемента: aria-label отражается платформой, поэтому element.ariaLabel возвращает null без заданного атрибута и перекрывает значение, которое вычисляет компонент.
  • selectable — boolean, по умолчанию true.
  • settings — boolean, по умолчанию true.
  • actions — boolean, по умолчанию true.
  • row-actions — boolean, по умолчанию true.
  • creatable — boolean, по умолчанию true. Кнопка создания и её меню видов записи среди действий. Представление данных выключает её для хоста на порте 1.10.0, который не объявил create-record.
  • filter-templates — boolean, по умолчанию true. Кнопка, которая сохраняет фильтр как шаблон. Представление данных выключает её, если хост не хранит сохранённые представления.
  • settings-menu — boolean, по умолчанию true. Шестерёнка в заголовке колонки настроек, которая открывает настройки колонок. Без неё колонка по-прежнему несёт меню каждой строки. Представление данных выключает её для хоста на порте 1.10.0, который не объявил personal-column-settings.
  • pagin — boolean, по умолчанию false.
  • filter-text — string, по умолчанию Filter.
  • clear-text — string, по умолчанию Clear.
  • search-placeholder — string, по умолчанию Search.
  • create-text — string, по умолчанию Create.
  • pagination-total — integer, по умолчанию 10, значения: от 0.
  • pagination-page-size — integer, по умолчанию 10, значения: от 1; до 100.
  • page-sizes — string, по умолчанию 10,20,30,40.
  • context-menu-columns — integer, по умолчанию 1, значения: от 1; до 4. На сколько столбцов меню настроек делит свои пункты. Один, пока хост не запросит больше: на протяжении всего существования этого входа значение читалось напрямую, поэтому ни объявленное значение по умолчанию, ни значение, переданное хостом, до меню не доходили.
  • remember-widths — boolean, по умолчанию false. Запоминать ширины колонок как персональный вид (SF.Preferences, под ключом preferences-key или table-settings-key) для таблицы, настройки которой хост не хранит; двойной щелчок по краю колонки забывает её ширину.
  • table-settings-key — string, по умолчанию пусто, значения: не короче 1. Какие сохранённые настройки использует таблица. Пустое значение означает id элемента, а при его отсутствии — id экземпляра, поэтому каждая таблица на странице хранит свои настройки. Реальное значение по умолчанию заставило бы все таблицы использовать один ключ и перезаписывать друг друга.
  • data-state — string, по умолчанию auto, значения: auto, loading, populated, empty, error.
  • loading-text — string, по умолчанию Loading.
  • empty-text — string, по умолчанию No data.
  • error-text — string, по умолчанию The data could not be loaded.
  • retry-text — string, по умолчанию Try again.
  • toolbar — boolean, по умолчанию true. Показывает встроенную панель инструментов; составной компонент может передать свою панель через слот.
  • pin-column-label — string, по умолчанию Pin the column. Доступное имя и подсказка элемента управления, закрепляющего столбец.
  • unpin-column-label — string, по умолчанию Unpin the column. Доступное имя и подсказка элемента управления, открепляющего столбец.
  • column-move-label — string, по умолчанию Move the column. Доступное имя маркера, перемещающего столбец в списке настроек; к нему добавляется подпись столбца.
  • column-search-placeholder — string, по умолчанию Search the fields. Placeholder и доступное имя поля поиска над списком настроек столбцов.
  • column-search-empty-text — string, по умолчанию No field matches. Выводится вместо списка настроек столбцов, когда поиск не нашёл ни одного поля.
  • vertical-scroll — string, по умолчанию self, значения: self, page. Прокручивается ли таблица внутри себя или прокручивается страница. Объявлено как строка с двумя значениями.
  • filter-apply-text — string, по умолчанию Apply. Подпись кнопки подтверждения в окне фильтра; пока есть черновик, к ней добавляется число условий, которые изменит нажатие.
  • layout — string, по умолчанию table, значения: auto, table, list. Как рисуются записи: таблицей, компактным списком или auto — таблицей, пока контейнер таблицы не уже list-below пикселей, и списком, когда уже. sf-data-view выбирает auto для списка на странице.
  • list-below — number, по умолчанию 600. Ширина контейнера в пикселях, уже которой режим auto рисует компактный список.
  • list-fields — number, по умолчанию 3. Сколько полей запись показывает под заголовком в компактном списке; поля выбираются по приоритету колонок.
  • size — string, по умолчанию 1, значения: 1/2, 1. Ступень лестницы размеров для элементов управления и строк таблицы: 1 или плотная 1/2 — элементы управления высотой 32 px, текст 14/20, строки высотой ступени. Размер 1, записанный на элементе, который рисует таблица, становится размером таблицы.
  • preferences-key — string, по умолчанию пусто. Ключ, под которым раскладка таблицы — порядок, видимость, закрепление, ширины — хранится как персональный вид (SF.Preferences, sf-table/<key>); представление данных передаёт свой. Без него используется table-settings-key, а без обоих ничего не хранится.
  • row-actions-visible — string, по умолчанию hover, значения: hover, always. Где видны кнопки действий строки: в строке под указателем, в фокусе или текущей (hover, по умолчанию) или во всех строках (always).
  • drag-rows — boolean, по умолчанию false. Строки можно перетащить из списка как записи (application/x-sf-records+json): запись строки или все выбранные записи, если строка среди них.
  • row-reorder — boolean, по умолчанию false. Строки можно переставить, перетаскивая их внутри списка; отпускание отправляет sf-table-rows-reorder {ids, before, order}. Представление данных ставит атрибут, когда хост предлагает возможность row-reorder.
  • inline-edit — boolean, по умолчанию false. Логическая ячейка, поле которой запись называет в editable, становится флажком; нажатие отправляет sf-table-cell-set {id, key, value, revision}, и ячейка ждёт ответа хоста. Представление данных ставит атрибут, когда хост предлагает возможность inline-edit.

Свойства в документе макета

Узел типа smart.data-view в документе макета (simai.composition.document.v1) принимает:

  • свойства: aria-label, table-settings-key, selectable, toolbar, settings, actions, row-actions, pagin, pagination-total, pagination-page-size, page-sizes, filter-text, clear-text, search-placeholder, create-text, loading-text, empty-text, error-text, retry-text, context-menu-columns, data-state;
  • данные: columns, rows.

Значения свойств те же, что у одноимённых атрибутов, и того же типа, что в списке атрибутов: строковое значение пишется строкой ("size": "1", а не 1 — число отклоняется с диагностикой schema_enum или schema_type), логическое — true или false.

Методы

  • addRows(rows: array) — возвращает object. Добавляет ещё одну страницу с бэкенда в режиме «показать ещё».
  • applyQueryResult(sequence: integer, rows: array) — возвращает boolean. Применяет строки, отвечающие на последний ожидающий запрос контекста. Для устаревшей, повторной или неизвестной последовательности возвращает false и ничего не меняет.
  • clearSelection() — возвращает object. Сбрасывает явное выделение этого экземпляра; при изменении один раз отправляет порт выделения.
  • getActiveFilterFieldKeys() — возвращает array. Какие поля фильтра отображаются, в порядке полей хоста.
  • getColumnSettings() — возвращает object. Читает текущее изменение настроек столбцов.
  • getFilterPayload() — возвращает object. Читает текущий черновик фильтра для проверки запроса на стороне хоста.
  • getInstanceId() — возвращает string. Идентификатор экземпляра: id автора, если он есть, иначе собственный счётчик. От него выводятся id, запасной ключ настроек и портал.
  • getQueryContext() — возвращает object | null. Читает неизменяемый контекст, последним полученный через входной порт контекста, или null.
  • getSelectedRecordIds() — возвращает array из string | integer. Читает типизированные идентификаторы записей, выбранных в этом результате таблицы, без разбора DOM.
  • getSort() — возвращает object. Читает сортировку, отображаемую в заголовках.
  • getToolbarActions() — возвращает array. Действия панели инструментов в объявленном виде, копия.
  • requestActionIntent(actionId: string, recordIds: array) — возвращает object. Отправляет типизированный запрос действия над строкой или пакетного действия; выполнение и авторизация на стороне хоста. При недопустимых аргументах до отправки выбрасывается TypeError.
  • requestContextQuery(sequence: integer) — возвращает object. Внутренний метод порта контекста: отправляет sf-table-query-intent для текущего контекста с новой ожидающей последовательностью.
  • requestCreateIntent(itemId: string|null) — возвращает object. Отправляет sf-table-create-intent для основной кнопки (null) или объявленного id пункта создания.
  • requestRetry() — возвращает object. Отправляет намерение повтора после неудачного запроса данных.
  • setActiveFilterFields(keys: array) — возвращает object. Показывает в выбранном шаблоне фильтра ровно эти поля фильтра. Используется при открытии сохранённого представления: settings.filter_fields перечисляет поля, которые в нём были показаны.
  • setBulkActions(actions: array) — возвращает object. Регистрирует подписанные непрозрачные действия для текущего выделения. При пустом выделении их элементы управления отключены.
  • setColumns(columns: array) — возвращает object. Заменяет канонические столбцы, полученные от бэкенда.
  • setCreateItems(items: array) — возвращает object. Задаёт пункты меню кнопки создания с разделённым действием (только {id, name}). Без пунктов у кнопки создания нет стрелки.
  • setDataState(state: string) — возвращает object. Переключает состояние отображения: автоматическое, загрузка, заполнено, пусто и ошибка.
  • setFilterFields(fields: array) — возвращает object. Регистрирует поля и элементы управления фильтра из разрешённого бэкендом списка.
  • setRows(rows: array) — возвращает object. Заменяет текущие строки результата бэкенда.
  • setSort(key: string|null, direction: any) — возвращает object. Показывает в заголовках текущую сортировку хоста без отправки события; (null, null) сбрасывает её.
  • setTableData(patch: object) — возвращает object. Обновляет столбцы, строки или связанное состояние таблицы, переданные хостом.
  • setTableSettings(settings: object) — возвращает object. Применяет изменение настроек столбцов без запроса на сохранение.
  • setTemplates(templates: array) — возвращает object. Применяет сохранённые шаблоны фильтров и представлений.
  • setToolbarActions(items: array) — возвращает object. Объявляет собственные действия представления для меню панели инструментов: {id, label, icon?, href?}. href должен указывать на этот же сайт. Без действий элемент управления не отрисовывается.
  • sfPortInput(port: any, value: array, meta: object) — возвращает null. Входной порт композиции, используемый sf-composition-scope. Принимает только объявленный порт контекста с record-ids.v1; при недопустимых портах или значениях до изменения состояния выбрасывается TypeError.
  • isTree() — возвращает boolean. Являются ли строки деревом: у какой-то строки есть __tree, которое представление данных пишет по уровням хоста.
  • treeColumnKey(columns?: array) — возвращает string | null. Колонка, от которой растёт дерево: колонка заголовка или первая колонка данных.
  • toggleTreeRow(row: object) — возвращает object. Сообщает, что строку дерева открыли или закрыли (sf-table-tree-toggle).
  • requestTreeMore(row: object) — возвращает object. Запрашивает следующую страницу уровня дерева (sf-table-tree-more).

События

Все события приходят на сам элемент и всплывают. Общие события базового элемента перечислены в главе Жизненный цикл → Этапы.

  • sf-port-output — detail: { port: any, value: array }. Выход порта композиции. Таблица отправляет порт selection (record-ids.v1) один раз при каждом изменении явного выделения, включая сброс; маршрутизирует его общий sf-composition-scope.
  • sf-table-action-intent — detail: { action_id: string, record_ids: array }. Запрашивает одну операцию над строкой или групповую операцию, которую выполняет хост. Источник события — экземпляр таблицы-владельца; отправка события не означает успех операции.
  • sf-table-column-settings-change — detail: { reason: string, tableSettingsKey: string, columnSettings: object }. Запрашивает сохранение изменений настроек столбцов после изменения ширины, порядка или видимости.
  • sf-table-column-settings-reset — detail: { target: string, tableSettingsKey: string|null }. Человек попросил вернуть колонки по умолчанию. Таблица убирает свою сохранённую раскладку и значений по умолчанию не называет: личный слой сбрасывает хост (или представление данных) и отвечает своими значениями.
  • sf-table-create-intent — detail: { item: string|null }. Пользователь нажал кнопку создания (item равен null) или выбрал пункт из её меню (id пункта). Только намерение: хост открывает свою форму создания.
  • sf-table-filter-change — detail: { templateKey: string, templateLabel: string, values: object, tags: object }. Запрашивает у хоста выборку после изменения активного фильтра: «Применить» в окне фильтра, удалённая метка или очищенный фильтр. Представление данных превращает его в query.change с filters из values.
  • sf-table-query-intent — detail: { reason: any, context: object, sequence: integer }. Запрашивает у хоста выборку после изменения входного порта контекста. Хост разрешает связь и права доступа и отвечает вызовом applyQueryResult(sequence, rows); более старые номера последовательности игнорируются.
  • sf-table-retry — detail: null. Запрашивает у хоста повторную загрузку после состояния ошибки.
  • sf-table-search-change — detail: string. Запрашивает у хоста выборку после изменения значения поиска (с задержкой debounce).
  • sf-table-sort-change — detail: { key: string, direction: any }. Пользователь активировал сортируемый заголовок. Направление циклически меняется: asc, desc, null (без сортировки). Только намерение: таблица отмечает заголовок, но не переупорядочивает строки; переупорядочивает или перезагружает их хост.
  • sf-table-template-delete — detail: { key: string }. Пользователь удалил сохранённые шаблоны на вкладке «Шаблоны» и нажал «Применить». Только намерение: хост удаляет сохранённое представление. Одно событие на каждый удалённый шаблон.
  • sf-table-template-save — detail: object | array. Запрашивает сохранение одного или нескольких шаблонов фильтра (порядок, закрепление, удаление, флаги по умолчанию и выбора или данные). О загрузке сохранённого представления сообщает событие sf-table-template-select.
  • sf-table-template-select — detail: { key: string }. Пользователь применил другой сохранённый шаблон на вкладке «Шаблоны». Только намерение: хост загружает это сохранённое представление.
  • sf-table-toolbar-action — detail: { action: string, href?: string|null }. Пользователь выбрал одно из собственных действий представления в меню панели инструментов. Только намерение, событие можно отменить: компонент переходит по href пункта на том же сайте, если хост не перехватит переход через preventDefault.
  • sf-table-tree-toggle — detail: { id?: string|integer, expanded?: boolean }. Пользователь открыл или закрыл строку дерева. Отвечает представление данных; таблица сообщает только, какая строка и была ли она открыта.
  • sf-table-tree-more — detail: { parent?: string|integer|null, cursor?: string|null }. Пользователь запросил следующую страницу уровня дерева.
  • sf-table-rows-drag — detail: { ids: array, source: string|null }. Строки с drag-rows начали перетаскивать из списка к цели вроде дерева; те же {ids, source} лежат в данных перетаскивания как application/x-sf-records+json.
  • sf-table-rows-reorder — detail: { ids?: array, before?: any, order?: array }. Строки перетащили в другой порядок внутри списка: перемещённые идентификаторы, строка, перед которой они теперь стоят (null — в конце), и весь показанный порядок.
  • sf-table-cell-set — detail: { id?: any, key?: string, value?: any, revision?: any }. Нажат флажок в ячейке: запись, поле, новое значение и ревизия записи.

Персональный вид

Ключ sf-table/<preferences-key>, общий для всех элементов этого вида — sf-table/*; версия формата — v: 1. В столбце «Для первой отрисовки» «да» значит, что сервер может положить поле в блок data-sf-preferences страницы.

Поле Тип Пишет Для первой отрисовки Что в нём
columnSettings object sf-table да Раскладка колонок человека по ключу колонки: visible (логическое), width (длина CSS), order (число), pinned (start или end). Накладывается на настройки колонок хоста, поэтому колонка, которой в ней нет, остаётся как у хоста.
widths object sf-table да Ширины колонок, которые человек задал перетаскиванием, по ключу колонки, в виде "<N>px". Хранятся и без preferences-key, если у таблицы есть remember-widths, — тогда под собственным ключом таблицы.
view object sf-table да Вид таблицы: density (compact, normal, spacious), stripes, lines, singleLine, stickyHead. Под sf-table/* это вид всех таблиц человека; он читается под видом этой таблицы.
sort array sf-data-view да Сортировка, которую выбрал человек: [{key, direction}]. Пишет и читает представление данных, в котором стоит таблица, поэтому первый запрос уже приходит в этом порядке.
pageSize integer sf-data-view да Размер страницы, который выбрал человек. Пишет и читает представление данных, поэтому первый запрос уже просит этот размер.

Доступность

  • Роль: область (region).
  • Доступное имя: обязательно.
  • Клавиши: Tab, Shift+Tab, Enter, Space, Escape, стрелки, ArrowLeft и ArrowRight меняют ширину колонки в фокусе, если её можно менять.
  • Фокус: У каждого действия только с иконкой и каждой контекстной поверхности есть доступное имя. Оверлеи экземпляра остаются в пределах визуального окна просмотра, закрываются по Escape и возвращают фокус на свой триггер. При изменении ширины столбца фокус остаётся на его нативной кнопке.

Минимальная разметка

HTML
<sf-table aria-label="Записи" table-settings-key="package.records"></sf-table>

Источник

  • simai/larena-ui@5f33ba576aebde377d5195ec71836eb4430aa84d:components/src/smart/table
  • simai/larena-ui@5f33ba576aebde377d5195ec71836eb4430aa84d:components/src/smart/table/rule.js#name=cl-table

Поиск по документации

Введите минимум 2 символа

    Настройки

    Тема
    Размер шрифта
    Ширина страницы