Skip to content

Saved reports and runtime bindings

A portable PivotReport contains field/measure IDs, axes, operation declarations, filters, ranking, totals and presentation. V2 explicitly admits derived fields and operation policies; opt into V2 parsing/execution. A native PivotConfig is a grid configuration, not the same persistence format.

Do not serialize source records, functions, DOM mounts, adapter instances, credentials or source revision callbacks as report authority. Restore named host bindings (sources, engines, aggregate callbacks, text callbacks) before executing a report that needs them. A missing binding is a recoverable integration error, not permission to fall back to a different engine.

const json = controller.exportReportJson();
// Send json to the application's authorized persistence endpoint.
// After restoring the matching runtime, parse/import with explicit V2 opt-in
// when the document uses version 2. Execute before updating the saved record.

The downloadable executable round-trips an executed V2 hierarchy through exportReportJson, explicit V2 parsing and serialization.

Use portable report APIs for exact V1/V2 parse/compile/serialize signatures. aggregationSemantics pins local/server execution; keep it with the existing operations when migrating. V1-only savePivotReport/loadPivotReport helpers are distinct from V1/V2 durable saved-view collections.

The stock attached menu is session-only unless configured. The public browser adapter supplies durable origin storage:

import { createBrowserPivotViewStorage } from '@revolist/pivot';
pivot.setSavedViewStorage({
scope: `${userId}/${workspaceId}/${reportId}`,
storage: createBrowserPivotViewStorage(),
});

Browser scopes separate application data but are not an authorization boundary. Browser writes require a secure context with Web Locks for atomic comparisons; storage-disabled/quota/unsupported errors remain visible. On user change replace/clear the storage integration. setSavedViewStorage() returns to a new empty session list without deleting durable records. Replacing storage cancels pending restores and retires the previous manager.

For a server store implement public PivotViewStorage.read and compareAndSwap with an authorized atomic compare-and-swap on the entire stored string. A separate read then write is not atomic. See Persistent saved views for the interface and failure behavior.

Setting/operationDefault/limitRecovery
Attached storageSession snapshotsInstall a durable adapter explicitly
Collection size200 views, 2000000 UTF-16 code unitsDelete/archive views; actual browser quota may be lower
Concurrent writeCompare-and-swap conflictReload views, inspect current state, retry explicitly
Failed saveDraft name retainedRepair storage/auth/quota and retry
Failed restoreCurrent report retainedRestore bindings/fields or repair/delete saved view
Malformed collectionNot overwrittenBack up and repair through host storage, then Reload views

Standalone configurator actions.viewManager.save/rename/remove may return a Promise; resolve only after durable host acceptance and reject on failure. list() and subscribe() stay synchronous: maintain a cached list and notify after changes. A write committed before cancellation cannot be undone by retiring the UI callback.

Authorize every server read/write against the authenticated user and workspace. Handle retention, sharing, encryption, conflict policy and schema migration in the application. Governed shared-view catalogs are deferred. Validate a restored report, reattach current runtime registries, execute it, inspect known KPIs, and only then announce success or save the migrated document.

For custom UIs attached to a grid use pivot.getAuthoringController() so history and committed state have one owner. It deliberately excludes source/runtime replacement and report.replace; use the plugin’s supported import path for report replacement. Standalone controllers expose their own full lifecycle. See custom integrations.