Data Fetching & Caching
Selection filters, value dialogs, notes and history/audit storage have different domain contracts. Their typed adapters use the same Query engine while retaining existing callbacks. They are opt-in: local synchronous providers and local formula calculation remain unchanged. There is no additional adapter package to install.
Configuration types and ownership
Section titled “Configuration types and ownership”ProviderQueryOptions is exported from @revolist/revogrid-pro. It describes
one-shot reads: source, resource, staleTime, gcTime, retry,
retryDelay, networkMode, meta and onStatus. Native callback types and values
follow configuration types. Default freshness is 0;
private contexts use the shared read defaults. Pass false to factories accepting
it for uncached reads. Polling, enabled, focus and reconnect policies require a
mounted observer and are deliberately absent from this one-shot type.
ValueSelectionDialogOpenOptions<T>.query uses the full
LoadQueryOptions<ValueSelectionDialogPage<T>> | false type: native polling,
focus/reconnect, enabled, consistency, reconciliation and status apply while the
dialog is open. Omitting it or passing false retains the original direct
loadValues({search, signal}) behavior. Search debounce and draft selection stay
in the dialog. Search replacement, every dialog close path and grid destruction
release the current observer and stop polling. Polling errors can recover on the
next read without discarding the draft.
A shared source must include tenant and authorization identity. Set resource to
include an endpoint, column and relevant filter/report context hidden in callback
closures. Keys retain request fields such as search text, note targets, exact row
batches and cursor/limit. Shared scopes coalesce equivalent
in-flight requests; distinct semantic keys remain separate. Results must be
structured-cloneable and are detached before consumers can edit them. Live
renderers, DOM nodes and callbacks must not be used as query keys. Normalize Date,
Map, Set and custom instances into primitive key fields.
| Owner / public factory | Existing callback and result | Integration and lifetime |
|---|---|---|
Pro createFilterQueryProvider(getItems, query?) | Existing GetItemsFn(prop, {search?,signal?}?) returns SelectionItem[]. | Pass returned getItems to selection.getItems. Filter search debounce and cancellation remain unchanged. dispose() releases this wrapper; accepted() fences its scope after a known external change. |
Pro value dialog open({ ..., query }) | Existing loadValues({search,signal}) returns {values,totalCount}. | Mounted only while open. Include column/filter identity in query.resource. Existing key/label/template/apply/clear callbacks are unchanged. |
Pro createGridNotesQueryAdapter(adapter, query?) | Existing GridNoteStorageAdapter methods and results, including mutationId and expectedVersion. | One wrapper per notes owner; share query.source between owners. Notes batches/projections, permissions, conflict handling, retry policy and version history stay in Notes. Owner destroy() releases reads; a later init() can reactivate it. |
Pro createGridNoteMentionsQueryProvider(mentions, query?) | Existing search(query, signal?) returns users. | Pass to gridNotes.mentions; host owns dispose() when removing this integration. UI debounce remains unchanged. |
Pro createHistoryQueryAdapter(storage, query?) | Existing optional load(), save(state), clear(). | Only present methods are exposed. Source IDs, provider ordering, timestamps, local-edit guards and undo/redo stay in History. Host disposes the wrapper on config removal/grid teardown. |
Pro createAuditHistoryQueryAdapter(storage, query?) | Existing optional load(), save(records), append(record,records), clear(). | Audit IDs, append order and restoration remain audit-owned. Host disposes the wrapper on config removal/grid teardown. |
All wrappers except the mentions helper expose accepted() to invalidate their
shared read scope after a confirmed external write. Successful storage/note writes
fence reads automatically. Thrown
writes do not. Cache/status notification failures cannot turn a confirmed write
into a failed write or cause a second submission. The original backend callbacks
still own durability and authorization; these legacy results do not become
command receipts.
Selection filters and dialogs
Section titled “Selection filters and dialogs”import { createDataQueryContext, createFilterQueryProvider,} from '@revolist/revogrid-pro';import type { ProviderQueryOptions } from '@revolist/revogrid-pro';
const context = createDataQueryContext();const source = context.source({ sourceId: 'workspace-api', schemaId: '1', tenantId: tenant.id, authorizationScope: session.permissionRevision,});const query: ProviderQueryOptions = { source, resource: 'orders/country-values', staleTime: 30_000, retry: 2,};const values = createFilterQueryProvider(existingGetItems, query);grid.filter = { ...existingFilterConfig, selection: { ...existingFilterConfig.selection, getItems: values.getItems },};
valueDialog.open({ ...existingDialogOptions, query: { source, resource: 'orders/country-dialog', refetchInterval: 10_000, refetchIntervalInBackground: true, retry: false, },});// On integration removal, after closing the dialog/removing grids:values.dispose();context.dispose();Synchronous structuredFilterAggregates.get/getPrepared supply already prepared
aggregate data. They remain synchronous and are not reinterpreted as network
callbacks. Application code may fetch data first, then provide those models.
Notes and storage
Section titled “Notes and storage”import { createGridNotesQueryAdapter, createGridNoteMentionsQueryProvider, createHistoryQueryAdapter, createAuditHistoryQueryAdapter,} from '@revolist/revogrid-pro';
const notes = createGridNotesQueryAdapter(existingNoteAdapter, { source, resource: 'orders/notes', staleTime: 30_000,});const mentions = createGridNoteMentionsQueryProvider(existingMentions, { source, resource: 'workspace/users', staleTime: 30_000,});grid.gridNotes = { ...existingNotesConfig, adapter: notes, mentions };
const history = createHistoryQueryAdapter(existingHistoryStorage, { source, resource: 'orders/undo-history',});grid.history = { storage: 'custom', sourceId: 'orders', storageAdapter: history };const audit = createAuditHistoryQueryAdapter(existingAuditStorage, { source, resource: 'orders/audit-history',});grid.auditHistory = { storage: 'custom', storageAdapter: audit };Note summary batching and loaded-row state remain in GridNoteStore. The optional second
loadSummaries(input, context?) argument {fresh?: boolean} marks explicit forced refreshes;
refreshNotes(rowKeys) sets it through the store, and the adapter bypasses cached
summary freshness. Ordinary existing adapters may ignore this extra argument; the existing input object is unchanged.
After a confirmed foreign note change, call await notes.accepted() to fence all
note read targets, then await notesPlugin.refreshNotes(rowKeys) to update its
projection. A Query invalidation alone does not replace a note store’s projection.
History and audit loads remain one-shot; their existing controllers decide whether
a result may hydrate. Wrapped reads return Promises, even if a supplied storage
adapter is synchronous. Leave local memory/browser adapters unwrapped when
synchronous loading is required. These wrappers add no write retries; Notes’
existing retry and idempotency policy remains with Notes.
Removing an integration does not remove durable data. Dispose application-owned history, audit and mention wrappers after detaching their consumers; Notes owns the wrapper supplied to its config. Dispose the shared context only after all owners have stopped using it. History/audit callbacks have no transport signal parameter: disposal rejects pending subscribers and discards late results, but cannot physically abort an opaque backend operation that ignores cancellation.