THE listing — tree icons, search, per-column sort, selection with bulk verbs; folders interleave by name.
The list a CMS lives in, as a component: CmsDataTable
(src/components/CmsDataTable.tsx) is the system data table. Container
contents, the media library, Site Info's inventory, and the Fields, Content
Types, and Layouts registries all render through it, so every listing in
the admin has the same anatomy:
tree icons on names, a search filter, per-column sorting, and a selection
column whose bulk verbs appear when a caller wires them. The markup
underneath is the mk-table grammar — this component is
that grammar with the behavior attached.
A row is data, not markup:
| Field | Says |
|---|---|
key |
Stable identity for React and selection. |
title |
The Name cell. Sorting and search read it. |
typeId |
The row's kind in the lane's own words — a content-type id, folder, a media kind. Search reads it too. |
icon |
Tree icon id (page, folder, container, …) — the same vocabulary the site tree uses. |
leading |
Custom leading visual (a media thumbnail); wins over icon. |
status / updated |
Feed the default asset columns. |
cells |
Values for custom columns, keyed by column key. |
onOpen |
What clicking the row does. Omit it and the row renders inert — a trashed asset, say. |
The row opens the entity; verbs ride in a trailing column. A row is not
a place for five buttons — actions go in a custom column marked
interactive: true, so clicks inside it do not also open the row.
The default trailing columns describe assets: Type, Last modified, Status.
A lane whose rows are not assets replaces them wholesale with columns —
Site Info passes a Count column, Fields passes Key and Type. A column with
a sortValue opts into header sorting; without one it is display-only.
Rows sort by the active column across all rows — folders interleave with everything else by name rather than pinning to the top. That is a ruling, not an accident: every folder view runs through this one table, and a folders-first exception would fork the listing again. If grouping is ever wanted, it arrives as a sortable kind column, not a pin rule.
Wire onSelectionChange and the checkbox column appears; bulkActions
renders the verbs beside the selection count while something is selected.
The checkboxes exist to facilitate bulk actions — no verbs, no checkboxes.