[data-reveal]{opacity:1!important;transform:none!important}
AntelopeJS DMS
DocumentationTable events and helpers

Table events and helpers

Exports, realtime updates, the metadata, the route helpers and the events of a table view.

These are the parts of a table view that run around its rows: exports, realtime updates, the metadata it registers, the route helpers and its events.

Exports

The export action is offered only when the controller registered all three ExportRoutes. Pressing it starts a background export job, polls its status, and downloads the result; the job machinery itself is shared with any other long export and is documented in Helpers. Which columns land in the file is decided by @Exported.

Realtime

Unless realtime: false is set, a table view registers two realtime topics for its page (and for each generated sub-page), and its routes publish every create, update and delete on the first and track who has a row open on the second. Both are named after the controller's location:

typescript
import {
  tableViewPresenceTopic,
  tableViewRowTopic,
} from "@antelopejs/interface-dms/base/table-view";

tableViewRowTopic("/api/orders"); // "tableview:row:/api/orders"
tableViewPresenceTopic("/api/orders"); // "tableview:presence:/api/orders"

The topics are registered with RegisterPageTopic from the table view's onCreated, so they belong to the module whose page it is, as described in Realtime. A module that publishes on a table's row topic itself, such as a background job updating rows, builds the name with tableViewRowTopic rather than spelling out the prefix, and passes the tenant of the rows as tenantId.

