Skip to content

TGrid definitions, sessions, and queries

View as Markdown

TGrid and table-grid exports come from @sapporta/frontend. Standalone runtime primitives come from @sapporta/grid.

  • defineTGrid() declares schema-table levels, parent relationships, query ownership, interaction configuration, and typed column builders.
  • useTGridSession() creates a session after React commit and disposes it on unmount. It returns null until the session exists.
  • createTGridSession() creates a session for tests and non-React hosts. Its owner must call dispose().
  • TGrid renders a configured session. TableRoute and SchemaTableGridView connect standard table routes.
  • useSchemaTableGrid() exposes the session when an application composition needs schema-derived defaults plus active-row or activation behavior.

Table-aware clients preserve Sapporta query syntax, lookups, row saves, auth, record navigation, CSV export, and URL query state.

TableGridView and SchemaTableGridView accept:

sessionRef?: React.Ref<TGridSession<RowsByLevel, AppServices>>

Use it when another component needs to inspect or control the live session without replacing the standard table UI—for example, to reload rows, observe session state, coordinate selection or expansion, or reveal a deep-linked row.

The view owns and disposes the session. The ref is set after creation and cleared to null when the session is replaced or released, so callback-ref subscriptions must clean up on null. The parameter is also available through TablePageGridOptions and TableGridOptionsByTable. useTableGrid() and useSchemaTableGrid() omit it because their returned binding already contains session.

SchemaTableGridView derives its columns from the table schema and supplies the whole table page: URL query state, filters, search, sort, pagination, CSV export, lookup labels, record routes, the toolbar, and New record. Its columns prop replaces that derived list for the root level, so a page can hide, reorder, restyle, or add columns without rebuilding the page as a defineTGrid definition. useSchemaTableGrid and defineSchemaTGrid take the same value, and TablePage takes it through gridOptions.

type SchemaTableColumns<AppServices = unknown> = TGridLevelColumns<
SchemaTableRowsByLevel,
AppServices,
string
>;

The value is the spec list or builder callback a defineTGrid level’s columns takes, built with columns.table(), columns.client(), and columns.remainingTable(). remainingTable() fills the gaps in schema order, so a page names only the columns it changes. The value is checked against the table when the grid builds, not when the grid is declared, and a new identity rebuilds the grid, so keep it in a module constant or useMemo. Child levels, fixedFilters, search, and CSV export are unchanged, and other views of the table still show every column.

expandTGridColumnSpecs is exported for an application that compiles the same value itself: it returns the visible columns, in order, with every name checked against the table. Change the standard page’s columns walks through the prop with worked examples.

TGridSession exposes:

  • getVisibleRows(levelId?, path?) and getLoadedRow(rowKey, levelId?, path?) for rows already loaded into the Grid;
  • getQueryState(levelId?) for host-owned query state;
  • reloadRows(), setLevelSort(), setLevelFilter(), and setLevelPage() for path-specific table controls;
  • csvExportUrl(levelId?) for the current fixed filters, visible filters, search, and sort; and
  • lookups, lookupForColumn, application services, and level metadata for custom cells and editors.

Loaded-row reads are not database queries. Use generated table reads, public table read functions and options, or an application endpoint when the row may not be loaded on the current page.

Host-owned query state supplies visible controls and URL state. Source-owned query state belongs to a relationship source. fixedFilters affect row loads and CSV exports but are not editable filter state. Row loads send a level’s parent-row constraint and fixedFilters as fixed conditions, and the user’s filters and search as filter conditions and q. CSV exports send all of them as filter conditions. Client query constraints do not enforce authorization.

A level whose table declares meta.tree shows its rows as one indented tree. The level’s tree option adjusts that:

type TGridLevelTreeConfig = false | Partial<TableTree>;
  • Leave tree out to follow the table’s declared tree.
  • tree: false shows a tree table as a flat, paged list, for example inside a picker.
  • An object overrides single fields of the declared tree: parentColumn, column, defaultExpanded, or matchContext.
  • A table without meta.tree can opt in by naming parentColumn. The level then builds the tree in the browser, and a search returns only the matching rows, because the server walks only a tree the table declares.

A tree level declares no childLevels; defineTGrid() throws when it does, and when parentColumn is not a column of the table. The hierarchy is shown in the declared column when the level shows it, otherwise in the card title column, otherwise in the first column. session.levelInfoById[level].tree is the resolved TableTree with the column actually used, or null for a flat level.

A tree level reads every row in one request so it can build the whole tree: the first page at MAX_PAGE_SIZE (1,000) rows. TGridLevelInfo.pagination is "all" for a tree level and "pages" for a flat one. Query state, setLevelPage(), URL state, and useTableLevelPager() follow it, so a custom page built from the table hooks shows a tree on one page.

When the table declares the same tree, each row load sends the level’s matchContext as the tree mode. A filter or search then keeps each match’s ancestors, and by default its subtree, inside the level’s fixed conditions. useTGridSourceStatus(session).treeResult reports the last load as a TGridTreeResult:

  • matchCount: rows that match the filter or search themselves, or null when neither is active;
  • loadedRowCount: rows the load returned;
  • truncated: true when the table holds more rows than one load returns, so the tree may be missing rows.

treeResult is null for a flat level and before the first load.