@pythia-software/query-table-react 0.9.5 → 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -85,6 +85,72 @@ Update only when `api.saved.canUpdate` is true. Optional last/default storage re
85
85
  failures fall back to table defaults; explicit broken URL links still block
86
86
  execution. A single empty `?q=` is treated as an absent query.
87
87
 
88
+ ### Host query state
89
+
90
+ A host that adds its own clauses to the builder (for example a keyword
91
+ condition rendered through the `whereRow` slot) can register their state so
92
+ the native Save, Update, Saved, Default, Share, Reset and Undo/Redo controls
93
+ treat it and the table query as one definition:
94
+
95
+ ```ts
96
+ const api = useQueryTable({
97
+ schema, transport, syncUrl: true,
98
+ hostQuery: {
99
+ ownedParameters: ["record_tool_calls"], // mirrored in the URL
100
+ defaults: { version: 1, params: {} }, // legacy saves and Reset
101
+ normalize: normalizeKeywordState, // validate, migrate; throw to reject
102
+ },
103
+ });
104
+ api.definition; // { query, hostState }
105
+ api.setDefinition(previous => ({ query: { ...previous.query, offset: 0 }, hostState: next }));
106
+ ```
107
+
108
+ `hostState` is `{ version, params: Record<string, string[]> }`. It rides in
109
+ `QueryState.hostState`, so history, saves, `encodeQuery` links and durable
110
+ `@…` snapshots carry it with the query, within the existing size budgets.
111
+ Every request the table sends carries the `hostState` it runs with
112
+ (`ServerQuery`, `ServerQueryV2`, `QueryRequestV3`, `MetricQuery`,
113
+ `AggregationRequest` and distinct-value requests), so the host's transport
114
+ never sees one definition's table query with another's host state; the Go
115
+ request types accept and expose it without interpreting it.
116
+
117
+ - One `setDefinition` is one history entry and one execution. Edits through
118
+ `setQuery` keep the current host state unless they set one.
119
+ - A save without host state, including every existing save, restores the
120
+ host `defaults`. Saved items compare as the definitions they load.
121
+ - `normalize` rejecting a state, or unreadable host state, fails the whole
122
+ restore or load: the live definition and URL stay as they were, and
123
+ `saved.load` throws. A table without `hostQuery` rejects a save that carries
124
+ host state rather than drop it.
125
+ - URL writes replace exactly `ownedParameters` and keep other parameters. A
126
+ table-only link restores host state from those parameters, and a URL with
127
+ only those parameters opens the default table query with that host state
128
+ (an explicit link: a rejected state is a restoration error).
129
+ - Grouping, HAVING and column edits keep the host state; it stays on the
130
+ grouped query, and leaving grouping or following a Records drill-down
131
+ carries it back to the source query.
132
+ - Storage must set `storesHostState: true` (the built-in adapters do) to save
133
+ or persist last-used definitions; otherwise Save reports that it cannot,
134
+ instead of storing a table-only query.
135
+
136
+ ### Last-used query and execution receipts
137
+
138
+ By default the last-used query is saved 400 ms after every change, even if it
139
+ never loads. `persistLast: "succeeded"` saves it only once rows and every
140
+ metric of that exact query have loaded, so a bare reload never restores a
141
+ query that failed, timed out or was cancelled; the failed query stays on
142
+ screen to retry or reset. Explicit links, named saves and the default saved
143
+ query are separate choices and are unaffected.
144
+
145
+ `api.execution` reports the current query's execution apart from
146
+ `api.restoration`: the exact `query`, an execution `key` and increasing
147
+ `generation`, an overall `status` (`running`, `succeeded`, `failed`) and
148
+ separate `rows` and `metrics` statuses with the `error`. An empty result,
149
+ including a page past the end, is a success; a metric that fails while rows
150
+ load is not. A slower earlier execution never updates a later receipt, and
151
+ the receipt is `null` while restoring or inactive. Hosts can use it to build
152
+ their own persistence, retry or reset policies.
153
+
88
154
  Item-detail property views hydrate independently, but synchronize into the
