Skip to content

Configurator API

definePivotConfigurator(element, config, actions) mounts the stock panel in your own host and returns cleanup. It renders configuration controls; it does not execute Pivot or own the grid. A custom visual constructor can use the attached authoring facade instead.

The checked stock-panel recipe forwards onUpdateConfiguration(patch: PivotConfigurationPatch) to an awaited plugin.updatePivotConfig call. This combined patch contains changed rows, columns, values and filters, plus member selections pruned by that layout change; it is not an unrestricted arbitrary config patch. Removing a field from its final filterable role sends its placement and cleared criteria together in one update. Cross-zone/group moves use the same combined route. Its local draft composes pending edits, then reconciles from accepted runtime state after success, veto or failure. It handles filter selections, Reset and disposal too.

Source code
stock-panel.tstypescript
import { definePivotConfigurator, disposePivotConfigurator, type PivotPlugin, type PivotConfig, type PivotConfigurationActions, type PivotConfigurationPatch } from '@revolist/pivot';

/** Optional stock UI. Custom constructors use the attached command facade instead. */
export function mountStockConfigurator(host: HTMLElement, plugin: PivotPlugin, applicationSorting: Pick<PivotConfigurationActions, 'sorting' | 'onToggleSort'> = {}) {
  let disposed = false; let generation = 0;
  let draft: Partial<PivotConfig> = { ...plugin.getRuntimeSnapshot()?.config };
  const authoring = plugin.getAuthoringController();
  const error = document.createElement('p'); error.setAttribute('role', 'alert'); host.after(error);
  async function apply(patch: Partial<PivotConfig>) {
    const call = ++generation;
    draft = { ...draft, ...patch };
    try {
      const accepted = await plugin.updatePivotConfig(draft);
      if (!disposed && call === generation) {
        if (!accepted) error.textContent = 'Configuration was not committed';
        draft = { ...plugin.getRuntimeSnapshot()?.config };
        render();
      }
    } catch (failure) {
      if (!disposed && call === generation) { error.textContent = String(failure); draft = { ...plugin.getRuntimeSnapshot()?.config }; render(); }
    }
  }
  function render() {
    if (disposed) return;
    definePivotConfigurator(host, draft, {
      onUpdateConfiguration: (patch: PivotConfigurationPatch) => { void apply(patch); },
      onUpdateFilterSelections: filterSelections => { void apply({ filterSelections }); },
      ...applicationSorting,
      onResetLayout: () => { void (async () => {
        try {
          const outcome = await authoring.reset();
          if (!disposed && outcome.status === 'failed') error.textContent = outcome.error.message;
        } catch (failure) { if (!disposed) error.textContent = String(failure); }
      })(); },
    });
  }
  const unsubscribe = authoring.subscribe(() => {
    if (authoring.getSnapshot().status !== 'loading') { draft = { ...plugin.getRuntimeSnapshot()?.config }; render(); }
  });
  render();
  return () => { disposed = true; generation++; unsubscribe(); error.remove(); disposePivotConfigurator(host); };
}

For calculation settings, use the explicit aggregation contract. The UI selects configured operation IDs; it does not infer null, invalid or count policies from labels. Server calculation choices depend on advertised capabilities and actual backend support. Persist accepted operations and the execution pin together.

  • onUpdateConfiguration(PivotConfigurationPatch): preferred combined layout update, including optional filterSelections when layout changes prune member criteria.
  • onUpdateColumns, onUpdateRows, onUpdateValues, onUpdateFilters: ordered zone callbacks retained for compatibility; combined wiring avoids multiple regenerations for one action.
  • onUpdateFilterSelections: individual member-filter edits, using inclusive arrays or explicit exclusion selections. Individual zone and selection callbacks remain supported, but separate application callbacks cannot guarantee one atomic external update.
  • sorting and onToggleSort(prop): application-supplied public sorting integration. The restricted authoring facade does not invent a sorting command.
  • onResetLayout: application reset action.

Sorting callbacks are consumed by the compact definePivotFieldPanel; the full definePivotConfigurator currently has no sort control. Forwarding them to the full helper does not enable sorting. Apply sorting through the plugin or a separate application control. Mount only one stock panel per host. Its cleanup disposes Preact rendering and mount classes and removes the subscription. Application teardown owns the grid/plugin separately.

Embedded hasConfigurator uses the same underlying component and plugin admission. Visibility and translation settings remain showRows, showColumns, showValues, showFilters, i18n and field-panel texts. Role metadata and stable dimensions keep valid placements discoverable; backend permissions remain separate.

Constructor arguments and controlled updates

Section titled “Constructor arguments and controlled updates”
Interactive example

Controlled authoring

Create full/compact stock mount, apply combined atomic patch, reconcile acceptance

The example loads when visible.

