Hosted oneric.vicenti.netvia theHypermedia Protocol

Query Block Table View Implementation Plan

Summary

Add a read-only Table view to the existing Query block so documents can render query results as configurable data tables. The table exposes each matching document's custom metadata attributes together with selected core fields.

This issue records all modeling options considered and selects Option 1: extend the existing Query block and payload. Attribute filtering remains client-side until the backend metadata-query model is designed.

Requirements

Data and default columns

    Reuse the Query block's target, Children / AllDescendants mode, limit, sort, and loading flow.

    Show user-defined attributes plus supported core metadata.

    Keep cells read-only; Title links to the source document.

    Infer custom values as string, number, boolean, date-like string, or multi-value list. Fall back to text for mixed/inconsistent values.

    Default visible order: Title → discovered custom attributes → Comments → Citations → Updated → Authors.

    Render Authors as an avatar face pile.

    Offer Created, Path, Child Count, and other supported core fields in the column picker, hidden by default.

Per-block configuration

Persist on each Query block:

    column order

    column visibility

    column widths

Duplicating a block copies its table configuration. Do not add shared saved views yet.

Interactions and UI

Use TanStack Table v8, already installed in frontend/packages/ui and used by All Documents.

    Sortable and resizable columns.

    Global search across all available row data, including hidden columns.

    Toolbar filter builder: Attribute → Operator → Value.

    Multiple temporary filters combine with AND and appear as removable rows/chips.

    Horizontal scrolling inside the document block with sticky Title column, including touch scrolling on narrow screens.

    Progressive row rendering, consistent with the current Query List view.

    Search-match highlighting/bold text is a nice-to-have after core behavior.

    Shared loading, empty, filtered-empty, error, hover, focus, resizing, and narrow-width states.

Persistence behavior

    In edit mode, header sorting updates the Query block's persisted query sort.

    In published/read-only mode, sorting is temporary and resets on reload.

    Search and attribute filters are temporary client-side state and are not persisted.

    Column order, visibility, and widths persist per block.

Surfaces

Use one shared renderer in:

    desktop editor

    web editor

    published/read-only documents

Modeling options

Option 1 — Extend the existing Query block and payload (selected)

Add Table alongside Card and List, plus one optional nested table configuration:

type QueryView = 'Card' | 'List' | 'Table' type QueryTableConfig = { columns: Array<{ id: string width?: number visible: boolean }> }

Separate:

    Query definition: target, traversal mode, limit, persisted author-selected sort.

    Persisted table configuration: column order, visibility, widths.

    Ephemeral reader state: search, temporary attribute filters, read-only sorting.

The existing query-block request remains the loading boundary, but results must reliably carry complete open metadata maps. Core fields remain strongly modeled.

Why this option

    Table is another view of the same query rather than a new data source.

    Authors can switch Card/List/Table without converting the block.

    Existing query settings, drafts, loading, and empty states are reused.

    Lowest compatibility and migration risk.

    Avoids prematurely introducing a database entity or formal attribute schema.

Trade-offs

    Query blocks gain Table-only configuration.

    Payloads may grow because each result needs complete metadata.

    Columns are discovered from loaded results; an attribute absent from every current result cannot be newly discovered, though a persisted column may remain configured.

Option 2 — Generic discriminated view configuration

Refactor all Query presentations:

type QueryPresentation = | {type: 'Card'; columnCount: number; banner: boolean} | {type: 'List'} | {type: 'Table'; columns: TableColumnConfig[]}

Advantages: stronger presentation-specific modeling and a cleaner base for gallery, board, calendar, or timeline views.

Why not now: requires migration/compatibility work for existing Card/List blocks and broader serialization, conversion, and renderer changes mainly for hypothetical future views.

Option 3 — Separate Database/Table block

Create a distinct block owning a query reference and database-view configuration.

Advantages: suitable if Seed later adds reusable databases, schemas, relations, formulas, aggregations, and inline editing.

Why not now: duplicates query targeting/loading/settings, makes view switching a block conversion, and is disproportionate to this read-only inferred-schema feature.

Backend-query boundary

The first implementation must not invent backend metadata predicate syntax.

Initially:

    The existing Query block fetches its result set.

    Complete result metadata reaches the shared table renderer.

    TanStack Table performs global search, typed attribute filters, and reader sorting over loaded rows.

    The existing query limit still bounds the client dataset, so the UI must make clear that temporary filtering searches loaded results.

A later backend design should decide:

    metadata predicate representation

    supported typed operators

    AND / OR grouping

    indexing and execution

    pagination/cursors

    whether predicates belong in the query model or a reusable saved-view model

The toolbar filter-builder should be adaptable to server predicates later without replacing the Table view model.

Existing code to build on

    frontend/packages/ui/src/all-documents-page.tsx — TanStack Table, shared table primitives, sorting/search, avatars, comments, citations, loading/empty states.

    frontend/packages/ui/src/query-block-content.tsx — shared Card/List rendering and progressive list rows.

    frontend/apps/desktop/src/editor/query-block.tsx — schema, settings, query loading, persistence, shared rendering.

    frontend/packages/client/src/hm-types.ts — Query, open metadata, and payload schemas.

    frontend/packages/shared/src/api-query-block.ts — payload assembly.

    frontend/packages/shared/src/models/queries.ts — shared Query block request.

Implementation stages

    Model and compatibility: add Table, optional nested config, HM/editor conversion, round-trip tests.

    Data contract: preserve complete custom metadata in HMDocumentInfo query results and test it.

    Shared model/renderer: stable column IDs, type inference/fallback, TanStack sorting/resizing/visibility/order/search/filters/progressive rendering/sticky Title.

    Authoring/persistence: Table selector, column picker/reordering, persisted layout and editor sort.

    Cross-surface verification: desktop editor, web editor, published rendering, accessibility and responsive states.

Acceptance criteria

    [ ] Existing Card/List blocks render and round-trip unchanged.

    [ ] Authors can select Table as the Query view.

    [ ] Default columns and ordering match the requirements above.

    [ ] Optional core columns can be enabled.

    [ ] Custom columns infer types with deterministic text fallback.

    [ ] Authors can reorder, resize, show, and hide columns; layout survives save/reload and duplication.

    [ ] Header sorting persists in edit mode and remains temporary in read-only mode.

    [ ] Global search covers visible and hidden values.

    [ ] Temporary typed AND filters do not mutate the saved query.

    [ ] Rows render progressively from the loaded result set.

    [ ] Title stays sticky during horizontal/touch scrolling.

    [ ] Title opens the source; all other cells remain read-only.

    [ ] One shared renderer works on all required surfaces.

    [ ] Tests cover serialization, metadata payloads, type inference, filtering/sorting, persistence callbacks, accessibility, and narrow layouts.

    [ ] Backend predicates, server pagination, inline editing, reusable views, and formal attribute schemas remain out of scope.

Scenarios to verify

    [ ] No custom attributes.

    [ ] Different rows have different keys.

    [ ] One key has mixed/invalid types.

    [ ] A configured attribute disappears from current results.

    [ ] Query limits constrain temporary search/filter.

    [ ] Enough rows trigger progressive rendering.

    [ ] The block is narrower than combined minimum widths.

    [ ] Legacy documents contain no table configuration.

Do you like what you are reading? Subscribe to receive updates.

Unsubscribe anytime