89
155
  collection query only after URL/saved-query restoration settles. Detail layouts
90
156
  encoded in the restored query take precedence over stored property views.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { FieldSchema, WhereClause, QueryState, GroupedRow, GroupingModel, GroupingView, SummaryOp, RepresentativeRow, SummaryColumn, SelectColumn, PropertyViewState, SavedPropertyView, PropertyViewStorage, QueryLink, QuerySnapshot, ItemPropertyMode, ItemPageOptions, ItemDetailMode, ItemDetailsState, RelationshipAdapter, RowId, FormulaNode, FormulaValue, FormulaResult, ComputedColumn, FieldDef, ComputedColumnDraft, FormulaPlan, ColumnPreview, SavedQuery, StorageAdapter, AggOp, AggregationClause, AggregationResult, DistinctValuesResult, FieldStats, OrderByClause, Transport, ComputedExecution, ComputedColumnStore, QueryLinkOptions, ObjectReference, ResolvedObjectReference } from '@pythia-software/query-table-core';
1
+ import { FieldSchema, WhereClause, QueryState, GroupedRow, GroupingModel, GroupingView, GroupKey, SummaryOp, RepresentativeRow, SummaryColumn, SelectColumn, PropertyViewState, SavedPropertyView, PropertyViewStorage, QueryLink, QuerySnapshot, ItemPropertyMode, ItemPageOptions, ItemDetailMode, ItemDetailsState, RelationshipAdapter, RowId, FormulaNode, FormulaValue, FormulaResult, ComputedColumn, FieldDef, ComputedColumnDraft, FormulaPlan, ColumnPreview, SavedQuery, StorageAdapter, AggOp, AggregationClause, AggregationResult, HostQueryState, DistinctValuesResult, FieldStats, OrderByClause, Transport, ComputedExecution, ComputedColumnStore, QueryLinkOptions, ObjectReference, ResolvedObjectReference } from '@pythia-software/query-table-core';
2
2
 
3
3
  /** Filter controls for either the result query or grouping's source query. */
4
4
  type QueryFilterApi<Row> = Pick<QueryTableApi<Row>, "query" | "setQuery" | "loading" | "addFilter" | "updateFilter" | "removeFilter" | "clearFilters" | "updatePredicate" | "removePredicate" | "negatePredicate" | "reorderFilters" | "mergeFilters" | "filterValues" | "fieldStats">;