definePivotConfigurator(el, config?, actions?, diagnostics?, templateContext?) returns a cleanup function. definePivotFieldPanel(el, config?, actions?, layout?, diagnostics?, templateContext?) mounts the compact variant. Both accept Partial<PivotConfig> and Partial<PivotConfigurationActions>; call the same helper again on its host with accepted config to update a controlled mount. Do not mutate a previously supplied config object and expect observation.

diagnostics accepts PivotUiDiagnostics (warnings?: string[], error?: string). templateContext supplies Core columnTypes and additionalData for existing field templates. The compact helper’s layout supplies generated columns, colSize, and optional resizedColumns for alignment with the table. These arguments describe UI context; they do not replace the analytical source.

Use a dedicated host. Cleanup disposes rendering, registrations and helper-added presentation classes/styles; dispose the helper before abandoning the host. Application code owns analytical subscriptions, backend work and grid disposal. All layout and display callbacks return void; await your own application update and re-render from accepted state, as the checked recipe does. A callback invocation or optimistic control state does not establish that a candidate was committed. plugin.updatePivotConfig(nextConfig) accepts a complete candidate, so merge a patch into the current authored draft rather than passing a partial patch directly.

PivotConfigurationActions memberIntegration contract
tableDropTargetAssociated table HTMLElement for direct field drops; scoped to this full configurator mount.
authoringExisting PivotAuthoringController used for full-panel Undo/Redo/status. The host still owns layout callback wiring.
onSaveViewFull-panel Save action; may return void or a Promise. Host owns persistence/export.
viewManagerFull-panel named-view manager; takes precedence over onSaveView.
onUpdateDisplayFull-panel PivotDisplayPatch callback for totals, values orientation, row-axis layout, flat headers and rowTree. Separate from PivotConfigurationPatch.
rowSizeCurrent Core grid row height for the full-panel density control.
onUpdateRowSizeFull-panel density callback; host updates the grid presentation. Density is not part of PivotConfig.
registerEditorRegisters a live PivotEditorBridge in either mount and returns its unregister cleanup.
loadFilterValuesAsync distinct member-choice loader in either mount. Explicit dimension filterOptions, including [], takes priority.
filterValuesContextScope lifecycle for async choices: getSnapshot() supplies revision/status and subscribe() supplies cleanup.

PivotDisplayPatch contains totals, valuesOnRows, rowAxisLayout, flatHeaders, and rowTree. Merge it into the current authored candidate through normal admission. Omission of onUpdateDisplay leaves a message explaining how to connect display controls. Density controls require onUpdateRowSize. These full-panel actions are not forwarded by the compact helper.

A PivotViewManager owns list(): readonly PivotNamedView[], subscribe(listener): () => void, save(name), rename(id, name), remove(id), and restore(id): Promise<boolean>. Named entries have immutable id and name. False from restore means the existing preventable update was not accepted. Payload storage and persistence live in the host; the native plugin’s built-in views last for the active Pivot session and disappear on close/reload.

PivotEditorBridge.canOpen(request) and open(request) handle an exact measure ID/prop or member field plus an origin element; a true result means UI scheduling was accepted. close() dismisses without applying or restoring focus. Keep only currently registered bridges, and revoke them on cleanup. Opening an editor does not change the report or persist a measure.

PivotFilterValuesLoader receives { field, search?, offset, limit, signal? } and resolves PivotFilterValuesResponse with values and totalCount. Return distinct finite scalar values for the requested fixed-offset window and a nonnegative safe-integer count for the matching scope. The page length must be min(limit, max(totalCount - offset, 0)); an approximate count with short pages is not this contract. Typed values such as 1 and '1' are distinct. Respond to the abort signal and keep paging/search ordering consistent.

Choices represent the current source/query scope excluding the edited field’s own member selection. Preserve selected members outside the current page/search. Standalone hosts must supply filterValuesContext or replace the loader whenever an otherwise invisible source/query scope changes. Notify for pending transitions even at the same revision; loading/inactive/destroyed scopes pause new edits. The host owns execution capabilities and authorization. Omission of a loader does not create a backend enumeration endpoint; existing selected members can still be removed or cleared when choices are unavailable.

Both stock constructors offer Add field for each visible area and an Actions button for each placed field. Actions can assign a field, move it earlier or later, duplicate an exact measure, or remove it. Clear affects one area. Search and destination choices respect field visibility and allowed roles; unavailable actions explain why they cannot run.

Rows and Columns are exclusive placements. Moving between them preserves independent Values and Filters. Adding a field to Values does not replace existing measures: use Duplicate measure to copy one exact measure with its settings and a fresh ID. Clearing Values preserves member criteria; removing a field from its final Rows, Columns or Filters placement prunes that field’s criteria in the same combined patch.

