@pythia-software/query-table-react 0.2.0 → 0.3.0
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 +9 -0
- package/dist/index.d.ts +44 -2
- package/dist/index.js +654 -115
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/useQueryTable.ts","../src/useAggregations.ts","../src/useSelection.ts","../src/useSelect.ts","../src/useColumnDrag.ts","../src/useSavedQueries.ts"],"sourcesContent":["// useQueryTable — the one hook that owns everything.\n//\n// The headless brain of the table: it holds the QueryState, keeps it in sync\n// with the URL (`?q=`) and the StorageAdapter, orchestrates fetches through the\n// Transport (debounced + abortable), and exposes intent-level mutators so a UI\n// never hand-edits QueryState. @pythia-software/query-table-ui is a thin layer over this; you\n// can also build an entirely custom table on it.\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n EMPTY_QUERY,\n applyQuery,\n decodeQuery,\n encodeQuery,\n memoryStorageAdapter,\n normalizeQueryState,\n readFieldValue,\n selectedFields,\n toServerQuery,\n queriesEqual,\n} from \"@pythia-software/query-table-core\";\n\nconst AUTOCOMPLETE_LIMIT = 50;\nconst MAX_AUTO_REFRESH_POLLS = 1000;\nimport type {\n QueryState,\n WhereClause,\n OrderByClause,\n AggOp,\n AggregationClause,\n AggregationResult,\n RowId,\n FieldDef,\n FieldSchema,\n Transport,\n StorageAdapter,\n DistinctValuesResult,\n} from \"@pythia-software/query-table-core\";\nimport { useAggregations } from \"./useAggregations\";\nimport { useSelection, type SelectionApi } from \"./useSelection\";\nimport { useSelect, type SelectApi } from \"./useSelect\";\nimport { useColumnDrag, type ColumnDragApi } from \"./useColumnDrag\";\nimport { useSavedQueries, type SavedQueriesApi } from \"./useSavedQueries\";\n\nexport interface UseQueryTableOptions<Row> {\n schema: FieldSchema<Row>;\n /** Data access. Omit for a purely client-side table driven by `clientRows`. */\n transport?: Transport<Row>;\n /** All rows, for client-side mode (applyQuery runs locally over these). */\n clientRows?: Row[];\n /** Saved/last-query persistence. Defaults to a non-durable in-memory adapter.\n * Pass localStorageAdapter() explicitly only when filter values are safe to\n * retain as cleartext JSON on the device. */\n storage?: StorageAdapter;\n /** Seed query, normalized and resource-bounded before use. When omitted the\n * hook resolves: opted-in URL → storage.loadLast → schema defaults. */\n initialQuery?: QueryState;\n /** Mirror QueryState to `?q=` via history.replaceState. Default false because\n * base64url is encoding, not encryption: filters will appear in browser\n * history, referrers, logs, analytics, and screenshots when enabled. */\n syncUrl?: boolean;\n /** Debounce (ms) between a query change and the fetch it triggers. Default 200. */\n debounceMs?: number;\n /** Injected clock for deterministic saved-query timestamps. Default Date.now. */\n now?: () => number;\n /** Side-effect to run on every refresh — both manual `api.refresh()` and each\n * auto-refresh tick. Fires *in addition to* the internal `setNonce` re-query,\n * so manual and auto stay identical. Use it in client mode (no transport) to\n * bridge a UI refresh to your own server fetch without monkey-patching the\n * returned `api`. Always read through a ref, so supplying it never tears down\n * and recreates the auto-refresh interval. */\n onRefresh?: () => void;\n}\n\nexport interface AutoRefreshConfig {\n frequencyMs: number;\n turnOffAfterMs: number;\n}\n\nexport interface AutoRefreshStatus extends AutoRefreshConfig {\n startedAt: number;\n stopsAt: number;\n pollCount: number;\n}\n\nexport interface AutoRefreshApi {\n status: AutoRefreshStatus | null;\n start: (config: AutoRefreshConfig) => void;\n stop: () => void;\n}\n\n/** A patch for one metric. `field`/`label` accept an explicit `undefined` to\n * CLEAR them (e.g. switching to an op whose measure no longer applies); an\n * absent key leaves the existing value untouched. */\nexport interface AggregationPatch {\n op?: AggOp;\n field?: string | undefined;\n groupBy?: string[];\n label?: string | undefined;\n}\n\nexport interface AggregationsApi {\n /** The metric specs currently in the query. */\n clauses: AggregationClause[];\n /** Server (or client-mirror) results, one entry per clause; null when none. */\n results: AggregationResult | null;\n loading: boolean;\n error: Error | null;\n /** Append a metric. Defaults to \"count all rows\"; pass a partial to override.\n * Returns the generated id. */\n add: (partial?: Partial<Omit<AggregationClause, \"id\">>) => string;\n /** Patch a metric by id. */\n update: (id: string, patch: AggregationPatch) => void;\n /** Reorder: move the metric `id` to `toIndex` (an index in the list with the\n * metric removed, so a drag preview's slot maps straight to the result). */\n move: (id: string, toIndex: number) => void;\n /** Remove a metric by id. */\n remove: (id: string) => void;\n /** Remove all metrics. */\n clear: () => void;\n}\n\nexport interface QueryTableApi<Row> {\n // state\n query: QueryState;\n /** Schema defaults used for reset controls. */\n defaults: QueryState;\n setQuery: (next: QueryState | ((prev: QueryState) => QueryState)) => void;\n /** Can move back to a previously applied local query state. */\n canUndo: boolean;\n /** Can move forward to a previously undone local query state. */\n canRedo: boolean;\n /** Move backward through local, unsaved query history. */\n undo: () => void;\n /** Move forward through local, unsaved query history. */\n redo: () => void;\n\n // data\n rows: Row[];\n total: number | null;\n loading: boolean;\n error: Error | null;\n refresh: () => void;\n autoRefresh: AutoRefreshApi;\n refreshRow: (id: RowId) => Promise<void>;\n\n // aggregation metrics (the dashboard panel above the table)\n aggregations: AggregationsApi;\n\n // filters\n addFilter: (clause: WhereClause) => void;\n updateFilter: (index: number, clause: WhereClause) => void;\n removeFilter: (index: number) => void;\n clearFilters: () => void;\n /** Reset the complete query state back to schema defaults. */\n resetAll: () => void;\n /** Keystroke-driven filter-value autocomplete (Transport.fetchDistinctValues). */\n filterValues: (field: string, search: string) => Promise<DistinctValuesResult>;\n\n // sorting (multi-sort): click header sets/cycles primary; shift-click appends.\n toggleSort: (field: string, additive?: boolean) => void;\n setSort: (orderBy: OrderByClause[]) => void;\n\n // select + pagination + selection + saved\n select: SelectApi<Row>;\n setLimit: (limit: number) => void;\n setOffset: (offset: number) => void;\n nextPage: () => void;\n prevPage: () => void;\n selection: SelectionApi;\n saved: SavedQueriesApi;\n /** Shared, transient column-reorder drag state (table headers + select chips). */\n columnDrag: ColumnDragApi;\n\n // resolved view\n visibleFields: FieldDef<Row>[];\n rowId: (row: Row) => RowId | null;\n}\n\nfunction defaultsFor<Row>(schema: FieldSchema<Row>): QueryState {\n return normalizeQueryState({\n select: schema.defaultSelect ?? [],\n where: [],\n orderBy: schema.defaultSort ?? [],\n limit: schema.defaultLimit ?? EMPTY_QUERY.limit,\n offset: 0,\n });\n}\n\nfunction cloneQueryState(q: QueryState): QueryState {\n const clone: QueryState = {\n select: q.select.map((column) => ({ ...column })),\n where: q.where.map((clause) => ({ ...clause })),\n orderBy: q.orderBy.map((term) => ({ ...term })),\n limit: q.limit,\n offset: q.offset,\n };\n if (q.aggregations) clone.aggregations = q.aggregations.map((a) => ({ ...a, groupBy: [...a.groupBy] }));\n return clone;\n}\n\n/** Apply a patch to a metric, building a fresh clause so optional `field`/`label`\n * can be dropped (passing them as `undefined` clears; omitting the key keeps the\n * current value) without ever materializing an `undefined`-valued property. */\nfunction mergeAggregation(a: AggregationClause, patch: AggregationPatch): AggregationClause {\n const next: AggregationClause = {\n id: a.id,\n op: patch.op ?? a.op,\n groupBy: patch.groupBy ?? a.groupBy,\n };\n const field = \"field\" in patch ? patch.field : a.field;\n if (field) next.field = field;\n const label = \"label\" in patch ? patch.label : a.label;\n if (label) next.label = label;\n return next;\n}\n\nfunction isNullLike(value: unknown): boolean {\n return value == null || (Array.isArray(value) && value.length === 0);\n}\n\nfunction asDistinctValue(value: unknown): string | null {\n if (isNullLike(value)) return null;\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n return null;\n}\n\nfunction fieldHasNullInRows<Row>(field: FieldDef<Row>, rows: Row[]): boolean {\n for (const row of rows) {\n if (isNullLike(readFieldValue(field, row))) return true;\n }\n return false;\n}\n\nfunction distinctValuesFromRows<Row>(field: FieldDef<Row>, rows: Row[], search: string): { values: string[]; hasMore: boolean } {\n const target = search.trim().toLowerCase();\n const values: string[] = [];\n const seen = new Set<string>();\n let hasMore = false;\n\n for (const row of rows) {\n const raw = asDistinctValue(readFieldValue(field, row));\n if (raw == null || seen.has(raw)) continue;\n if (target && !raw.toLowerCase().includes(target)) continue;\n\n if (values.length < AUTOCOMPLETE_LIMIT) {\n seen.add(raw);\n values.push(raw);\n continue;\n }\n\n hasMore = true;\n break;\n }\n\n return { values: values.sort((a, b) => a.localeCompare(b)), hasMore };\n}\n\nfunction resolveInitial<Row>(opts: UseQueryTableOptions<Row>): { q: QueryState; fromUrl: boolean } {\n const defaults = defaultsFor(opts.schema);\n if (opts.initialQuery) return { q: normalizeQueryState(opts.initialQuery, defaults), fromUrl: false };\n if (opts.syncUrl === true && typeof window !== \"undefined\") {\n const token = new URLSearchParams(window.location.search).get(\"q\");\n if (token) return { q: normalizeQueryState(decodeQuery(token), defaults), fromUrl: true };\n }\n return { q: defaults, fromUrl: false };\n}\n\nexport function useQueryTable<Row>(opts: UseQueryTableOptions<Row>): QueryTableApi<Row> {\n const { schema, transport, clientRows, initialQuery, syncUrl = false, debounceMs = 200 } = opts;\n const storage = useMemo(() => opts.storage ?? memoryStorageAdapter(), [opts.storage]);\n const now = opts.now ?? Date.now;\n const nowRef = useRef(now);\n const onRefreshRef = useRef(opts.onRefresh);\n const defaults = useMemo(() => defaultsFor(schema), [schema]);\n const byName = useMemo(() => new Map(schema.fields.map((f) => [f.name, f])), [schema]);\n\n const initRef = useRef(resolveInitial(opts));\n const aggIdRef = useRef(0);\n const [query, setQueryState] = useState<QueryState>(initRef.current.q);\n const undoStack = useRef<QueryState[]>([cloneQueryState(initRef.current.q)]);\n const redoStack = useRef<QueryState[]>([]);\n const [rows, setRows] = useState<Row[]>([]);\n const [total, setTotal] = useState<number | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [nonce, setNonce] = useState(0);\n const [autoRefreshStatus, setAutoRefreshStatus] = useState<AutoRefreshStatus | null>(null);\n\n useEffect(() => {\n nowRef.current = now;\n }, [now]);\n\n useEffect(() => {\n onRefreshRef.current = opts.onRefresh;\n }, [opts.onRefresh]);\n\n const setQuery = useCallback<QueryTableApi<Row>[\"setQuery\"]>((next) => {\n setQueryState((prev) => {\n const candidate = typeof next === \"function\" ? (next as (p: QueryState) => QueryState)(prev) : next;\n const nextQuery = normalizeQueryState(candidate, defaults);\n if (queriesEqual(prev, nextQuery)) return prev;\n undoStack.current.push(cloneQueryState(prev));\n redoStack.current = [];\n return cloneQueryState(nextQuery);\n });\n }, [defaults]);\n\n // Restore the default saved query (preferred) or last query on mount when\n // nothing explicit seeded the view.\n useEffect(() => {\n if (initRef.current.fromUrl || initialQuery) return;\n let cancelled = false;\n void (async () => {\n const defaultSaved = await storage.loadDefaultSaved?.(schema.name);\n const restored = defaultSaved?.query ?? (await storage.loadLast(schema.name));\n if (!cancelled && restored) {\n const normalized = normalizeQueryState(restored, defaults);\n undoStack.current = [cloneQueryState(normalized)];\n redoStack.current = [];\n setQueryState(normalized);\n }\n })();\n return () => {\n cancelled = true;\n };\n // mount-only\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // Fetch (debounced + abortable). Transport mode, or client-side applyQuery.\n const queryKey = useMemo(() => encodeQuery(query), [query]);\n const serverRowQuery = useMemo(() => toServerQuery(query, schema), [queryKey, schema]);\n // Keep presentation-only query changes out of the expensive row pipeline.\n // Widths do not leave the client at all, and SELECT does not affect client-side\n // filtering/sorting/paging. The full queryKey still drives URL + persistence.\n const rowQueryKey = useMemo(\n () => transport\n ? `server:${JSON.stringify(serverRowQuery)}`\n : `client:${JSON.stringify([query.where, query.orderBy, query.limit, query.offset])}`,\n [transport, serverRowQuery, query.where, query.orderBy, query.limit, query.offset],\n );\n useEffect(() => {\n const ac = new AbortController();\n let cancelled = false;\n const run = async () => {\n setLoading(true);\n setError(null);\n try {\n if (transport) {\n const res = await transport.fetchRows(serverRowQuery, ac.signal);\n if (!cancelled) {\n setRows(res.rows);\n setTotal(res.total);\n }\n } else {\n const res = applyQuery(clientRows ?? [], query, schema);\n if (!cancelled) {\n setRows(res.rows);\n setTotal(res.total);\n }\n }\n } catch (e) {\n if (!cancelled && !ac.signal.aborted) setError(e as Error);\n } finally {\n if (!cancelled) setLoading(false);\n }\n };\n const t = setTimeout(run, debounceMs);\n return () => {\n cancelled = true;\n clearTimeout(t);\n ac.abort();\n };\n // rowQueryKey captures only row-affecting query state; clientRows/nonce\n // force refetch. Presentation changes still sync/persist via queryKey below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [rowQueryKey, transport, clientRows, schema, debounceMs, nonce]);\n\n // URL sync.\n useEffect(() => {\n if (!syncUrl || typeof window === \"undefined\") return;\n const url = new URL(window.location.href);\n const token = encodeQuery(query);\n if (token) url.searchParams.set(\"q\", token);\n else url.searchParams.delete(\"q\");\n window.history.replaceState(null, \"\", url.toString());\n }, [queryKey, syncUrl, query]);\n\n // Persist last query (debounced).\n useEffect(() => {\n const t = setTimeout(() => void storage.saveLast(schema.name, query), 400);\n return () => clearTimeout(t);\n }, [queryKey, storage, schema.name, query]);\n\n // Resolved id accessor.\n const idField = useMemo(() => schema.fields.find((f) => f.name === schema.idField), [schema]);\n const rowId = useCallback(\n (row: Row): RowId | null => (idField ? (readFieldValue(idField, row) as RowId | null) : null),\n [idField],\n );\n\n // Sub-APIs.\n const displayedIds = useMemo(() => rows.map(rowId).filter((id): id is RowId => id != null), [rows, rowId]);\n const selection = useSelection(displayedIds);\n const select = useSelect(query, setQuery, schema);\n const columnDrag = useColumnDrag();\n const saved = useSavedQueries(\n schema.name,\n query,\n (q) => setQuery(q),\n storage,\n now,\n );\n const aggState = useAggregations(query, schema, transport, clientRows, debounceMs, nonce);\n\n const canUndo = undoStack.current.length > 0;\n const canRedo = redoStack.current.length > 0;\n\n const undo = useCallback(() => {\n setQueryState((prev) => {\n const previous = undoStack.current.pop();\n if (!previous) return prev;\n redoStack.current.push(cloneQueryState(prev));\n return cloneQueryState(previous);\n });\n }, []);\n\n const redo = useCallback(() => {\n setQueryState((prev) => {\n const next = redoStack.current.pop();\n if (!next) return prev;\n undoStack.current.push(cloneQueryState(prev));\n return cloneQueryState(next);\n });\n }, []);\n\n // ---- intent helpers (keep offset/url/storage coherent) ----\n const patch = useCallback((p: Partial<QueryState>) => setQuery((prev) => ({ ...prev, ...p })), [setQuery]);\n\n const addFilter = useCallback((clause: WhereClause) => setQuery((q) => ({ ...q, offset: 0, where: [...q.where, clause] })), [setQuery]);\n const updateFilter = useCallback(\n (index: number, clause: WhereClause) =>\n setQuery((q) => ({ ...q, offset: 0, where: q.where.map((c, i) => (i === index ? clause : c)) })),\n [setQuery],\n );\n const removeFilter = useCallback(\n (index: number) => setQuery((q) => ({ ...q, offset: 0, where: q.where.filter((_, i) => i !== index) })),\n [setQuery],\n );\n const clearFilters = useCallback(() => setQuery((q) => ({ ...q, offset: 0, where: [] })), [setQuery]);\n const resetAll = useCallback(() => setQuery(() => cloneQueryState(defaults)), [setQuery, defaults]);\n\n // ---- aggregation metric mutators (don't touch paging — scope is the whole set) ----\n const addAggregation = useCallback<AggregationsApi[\"add\"]>(\n (partial) => {\n const id = `a${nowRef.current()}-${aggIdRef.current++}`;\n const clause: AggregationClause = { id, op: \"count\", groupBy: [], ...partial };\n setQuery((q) => ({ ...q, aggregations: [...(q.aggregations ?? []), clause] }));\n return id;\n },\n [setQuery],\n );\n const updateAggregation = useCallback<AggregationsApi[\"update\"]>(\n (id, patch) =>\n setQuery((q) => ({\n ...q,\n aggregations: (q.aggregations ?? []).map((a) => (a.id === id ? mergeAggregation(a, patch) : a)),\n })),\n [setQuery],\n );\n const moveAggregation = useCallback<AggregationsApi[\"move\"]>(\n (id, toIndex) =>\n setQuery((q) => {\n const current = q.aggregations ?? [];\n const from = current.findIndex((a) => a.id === id);\n if (from === -1) return q;\n const next = [...current];\n const [item] = next.splice(from, 1);\n next.splice(Math.max(0, Math.min(toIndex, next.length)), 0, item!);\n return { ...q, aggregations: next };\n }),\n [setQuery],\n );\n const removeAggregation = useCallback<AggregationsApi[\"remove\"]>(\n (id) => setQuery((q) => ({ ...q, aggregations: (q.aggregations ?? []).filter((a) => a.id !== id) })),\n [setQuery],\n );\n const clearAggregations = useCallback<AggregationsApi[\"clear\"]>(\n () => setQuery((q) => ({ ...q, aggregations: [] })),\n [setQuery],\n );\n\n const setSort = useCallback((orderBy: OrderByClause[]) => setQuery((q) => ({ ...q, offset: 0, orderBy })), [setQuery]);\n const toggleSort = useCallback(\n (field: string, additive = false) =>\n setQuery((q) => ({ ...q, offset: 0, orderBy: nextOrderBy(q.orderBy, field, additive) })),\n [setQuery],\n );\n\n const setLimit = useCallback((limit: number) => patch({ limit, offset: 0 }), [patch]);\n const setOffset = useCallback((offset: number) => patch({ offset }), [patch]);\n const nextPage = useCallback(() => setQuery((q) => ({ ...q, offset: q.offset + q.limit })), [setQuery]);\n const prevPage = useCallback(() => setQuery((q) => ({ ...q, offset: Math.max(0, q.offset - q.limit) })), [setQuery]);\n\n const filterValues = useCallback(\n async (field: string, search: string): Promise<DistinctValuesResult> => {\n if (!transport?.fetchDistinctValues) {\n const f = byName.get(field);\n if (!f || !clientRows) return { values: [], hasMore: false };\n\n const fieldHasNull = fieldHasNullInRows(f, clientRows);\n const matches = distinctValuesFromRows(f, clientRows, search);\n\n return {\n values: matches.values,\n hasMore: matches.hasMore,\n hasNull: fieldHasNull,\n };\n }\n return transport.fetchDistinctValues({ field, search });\n },\n [transport, byName, clientRows],\n );\n\n // Single refresh seam: re-runs the internal query (setNonce) and fires the\n // consumer's onRefresh, if any. Both the manual `api.refresh()` and every\n // auto-refresh tick go through here, so they stay observably identical. Read\n // onRefresh through a ref to keep this callback (and the interval that depends\n // on it) stable across renders.\n const refresh = useCallback(() => {\n setNonce((n) => n + 1);\n onRefreshRef.current?.();\n }, []);\n const stopAutoRefresh = useCallback(() => setAutoRefreshStatus(null), []);\n const startAutoRefresh = useCallback(\n ({ frequencyMs, turnOffAfterMs }: AutoRefreshConfig) => {\n const pollCount = frequencyMs > 0 && turnOffAfterMs > 0 ? Math.floor(turnOffAfterMs / frequencyMs) : 0;\n if (pollCount < 1 || pollCount > MAX_AUTO_REFRESH_POLLS) {\n throw new Error(\"Auto-refresh must schedule between 1 and 1000 polls.\");\n }\n\n const startedAt = nowRef.current();\n refresh();\n setAutoRefreshStatus({\n frequencyMs,\n turnOffAfterMs,\n startedAt,\n stopsAt: startedAt + turnOffAfterMs,\n pollCount: 1,\n });\n },\n [refresh],\n );\n\n const autoRefreshFrequencyMs = autoRefreshStatus?.frequencyMs ?? null;\n const autoRefreshStopsAt = autoRefreshStatus?.stopsAt ?? null;\n\n useEffect(() => {\n if (autoRefreshFrequencyMs == null || autoRefreshStopsAt == null) return;\n\n const tick = () => {\n if (nowRef.current() >= autoRefreshStopsAt) {\n setAutoRefreshStatus((current) => (current?.stopsAt === autoRefreshStopsAt ? null : current));\n return;\n }\n\n refresh();\n setAutoRefreshStatus((current) => {\n if (!current) return current;\n if (current.stopsAt !== autoRefreshStopsAt) return current;\n return { ...current, pollCount: current.pollCount + 1 };\n });\n };\n\n const interval = setInterval(tick, autoRefreshFrequencyMs);\n const timeout = setTimeout(\n () => setAutoRefreshStatus((current) => (current?.stopsAt === autoRefreshStopsAt ? null : current)),\n Math.max(0, autoRefreshStopsAt - nowRef.current()),\n );\n\n return () => {\n clearInterval(interval);\n clearTimeout(timeout);\n };\n }, [autoRefreshFrequencyMs, autoRefreshStopsAt, refresh]);\n\n const autoRefresh = useMemo<AutoRefreshApi>(\n () => ({\n status: autoRefreshStatus,\n start: startAutoRefresh,\n stop: stopAutoRefresh,\n }),\n [autoRefreshStatus, startAutoRefresh, stopAutoRefresh],\n );\n\n const refreshRow = useCallback(\n async (id: RowId) => {\n if (!transport?.fetchRow) return;\n const updated = await transport.fetchRow(id);\n setRows((prev) => prev.map((r) => (rowId(r) === id ? updated ?? r : r)));\n },\n [transport, rowId],\n );\n\n const visibleFields = useMemo(() => selectedFields(schema, query), [schema, query]);\n\n const aggregations = useMemo<AggregationsApi>(\n () => ({\n clauses: query.aggregations ?? [],\n results: aggState.results,\n loading: aggState.loading,\n error: aggState.error,\n add: addAggregation,\n update: updateAggregation,\n move: moveAggregation,\n remove: removeAggregation,\n clear: clearAggregations,\n }),\n [\n query.aggregations,\n aggState.results,\n aggState.loading,\n aggState.error,\n addAggregation,\n updateAggregation,\n moveAggregation,\n removeAggregation,\n clearAggregations,\n ],\n );\n\n return {\n query,\n defaults,\n setQuery,\n rows,\n total,\n loading,\n error,\n canUndo,\n canRedo,\n undo,\n redo,\n refresh,\n autoRefresh,\n refreshRow,\n aggregations,\n addFilter,\n updateFilter,\n removeFilter,\n clearFilters,\n resetAll,\n filterValues,\n toggleSort,\n setSort,\n select,\n setLimit,\n setOffset,\n nextPage,\n prevPage,\n selection,\n saved,\n columnDrag,\n visibleFields,\n rowId,\n };\n}\n\n/** Multi-sort header click logic.\n * - plain click on the sole sorted column → flip its direction\n * - plain click on another column → make it the only sort (desc)\n * - shift-click a new column → append it (desc) as a secondary term\n * - shift-click an existing term → cycle desc → asc → remove */\nfunction nextOrderBy(existing: OrderByClause[], field: string, additive: boolean): OrderByClause[] {\n const i = existing.findIndex((s) => s.field === field);\n if (!additive) {\n if (i === 0 && existing.length === 1) {\n const flipped: \"asc\" | \"desc\" = existing[0]!.dir === \"desc\" ? \"asc\" : \"desc\";\n return [{ field, dir: flipped }];\n }\n return [{ field, dir: \"desc\" }];\n }\n if (i === -1) return [...existing, { field, dir: \"desc\" }];\n const cur = existing[i]!;\n if (cur.dir === \"desc\") {\n const next = [...existing];\n next[i] = { field, dir: \"asc\" };\n return next;\n }\n return existing.filter((_, k) => k !== i); // asc → remove\n}\n","// useAggregations — the metric panel's data side.\n//\n// Runs the optional GROUP BY queries that back the metrics shown above the table.\n// Kept separate from the rows fetch so the panel loads/refreshes independently:\n// metrics depend ONLY on the WHERE filter + the aggregation specs (scope is the\n// whole filtered set — never the page window), so paging or re-sorting the table\n// does not re-issue them. Debounced + abortable, mirroring the rows fetch.\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport { applyAggregations, toAggregationQuery } from \"@pythia-software/query-table-core\";\nimport type { AggregationResult, FieldSchema, QueryState, Transport } from \"@pythia-software/query-table-core\";\n\nexport interface AggregationsApiState {\n results: AggregationResult | null;\n loading: boolean;\n error: Error | null;\n}\n\nconst EMPTY_RESULT: AggregationResult = { metrics: [] };\n\nexport function useAggregations<Row>(\n query: QueryState,\n schema: FieldSchema<Row>,\n transport: Transport<Row> | undefined,\n clientRows: Row[] | undefined,\n debounceMs: number,\n nonce: number,\n): AggregationsApiState {\n const [results, setResults] = useState<AggregationResult | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Metrics depend only on WHERE + the agg specs. Keying on just those avoids\n // refetching when the user pages or re-sorts the table.\n const key = useMemo(\n () => JSON.stringify({ where: query.where, aggregations: query.aggregations ?? [] }),\n [query.where, query.aggregations],\n );\n const hasAggregations = (query.aggregations?.length ?? 0) > 0;\n\n useEffect(() => {\n if (!hasAggregations) {\n setResults(null);\n setError(null);\n setLoading(false);\n return;\n }\n\n const ac = new AbortController();\n let cancelled = false;\n const run = async () => {\n setLoading(true);\n setError(null);\n try {\n let res: AggregationResult;\n if (transport?.fetchAggregations) {\n res = await transport.fetchAggregations(toAggregationQuery(query, schema), ac.signal);\n } else if (clientRows) {\n res = applyAggregations(clientRows, query, schema);\n } else {\n res = EMPTY_RESULT;\n }\n if (!cancelled) setResults(res);\n } catch (e) {\n if (!cancelled && !ac.signal.aborted) setError(e as Error);\n } finally {\n if (!cancelled) setLoading(false);\n }\n };\n const t = setTimeout(run, debounceMs);\n return () => {\n cancelled = true;\n clearTimeout(t);\n ac.abort();\n };\n // `key` captures the relevant query subset; clientRows/nonce force a refetch.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [key, hasAggregations, transport, clientRows, schema, debounceMs, nonce]);\n\n return { results, loading, error };\n}\n","// useSelection — row selection for paged and re-sortable datasets.\n//\n// - Shift-click range select, anchored by ROW ID (not index) so a\n// range survives re-sort / re-filter / paging. Index anchors break the moment\n// the data reorders; id anchors don't.\n// - Indeterminate header checkbox + select-all-on-page.\n\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport type { RowId } from \"@pythia-software/query-table-core\";\n\nexport interface SelectionApi {\n selected: Set<RowId>;\n isSelected: (id: RowId) => boolean;\n /** Toggle one row. With `shiftKey`, extend from the last-toggled anchor to `id`\n * across the *currently displayed* order (falls back to a plain toggle if the\n * anchor row is no longer present). */\n toggle: (id: RowId, shiftKey?: boolean) => void;\n /** Select / clear every row currently on the page. */\n setPage: (ids: RowId[], selected: boolean) => void;\n /** Header checkbox tri-state for the current page. */\n pageState: (pageIds: RowId[]) => \"none\" | \"some\" | \"all\";\n clear: () => void;\n count: number;\n}\n\n/** `displayedIds` is the page's id list in display order; the hook uses it to\n * resolve shift-ranges and header tri-state against what the user sees. */\nexport function useSelection(displayedIds: RowId[]): SelectionApi {\n const [selected, setSelected] = useState<Set<RowId>>(() => new Set());\n const anchor = useRef<RowId | null>(null);\n\n const toggle = useCallback(\n (id: RowId, shiftKey = false) => {\n setSelected((prev) => {\n const next = new Set(prev);\n const a = anchor.current;\n if (shiftKey && a != null) {\n const i = displayedIds.indexOf(a);\n const j = displayedIds.indexOf(id);\n if (i !== -1 && j !== -1) {\n const [lo, hi] = i <= j ? [i, j] : [j, i];\n const span = displayedIds.slice(lo, hi + 1);\n const allChecked = span.every((rowId) => prev.has(rowId));\n for (const rowId of span) {\n if (allChecked) next.delete(rowId);\n else next.add(rowId);\n }\n anchor.current = id;\n return next;\n }\n }\n if (next.has(id)) next.delete(id);\n else next.add(id);\n anchor.current = id;\n return next;\n });\n },\n [displayedIds],\n );\n\n const setPage = useCallback((ids: RowId[], select: boolean) => {\n setSelected((prev) => {\n const next = new Set(prev);\n for (const id of ids) {\n if (select) next.add(id);\n else next.delete(id);\n }\n return next;\n });\n }, []);\n\n const pageState = useCallback(\n (pageIds: RowId[]): \"none\" | \"some\" | \"all\" => {\n if (pageIds.length === 0) return \"none\";\n let n = 0;\n for (const id of pageIds) if (selected.has(id)) n++;\n return n === 0 ? \"none\" : n === pageIds.length ? \"all\" : \"some\";\n },\n [selected],\n );\n\n const clear = useCallback(() => {\n anchor.current = null;\n setSelected(new Set());\n }, []);\n\n return useMemo<SelectionApi>(\n () => ({\n selected,\n isSelected: (id) => selected.has(id),\n toggle,\n setPage,\n pageState,\n clear,\n count: selected.size,\n }),\n [selected, toggle, setPage, pageState, clear],\n );\n}\n","// useSelect — the SELECT list: visible columns, their order, and their widths,\n// all persisted INTO the query (decision #5, so one URL renders identically\n// anywhere). This API mutates QueryState.select; it holds no state of its own.\n// Width changes should be debounced by the caller before they hit the query to\n// avoid flooding history during a drag (useQueryTable does this).\n\nimport { useCallback, useMemo } from \"react\";\nimport type { QueryState, SelectColumn, FieldDef, FieldSchema } from \"@pythia-software/query-table-core\";\nimport { selectedFields } from \"@pythia-software/query-table-core\";\n\nexport interface SelectApi<Row> {\n /** Ordered visible columns (resolved: schema defaults when query.select is empty). */\n visible: SelectColumn[];\n /** The corresponding FieldDefs, same order. */\n fields: FieldDef<Row>[];\n /** Selectable fields not currently shown (for the \"add column\" picker). */\n hidden: FieldDef<Row>[];\n\n show: (field: string) => void;\n hide: (field: string) => void;\n /** Reorder via drag-drop: move `field` to `toIndex` in the visible order. */\n move: (field: string, toIndex: number) => void;\n /** Set a column's pixel width. */\n setWidth: (field: string, width: number) => void;\n /** Reset to the schema's default columns (clears query.select). */\n reset: () => void;\n}\n\ntype SetQuery = (next: QueryState | ((prev: QueryState) => QueryState)) => void;\n\nexport function useSelect<Row>(query: QueryState, setQuery: SetQuery, schema: FieldSchema<Row>): SelectApi<Row> {\n const fields = useMemo(() => selectedFields(schema, query), [schema, query]);\n\n // The materialized SelectColumn[] (resolve defaults so the UI always has a\n // concrete, reorderable list even before the user customizes it).\n const visible = useMemo<SelectColumn[]>(() => fields.map((f) => columnFor(query.select, f.name)), [fields, query.select]);\n\n const hidden = useMemo<FieldDef<Row>[]>(() => {\n const shown = new Set(fields.map((f) => f.name));\n return schema.fields.filter((f) => !shown.has(f.name) && (f.select?.enabled ?? true));\n }, [schema, fields]);\n\n const writeSelect = useCallback(\n (mutate: (cols: SelectColumn[]) => SelectColumn[]) => {\n setQuery((prev) => {\n // Materialize current (resolved) columns the first time we diverge from defaults.\n const current = prev.select.length ? prev.select : visible;\n return { ...prev, select: mutate([...current]) };\n });\n },\n [setQuery, visible],\n );\n\n const show = useCallback((field: string) => writeSelect((c) => (c.some((x) => x.field === field) ? c : [...c, { field }])), [writeSelect]);\n const hide = useCallback((field: string) => writeSelect((c) => c.filter((x) => x.field !== field)), [writeSelect]);\n const move = useCallback(\n (field: string, toIndex: number) =>\n writeSelect((c) => {\n const from = c.findIndex((x) => x.field === field);\n if (from === -1) return c;\n const [item] = c.splice(from, 1);\n c.splice(Math.max(0, Math.min(toIndex, c.length)), 0, item!);\n return c;\n }),\n [writeSelect],\n );\n const setWidth = useCallback(\n (field: string, width: number) =>\n writeSelect((c) => c.map((x) => (x.field === field ? { ...x, width: Math.round(width) } : x))),\n [writeSelect],\n );\n const reset = useCallback(() => setQuery((prev) => ({ ...prev, select: [] })), [setQuery]);\n\n return { visible, fields, hidden, show, hide, move, setWidth, reset };\n}\n\nfunction columnFor(select: SelectColumn[], name: string): SelectColumn {\n const found = select.find((c) => c.field === name);\n return found ?? { field: name };\n}\n","// useColumnDrag — transient, SHARED state for a column-reorder drag. One instance\n// is owned by useQueryTable and read by BOTH the table headers and the\n// QueryBuilder select chips, so a drag started in either surface live-previews\n// (and dims) the same column in the other. It holds no query state; the reorder\n// is committed to QueryState.select by whichever surface handles the drop.\n\nimport { useCallback, useMemo, useState } from \"react\";\n\nexport interface ColumnDragApi {\n /** Field name currently being dragged, or null when idle. */\n source: string | null;\n /** Insertion index within the order with `source` removed (0..n; n = append). */\n overIndex: number | null;\n /** True while a column drag is in progress. */\n active: boolean;\n /** Begin dragging `field`, initially previewed at `index` (its own slot). */\n start: (field: string, index: number) => void;\n /** Update the previewed insertion index (no-op if unchanged). */\n over: (index: number) => void;\n /** End the drag (on drop or cancel). */\n end: () => void;\n /** The live order to render while dragging: `source` moved to `overIndex`.\n * Returns `order` unchanged when idle, or when `source` isn't in `order`. */\n preview: (order: string[]) => string[];\n}\n\ninterface DragState {\n source: string;\n overIndex: number;\n}\n\nexport function useColumnDrag(): ColumnDragApi {\n const [state, setState] = useState<DragState | null>(null);\n\n const start = useCallback((field: string, index: number) => setState({ source: field, overIndex: index }), []);\n const over = useCallback(\n (index: number) =>\n // Keep the SAME object reference when unchanged so React can bail out of the\n // re-render — onDragOver fires continuously while the cursor moves.\n setState((s) => (s && s.overIndex !== index ? { source: s.source, overIndex: index } : s)),\n [],\n );\n const end = useCallback(() => setState(null), []);\n\n const preview = useCallback(\n (order: string[]): string[] => {\n if (!state) return order;\n const without = order.filter((n) => n !== state.source);\n if (without.length === order.length) return order; // source not part of this list\n const at = Math.max(0, Math.min(state.overIndex, without.length));\n return [...without.slice(0, at), state.source, ...without.slice(at)];\n },\n [state],\n );\n\n return useMemo(\n () => ({\n source: state?.source ?? null,\n overIndex: state?.overIndex ?? null,\n active: state != null,\n start,\n over,\n end,\n preview,\n }),\n [state, start, over, end, preview],\n );\n}\n","// useSavedQueries — named query snapshots over a StorageAdapter.\n//\n// \"Last query\" auto-restore and named saves both flow through the injected\n// StorageAdapter (in-memory by default, explicitly durable when the caller\n// provides one). Loading a saved query pushes its QueryState into the controller.\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport type { QueryState, SavedQuery, StorageAdapter } from \"@pythia-software/query-table-core\";\n\nexport interface SavedQueriesApi {\n items: SavedQuery[];\n loading: boolean;\n /** Saved query id used as the default view when no query is specified. */\n defaultId: string | null;\n /** Persist the current query under a name. Rejects on duplicate names. */\n save: (name: string) => Promise<SavedQuery>;\n /** Load a saved query into the live controller. */\n load: (id: string) => void;\n /** Mark a saved query as the default view. No-op when storage lacks support. */\n setDefault: (id: string) => Promise<void>;\n /** Clear the saved-query default view. */\n clearDefault: () => Promise<void>;\n remove: (id: string) => Promise<void>;\n}\n\nexport function useSavedQueries(\n key: string,\n currentQuery: QueryState,\n applyQueryState: (q: QueryState) => void,\n storage: StorageAdapter,\n /** Injected clock so saves are deterministic/testable. */\n now: () => number,\n): SavedQueriesApi {\n const [items, setItems] = useState<SavedQuery[]>([]);\n const [defaultId, setDefaultId] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n\n const refresh = useCallback(async () => {\n setLoading(true);\n try {\n const [savedItems, defaultSaved] = await Promise.all([\n storage.listSaved(key),\n storage.loadDefaultSaved?.(key) ?? Promise.resolve(null),\n ]);\n setItems(savedItems);\n setDefaultId(defaultSaved?.id ?? null);\n } finally {\n setLoading(false);\n }\n }, [storage, key]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const save = useCallback(\n async (name: string) => {\n const saved = await storage.saveNamed(key, name, currentQuery, now());\n await refresh();\n return saved;\n },\n [storage, key, currentQuery, now, refresh],\n );\n\n const load = useCallback(\n (id: string) => {\n const found = items.find((q) => q.id === id);\n if (found) applyQueryState(found.query);\n },\n [items, applyQueryState],\n );\n\n const setDefault = useCallback(\n async (id: string) => {\n await storage.setDefaultSaved?.(key, id);\n await refresh();\n },\n [storage, key, refresh],\n );\n\n const clearDefault = useCallback(async () => {\n await storage.setDefaultSaved?.(key, null);\n await refresh();\n }, [storage, key, refresh]);\n\n const remove = useCallback(\n async (id: string) => {\n if (id === defaultId) await storage.setDefaultSaved?.(key, null);\n await storage.deleteSaved(key, id);\n await refresh();\n },\n [storage, key, defaultId, refresh],\n );\n\n return { items, loading, defaultId, save, load, setDefault, clearDefault, remove };\n}\n"],"mappings":"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","names":["useCallback","useEffect","useMemo","useRef","useState","selectedFields","useMemo","useState","useCallback","useMemo","useCallback","useMemo","useState","useCallback","useEffect","useState","useMemo","useRef","useState","useEffect","useCallback","patch","selectedFields"]}
|
|
1
|
+
{"version":3,"sources":["../src/useComputedColumns.ts","../src/formulaWorker.ts","../src/useQueryTable.ts","../src/useAggregations.ts","../src/useSelection.ts","../src/useSelect.ts","../src/useColumnDrag.ts","../src/useSavedQueries.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n applyQuery,\n compileFormula,\n computedFieldName,\n groupPreview,\n isComputedField,\n memoryComputedColumnStore,\n readFieldValue,\n toServerQuery,\n validateComputedColumn,\n isSelectable,\n type ColumnPreview,\n type ComputedColumn,\n type ComputedColumnDraft,\n type ComputedColumnStore,\n type FieldDef,\n type FieldSchema,\n type FormulaPlan,\n type FormulaResult,\n type FormulaValue,\n type QueryState,\n type Transport,\n} from \"@pythia-software/query-table-core\";\nimport {\n evaluateFormulaRows,\n type FormulaWorkerFactory,\n} from \"./formulaWorker\";\n\nexport interface ComputedColumnsApi<Row> {\n definitions: ComputedColumn[];\n catalogue: FieldDef<Row>[];\n loading: boolean;\n error: string | null;\n reload: () => Promise<void>;\n save: (\n column: ComputedColumnDraft,\n expectedRevision: string | null,\n ) => Promise<ComputedColumn>;\n compile: (source: string, editingId?: string) => FormulaPlan;\n /** Sample the first N matching rows in current sort order, independent of table paging. */\n preview: (\n source: string,\n count: number,\n signal?: AbortSignal,\n editingId?: string,\n includeInputs?: boolean,\n ) => Promise<ColumnPreview>;\n}\ninterface Options<Row> {\n schema: FieldSchema<Row>;\n query: QueryState;\n rows: Row[];\n store?: ComputedColumnStore;\n transport?: Transport<Row>;\n clientRows?: Row[];\n workerFactory?: FormulaWorkerFactory;\n}\nexport function useComputedColumns<Row>(options: Options<Row>): {\n api: ComputedColumnsApi<Row>;\n displaySchema: FieldSchema<Row>;\n} {\n const { schema, query, rows, transport, clientRows, workerFactory } = options;\n const store = useMemo(\n () => options.store ?? memoryComputedColumnStore(),\n [options.store],\n );\n const [catalogue, setCatalogue] = useState<{\n dataset: string;\n store: ComputedColumnStore;\n items: ComputedColumn[];\n } | null>(null);\n const definitions = useMemo(\n () =>\n catalogue?.dataset === schema.name && catalogue.store === store\n ? catalogue.items\n : [],\n [catalogue, schema.name, store],\n );\n const [loading, setLoading] = useState(false),\n [error, setError] = useState<string | null>(null);\n const catalogueRequest = useRef<AbortController | null>(null);\n const reload = useCallback(async () => {\n catalogueRequest.current?.abort();\n const ac = new AbortController();\n catalogueRequest.current = ac;\n setLoading(true);\n setError(null);\n try {\n const items = await store.list(schema.name, ac.signal);\n if (ac.signal.aborted) return;\n const valid = items\n .map(validateComputedColumn)\n .sort((a, b) => a.id.localeCompare(b.id));\n if (new Set(valid.map((c) => c.id)).size !== valid.length)\n throw new Error(\"Duplicate computed column IDs.\");\n setCatalogue((previous) =>\n previous?.dataset === schema.name &&\n previous.store === store &&\n JSON.stringify(previous.items) === JSON.stringify(valid)\n ? previous\n : { dataset: schema.name, store, items: valid },\n );\n } catch (e) {\n if (!ac.signal.aborted)\n setError(e instanceof Error ? e.message : String(e));\n } finally {\n if (!ac.signal.aborted) setLoading(false);\n }\n }, [store, schema.name]);\n useEffect(() => {\n void reload();\n return () => catalogueRequest.current?.abort();\n }, [reload]);\n useEffect(\n () =>\n store.subscribe?.(schema.name, () => {\n void reload();\n }),\n [store, schema.name, reload],\n );\n useEffect(() => {\n const focus = () => {\n void reload();\n };\n window.addEventListener(\"focus\", focus);\n return () => window.removeEventListener(\"focus\", focus);\n }, [reload]);\n const inputFields = useMemo(\n () =>\n schema.fields\n .filter(isSelectable)\n .filter(\n (f) =>\n f.source.kind === \"backend\" ||\n (f.source.accessor && f.source.dependencies),\n ),\n [schema],\n );\n const compile = useCallback(\n (source: string, editingId?: string): FormulaPlan => {\n const stack = new Set<string>(editingId ? [editingId] : []);\n let expanded = 0;\n const resolve = (name: string): FormulaPlan | undefined => {\n if (!isComputedField(name)) return undefined;\n const id = name.slice(\"@computed/\".length),\n def = definitions.find((d) => d.id === id);\n if (!def) throw new Error(`Computed column unavailable: ${id}`);\n if (stack.has(id))\n throw new Error(`Circular computed-column reference: ${def.label}`);\n if (stack.size >= 20 || ++expanded > 100)\n throw new Error(\"Computed dependency graph is too large.\");\n stack.add(id);\n try {\n return compileFormula(def.expression.source, inputFields, resolve);\n } finally {\n stack.delete(id);\n }\n };\n return compileFormula(source, inputFields, resolve);\n },\n [inputFields, definitions],\n );\n const plans = useMemo(\n () =>\n new Map<string, { plan?: FormulaPlan; error?: string }>(\n definitions.map((def) => {\n try {\n return [\n def.id,\n { plan: compile(def.expression.source, def.id) },\n ] as const;\n } catch (e) {\n return [\n def.id,\n { error: e instanceof Error ? e.message : String(e) },\n ] as const;\n }\n }),\n ),\n [definitions, compile],\n );\n const backendDependencies = useCallback(\n (plan: FormulaPlan) =>\n [\n ...new Set(\n plan.dependencies.flatMap((name) => {\n const f = inputFields.find((f) => f.name === name);\n return f?.source.kind === \"backend\"\n ? [name]\n : (f?.source.dependencies ?? []);\n }),\n ),\n ]\n .filter((name) =>\n schema.fields.some(\n (f) => f.name === name && f.source.kind === \"backend\",\n ),\n )\n .sort(),\n [schema, inputFields],\n );\n const inputsFor = useCallback(\n (plan: FormulaPlan, batch: Row[]) => {\n let size = 0;\n return batch.map((row) => {\n const values: Record<string, FormulaValue> = Object.create(null);\n for (const name of plan.dependencies) {\n const field = inputFields.find((f) => f.name === name)!;\n const raw = readFieldValue(field, row);\n values[name] =\n raw instanceof Date ? raw.toISOString() : (raw as FormulaValue);\n }\n size += JSON.stringify(values).length;\n if (size > 16000000)\n throw new Error(\n \"Input sample exceeds 16 MB. Reduce the rows to process.\",\n );\n return values;\n });\n },\n [inputFields],\n );\n const activeSelect = query.select.length\n ? query.select\n : (schema.defaultSelect ?? []);\n const activeIds = activeSelect\n .filter((c) => isComputedField(c.field))\n .map((c) => c.field.slice(\"@computed/\".length))\n .sort()\n .join(\",\");\n const [evaluated, setEvaluated] = useState<{\n rows: Row[];\n plans: typeof plans;\n values: Map<string, FormulaResult[]>;\n } | null>(null);\n useEffect(() => {\n const ac = new AbortController();\n const values = new Map<string, FormulaResult[]>();\n void (async () => {\n for (const id of activeIds.split(\",\").filter(Boolean)) {\n const entry = plans.get(id);\n if (!entry?.plan) continue;\n try {\n values.set(\n id,\n await evaluateFormulaRows(\n entry.plan.ast,\n inputsFor(entry.plan, rows),\n ac.signal,\n workerFactory,\n ),\n );\n } catch (e) {\n if (ac.signal.aborted) return;\n values.set(\n id,\n rows.map(() => ({\n value: null,\n error: e instanceof Error ? e.message : String(e),\n })),\n );\n }\n }\n if (!ac.signal.aborted) setEvaluated({ rows, plans, values });\n })();\n return () => ac.abort();\n }, [activeIds, rows, plans, inputsFor, workerFactory]);\n const displaySchema = useMemo<FieldSchema<Row>>(() => {\n const indices = new Map(rows.map((row, i) => [row, i]));\n const fields: FieldDef<Row>[] = definitions.map((def) => {\n const entry = plans.get(def.id);\n return {\n name: computedFieldName(def.id),\n label: def.label,\n type:\n entry?.plan?.type === \"null\" ? \"text\" : (entry?.plan?.type ?? \"text\"),\n group: \"Computed columns\",\n source: {\n kind: \"derived\",\n computedId: def.id,\n dependencies: entry?.plan ? backendDependencies(entry.plan) : [],\n accessor: (row: Row) => {\n if (entry?.error) return { computedError: entry.error };\n const result =\n evaluated?.rows === rows && evaluated.plans === plans\n ? evaluated.values.get(def.id)?.[indices.get(row) ?? -1]\n : undefined;\n return result?.error\n ? { computedError: result.error }\n : result\n ? result.value\n : { computedError: \"Calculating…\" };\n },\n },\n filter: { enabled: false },\n sort: { enabled: false },\n aggregate: { measure: false, groupable: false },\n };\n });\n for (const col of activeSelect)\n if (\n isComputedField(col.field) &&\n !fields.some((f) => f.name === col.field)\n )\n fields.push({\n name: col.field,\n label: col.field.slice(10),\n type: \"text\",\n source: {\n kind: \"derived\",\n computedId: col.field.slice(10),\n accessor: () => ({\n computedError: loading\n ? \"Loading definition…\"\n : \"Definition unavailable. Reload the catalogue or contact its owner.\",\n }),\n },\n filter: { enabled: false },\n sort: { enabled: false },\n aggregate: { measure: false, groupable: false },\n });\n return { ...schema, fields: [...schema.fields, ...fields] };\n }, [\n schema,\n definitions,\n plans,\n backendDependencies,\n evaluated,\n rows,\n query.select,\n schema.defaultSelect,\n loading,\n ]);\n const save = useCallback(\n async (column: ComputedColumnDraft, expectedRevision: string | null) => {\n compile(column.expression.source, column.id);\n const saved = validateComputedColumn(\n await store.save(schema.name, column, expectedRevision),\n );\n setCatalogue((prev) => ({\n dataset: schema.name,\n store,\n items: [\n ...(prev?.dataset === schema.name && prev.store === store\n ? prev.items.filter((d) => d.id !== saved.id)\n : []),\n saved,\n ],\n }));\n return saved;\n },\n [compile, store, schema.name],\n );\n const preview = useCallback(\n async (\n source: string,\n count: number,\n signal?: AbortSignal,\n editingId?: string,\n includeInputs = true,\n ): Promise<ColumnPreview> => {\n if (!Number.isInteger(count) || count < 1 || count > 10000)\n throw new Error(\"Choose between 1 and 10,000 rows.\");\n const plan = compile(source, editingId);\n let batch: Row[] = [],\n total = 0;\n if (transport) {\n const request = toServerQuery(\n {\n ...query,\n select: [\n ...new Set([schema.idField, ...backendDependencies(plan)]),\n ].map((field) => ({ field })),\n limit: Math.min(count, 500),\n offset: 0,\n },\n schema,\n );\n while (batch.length < count) {\n if (signal?.aborted) throw new DOMException(\"Aborted\", \"AbortError\");\n const res = await transport.fetchRows(\n {\n ...request,\n offset: batch.length,\n limit: Math.min(500, count - batch.length),\n },\n signal,\n );\n total = res.total;\n batch.push(...res.rows.slice(0, count - batch.length));\n if (!res.rows.length || batch.length >= total) break;\n }\n } else {\n const result = applyQuery(\n clientRows ?? [],\n { ...query, limit: count, offset: 0 },\n schema,\n );\n batch = result.rows;\n total = result.total;\n }\n const inputs = inputsFor(plan, batch),\n results = await evaluateFormulaRows(\n plan.ast,\n inputs,\n signal,\n workerFactory,\n );\n return groupPreview(\n includeInputs ? plan.dependencies : [],\n inputs,\n results,\n total,\n );\n },\n [\n compile,\n transport,\n query,\n schema,\n backendDependencies,\n clientRows,\n inputsFor,\n workerFactory,\n ],\n );\n return {\n displaySchema,\n api: {\n definitions,\n catalogue: displaySchema.fields,\n loading,\n error,\n reload,\n save,\n compile,\n preview,\n },\n };\n}\n","import {\n formulaRuntime,\n type FormulaNode,\n type FormulaResult,\n type FormulaValue,\n} from \"@pythia-software/query-table-core\";\n\nexport type FormulaWorkerFactory = () => Worker;\n/** Host applications with a restrictive CSP can supply their own worker factory. */\nexport const createFormulaWorker: FormulaWorkerFactory = () => {\n const code = `const evaluate = ${formulaRuntime.toString()}; self.onmessage = e => { const { ast, inputs } = e.data; self.postMessage(inputs.map(row => evaluate(ast, row))); };`;\n const url = URL.createObjectURL(\n new Blob([code], { type: \"text/javascript\" }),\n );\n try {\n return new Worker(url);\n } finally {\n URL.revokeObjectURL(url);\n }\n};\nexport function evaluateFormulaRows(\n ast: FormulaNode,\n inputs: Record<string, FormulaValue>[],\n signal?: AbortSignal,\n factory: FormulaWorkerFactory = createFormulaWorker,\n): Promise<FormulaResult[]> {\n if (signal?.aborted)\n return Promise.reject(new DOMException(\"Aborted\", \"AbortError\"));\n if (!inputs.length) return Promise.resolve([]);\n return new Promise((resolve, reject) => {\n let worker: Worker;\n try {\n worker = factory();\n } catch (e) {\n reject(\n new Error(\n `Formula worker unavailable: ${e instanceof Error ? e.message : String(e)}`,\n ),\n );\n return;\n }\n let timer: ReturnType<typeof setTimeout>;\n const started = Date.now();\n let offset = 0;\n const results: FormulaResult[] = [];\n const cleanup = () => {\n clearTimeout(timer);\n worker.terminate();\n signal?.removeEventListener(\"abort\", abort);\n };\n const abort = () => {\n cleanup();\n reject(new DOMException(\"Aborted\", \"AbortError\"));\n };\n const send = () => {\n if (Date.now() - started > 30000) {\n cleanup();\n reject(\n new Error(\n \"Formula exceeded the 30-second processing budget. Reduce the row count or simplify the formula.\",\n ),\n );\n return;\n }\n timer = setTimeout(() => {\n cleanup();\n reject(\n new Error(\n \"Formula timed out. Check the regex or reduce the row count.\",\n ),\n );\n }, 2000);\n try {\n worker.postMessage({ ast, inputs: inputs.slice(offset, offset + 200) });\n } catch (e) {\n cleanup();\n reject(e);\n }\n };\n signal?.addEventListener(\"abort\", abort, { once: true });\n worker.onerror = () => {\n cleanup();\n reject(new Error(\"Formula worker failed.\"));\n };\n worker.onmessage = (event: MessageEvent<FormulaResult[]>) => {\n clearTimeout(timer);\n results.push(...event.data);\n offset += event.data.length;\n if (offset >= inputs.length) {\n cleanup();\n resolve(results);\n } else send();\n };\n send();\n });\n}\n","// useQueryTable — the one hook that owns everything.\n//\n// The headless brain of the table: it holds the QueryState, keeps it in sync\n// with the URL (`?q=`) and the StorageAdapter, orchestrates fetches through the\n// Transport (debounced + abortable), and exposes intent-level mutators so a UI\n// never hand-edits QueryState. @pythia-software/query-table-ui is a thin layer over this; you\n// can also build an entirely custom table on it.\n\nimport { useComputedColumns, type ComputedColumnsApi } from \"./useComputedColumns\";\nimport type { FormulaWorkerFactory } from \"./formulaWorker\";\nimport type { ComputedColumnStore } from \"@pythia-software/query-table-core\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport {\n EMPTY_QUERY,\n applyQuery,\n decodeQuery,\n encodeQuery,\n memoryStorageAdapter,\n normalizeQueryState,\n readFieldValue,\n selectedFields,\n toServerQuery,\n queriesEqual,\n isOrGroup,\n predicatesOf,\n negateClause,\n opsForField,\n} from \"@pythia-software/query-table-core\";\n\nconst AUTOCOMPLETE_LIMIT = 50;\nconst MAX_AUTO_REFRESH_POLLS = 1000;\nimport type {\n QueryState,\n WhereClause,\n WhereTerm,\n OrderByClause,\n AggOp,\n AggregationClause,\n AggregationResult,\n RowId,\n FieldDef,\n FieldSchema,\n Transport,\n StorageAdapter,\n DistinctValuesResult,\n} from \"@pythia-software/query-table-core\";\nimport { useAggregations } from \"./useAggregations\";\nimport { useSelection, type SelectionApi } from \"./useSelection\";\nimport { useSelect, type SelectApi } from \"./useSelect\";\nimport { useColumnDrag, type ColumnDragApi } from \"./useColumnDrag\";\nimport { useSavedQueries, type SavedQueriesApi } from \"./useSavedQueries\";\n\nexport interface UseQueryTableOptions<Row> {\n schema: FieldSchema<Row>;\n /** Data access. Omit for a purely client-side table driven by `clientRows`. */\n transport?: Transport<Row>;\n /** All rows, for client-side mode (applyQuery runs locally over these). */\n clientRows?: Row[];\n /** Saved/last-query persistence. Defaults to a non-durable in-memory adapter.\n * Pass localStorageAdapter() explicitly only when filter values are safe to\n * retain as cleartext JSON on the device. */\n storage?: StorageAdapter;\n /** Shared reusable definitions, independent of saved-query storage. */\n computedColumnStore?: ComputedColumnStore;\n /** Override the worker factory when CSP disallows blob workers. */\n formulaWorkerFactory?: FormulaWorkerFactory;\n /** Seed query, normalized and resource-bounded before use. When omitted the\n * hook resolves: opted-in URL → storage.loadLast → schema defaults. */\n initialQuery?: QueryState;\n /** Mirror QueryState to `?q=` via history.replaceState. Default false because\n * base64url is encoding, not encryption: filters will appear in browser\n * history, referrers, logs, analytics, and screenshots when enabled. */\n syncUrl?: boolean;\n /** Debounce (ms) between a query change and the fetch it triggers. Default 200. */\n debounceMs?: number;\n /** Injected clock for deterministic saved-query timestamps. Default Date.now. */\n now?: () => number;\n /** Side-effect to run on every refresh — both manual `api.refresh()` and each\n * auto-refresh tick. Fires *in addition to* the internal `setNonce` re-query,\n * so manual and auto stay identical. Use it in client mode (no transport) to\n * bridge a UI refresh to your own server fetch without monkey-patching the\n * returned `api`. Always read through a ref, so supplying it never tears down\n * and recreates the auto-refresh interval. */\n onRefresh?: () => void;\n}\n\nexport interface AutoRefreshConfig {\n frequencyMs: number;\n turnOffAfterMs: number;\n}\n\nexport interface AutoRefreshStatus extends AutoRefreshConfig {\n startedAt: number;\n stopsAt: number;\n pollCount: number;\n}\n\nexport interface AutoRefreshApi {\n status: AutoRefreshStatus | null;\n start: (config: AutoRefreshConfig) => void;\n stop: () => void;\n}\n\n/** A patch for one metric. `field`/`label` accept an explicit `undefined` to\n * CLEAR them (e.g. switching to an op whose measure no longer applies); an\n * absent key leaves the existing value untouched. */\nexport interface AggregationPatch {\n op?: AggOp;\n field?: string | undefined;\n groupBy?: string[];\n label?: string | undefined;\n}\n\nexport interface AggregationsApi {\n /** The metric specs currently in the query. */\n clauses: AggregationClause[];\n /** Server (or client-mirror) results, one entry per clause; null when none. */\n results: AggregationResult | null;\n loading: boolean;\n error: Error | null;\n /** Append a metric. Defaults to \"count all rows\"; pass a partial to override.\n * Returns the generated id. */\n add: (partial?: Partial<Omit<AggregationClause, \"id\">>) => string;\n /** Patch a metric by id. */\n update: (id: string, patch: AggregationPatch) => void;\n /** Reorder: move the metric `id` to `toIndex` (an index in the list with the\n * metric removed, so a drag preview's slot maps straight to the result). */\n move: (id: string, toIndex: number) => void;\n /** Remove a metric by id. */\n remove: (id: string) => void;\n /** Remove all metrics. */\n clear: () => void;\n}\n\nexport interface QueryTableApi<Row> {\n // state\n query: QueryState;\n /** Schema defaults used for reset controls. */\n defaults: QueryState;\n setQuery: (next: QueryState | ((prev: QueryState) => QueryState)) => void;\n /** Can move back to a previously applied local query state. */\n canUndo: boolean;\n /** Can move forward to a previously undone local query state. */\n canRedo: boolean;\n /** Move backward through local, unsaved query history. */\n undo: () => void;\n /** Move forward through local, unsaved query history. */\n redo: () => void;\n\n // data\n rows: Row[];\n total: number | null;\n loading: boolean;\n error: Error | null;\n refresh: () => void;\n autoRefresh: AutoRefreshApi;\n refreshRow: (id: RowId) => Promise<void>;\n\n // aggregation metrics (the dashboard panel above the table)\n aggregations: AggregationsApi;\n\n // filters — WHERE is CNF: `query.where` is an array of terms (a literal or an\n // OR group), ANDed together. The top-level intents address a whole term by\n // index; the predicate-level intents address one literal within a term.\n /** Append a predicate as its own AND term. */\n addFilter: (clause: WhereClause) => void;\n /** Replace the whole term at `index` with a single predicate. */\n updateFilter: (index: number, clause: WhereClause) => void;\n /** Remove the whole term at `index`. */\n removeFilter: (index: number) => void;\n clearFilters: () => void;\n /** Replace one predicate inside a term (predIndex 0 for a literal term). */\n updatePredicate: (termIndex: number, predIndex: number, clause: WhereClause) => void;\n /** Remove one predicate; a group of one flattens to a literal, an emptied term drops. */\n removePredicate: (termIndex: number, predIndex: number) => void;\n /** Logically invert one predicate (flips the op, else toggles its NOT flag). */\n negatePredicate: (termIndex: number, predIndex: number) => void;\n /** Move the term at `fromIndex` to `toIndex` (an index in the list with the\n * dragged term removed, so a drag preview's slot maps straight to the result). */\n reorderFilters: (fromIndex: number, toIndex: number) => void;\n /** OR-merge the term at `sourceIndex` into the term at `targetIndex`: the\n * target becomes (or stays) an OR group holding both terms' predicates, and\n * the source term is removed. This is the drag-onto-another-filter gesture. */\n mergeFilters: (sourceIndex: number, targetIndex: number) => void;\n /** Reset the complete query state back to schema defaults. */\n resetAll: () => void;\n /** Keystroke-driven filter-value autocomplete (Transport.fetchDistinctValues). */\n filterValues: (field: string, search: string) => Promise<DistinctValuesResult>;\n\n // sorting (multi-sort): click header sets/cycles primary; shift-click appends.\n toggleSort: (field: string, additive?: boolean) => void;\n setSort: (orderBy: OrderByClause[]) => void;\n\n // select + pagination + selection + saved\n select: SelectApi<Row>;\n computed: ComputedColumnsApi<Row>;\n setLimit: (limit: number) => void;\n setOffset: (offset: number) => void;\n nextPage: () => void;\n prevPage: () => void;\n selection: SelectionApi;\n saved: SavedQueriesApi;\n /** Shared, transient column-reorder drag state (table headers + select chips). */\n columnDrag: ColumnDragApi;\n\n // resolved view\n visibleFields: FieldDef<Row>[];\n rowId: (row: Row) => RowId | null;\n}\n\nfunction defaultsFor<Row>(schema: FieldSchema<Row>): QueryState {\n return normalizeQueryState({\n select: schema.defaultSelect ?? [],\n where: [],\n orderBy: schema.defaultSort ?? [],\n limit: schema.defaultLimit ?? EMPTY_QUERY.limit,\n offset: 0,\n });\n}\n\nfunction cloneWhereTerm(term: WhereTerm): WhereTerm {\n return isOrGroup(term) ? { any: term.any.map((c) => ({ ...c })) } : { ...term };\n}\n\nfunction cloneQueryState(q: QueryState): QueryState {\n const clone: QueryState = {\n select: q.select.map((column) => ({ ...column })),\n where: q.where.map(cloneWhereTerm),\n orderBy: q.orderBy.map((term) => (term.extract ? { ...term, extract: { ...term.extract } } : { ...term })),\n limit: q.limit,\n offset: q.offset,\n };\n if (q.aggregations) clone.aggregations = q.aggregations.map((a) => ({ ...a, groupBy: [...a.groupBy] }));\n return clone;\n}\n\n/** Apply a patch to a metric, building a fresh clause so optional `field`/`label`\n * can be dropped (passing them as `undefined` clears; omitting the key keeps the\n * current value) without ever materializing an `undefined`-valued property. */\nfunction mergeAggregation(a: AggregationClause, patch: AggregationPatch): AggregationClause {\n const next: AggregationClause = {\n id: a.id,\n op: patch.op ?? a.op,\n groupBy: patch.groupBy ?? a.groupBy,\n };\n const field = \"field\" in patch ? patch.field : a.field;\n if (field) next.field = field;\n const label = \"label\" in patch ? patch.label : a.label;\n if (label) next.label = label;\n return next;\n}\n\nfunction isNullLike(value: unknown): boolean {\n return value == null || (Array.isArray(value) && value.length === 0);\n}\n\nfunction asDistinctValue(value: unknown): string | null {\n if (isNullLike(value)) return null;\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n return null;\n}\n\nfunction fieldHasNullInRows<Row>(field: FieldDef<Row>, rows: Row[]): boolean {\n for (const row of rows) {\n if (isNullLike(readFieldValue(field, row))) return true;\n }\n return false;\n}\n\nfunction distinctValuesFromRows<Row>(field: FieldDef<Row>, rows: Row[], search: string): { values: string[]; hasMore: boolean } {\n const target = search.trim().toLowerCase();\n const values: string[] = [];\n const seen = new Set<string>();\n let hasMore = false;\n\n for (const row of rows) {\n const raw = asDistinctValue(readFieldValue(field, row));\n if (raw == null || seen.has(raw)) continue;\n if (target && !raw.toLowerCase().includes(target)) continue;\n\n if (values.length < AUTOCOMPLETE_LIMIT) {\n seen.add(raw);\n values.push(raw);\n continue;\n }\n\n hasMore = true;\n break;\n }\n\n return { values: values.sort((a, b) => a.localeCompare(b)), hasMore };\n}\n\nfunction resolveInitial<Row>(opts: UseQueryTableOptions<Row>): { q: QueryState; fromUrl: boolean } {\n const defaults = defaultsFor(opts.schema);\n if (opts.initialQuery) return { q: normalizeQueryState(opts.initialQuery, defaults), fromUrl: false };\n if (opts.syncUrl === true && typeof window !== \"undefined\") {\n const token = new URLSearchParams(window.location.search).get(\"q\");\n if (token) return { q: normalizeQueryState(decodeQuery(token), defaults), fromUrl: true };\n }\n return { q: defaults, fromUrl: false };\n}\n\nexport function useQueryTable<Row>(opts: UseQueryTableOptions<Row>): QueryTableApi<Row> {\n const { schema, transport, clientRows, initialQuery, syncUrl = false, debounceMs = 200 } = opts;\n const storage = useMemo(() => opts.storage ?? memoryStorageAdapter(), [opts.storage]);\n const now = opts.now ?? Date.now;\n const nowRef = useRef(now);\n const onRefreshRef = useRef(opts.onRefresh);\n const defaults = useMemo(() => defaultsFor(schema), [schema]);\n const byName = useMemo(() => new Map(schema.fields.map((f) => [f.name, f])), [schema]);\n\n const initRef = useRef(resolveInitial(opts));\n const aggIdRef = useRef(0);\n const [query, setQueryState] = useState<QueryState>(initRef.current.q);\n const undoStack = useRef<QueryState[]>([cloneQueryState(initRef.current.q)]);\n const redoStack = useRef<QueryState[]>([]);\n const [rows, setRows] = useState<Row[]>([]);\n const [total, setTotal] = useState<number | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [nonce, setNonce] = useState(0);\n const [autoRefreshStatus, setAutoRefreshStatus] = useState<AutoRefreshStatus | null>(null);\n\n useEffect(() => {\n nowRef.current = now;\n }, [now]);\n\n useEffect(() => {\n onRefreshRef.current = opts.onRefresh;\n }, [opts.onRefresh]);\n\n const setQuery = useCallback<QueryTableApi<Row>[\"setQuery\"]>((next) => {\n setQueryState((prev) => {\n const candidate = typeof next === \"function\" ? (next as (p: QueryState) => QueryState)(prev) : next;\n const nextQuery = normalizeQueryState(candidate, defaults);\n if (queriesEqual(prev, nextQuery)) return prev;\n undoStack.current.push(cloneQueryState(prev));\n redoStack.current = [];\n return cloneQueryState(nextQuery);\n });\n }, [defaults]);\n\n // Restore the default saved query (preferred) or last query on mount when\n // nothing explicit seeded the view.\n useEffect(() => {\n if (initRef.current.fromUrl || initialQuery) return;\n let cancelled = false;\n void (async () => {\n const defaultSaved = await storage.loadDefaultSaved?.(schema.name);\n const restored = defaultSaved?.query ?? (await storage.loadLast(schema.name));\n if (!cancelled && restored) {\n const normalized = normalizeQueryState(restored, defaults);\n undoStack.current = [cloneQueryState(normalized)];\n redoStack.current = [];\n setQueryState(normalized);\n }\n })();\n return () => {\n cancelled = true;\n };\n // mount-only\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const { api: computed, displaySchema } = useComputedColumns({\n schema, query, rows,\n ...(opts.computedColumnStore ? {store:opts.computedColumnStore} : {}),\n ...(opts.formulaWorkerFactory ? {workerFactory:opts.formulaWorkerFactory} : {}),\n ...(transport ? {transport} : {}), ...(clientRows ? {clientRows} : {}),\n });\n\n // Fetch (debounced + abortable). Transport mode, or client-side applyQuery.\n const queryKey = useMemo(() => encodeQuery(query), [query]);\n const serverRowQuery = useMemo(() => toServerQuery(query, displaySchema), [queryKey, displaySchema]);\n // Keep presentation-only query changes out of the expensive row pipeline.\n // Widths do not leave the client at all, and SELECT does not affect client-side\n // filtering/sorting/paging. The full queryKey still drives URL + persistence.\n const rowQueryKey = useMemo(\n () => transport\n ? `server:${JSON.stringify(serverRowQuery)}`\n : `client:${JSON.stringify([query.where, query.orderBy, query.limit, query.offset])}`,\n [transport, serverRowQuery, query.where, query.orderBy, query.limit, query.offset],\n );\n useEffect(() => {\n const ac = new AbortController();\n let cancelled = false;\n const run = async () => {\n setLoading(true);\n setError(null);\n try {\n if (transport) {\n const res = await transport.fetchRows(serverRowQuery, ac.signal);\n if (!cancelled) {\n setRows(res.rows);\n setTotal(res.total);\n }\n } else {\n const res = applyQuery(clientRows ?? [], query, schema);\n if (!cancelled) {\n setRows(res.rows);\n setTotal(res.total);\n }\n }\n } catch (e) {\n if (!cancelled && !ac.signal.aborted) setError(e as Error);\n } finally {\n if (!cancelled) setLoading(false);\n }\n };\n const t = setTimeout(run, debounceMs);\n return () => {\n cancelled = true;\n clearTimeout(t);\n ac.abort();\n };\n // rowQueryKey captures only row-affecting query state; clientRows/nonce\n // force refetch. Presentation changes still sync/persist via queryKey below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [rowQueryKey, transport, clientRows, schema, debounceMs, nonce]);\n\n // URL sync.\n useEffect(() => {\n if (!syncUrl || typeof window === \"undefined\") return;\n const url = new URL(window.location.href);\n const token = encodeQuery(query);\n if (token) url.searchParams.set(\"q\", token);\n else url.searchParams.delete(\"q\");\n window.history.replaceState(null, \"\", url.toString());\n }, [queryKey, syncUrl, query]);\n\n // Persist last query (debounced).\n useEffect(() => {\n const t = setTimeout(() => void storage.saveLast(schema.name, query), 400);\n return () => clearTimeout(t);\n }, [queryKey, storage, schema.name, query]);\n\n // Resolved id accessor.\n const idField = useMemo(() => schema.fields.find((f) => f.name === schema.idField), [schema]);\n const rowId = useCallback(\n (row: Row): RowId | null => (idField ? (readFieldValue(idField, row) as RowId | null) : null),\n [idField],\n );\n\n // Sub-APIs.\n const displayedIds = useMemo(() => rows.map(rowId).filter((id): id is RowId => id != null), [rows, rowId]);\n const selection = useSelection(displayedIds);\n const select = useSelect(query, setQuery, displaySchema);\n const columnDrag = useColumnDrag();\n const saved = useSavedQueries(\n schema.name,\n query,\n (q) => setQuery(q),\n storage,\n now,\n );\n const aggState = useAggregations(query, schema, transport, clientRows, debounceMs, nonce);\n\n const canUndo = undoStack.current.length > 0;\n const canRedo = redoStack.current.length > 0;\n\n const undo = useCallback(() => {\n setQueryState((prev) => {\n const previous = undoStack.current.pop();\n if (!previous) return prev;\n redoStack.current.push(cloneQueryState(prev));\n return cloneQueryState(previous);\n });\n }, []);\n\n const redo = useCallback(() => {\n setQueryState((prev) => {\n const next = redoStack.current.pop();\n if (!next) return prev;\n undoStack.current.push(cloneQueryState(prev));\n return cloneQueryState(next);\n });\n }, []);\n\n // ---- intent helpers (keep offset/url/storage coherent) ----\n const patch = useCallback((p: Partial<QueryState>) => setQuery((prev) => ({ ...prev, ...p })), [setQuery]);\n\n const addFilter = useCallback((clause: WhereClause) => setQuery((q) => ({ ...q, offset: 0, where: [...q.where, clause] })), [setQuery]);\n const updateFilter = useCallback(\n (index: number, clause: WhereClause) =>\n setQuery((q) => ({ ...q, offset: 0, where: q.where.map((t, i) => (i === index ? clause : t)) })),\n [setQuery],\n );\n const removeFilter = useCallback(\n (index: number) => setQuery((q) => ({ ...q, offset: 0, where: q.where.filter((_, i) => i !== index) })),\n [setQuery],\n );\n const clearFilters = useCallback(() => setQuery((q) => ({ ...q, offset: 0, where: [] })), [setQuery]);\n\n const updatePredicate = useCallback<QueryTableApi<Row>[\"updatePredicate\"]>(\n (termIndex, predIndex, clause) =>\n setQuery((q) => ({\n ...q,\n offset: 0,\n where: q.where.map((term, i) => {\n if (i !== termIndex) return term;\n if (isOrGroup(term)) return { any: term.any.map((c, j) => (j === predIndex ? clause : c)) };\n return clause;\n }),\n })),\n [setQuery],\n );\n const removePredicate = useCallback<QueryTableApi<Row>[\"removePredicate\"]>(\n (termIndex, predIndex) =>\n setQuery((q) => {\n const where: WhereTerm[] = [];\n q.where.forEach((term, i) => {\n if (i !== termIndex) {\n where.push(term);\n return;\n }\n if (isOrGroup(term)) {\n const members = term.any.filter((_, j) => j !== predIndex);\n if (members.length === 1) where.push(members[0]!);\n else if (members.length > 1) where.push({ any: members });\n return; // 0 members → drop the term\n }\n // literal term → removing its predicate drops the whole term\n });\n return { ...q, offset: 0, where };\n }),\n [setQuery],\n );\n const negateOne = useCallback(\n (clause: WhereClause): WhereClause => {\n const field = byName.get(clause.field);\n return negateClause(clause, field ? opsForField(field) : undefined);\n },\n [byName],\n );\n const negatePredicate = useCallback<QueryTableApi<Row>[\"negatePredicate\"]>(\n (termIndex, predIndex) =>\n setQuery((q) => ({\n ...q,\n offset: 0,\n where: q.where.map((term, i) => {\n if (i !== termIndex) return term;\n if (isOrGroup(term)) return { any: term.any.map((c, j) => (j === predIndex ? negateOne(c) : c)) };\n return negateOne(term);\n }),\n })),\n [setQuery, negateOne],\n );\n const reorderFilters = useCallback<QueryTableApi<Row>[\"reorderFilters\"]>(\n (fromIndex, toIndex) =>\n setQuery((q) => {\n if (fromIndex < 0 || fromIndex >= q.where.length) return q;\n const where = [...q.where];\n const [moved] = where.splice(fromIndex, 1);\n where.splice(Math.max(0, Math.min(toIndex, where.length)), 0, moved!);\n return { ...q, offset: 0, where };\n }),\n [setQuery],\n );\n const mergeFilters = useCallback<QueryTableApi<Row>[\"mergeFilters\"]>(\n (sourceIndex, targetIndex) =>\n setQuery((q) => {\n if (sourceIndex === targetIndex) return q;\n const source = q.where[sourceIndex];\n const target = q.where[targetIndex];\n if (!source || !target) return q;\n const merged: WhereTerm = { any: [...predicatesOf(target), ...predicatesOf(source)] };\n const where: WhereTerm[] = [];\n q.where.forEach((term, i) => {\n if (i === sourceIndex) return; // remove the dragged term\n where.push(i === targetIndex ? merged : term);\n });\n return { ...q, offset: 0, where };\n }),\n [setQuery],\n );\n const resetAll = useCallback(() => setQuery(() => cloneQueryState(defaults)), [setQuery, defaults]);\n\n // ---- aggregation metric mutators (don't touch paging — scope is the whole set) ----\n const addAggregation = useCallback<AggregationsApi[\"add\"]>(\n (partial) => {\n const id = `a${nowRef.current()}-${aggIdRef.current++}`;\n const clause: AggregationClause = { id, op: \"count\", groupBy: [], ...partial };\n setQuery((q) => ({ ...q, aggregations: [...(q.aggregations ?? []), clause] }));\n return id;\n },\n [setQuery],\n );\n const updateAggregation = useCallback<AggregationsApi[\"update\"]>(\n (id, patch) =>\n setQuery((q) => ({\n ...q,\n aggregations: (q.aggregations ?? []).map((a) => (a.id === id ? mergeAggregation(a, patch) : a)),\n })),\n [setQuery],\n );\n const moveAggregation = useCallback<AggregationsApi[\"move\"]>(\n (id, toIndex) =>\n setQuery((q) => {\n const current = q.aggregations ?? [];\n const from = current.findIndex((a) => a.id === id);\n if (from === -1) return q;\n const next = [...current];\n const [item] = next.splice(from, 1);\n next.splice(Math.max(0, Math.min(toIndex, next.length)), 0, item!);\n return { ...q, aggregations: next };\n }),\n [setQuery],\n );\n const removeAggregation = useCallback<AggregationsApi[\"remove\"]>(\n (id) => setQuery((q) => ({ ...q, aggregations: (q.aggregations ?? []).filter((a) => a.id !== id) })),\n [setQuery],\n );\n const clearAggregations = useCallback<AggregationsApi[\"clear\"]>(\n () => setQuery((q) => ({ ...q, aggregations: [] })),\n [setQuery],\n );\n\n const setSort = useCallback((orderBy: OrderByClause[]) => setQuery((q) => ({ ...q, offset: 0, orderBy })), [setQuery]);\n const toggleSort = useCallback(\n (field: string, additive = false) =>\n setQuery((q) => ({ ...q, offset: 0, orderBy: nextOrderBy(q.orderBy, field, additive) })),\n [setQuery],\n );\n\n const setLimit = useCallback((limit: number) => patch({ limit, offset: 0 }), [patch]);\n const setOffset = useCallback((offset: number) => patch({ offset }), [patch]);\n const nextPage = useCallback(() => setQuery((q) => ({ ...q, offset: q.offset + q.limit })), [setQuery]);\n const prevPage = useCallback(() => setQuery((q) => ({ ...q, offset: Math.max(0, q.offset - q.limit) })), [setQuery]);\n\n const filterValues = useCallback(\n async (field: string, search: string): Promise<DistinctValuesResult> => {\n if (!transport?.fetchDistinctValues) {\n const f = byName.get(field);\n if (!f || !clientRows) return { values: [], hasMore: false };\n\n const fieldHasNull = fieldHasNullInRows(f, clientRows);\n const matches = distinctValuesFromRows(f, clientRows, search);\n\n return {\n values: matches.values,\n hasMore: matches.hasMore,\n hasNull: fieldHasNull,\n };\n }\n return transport.fetchDistinctValues({ field, search });\n },\n [transport, byName, clientRows],\n );\n\n // Single refresh seam: re-runs the internal query (setNonce) and fires the\n // consumer's onRefresh, if any. Both the manual `api.refresh()` and every\n // auto-refresh tick go through here, so they stay observably identical. Read\n // onRefresh through a ref to keep this callback (and the interval that depends\n // on it) stable across renders.\n const refresh = useCallback(() => {\n setNonce((n) => n + 1);\n onRefreshRef.current?.();\n }, []);\n const stopAutoRefresh = useCallback(() => setAutoRefreshStatus(null), []);\n const startAutoRefresh = useCallback(\n ({ frequencyMs, turnOffAfterMs }: AutoRefreshConfig) => {\n const pollCount = frequencyMs > 0 && turnOffAfterMs > 0 ? Math.floor(turnOffAfterMs / frequencyMs) : 0;\n if (pollCount < 1 || pollCount > MAX_AUTO_REFRESH_POLLS) {\n throw new Error(\"Auto-refresh must schedule between 1 and 1000 polls.\");\n }\n\n const startedAt = nowRef.current();\n refresh();\n setAutoRefreshStatus({\n frequencyMs,\n turnOffAfterMs,\n startedAt,\n stopsAt: startedAt + turnOffAfterMs,\n pollCount: 1,\n });\n },\n [refresh],\n );\n\n const autoRefreshFrequencyMs = autoRefreshStatus?.frequencyMs ?? null;\n const autoRefreshStopsAt = autoRefreshStatus?.stopsAt ?? null;\n\n useEffect(() => {\n if (autoRefreshFrequencyMs == null || autoRefreshStopsAt == null) return;\n\n const tick = () => {\n if (nowRef.current() >= autoRefreshStopsAt) {\n setAutoRefreshStatus((current) => (current?.stopsAt === autoRefreshStopsAt ? null : current));\n return;\n }\n\n refresh();\n setAutoRefreshStatus((current) => {\n if (!current) return current;\n if (current.stopsAt !== autoRefreshStopsAt) return current;\n return { ...current, pollCount: current.pollCount + 1 };\n });\n };\n\n const interval = setInterval(tick, autoRefreshFrequencyMs);\n const timeout = setTimeout(\n () => setAutoRefreshStatus((current) => (current?.stopsAt === autoRefreshStopsAt ? null : current)),\n Math.max(0, autoRefreshStopsAt - nowRef.current()),\n );\n\n return () => {\n clearInterval(interval);\n clearTimeout(timeout);\n };\n }, [autoRefreshFrequencyMs, autoRefreshStopsAt, refresh]);\n\n const autoRefresh = useMemo<AutoRefreshApi>(\n () => ({\n status: autoRefreshStatus,\n start: startAutoRefresh,\n stop: stopAutoRefresh,\n }),\n [autoRefreshStatus, startAutoRefresh, stopAutoRefresh],\n );\n\n const refreshRow = useCallback(\n async (id: RowId) => {\n if (!transport?.fetchRow) return;\n const updated = await transport.fetchRow(id);\n setRows((prev) => prev.map((r) => (rowId(r) === id ? updated ?? r : r)));\n },\n [transport, rowId],\n );\n\n const visibleFields = useMemo(() => selectedFields(displaySchema, query), [displaySchema, query]);\n\n const aggregations = useMemo<AggregationsApi>(\n () => ({\n clauses: query.aggregations ?? [],\n results: aggState.results,\n loading: aggState.loading,\n error: aggState.error,\n add: addAggregation,\n update: updateAggregation,\n move: moveAggregation,\n remove: removeAggregation,\n clear: clearAggregations,\n }),\n [\n query.aggregations,\n aggState.results,\n aggState.loading,\n aggState.error,\n addAggregation,\n updateAggregation,\n moveAggregation,\n removeAggregation,\n clearAggregations,\n ],\n );\n\n return {\n query,\n defaults,\n setQuery,\n rows,\n total,\n loading,\n error,\n canUndo,\n canRedo,\n undo,\n redo,\n refresh,\n autoRefresh,\n refreshRow,\n aggregations,\n addFilter,\n updateFilter,\n removeFilter,\n clearFilters,\n updatePredicate,\n removePredicate,\n negatePredicate,\n reorderFilters,\n mergeFilters,\n resetAll,\n filterValues,\n toggleSort,\n setSort,\n select,\n computed,\n setLimit,\n setOffset,\n nextPage,\n prevPage,\n selection,\n saved,\n columnDrag,\n visibleFields,\n rowId,\n };\n}\n\n/** Multi-sort header click logic.\n * - plain click on the sole sorted column → flip its direction\n * - plain click on another column → make it the only sort (desc)\n * - shift-click a new column → append it (desc) as a secondary term\n * - shift-click an existing term → cycle desc → asc → remove */\nfunction nextOrderBy(existing: OrderByClause[], field: string, additive: boolean): OrderByClause[] {\n const i = existing.findIndex((s) => s.field === field);\n if (!additive) {\n if (i === 0 && existing.length === 1) {\n const flipped: \"asc\" | \"desc\" = existing[0]!.dir === \"desc\" ? \"asc\" : \"desc\";\n return [{ ...existing[0]!, dir: flipped }];\n }\n return [{ field, dir: \"desc\" }];\n }\n if (i === -1) return [...existing, { field, dir: \"desc\" }];\n const cur = existing[i]!;\n if (cur.dir === \"desc\") {\n const next = [...existing];\n next[i] = { ...cur, dir: \"asc\" };\n return next;\n }\n return existing.filter((_, k) => k !== i); // asc → remove\n}\n","// useAggregations — the metric panel's data side.\n//\n// Runs the optional GROUP BY queries that back the metrics shown above the table.\n// Kept separate from the rows fetch so the panel loads/refreshes independently:\n// metrics depend ONLY on the WHERE filter + the aggregation specs (scope is the\n// whole filtered set — never the page window), so paging or re-sorting the table\n// does not re-issue them. Debounced + abortable, mirroring the rows fetch.\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport { applyAggregations, toAggregationQuery } from \"@pythia-software/query-table-core\";\nimport type { AggregationResult, FieldSchema, QueryState, Transport } from \"@pythia-software/query-table-core\";\n\nexport interface AggregationsApiState {\n results: AggregationResult | null;\n loading: boolean;\n error: Error | null;\n}\n\nconst EMPTY_RESULT: AggregationResult = { metrics: [] };\n\nexport function useAggregations<Row>(\n query: QueryState,\n schema: FieldSchema<Row>,\n transport: Transport<Row> | undefined,\n clientRows: Row[] | undefined,\n debounceMs: number,\n nonce: number,\n): AggregationsApiState {\n const [results, setResults] = useState<AggregationResult | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n // Metrics depend only on WHERE + the agg specs. Keying on just those avoids\n // refetching when the user pages or re-sorts the table.\n const key = useMemo(\n () => JSON.stringify({ where: query.where, aggregations: query.aggregations ?? [] }),\n [query.where, query.aggregations],\n );\n const hasAggregations = (query.aggregations?.length ?? 0) > 0;\n\n useEffect(() => {\n if (!hasAggregations) {\n setResults(null);\n setError(null);\n setLoading(false);\n return;\n }\n\n const ac = new AbortController();\n let cancelled = false;\n const run = async () => {\n setLoading(true);\n setError(null);\n try {\n let res: AggregationResult;\n if (transport?.fetchAggregations) {\n res = await transport.fetchAggregations(toAggregationQuery(query, schema), ac.signal);\n } else if (clientRows) {\n res = applyAggregations(clientRows, query, schema);\n } else {\n res = EMPTY_RESULT;\n }\n if (!cancelled) setResults(res);\n } catch (e) {\n if (!cancelled && !ac.signal.aborted) setError(e as Error);\n } finally {\n if (!cancelled) setLoading(false);\n }\n };\n const t = setTimeout(run, debounceMs);\n return () => {\n cancelled = true;\n clearTimeout(t);\n ac.abort();\n };\n // `key` captures the relevant query subset; clientRows/nonce force a refetch.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [key, hasAggregations, transport, clientRows, schema, debounceMs, nonce]);\n\n return { results, loading, error };\n}\n","// useSelection — row selection for paged and re-sortable datasets.\n//\n// - Shift-click range select, anchored by ROW ID (not index) so a\n// range survives re-sort / re-filter / paging. Index anchors break the moment\n// the data reorders; id anchors don't.\n// - Indeterminate header checkbox + select-all-on-page.\n\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport type { RowId } from \"@pythia-software/query-table-core\";\n\nexport interface SelectionApi {\n selected: Set<RowId>;\n isSelected: (id: RowId) => boolean;\n /** Toggle one row. With `shiftKey`, extend from the last-toggled anchor to `id`\n * across the *currently displayed* order (falls back to a plain toggle if the\n * anchor row is no longer present). */\n toggle: (id: RowId, shiftKey?: boolean) => void;\n /** Select / clear every row currently on the page. */\n setPage: (ids: RowId[], selected: boolean) => void;\n /** Atomically replace the complete selection with arbitrary stable row ids. */\n replace: (ids: Iterable<RowId>) => void;\n /** Atomically retain only selected ids that are also present in `ids`. */\n retain: (ids: Iterable<RowId>) => void;\n /** Header checkbox tri-state for the current page. */\n pageState: (pageIds: RowId[]) => \"none\" | \"some\" | \"all\";\n clear: () => void;\n count: number;\n}\n\n/** `displayedIds` is the page's id list in display order; the hook uses it to\n * resolve shift-ranges and header tri-state against what the user sees. */\nexport function useSelection(displayedIds: RowId[]): SelectionApi {\n const [selected, setSelected] = useState<Set<RowId>>(() => new Set());\n const anchor = useRef<RowId | null>(null);\n\n const toggle = useCallback(\n (id: RowId, shiftKey = false) => {\n setSelected((prev) => {\n const next = new Set(prev);\n const a = anchor.current;\n if (shiftKey && a != null) {\n const i = displayedIds.indexOf(a);\n const j = displayedIds.indexOf(id);\n if (i !== -1 && j !== -1) {\n const [lo, hi] = i <= j ? [i, j] : [j, i];\n const span = displayedIds.slice(lo, hi + 1);\n const allChecked = span.every((rowId) => prev.has(rowId));\n for (const rowId of span) {\n if (allChecked) next.delete(rowId);\n else next.add(rowId);\n }\n anchor.current = id;\n return next;\n }\n }\n if (next.has(id)) next.delete(id);\n else next.add(id);\n anchor.current = id;\n return next;\n });\n },\n [displayedIds],\n );\n\n const setPage = useCallback((ids: RowId[], select: boolean) => {\n setSelected((prev) => {\n const next = new Set(prev);\n for (const id of ids) {\n if (select) next.add(id);\n else next.delete(id);\n }\n return next;\n });\n }, []);\n\n const replace = useCallback((ids: Iterable<RowId>) => {\n const next = new Set(ids);\n anchor.current = null;\n setSelected(next);\n }, []);\n\n const retain = useCallback((ids: Iterable<RowId>) => {\n const allowed = new Set(ids);\n anchor.current = null;\n setSelected((prev) => {\n const next = new Set<RowId>();\n for (const id of prev) if (allowed.has(id)) next.add(id);\n return next;\n });\n }, []);\n\n const pageState = useCallback(\n (pageIds: RowId[]): \"none\" | \"some\" | \"all\" => {\n if (pageIds.length === 0) return \"none\";\n let n = 0;\n for (const id of pageIds) if (selected.has(id)) n++;\n return n === 0 ? \"none\" : n === pageIds.length ? \"all\" : \"some\";\n },\n [selected],\n );\n\n const clear = useCallback(() => {\n anchor.current = null;\n setSelected(new Set());\n }, []);\n\n return useMemo<SelectionApi>(\n () => ({\n selected,\n isSelected: (id) => selected.has(id),\n toggle,\n setPage,\n replace,\n retain,\n pageState,\n clear,\n count: selected.size,\n }),\n [selected, toggle, setPage, replace, retain, pageState, clear],\n );\n}\n","// useSelect — the SELECT list: visible columns, their order, and their widths,\n// all persisted INTO the query (decision #5, so one URL renders identically\n// anywhere). This API mutates QueryState.select; it holds no state of its own.\n// Width changes should be debounced by the caller before they hit the query to\n// avoid flooding history during a drag (useQueryTable does this).\n\nimport { useCallback, useMemo } from \"react\";\nimport type { QueryState, SelectColumn, FieldDef, FieldSchema } from \"@pythia-software/query-table-core\";\nimport { selectedFields } from \"@pythia-software/query-table-core\";\n\nexport interface SelectApi<Row> {\n /** Ordered visible columns (resolved: schema defaults when query.select is empty). */\n visible: SelectColumn[];\n /** The corresponding FieldDefs, same order. */\n fields: FieldDef<Row>[];\n /** Selectable fields not currently shown (for the \"add column\" picker). */\n hidden: FieldDef<Row>[];\n\n show: (field: string) => void;\n hide: (field: string) => void;\n /** Reorder via drag-drop: move `field` to `toIndex` in the visible order. */\n move: (field: string, toIndex: number) => void;\n /** Set a column's pixel width. */\n setWidth: (field: string, width: number) => void;\n /** Reset to the schema's default columns (clears query.select). */\n reset: () => void;\n}\n\ntype SetQuery = (next: QueryState | ((prev: QueryState) => QueryState)) => void;\n\nexport function useSelect<Row>(query: QueryState, setQuery: SetQuery, schema: FieldSchema<Row>): SelectApi<Row> {\n const fields = useMemo(() => selectedFields(schema, query), [schema, query]);\n\n // The materialized SelectColumn[] (resolve defaults so the UI always has a\n // concrete, reorderable list even before the user customizes it).\n const visible = useMemo<SelectColumn[]>(() => fields.map((f) => columnFor(query.select, f.name)), [fields, query.select]);\n\n const hidden = useMemo<FieldDef<Row>[]>(() => {\n const shown = new Set(fields.map((f) => f.name));\n return schema.fields.filter((f) => !shown.has(f.name) && (f.select?.enabled ?? true));\n }, [schema, fields]);\n\n const writeSelect = useCallback(\n (mutate: (cols: SelectColumn[]) => SelectColumn[]) => {\n setQuery((prev) => {\n // Materialize current (resolved) columns the first time we diverge from defaults.\n const current = prev.select.length ? prev.select : visible;\n return { ...prev, select: mutate([...current]) };\n });\n },\n [setQuery, visible],\n );\n\n const show = useCallback((field: string) => writeSelect((c) => (c.some((x) => x.field === field) ? c : [...c, { field }])), [writeSelect]);\n const hide = useCallback((field: string) => writeSelect((c) => c.filter((x) => x.field !== field)), [writeSelect]);\n const move = useCallback(\n (field: string, toIndex: number) =>\n writeSelect((c) => {\n const from = c.findIndex((x) => x.field === field);\n if (from === -1) return c;\n const [item] = c.splice(from, 1);\n c.splice(Math.max(0, Math.min(toIndex, c.length)), 0, item!);\n return c;\n }),\n [writeSelect],\n );\n const setWidth = useCallback(\n (field: string, width: number) =>\n writeSelect((c) => c.map((x) => (x.field === field ? { ...x, width: Math.round(width) } : x))),\n [writeSelect],\n );\n const reset = useCallback(() => setQuery((prev) => ({ ...prev, select: [] })), [setQuery]);\n\n return { visible, fields, hidden, show, hide, move, setWidth, reset };\n}\n\nfunction columnFor(select: SelectColumn[], name: string): SelectColumn {\n const found = select.find((c) => c.field === name);\n return found ?? { field: name };\n}\n","// useColumnDrag — transient, SHARED state for a column-reorder drag. One instance\n// is owned by useQueryTable and read by BOTH the table headers and the\n// QueryBuilder select chips, so a drag started in either surface live-previews\n// (and dims) the same column in the other. It holds no query state; the reorder\n// is committed to QueryState.select by whichever surface handles the drop.\n\nimport { useCallback, useMemo, useState } from \"react\";\n\nexport interface ColumnDragApi {\n /** Field name currently being dragged, or null when idle. */\n source: string | null;\n /** Insertion index within the order with `source` removed (0..n; n = append). */\n overIndex: number | null;\n /** True while a column drag is in progress. */\n active: boolean;\n /** Begin dragging `field`, initially previewed at `index` (its own slot). */\n start: (field: string, index: number) => void;\n /** Update the previewed insertion index (no-op if unchanged). */\n over: (index: number) => void;\n /** End the drag (on drop or cancel). */\n end: () => void;\n /** The live order to render while dragging: `source` moved to `overIndex`.\n * Returns `order` unchanged when idle, or when `source` isn't in `order`. */\n preview: (order: string[]) => string[];\n}\n\ninterface DragState {\n source: string;\n overIndex: number;\n}\n\nexport function useColumnDrag(): ColumnDragApi {\n const [state, setState] = useState<DragState | null>(null);\n\n const start = useCallback((field: string, index: number) => setState({ source: field, overIndex: index }), []);\n const over = useCallback(\n (index: number) =>\n // Keep the SAME object reference when unchanged so React can bail out of the\n // re-render — onDragOver fires continuously while the cursor moves.\n setState((s) => (s && s.overIndex !== index ? { source: s.source, overIndex: index } : s)),\n [],\n );\n const end = useCallback(() => setState(null), []);\n\n const preview = useCallback(\n (order: string[]): string[] => {\n if (!state) return order;\n const without = order.filter((n) => n !== state.source);\n if (without.length === order.length) return order; // source not part of this list\n const at = Math.max(0, Math.min(state.overIndex, without.length));\n return [...without.slice(0, at), state.source, ...without.slice(at)];\n },\n [state],\n );\n\n return useMemo(\n () => ({\n source: state?.source ?? null,\n overIndex: state?.overIndex ?? null,\n active: state != null,\n start,\n over,\n end,\n preview,\n }),\n [state, start, over, end, preview],\n );\n}\n","// useSavedQueries — named query snapshots over a StorageAdapter.\n//\n// \"Last query\" auto-restore and named saves both flow through the injected\n// StorageAdapter (in-memory by default, explicitly durable when the caller\n// provides one). Loading a saved query pushes its QueryState into the controller.\n\nimport { useCallback, useEffect, useState } from \"react\";\nimport type { QueryState, SavedQuery, StorageAdapter } from \"@pythia-software/query-table-core\";\n\nexport interface SavedQueriesApi {\n items: SavedQuery[];\n loading: boolean;\n /** Saved query id used as the default view when no query is specified. */\n defaultId: string | null;\n /** Persist the current query under a name. Rejects on duplicate names. */\n save: (name: string) => Promise<SavedQuery>;\n /** Load a saved query into the live controller. */\n load: (id: string) => void;\n /** Mark a saved query as the default view. No-op when storage lacks support. */\n setDefault: (id: string) => Promise<void>;\n /** Clear the saved-query default view. */\n clearDefault: () => Promise<void>;\n remove: (id: string) => Promise<void>;\n}\n\nexport function useSavedQueries(\n key: string,\n currentQuery: QueryState,\n applyQueryState: (q: QueryState) => void,\n storage: StorageAdapter,\n /** Injected clock so saves are deterministic/testable. */\n now: () => number,\n): SavedQueriesApi {\n const [items, setItems] = useState<SavedQuery[]>([]);\n const [defaultId, setDefaultId] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n\n const refresh = useCallback(async () => {\n setLoading(true);\n try {\n const [savedItems, defaultSaved] = await Promise.all([\n storage.listSaved(key),\n storage.loadDefaultSaved?.(key) ?? Promise.resolve(null),\n ]);\n setItems(savedItems);\n setDefaultId(defaultSaved?.id ?? null);\n } finally {\n setLoading(false);\n }\n }, [storage, key]);\n\n useEffect(() => {\n void refresh();\n }, [refresh]);\n\n const save = useCallback(\n async (name: string) => {\n const saved = await storage.saveNamed(key, name, currentQuery, now());\n await refresh();\n return saved;\n },\n [storage, key, currentQuery, now, refresh],\n );\n\n const load = useCallback(\n (id: string) => {\n const found = items.find((q) => q.id === id);\n if (found) applyQueryState(found.query);\n },\n [items, applyQueryState],\n );\n\n const setDefault = useCallback(\n async (id: string) => {\n await storage.setDefaultSaved?.(key, id);\n await refresh();\n },\n [storage, key, refresh],\n );\n\n const clearDefault = useCallback(async () => {\n await storage.setDefaultSaved?.(key, null);\n await refresh();\n }, [storage, key, refresh]);\n\n const remove = useCallback(\n async (id: string) => {\n if (id === defaultId) await storage.setDefaultSaved?.(key, null);\n await storage.deleteSaved(key, id);\n await refresh();\n },\n [storage, key, defaultId, refresh],\n );\n\n return { items, loading, defaultId, save, load, setDefault, clearDefault, remove };\n}\n"],"mappings":"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","names":["f","useCallback","useEffect","useMemo","useRef","useState","applyQuery","readFieldValue","selectedFields","toServerQuery","useEffect","useMemo","useState","useCallback","useMemo","useRef","useState","useCallback","useMemo","useCallback","useMemo","useState","useCallback","useEffect","useState","readFieldValue","useMemo","useRef","useState","useEffect","useCallback","toServerQuery","applyQuery","patch","selectedFields"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pythia-software/query-table-react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Schema-driven data table — headless React hooks.",
|
|
5
5
|
"keywords": ["data-table", "query-builder", "react", "hooks", "typescript"],
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"typecheck": "tsc --noEmit"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@pythia-software/query-table-core": "0.
|
|
36
|
+
"@pythia-software/query-table-core": "0.3.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"react": ">=18 <20"
|