The topics are the same for every tenant, but what is published on them is not: the routes publish each change, and each presence, for the tenant the request was made in, so the sessions of the other tenants neither refetch nor see who has a row open. The DMS decides who else receives them, with no option on the table: a table whose rows live in the schema every tenant shares (CORE_SCHEMA_NAME) publishes to every tenant, and a session on a platform page (a module's page) receives the changes of every tenant, as such a page lists the data of all of them. RealtimeMutationContext and RealtimePresenceContext carry the tenant as tenantId, absent on a table of the shared schema.

Two functions let other modules observe those mutations:

typescript
import {
  registerRealtimeMutationListener,
  unregisterRealtimeMutationListener,
  type RealtimeMutationContext,
} from "@antelopejs/interface-dms/base/table-view";

const listener = (context: RealtimeMutationContext) => {
  // context.controllerLocation, context.eventType, context.ids, …
};

registerRealtimeMutationListener(listener);

Listeners are additive side observers: they run after the DMS has published the mutation, and a listener that throws is logged, never propagated to the mutating request. A listener is released with the module that registered it, including when that module reloads in development; unregisterRealtimeMutationListener is for a module that stops listening while it stays loaded.

TypeShape
RealtimeMutationEventType"created" | "updated" | "deleted"
RealtimeMutationContextcontrollerLocation, rowIdKey, eventType, ids: string[], sessionId?, actor?: RealtimePresenceActor
RealtimePresenceActorid, displayName?, avatarUrl?
RealtimePresenceContextcontrollerLocation, rowIdKey, sessionId, rowId, actor

The routes reach the DMS through two interface functions it implements, internal.PublishMutation and internal.AcquirePresence. They are internal: nothing outside the DMS implements them, and the core binds them to each generation of the DMS module, so a mutation made while the DMS reloads waits for the next generation instead of reaching the one being torn down.

Metadata

TableViewMeta is the metadata object the decorators write to and the builder reads from. Retrieve it with GetMetadata(controller, TableViewMeta).

MemberDescription
columnsRecord<string, ColumnOptions> keyed by field name.
groupsRecord<string, ColumnGroupConfig> keyed by group id.
optionsThe TableViewOptions of the writing TableView, or of the last one built while none writes.
archiveFieldField name recorded by @ArchiveField.
controllerRowActionRulesThe rules the write routes enforce: the writing table view's rowActions, archive-mode defaults included.
controllerGuardsGuards promoted to controller-wide guards.
componentBuildersEvery live TableView builder built on the controller, in build order.
writingComponentBuildersThe live builders of componentBuilders that write through the data routes.
actionPermissionIds(actionId)The permission id the action carries on each mounted table view of the controller, on the writing one only for a write action.
addComponentBuilder(builder, access?)Writer the builder calls to record itself, with its TableViewAccess ("read" or "write", the default). A custom component standing in for a table view (the roles editor) records itself the same way.
resourceFormBuildersEvery live new / edit form built over the controller, in build order: the ResourceForm blocks and the forms each table view opens.
addResourceFormBuilderWriter the form builder calls to record a form that submits to the controller.
writingComponentsEvery live component that submits to the controller's write routes: its writing table view and its new / edit forms, including the ones a page-mode table view mounts on its form sub-pages. A native file staged by any of them is accepted on save; one staged by any other component is refused.
inherit(parent)Called by GetMetadata for a derived controller: copies the parent's columns (each with its own copy of its data type), groups, options and archiveField, never its table views or forms.
configGetter returning { location, columns }, the serialized column list plus the controller's route location.
getFormFields(mode)Builds the FormFieldOrGroup[] for "view", "edit" or "new".
setColumn, setGroup, setOptions, setArchiveField, setControllerRowActionRules, setControllerGuardsWriters used by the decorators and the builder.

Each entry of config.columns carries id, header, isVisible, type (the serialized data type), accessorKey, listable, enableSorting, enableColumnFilter, defaultValue, accessMode and readonlyBehavior.

Route helpers

table-view also exports the interface functions the wrapped routes call. They are the seam between the interface and its implementation. A consumer wires them by declaring TableViewRoutes, and does not normally call them directly.

FunctionRole
listWithSearchRuns the list query with search, filters, sorting and pagination; returns { results, total, offset, limit }.
countWithSearchSame query, count only; returns { total }.
startExportQueues an export job; returns { jobId, format, extension }.
getExportStatusReturns { status, progress, error? } for a job.
downloadExportStreams a completed job's file to the response.
archiveRowsSets the archive field on the given ids; returns { success, archivedCount }.
restoreRowsClears it; returns { success, restoredCount }.
validateRowsAgainstRuleSplits ids into { eligibleIds, rejectedIds } against a RowActionRule.
fetchRowForGuardLoads one row by id field, for the edit guard and the file-cleanup passes.

Events and functions

Namespace memberValue
TableViewEvents.ROW_CLICK"DmsComponent.TableView.RowClick"
TableViewEvents.ROW_SELECT"DmsComponent.TableView.RowSelect"
TableViewEvents.ROW_DELETE"DmsComponent.TableView.RowDelete"
TableViewEvents.ROW_ADD"DmsComponent.TableView.RowAdd"
TableViewEvents.ROW_EDIT"DmsComponent.TableView.RowEdit"
TableViewEvents.FILTER_CHANGE"DmsComponent.TableView.FilterChange"
TableViewEvents.SORT_CHANGE"DmsComponent.TableView.SortChange"
TableViewEvents.EXPORT"DmsComponent.TableView.Export"
TableViewFunctions.CUSTOM_PAGE_FORM_SUCCESS"DmsComponent.TableView.CustomPageFormSuccess"

CUSTOM_PAGE_FORM_SUCCESS registers { url: string; preserveQuery?: string[] } in WatchFunctionParamMap. The builder uses it itself: the generated new and edit page forms watch FormEvents.SUBMIT_SUCCESS and navigate back to the table, preserving the query parameters named in queryParamFilters. The handler resolves {{params.X}} / {{query.X}} tokens in url against the route being left before navigating; the generated forms rely on it to send the user back to a page whose slug carries parameters: each placeholder of the page's slug becomes the token reading it on the form route (/workspaces/:id becomes /workspaces/{{params.id:1}} from /workspaces/:id/invoiceTable/:id/edit, /workspaces/{{params.id}} from /workspaces/:id/invoiceTable/new). A slug without parameters is used as is. The view form submits nothing and carries no such watch. All three generated pages are registered with FormPageLayout(), the constrained-column layout (Layout and containers).