Use fieldPanel.allowFieldActions: false to hide the new Add, Actions and Clear controls. It defaults to true and is independent of allowFieldDragging; disabling dragging still permits keyboard actions. allowFieldRemoving controls Remove and Clear, defaulting to true in the full configurator and false in the compact panel. An explicit false now also suppresses the existing full-configurator Remove buttons. These options control UI availability, not application authorization.

Individual callback integrations must supply every callback needed by an action. For example, moving between axes requires both axis callbacks; removing the final filterable placement can also require onUpdateFilterSelections. An incomplete integration disables that action. Prefer the combined callback for atomic owner updates. Stock callbacks return void, so an optimistic control change does not establish that an application accepted or persisted the report. The checked recipe above handles acceptance and reconciliation explicitly.

Interactive example

Measure settings

Stage edits, target stable IDs through reorder, reload conflict, preserve advanced settings

The example loads when visible.

In either stock constructor, open a measure’s Actions → Edit measure to stage its display label, aggregation, numeric formatting, calculation and summary operations. Typing and selecting leave the report unchanged until Apply; Cancel or Escape discards the draft. The editor is an inline region, so it also works in standalone mounts without a grid-owned dialog. The existing aggregation selector remains available for quick changes.

A blank display label clears only the label override and reveals the existing measure name or field caption shown in the preview. The source field and stable measure ID stay unchanged. Measures using the same source field are edited independently; supply distinct IDs when configuring them. An existing aggregation absent from the current registry is preserved during label-only edits. New choices come from the matching dimension’s aggregator registry, with the same defaults as the quick selector; the analytical owner still validates execution support.

Apply merges changed settings into the latest exact measure and preserves its other metadata. A draft follows a unique stable ID through reorder. If a setting being edited changes externally, reload current settings or cancel before applying. Returning an input to its opening value relinquishes that draft change. Removed or ambiguous targets cannot be applied; measures without IDs are conservatively invalidated by external replacement or reorder.

Editing requires onUpdateConfiguration or onUpdateValues, visible Values and enabled field actions. Dragging and removal flags do not disable settings editing. Apply submits through the existing void callback contract; it does not certify persistence. Standalone applications own callback exceptions, admission and controlled reconciliation in both individual immediate and scheduled combined integrations. The native plugin owns proposal-veto and asynchronous-failure reconciliation.

Expand Format to select Number, Currency or Percent, set optional minimum and maximum decimal places, and keep, remove or override the current locale. Blank decimal bounds use Intl defaults; entered bounds must be integers from 0 to 20, with minimum no greater than maximum. Currency requires an explicit code. The preview uses an illustrative sample, not the current aggregate. Invalid drafts stay local and cannot be applied. Automatic removes the explicit format override and uses report defaults, including calculation formatting.

Existing date and advanced formats are preserved until you deliberately replace them. Changing the preset replaces preset-specific options; the editor explains which common settings are retained or replaced. Basic label and aggregation edits preserve untouched formatting. A dirty format conflicts with any external replacement of that format object; reload to establish the new baseline. Reverting format controls restores the original format reference. Formatting affects displayed values; raw analytical values and raw data exports retain their numbers.

Expand Show values as for percentages of grand, row, column or parent totals, index, running totals, percent running totals, rank, and differences or percent differences from the previous or next member. Sequence calculations require a field on the selected current axis. They follow the current cube order within each parent; selecting a date field does not create chronological sorting. Missing comparisons and zero denominators produce null results, blank by default; explicit null-display formatting still applies. Running totals treat missing values as zero. No calculation clears the override.

Calculations change analytical result numbers; number formatting only changes their display. Original source facts remain unchanged. A percentage calculation produces a fraction, and an explicit format can override its default percentage presentation. Existing formula ASTs and comparisons with explicit member bases are preserved as advanced settings. This editor does not create formulas or arbitrary member-base comparisons; their existing typed APIs remain available.

Expand Summary operations to choose separate registered operations for group/subtotal/collapsed coordinates and grand totals. Each scope can inherit the leaf aggregation; grand totals do not inherit the group override. These operations aggregate the original eligible facts, so averaging displayed averages is not equivalent. Grand-total scope takes precedence at intersections. The controls do not turn on visible totals, and existing collapsed-column operation overrides retain their own policy.

Independent summary overrides require local execution without a supplied adapter or remote store. Formula summaries belong to their dependency measures. Remote calculation choices require explicit engine support; omitted or opaque capability information does not establish support. Native mounts receive their engine configuration automatically. Standalone constructors can pass the existing optional engine configuration; omitting it assumes local configuration authoring, with execution admission still owned by the host. Current unsupported settings remain preservable during unrelated edits.

Calculation and summary drafts own separate references. An external replacement of a setting being edited requires Reload or Cancel, while untouched settings follow the latest measure. Returning controls to their opening settings restores the original reference and relinquishes the change. Apply submits all changed measure settings together. Analytical changes may recompute or request data; the formatting-only request-reuse guarantee does not apply to them.