Skip to content

Persistent saved views

The attached configurator’s Save views menu uses session snapshots by default. To keep named views after a page reload, configure the plugin instance with an explicit storage scope:

import { PivotPlugin, createBrowserPivotViewStorage } from '@revolist/pivot';
const pivot = (await grid.getPlugins()).find(plugin => plugin instanceof PivotPlugin);
pivot.setSavedViewStorage({
scope: `${authenticatedUserId}/${workspaceId}/${reportId}`,
storage: createBrowserPivotViewStorage(),
});

The menu can create a view, update it with the current report, restore it, rename it, delete it, or reload the saved list. Updates keep the name and identity. Persistent views contain validated portable report documents (V1 or V2) and row height. They do not contain source rows or serialized callbacks. Register runtime bindings with setPivotReportRuntime before restoring reports that require them. Portable reports use the existing validation, migration and preventable import lifecycle.

Use a separate scope for each authenticated user, workspace and report. Browser storage belongs to the origin and is not an authorization boundary. Clear or replace the integration when the authenticated user changes. pivot.setSavedViewStorage() returns the menu to session snapshots; it never deletes durable data. Every storage integration switch cancels pending restores and clears the detached session snapshots. Returning to session mode starts with an empty list, so previous user names and runtime bindings cannot reappear.

The browser adapter uses localStorage and origin-wide Web Locks for atomic comparisons between participating tabs. It requires a secure context with Web Locks for writes. It surfaces unsupported-browser, storage-disabled and quota errors. Applications needing a server store or a browser without Web Locks can implement PivotViewStorage:

import type { PivotViewStorage } from '@revolist/pivot';
const storage: PivotViewStorage = {
async read(scope, signal) { /* return the exact stored string, or null */ },
async compareAndSwap(scope, expected, next, signal) {
// Authorize scope on the server. Atomically replace only if the entire
// current value equals expected. Return false on conflict.
// Honor abort before committing. Do not implement a separate read/write pair.
},
};
pivot.setSavedViewStorage({ scope, storage });

Changes from another session cause a conflict rather than an overwrite. Select Reload views, inspect the latest list and retry. The library does not silently merge or automatically retry conflicting writes. All writers to the same browser key must use the same locking contract. A write already committed before cancellation cannot be undone.

A failed restore keeps the current report. Missing fields or runtime bindings are diagnosed; restore the host bindings, update the saved view with the current valid report, or delete that view. The field check conservatively requires the saved field catalog to exist in the current report. Malformed collection data is kept intact and never overwritten: back it up and repair it through the host storage, then select Reload views. A failed save retains the name draft so the user can retry.

The collection has a limit of 200 views and 2 million UTF-16 code units of serialized data. Actual browser storage quotas can be lower. clearPivot() cancels in-flight saved-view operations while keeping durable records; destroying the plugin or replacing storage retires the old manager and aborts pending restoration.