@deephaven/iris-grid 1.22.2-alpha-pivot-builder.0 → 1.23.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/dist/IrisGrid.js CHANGED
@@ -272,8 +272,8 @@ class IrisGrid extends Component {
272
272
  /**
273
273
  * Apply the `transformTableOptions` transform (if any) to the
274
274
  * default option list.
275
- * Catches exceptions so a buggy plugin can't break the grid,
276
- * and warns about duplicate `type` collisions.
275
+ * Catches exceptions so a buggy plugin can't break the grid, and collapses
276
+ * duplicate `type` entries (last writer wins) before sorting by `order`.
277
277
  */
278
278
  _defineProperty(this, "getCachedTransformedOptionItems", memoize((items, transformTableOptions) => {
279
279
  if (transformTableOptions == null) {
@@ -286,11 +286,23 @@ class IrisGrid extends Component {
286
286
  log.error('transformTableOptions threw an error; falling back to defaults.', err);
287
287
  return items;
288
288
  }
289
+ // Collapse duplicate `type` entries before sorting. A duplicate `type`
290
+ // would otherwise collide on the `<Menu>` / `<Page>` React key and cause
291
+ // incorrect page reuse. Per the documented composition rule (see the
292
+ // package README), the last writer wins: a later entry — e.g. from a
293
+ // downstream middleware — overrides an earlier one with the same type.
294
+ // `Map.set` keeps the most recent value while preserving the original
295
+ // insertion slot, so an override stays in place unless it changes
296
+ // `order`.
297
+ var byType = new Map();
298
+ transformedItems.forEach(item => {
299
+ byType.set(String(item.type), item);
300
+ });
289
301
  // Stably sort by ascending `order`. Items without an `order` sink to
290
302
  // the end of the menu (default `Infinity`), while items with an `order`
291
303
  // are positioned by their weight. Decorate-sort-undecorate guarantees
292
304
  // stability regardless of the engine's sort implementation.
293
- var sortedItems = transformedItems.map((item, index) => ({
305
+ var sortedItems = [...byType.values()].map((item, index) => ({
294
306
  item,
295
307
  index
296
308
  })).sort((a, b) => {
@@ -300,15 +312,6 @@ class IrisGrid extends Component {
300
312
  var item = _ref2.item;
301
313
  return item;
302
314
  });
303
- var keys = new Set();
304
- for (var i = 0; i < sortedItems.length; i += 1) {
305
- var key = String(sortedItems[i].type);
306
- if (keys.has(key)) {
307
- log.warn("transformTableOptions produced duplicate type \"".concat(key, "\"; ") + 'only the first entry will be accessible from the menu.');
308
- break;
309
- }
310
- keys.add(key);
311
- }
312
315
  return Object.freeze(sortedItems);
313
316
  }, {
314
317
  max: 1
@@ -316,6 +319,17 @@ class IrisGrid extends Component {
316
319
  _defineProperty(this, "getCachedHiddenColumns", memoize((metricCalculator, userColumnWidths) => IrisGridUtils.getHiddenColumns(new Map([...metricCalculator.initialColumnWidths, ...userColumnWidths])), {
317
320
  max: 1
318
321
  }));
322
+ _defineProperty(this, "getCachedHiddenColumnNames", memoize((hiddenColumns, columns) => Object.freeze(hiddenColumns.map(idx => {
323
+ var _columns$idx;
324
+ return (_columns$idx = columns[idx]) === null || _columns$idx === void 0 ? void 0 : _columns$idx.name;
325
+ }).filter(n => n != null)), {
326
+ max: 1
327
+ }));
328
+ _defineProperty(this, "getCachedViewState", memoize(hiddenColumns => Object.freeze({
329
+ hiddenColumns
330
+ }), {
331
+ max: 1
332
+ }));
319
333
  _defineProperty(this, "getAggregationMap", memoize((columns, aggregations) => {
320
334
  var aggregationMap = {};
321
335
  aggregations.forEach(_ref3 => {
@@ -602,7 +616,7 @@ class IrisGrid extends Component {
602
616
  this.handleHeaderGroupsChanged = this.handleHeaderGroupsChanged.bind(this);
603
617
  this.handleUpdate = this.handleUpdate.bind(this);
604
618
  this.handleTableChanged = this.handleTableChanged.bind(this);
605
- this.handleModelChanged = this.handleModelChanged.bind(this);
619
+ this.handleSchemaChanged = this.handleSchemaChanged.bind(this);
606
620
  this.handleTooltipRef = this.handleTooltipRef.bind(this);
607
621
  this.handleViewChanged = this.handleViewChanged.bind(this);
608
622
  this.handleFormatSelection = this.handleFormatSelection.bind(this);
@@ -727,17 +741,18 @@ class IrisGrid extends Component {
727
741
  }
728
742
  var _movedColumns = movedColumnsProp.length > 0 ? movedColumnsProp : _model.initialMovedColumns;
729
743
  var movedRows = movedRowsProp.length > 0 ? movedRowsProp : _model.initialMovedRows;
730
- var metricCalculatorFactory = getMetricCalculator;
731
- var _metricCalculator = metricCalculatorFactory({
744
+ var _metricCalculator = getMetricCalculator({
732
745
  userColumnWidths: new Map(_userColumnWidths),
733
746
  userColumnWidthsByName: userColumnWidthsByName != null ? new Map(userColumnWidthsByName) : undefined,
734
747
  userRowHeights: new Map(userRowHeights),
735
748
  movedColumns: _movedColumns,
736
749
  initialColumnWidths: new Map(_model === null || _model === void 0 || (_model$layoutHints = _model.layoutHints) === null || _model$layoutHints === void 0 || (_model$layoutHints = _model$layoutHints.hiddenColumns) === null || _model$layoutHints === void 0 ? void 0 : _model$layoutHints.map(name => [_model.getColumnIndexByName(name), 0]))
737
750
  });
738
- // Remember the factory we used so we can detect a model-driven swap
739
- // (e.g. pivot-builder's proxy swapping its inner model) on COLUMNS_CHANGED.
740
- this.lastMetricCalculatorFactory = metricCalculatorFactory;
751
+ // Remember the factory we used so `maybeRebuildMetricCalculator` (called
752
+ // from `componentDidUpdate` when the `getMetricCalculator` prop changes)
753
+ // can detect a model-driven swap, e.g. pivot-builder's proxy swapping its
754
+ // inner model.
755
+ this.lastMetricCalculatorFactory = getMetricCalculator;
741
756
  var searchColumns = _selectedSearchColumns !== null && _selectedSearchColumns !== void 0 ? _selectedSearchColumns : [];
742
757
  var _searchFilter = CrossColumnSearch.createSearchFilter(_dh, _searchValue, searchColumns, _model.columns, _invertSearchColumns);
743
758
  this.tableUtils = new TableUtils(_dh);
@@ -857,7 +872,7 @@ class IrisGrid extends Component {
857
872
  // component state, so mirror that path when the `getMetricCalculator` prop
858
873
  // changes (e.g. the pivot-builder middleware swapping the pivot factory in
859
874
  // or out) so the calculator stays in sync. Moved columns are not touched
860
- // here — a model swap resets them via `handleModelChanged`.
875
+ // here — a model swap resets them via `handleSchemaChanged`.
861
876
  if (getMetricCalculator !== prevProps.getMetricCalculator) {
862
877
  this.maybeRebuildMetricCalculator();
863
878
  }
@@ -1705,7 +1720,7 @@ class IrisGrid extends Component {
1705
1720
  model.addEventListener(IrisGridModel.EVENT.PENDING_DATA_UPDATED, this.handlePendingDataUpdated);
1706
1721
  model.addEventListener(IrisGridModel.EVENT.VIEWPORT_UPDATED, this.handleViewportUpdated);
1707
1722
  model.addEventListener(IrisGridModel.EVENT.TABLE_CHANGED, this.handleTableChanged);
1708
- model.addEventListener(IrisGridModel.EVENT.MODEL_CHANGED, this.handleModelChanged);
1723
+ model.addEventListener(IrisGridModel.EVENT.SCHEMA_CHANGED, this.handleSchemaChanged);
1709
1724
  }
1710
1725
  stopListening(model) {
1711
1726
  model.removeEventListener(IrisGridModel.EVENT.UPDATED, this.handleUpdate);
@@ -1716,7 +1731,7 @@ class IrisGrid extends Component {
1716
1731
  model.removeEventListener(IrisGridModel.EVENT.PENDING_DATA_UPDATED, this.handlePendingDataUpdated);
1717
1732
  model.removeEventListener(IrisGridModel.EVENT.VIEWPORT_UPDATED, this.handleViewportUpdated);
1718
1733
  model.removeEventListener(IrisGridModel.EVENT.TABLE_CHANGED, this.handleTableChanged);
1719
- model.removeEventListener(IrisGridModel.EVENT.MODEL_CHANGED, this.handleModelChanged);
1734
+ model.removeEventListener(IrisGridModel.EVENT.SCHEMA_CHANGED, this.handleSchemaChanged);
1720
1735
  }
1721
1736
  focus() {
1722
1737
  var _this$grid3;
@@ -2482,6 +2497,16 @@ class IrisGrid extends Component {
2482
2497
  * Clear the loading scrim in response to a model-driven `PENDING_CLEARED`
2483
2498
  * event. Only needed for operations that do not naturally end in
2484
2499
  * `UPDATED`/`COLUMNS_CHANGED`/`REQUEST_FAILED`.
2500
+ *
2501
+ * The current contract assumes a single outstanding model-driven operation:
2502
+ * `handlePending` collapses concurrent `PENDING` events into one scrim, so
2503
+ * this clears unconditionally. That is consistent with the existing scrim,
2504
+ * which any model stop signal already clears regardless of what else is in
2505
+ * flight. Ref-counting overlapping operations is intentionally deferred to
2506
+ * the planned migration that routes the built-in `startLoading` calls
2507
+ * through `PENDING`/`PENDING_CLEARED`; only once every raise/clear goes
2508
+ * through this pair can a depth counter stay balanced (a counter added now
2509
+ * would desync against the direct `startLoading` callers).
2485
2510
  */
2486
2511
  handlePendingCleared() {
2487
2512
  this.stopLoading();
@@ -2528,7 +2553,7 @@ class IrisGrid extends Component {
2528
2553
  }
2529
2554
 
2530
2555
  /**
2531
- * Handle an inner-model swap on a proxy model (`MODEL_CHANGED`). The previous
2556
+ * Handle an inner-model swap on a proxy model (`SCHEMA_CHANGED`). The previous
2532
2557
  * model's `movedColumns` reference indices that may not exist in the new
2533
2558
  * model (e.g. a pivot exposes a different column set), so reset them to the
2534
2559
  * new model's initial order. The metric calculator is rebuilt separately when
@@ -2536,7 +2561,7 @@ class IrisGrid extends Component {
2536
2561
  * whose seed `movedColumns` are now stale self-heals because `getMetrics`
2537
2562
  * reconciles against the grid's current `movedColumns` at draw time.
2538
2563
  */
2539
- handleModelChanged() {
2564
+ handleSchemaChanged() {
2540
2565
  var model = this.props.model;
2541
2566
  this.setState({
2542
2567
  movedColumns: model.initialMovedColumns
@@ -2761,8 +2786,8 @@ class IrisGrid extends Component {
2761
2786
  * carried over: a factory swap means the column set has effectively changed,
2762
2787
  * so the stored sizes wouldn't map to anything meaningful.
2763
2788
  *
2764
- * Moved columns are NOT reset here — that is owned by `handleModelChanged`
2765
- * (the `MODEL_CHANGED` event) so that a plain prop swap against the same
2789
+ * Moved columns are NOT reset here — that is owned by `handleSchemaChanged`
2790
+ * (the `SCHEMA_CHANGED` event) so that a plain prop swap against the same
2766
2791
  * model preserves the user's layout. The new calculator is seeded with the
2767
2792
  * current moved columns; `getMetrics` reconciles against the grid's live
2768
2793
  * `movedColumns` at draw time, so a later reset stays consistent.
@@ -2770,17 +2795,16 @@ class IrisGrid extends Component {
2770
2795
  maybeRebuildMetricCalculator() {
2771
2796
  var _model$layoutHints4;
2772
2797
  var getMetricCalculator = this.props.getMetricCalculator;
2773
- var factory = getMetricCalculator;
2774
- if (factory === this.lastMetricCalculatorFactory) return;
2798
+ if (getMetricCalculator === this.lastMetricCalculatorFactory) return;
2775
2799
  var model = this.props.model;
2776
2800
  var movedColumns = this.state.movedColumns;
2777
- var next = factory({
2801
+ var next = getMetricCalculator({
2778
2802
  userColumnWidths: new Map(),
2779
2803
  userRowHeights: new Map(),
2780
2804
  movedColumns,
2781
2805
  initialColumnWidths: new Map(model === null || model === void 0 || (_model$layoutHints4 = model.layoutHints) === null || _model$layoutHints4 === void 0 || (_model$layoutHints4 = _model$layoutHints4.hiddenColumns) === null || _model$layoutHints4 === void 0 ? void 0 : _model$layoutHints4.map(name => [model.getColumnIndexByName(name), 0]))
2782
2806
  });
2783
- this.lastMetricCalculatorFactory = factory;
2807
+ this.lastMetricCalculatorFactory = getMetricCalculator;
2784
2808
  log.debug('Swapping metric calculator', next);
2785
2809
  // Also push the new calculator onto the Grid synchronously so any
2786
2810
  // immediately-following read of `Grid.metricCalculator` (before React has
@@ -3890,9 +3914,9 @@ class IrisGrid extends Component {
3890
3914
  }
3891
3915
  return /*#__PURE__*/_jsx(PluginTableOptionsErrorBoundary, {
3892
3916
  itemType: String(option.type),
3893
- onBack: this.handleMenuBack,
3894
3917
  children: /*#__PURE__*/_jsx(PluginPage, {
3895
3918
  model: model,
3919
+ viewState: this.getCachedViewState(this.getCachedHiddenColumnNames(hiddenColumns, model.columns)),
3896
3920
  onBack: this.handleMenuBack
3897
3921
  })
3898
3922
  }, String(option.type));