@@ -40,7 +40,9 @@ interface GroupingApi<Row> {
40
40
  inputs: Row[];
41
41
  notice: string;
42
42
  setNotice: (notice: string) => void;
43
- changeKeys: (keys: string[]) => void;
43
+ /** Field names, or calendar keys (`{ field, interval, timeZone }`) for
44
+ * datetime fields. */
45
+ changeKeys: (keys: GroupKey[]) => void;
44
46
  addSummary: (op: SummaryOp, field?: string) => void;
45
47
  changeSummary: (id: string, op: SummaryOp) => void;
46
48
  changeRepresentative: (rule: RepresentativeRow | null) => void;
@@ -114,6 +116,8 @@ interface ItemDetailsOptions<Row> {
114
116
  loadRow?: (id: RowId, signal: AbortSignal) => Promise<ItemDetailRecord<Row> | null>;
115
117
  }
116
118
  interface ItemDetailsApi<Row> {
119
+ /** "group" details describe grouped result rows, identified by their group identity. */
120
+ subject?: "item" | "group";
117
121
  links?: QueryLinksApi;
118
122
  schema: FieldSchema<Row>;
119
123
  /** Collection catalogue used to resolve Page template fields. */
@@ -242,7 +246,8 @@ interface SavedQueriesApi {
242
246
  canUpdate: boolean;
243
247
  /** Replace a saved query with the current state, retaining its id and default. */
244
248
  update: (id: string) => Promise<SavedQuery>;
245
- /** Load a saved query into the live controller. */
249
+ /** Load a saved query into the live controller. Throws, changing nothing,
250
+ * when the table cannot accept it (for example unreadable host state). */
246
251
  load: (id: string) => void;
247
252
  /** Mark a saved query as the default view. No-op when storage lacks support. */
248
253
  setDefault: (id: string) => Promise<void>;
@@ -282,6 +287,16 @@ interface UseQueryTableOptions<Row> {
282
287
  * Pass localStorageAdapter() explicitly only when filter values are safe to
283
288
  * retain as cleartext JSON on the device. */
284
289
  storage?: StorageAdapter;
290
+ /** When `storage.saveLast` records the last-used query: "always" (default)
291
+ * 400 ms after every change, or "succeeded" once rows and every metric of
292
+ * that exact query have loaded. A failure, timeout or cancellation keeps the
293
+ * previous last-used query; explicit links, named saves and the default are
294
+ * separate choices and are never touched by it. */
295
+ persistLast?: "always" | "succeeded";
296
+ /** Host-owned query state that travels with the table query as one
297
+ * definition: saved, restored, shared, reset and undone together. The host
298
+ * keeps rendering and running its own clauses from `api.definition`. */
299
+ hostQuery?: HostQueryOptions;
285
300
  /** Shared reusable definitions, independent of saved-query storage. */
286
301
  computedColumnStore?: ComputedColumnStore;
287
302
  /** Authoritative host handshake for versioned server SELECT, sorts, and metrics. */
@@ -365,6 +380,42 @@ interface AggregationsApi {
365
380
  /** Invalidation token for page, refresh, schema, and definition changes. */
366
381
  contextKey?: string;
367
382
  }
383
+ /** Registers host-owned query state with `useQueryTable`. */
384
+ interface HostQueryOptions {
385
+ /** URL parameters that mirror `hostState.params` when `syncUrl` is on. URL
386
+ * writes replace exactly these, keeping every other parameter. They may not
387
+ * include the table's own query parameter. */
388
+ ownedParameters: readonly string[];
389
+ /** The state a query without host state takes, including every save made
390
+ * before the host registered, and the state Reset restores. */
391
+ defaults: HostQueryState;
392
+ /** Validate, migrate and canonicalize; throw to reject. A rejected state
393
+ * rejects the whole restore or edit, leaving the live definition as it was. */
394
+ normalize?: (state: HostQueryState) => HostQueryState;
395
+ }
396
+ /** The committed table query and host state, as one unit. */
397
+ interface QueryDefinition {
398
+ query: QueryState;
399
+ hostState: HostQueryState;
400
+ }
401
+ /** The outcome of executing one exact query; see `QueryTableApi.execution`. */
402
+ interface QueryExecutionReceipt {
403
+ /** The query whose rows and metrics this receipt describes. */
404
+ query: QueryState;
405
+ /** Execution identity: changes with every row- or metric-affecting edit and
406
+ * refresh, but not with presentation such as widths. */
407
+ key: string;
408
+ /** Increases with every new execution identity of this table. */
409
+ generation: number;
410
+ /** "succeeded" only when rows and every metric loaded; an empty result,
411
+ * including a page past the end, is a success. */
412
+ status: "running" | "succeeded" | "failed";
413
+ rows: "running" | "succeeded" | "failed";
414
+ /** "none" when the query has no metrics. A metric error fails the receipt. */
415
+ metrics: "none" | "running" | "succeeded" | "failed";
416
+ /** The row or metric error behind a failure. */
417
+ error: Error | null;
418
+ }
368
419
  interface QueryTableApi<Row> {
369
420
  /** Dependent source fetches can use ready without parsing display errors. */
370
421
  restoration: {
@@ -372,6 +423,16 @@ interface QueryTableApi<Row> {
372
423
  ready: boolean;
373
424
  error: Error | null;
374
425
  };
426
+ /** Execution of the current query, separate from restoration. Null while
427
+ * restoring, after a restoration error and while the table is inactive, so
428
+ * a cancelled or hidden table never publishes a stale receipt. */
429
+ execution: QueryExecutionReceipt | null;
430
+ /** With `hostQuery`: the committed definition (`query` without its
431
+ * `hostState`, and the host state). */
432
+ definition?: QueryDefinition;
433
+ /** With `hostQuery`: commit a new definition as one history entry and one
434
+ * execution. Throws, changing nothing, when `hostQuery.normalize` rejects. */
435
+ setDefinition?: (next: QueryDefinition | ((previous: QueryDefinition) => QueryDefinition)) => void;
375
436
  /** Call after a host pushState/router update, with an absolute URL or a location
376
437
  * relative to window.location.href. Supersedes prior resolution;
377
438
  * abort or an intervening query edit prevents stale publication. */
@@ -415,7 +476,8 @@ interface QueryTableApi<Row> {
415
476
  /** Remove the whole term at `index`. */
416
477
  removeFilter: (index: number) => void;
417
478
  clearFilters: () => void;
418
- /** Replace one predicate inside a term (predIndex 0 for a literal term). */
479
+ /** Replace one predicate inside a term (predIndex 0 for a literal term). In
480
+ * an OR of conjunctions, predIndex counts literals in `predicatesOf` order. */
419
481
  updatePredicate: (termIndex: number, predIndex: number, clause: WhereClause) => void;
420
482
  /** Remove one predicate; a group of one flattens to a literal, an emptied term drops. */
421
483
  removePredicate: (termIndex: number, predIndex: number) => void;
@@ -425,8 +487,8 @@ interface QueryTableApi<Row> {
425
487
  * dragged term removed, so a drag preview's slot maps straight to the result). */
426
488
  reorderFilters: (fromIndex: number, toIndex: number) => void;
427
489
  /** OR-merge the term at `sourceIndex` into the term at `targetIndex`: the
428
- * target becomes (or stays) an OR group holding both terms' predicates, and
429
- * the source term is removed. This is the drag-onto-another-filter gesture. */
490
+ * target becomes (or stays) an OR group holding both terms' branches (a
491
+ * conjunction stays one AND branch), and the source term is removed. This is the drag-onto-another-filter gesture. */
430
492
  mergeFilters: (sourceIndex: number, targetIndex: number) => void;
431
493
  /** Reset the complete query state back to schema defaults. */
432
494
  resetAll: () => void;
@@ -486,4 +548,4 @@ declare function useObjectReferences(references: ObjectReference[], adapter?: Re
486
548
  error: Error | null;
487
549
  };
488
550
 
489
- export { type AggregationPatch, type AggregationsApi, type AggregationsApiState, type AutoRefreshApi, type AutoRefreshConfig, type AutoRefreshStatus, type ColumnDragApi, type ComputedColumnsApi, type FormulaWorkerFactory, type GroupingApi, type GroupingSourceApi, type ItemDetailRecord, type ItemDetailsApi, type ItemDetailsOptions, type PropertyViewApi, type QueryFilterApi, type QueryLinksApi, type QueryTableApi, type RequestActivityApi, type RequestActivityEntry, type SavedQueriesApi, type SelectApi, type SelectionApi, type UsePropertyViewOptions, type UseQueryTableOptions, createFormulaWorker, evaluateFormulaRows, useAggregations, useColumnDrag, useObjectReferences, usePropertyView, useQueryFilters, useQueryTable, useSavedQueries, useSelect, useSelection };
551
+ export { type AggregationPatch, type AggregationsApi, type AggregationsApiState, type AutoRefreshApi, type AutoRefreshConfig, type AutoRefreshStatus, type ColumnDragApi, type ComputedColumnsApi, type FormulaWorkerFactory, type GroupingApi, type GroupingSourceApi, type HostQueryOptions, type ItemDetailRecord, type ItemDetailsApi, type ItemDetailsOptions, type PropertyViewApi, type QueryDefinition, type QueryExecutionReceipt, type QueryFilterApi, type QueryLinksApi, type QueryTableApi, type RequestActivityApi, type RequestActivityEntry, type SavedQueriesApi, type SelectApi, type SelectionApi, type UsePropertyViewOptions, type UseQueryTableOptions, createFormulaWorker, evaluateFormulaRows, useAggregations, useColumnDrag, useObjectReferences, usePropertyView, useQueryFilters, useQueryTable, useSavedQueries, useSelect, useSelection };