@deephaven/js-plugin-pivot 0.1.0 → 0.2.1-dev.1002

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.
Files changed (2) hide show
  1. package/dist/index.js +397 -421
  2. package/package.json +10 -10
package/dist/index.js CHANGED
@@ -10,8 +10,8 @@ const plugin = require("@deephaven/plugin");
10
10
  const icons = require("@deephaven/icons");
11
11
  const React = require("react");
12
12
  const irisGrid = require("@deephaven/iris-grid");
13
- const jsapiBootstrap = require("@deephaven/jsapi-bootstrap");
14
13
  const components = require("@deephaven/components");
14
+ const jsapiBootstrap = require("@deephaven/jsapi-bootstrap");
15
15
  const Log = require("@deephaven/log");
16
16
  const jsapiUtils = require("@deephaven/jsapi-utils");
17
17
  const dashboardCorePlugins = require("@deephaven/dashboard-core-plugins");
@@ -499,9 +499,6 @@ function isEditableGridModel(model) {
499
499
  function isExpandableGridModel(model) {
500
500
  return (model === null || model === void 0 ? void 0 : model.hasExpandableRows) !== void 0;
501
501
  }
502
- function isExpandableColumnGridModel(model) {
503
- return (model === null || model === void 0 ? void 0 : model.hasExpandableColumns) !== void 0;
504
- }
505
502
  var NAN = 0 / 0;
506
503
  var symbolTag = "[object Symbol]";
507
504
  var reTrim = /^\s+|\s+$/g;
@@ -7311,20 +7308,20 @@ class GridColumnSeparatorMouseHandler extends GridSeparatorMouseHandler$1 {
7311
7308
  var {
7312
7309
  x,
7313
7310
  y,
7314
- columnHeaderDepth
7311
+ columnHeaderDepth: depth
7315
7312
  } = gridPoint;
7316
7313
  var {
7317
7314
  modelColumns
7318
7315
  } = metrics;
7319
7316
  var separatorIndex = GridUtils.getColumnSeparatorIndex(x, y, metrics, theme);
7320
- if (separatorIndex == null || columnHeaderDepth == null || columnHeaderDepth > 0) {
7317
+ if (separatorIndex == null || depth == null) {
7321
7318
  return null;
7322
7319
  }
7323
7320
  var columnIndex = modelColumns.get(separatorIndex);
7324
7321
  if (columnIndex != null) {
7325
7322
  return {
7326
7323
  index: separatorIndex,
7327
- depth: 0
7324
+ depth
7328
7325
  };
7329
7326
  }
7330
7327
  return null;
@@ -9978,7 +9975,14 @@ function makeColumn({
9978
9975
  isSortable = false,
9979
9976
  depth = ROOT_DEPTH,
9980
9977
  hasChildren = false,
9981
- isExpanded = false
9978
+ isExpanded = false,
9979
+ isProxy = false,
9980
+ filter = () => {
9981
+ throw new Error("Filter not implemented for virtual column");
9982
+ },
9983
+ sort = () => {
9984
+ throw new Error("Sort not implemented for virtual column");
9985
+ }
9982
9986
  }) {
9983
9987
  return {
9984
9988
  name,
@@ -9986,18 +9990,14 @@ function makeColumn({
9986
9990
  type,
9987
9991
  isPartitionColumn: false,
9988
9992
  isSortable,
9989
- isProxy: false,
9993
+ isProxy,
9990
9994
  description,
9991
9995
  index,
9992
9996
  depth,
9993
9997
  hasChildren,
9994
9998
  isExpanded,
9995
- filter: () => {
9996
- throw new Error("Filter not implemented for virtual column");
9997
- },
9998
- sort: () => {
9999
- throw new Error("Sort not implemented for virtual column");
10000
- },
9999
+ filter,
10000
+ sort,
10001
10001
  formatColor: () => {
10002
10002
  throw new Error("Color not implemented for virtual column");
10003
10003
  },
@@ -10030,7 +10030,7 @@ function makeColumnGroupName(keys2, columnSources, depth) {
10030
10030
  function makeValueSourceColumnName(columnName, valueSource) {
10031
10031
  return `${columnName}/${valueSource.name}`;
10032
10032
  }
10033
- function makeExpandableDisplayColumn(snapshotDim, valueSource, originalIndex, offset) {
10033
+ function makeColumnFromSnapshot(snapshotDim, valueSource, originalIndex, offset) {
10034
10034
  const keys2 = snapshotDim.getKeys(originalIndex);
10035
10035
  const depth = snapshotDim.getDepth(originalIndex);
10036
10036
  const hasChildren = snapshotDim.hasChildren(originalIndex);
@@ -10052,7 +10052,7 @@ function makeExpandableDisplayColumn(snapshotDim, valueSource, originalIndex, of
10052
10052
  hasChildren
10053
10053
  });
10054
10054
  }
10055
- function makePlaceholderDisplayColumn(valueSource, originalIndex, offset) {
10055
+ function makePlaceholderColumn(valueSource, originalIndex, offset) {
10056
10056
  return makeColumn({
10057
10057
  name: makePlaceholderColumnName(originalIndex, valueSource),
10058
10058
  displayName: "",
@@ -10063,21 +10063,30 @@ function makePlaceholderDisplayColumn(valueSource, originalIndex, offset) {
10063
10063
  hasChildren: false
10064
10064
  });
10065
10065
  }
10066
- function makeRowSourceColumn(source, index) {
10066
+ function makeColumnFromSource(source, index) {
10067
10067
  const { name, type, isSortable, description } = source;
10068
- return makeColumn({ name, type, index, isSortable, description });
10068
+ return makeColumn({
10069
+ name,
10070
+ type,
10071
+ index,
10072
+ isSortable,
10073
+ description,
10074
+ filter: source.filter.bind(source),
10075
+ sort: source.sort.bind(source)
10076
+ });
10069
10077
  }
10070
10078
  function checkColumnsChanged(prevColumns, newColumns) {
10071
10079
  return prevColumns.length !== newColumns.length || prevColumns.some((col, i) => col.name !== newColumns[i].name);
10072
10080
  }
10073
- function getKeyColumnGroups(columnSources, rowSources) {
10081
+ function makeKeyColumnGroups(columnSources, rowSources, includeGroupColumn) {
10082
+ const groupName = includeGroupColumn ? ["__GROUP__"] : [];
10074
10083
  const groups = columnSources.length === 0 ? [
10075
10084
  new PivotColumnHeaderGroup({
10076
10085
  name: "/",
10077
10086
  displayName: "",
10078
10087
  // For empty row sources we will render a "dead column"
10079
10088
  // or a Groups column, depending on the table settings
10080
- children: rowSources.map((c) => c.name),
10089
+ children: [...groupName, ...rowSources.map((c) => c.name)],
10081
10090
  childIndexes: [],
10082
10091
  isKeyColumnGroup: true,
10083
10092
  depth: 1,
@@ -10087,7 +10096,7 @@ function getKeyColumnGroups(columnSources, rowSources) {
10087
10096
  (source, i) => new PivotColumnHeaderGroup({
10088
10097
  name: source.name,
10089
10098
  displayName: source.name,
10090
- children: i === columnSources.length - 1 ? rowSources.map((c) => c.name) : [columnSources[i + 1].name],
10099
+ children: i === columnSources.length - 1 ? [...groupName, ...rowSources.map((c) => c.name)] : [columnSources[i + 1].name],
10091
10100
  childIndexes: [],
10092
10101
  isKeyColumnGroup: true,
10093
10102
  depth: columnSources.length - i,
@@ -10099,7 +10108,7 @@ function getKeyColumnGroups(columnSources, rowSources) {
10099
10108
  []
10100
10109
  ) : groups;
10101
10110
  }
10102
- function getTotalsColumnGroups(columnSources, valueSources, isRootColumnExpanded) {
10111
+ function makeTotalsColumnGroups(columnSources, valueSources, isRootColumnExpanded) {
10103
10112
  const groupName = pluralize(valueSources.length, GRAND_TOTALS_GROUP_NAME);
10104
10113
  return columnSources.length === 0 ? [
10105
10114
  new PivotColumnHeaderGroup({
@@ -10123,7 +10132,7 @@ function getTotalsColumnGroups(columnSources, valueSources, isRootColumnExpanded
10123
10132
  })
10124
10133
  );
10125
10134
  }
10126
- function getSnapshotColumnGroups(snapshotColumns, columnSources, valueSources, formatValue) {
10135
+ function makeSnapshotColumnGroups(snapshotColumns, columnSources, valueSources, formatValue) {
10127
10136
  const maxDepth = Math.max(columnSources.length, 1);
10128
10137
  const groupMap = /* @__PURE__ */ new Map();
10129
10138
  const groupName = pluralize(valueSources.length, TOTALS_GROUP_NAME);
@@ -10163,16 +10172,20 @@ function getSnapshotColumnGroups(snapshotColumns, columnSources, valueSources, f
10163
10172
  }
10164
10173
  return [...groupMap.values()];
10165
10174
  }
10166
- function getColumnGroups(pivotTable, snapshotColumns, isRootColumnExpanded = true, formatValue = (v, t) => String(v)) {
10175
+ function makeColumnGroups(pivotTable, snapshotColumns, isRootColumnExpanded = true, includeGroupColumn = false, formatValue = (v, t) => String(v)) {
10167
10176
  const virtualColumnGroups = [
10168
- ...getKeyColumnGroups(pivotTable.columnSources, pivotTable.rowSources),
10169
- ...getTotalsColumnGroups(
10177
+ ...makeKeyColumnGroups(
10178
+ pivotTable.columnSources,
10179
+ pivotTable.rowSources,
10180
+ includeGroupColumn
10181
+ ),
10182
+ ...makeTotalsColumnGroups(
10170
10183
  pivotTable.columnSources,
10171
10184
  pivotTable.valueSources,
10172
10185
  isRootColumnExpanded
10173
10186
  )
10174
10187
  ];
10175
- const snapshotColumnGroups = snapshotColumns == null ? [] : getSnapshotColumnGroups(
10188
+ const snapshotColumnGroups = snapshotColumns == null ? [] : makeSnapshotColumnGroups(
10176
10189
  snapshotColumns,
10177
10190
  pivotTable.columnSources,
10178
10191
  pivotTable.valueSources
@@ -10184,6 +10197,16 @@ const SET_VIEWPORT_THROTTLE = 150;
10184
10197
  const APPLY_VIEWPORT_THROTTLE = 0;
10185
10198
  const ROW_BUFFER_PAGES = 1;
10186
10199
  const COLUMN_BUFFER_PAGES = 1;
10200
+ const VirtualGroupColumn = Object.freeze(
10201
+ makeColumn({
10202
+ name: "__GROUP__",
10203
+ displayName: "Group",
10204
+ type: "java.lang.String",
10205
+ index: 0,
10206
+ depth: 2,
10207
+ isProxy: true
10208
+ })
10209
+ );
10187
10210
  function isIrisGridPivotModel(model) {
10188
10211
  return typeof model === "object" && model !== null && "pivotTable" in model && "keyColumns" in model && "expandAll" in model && "collapseAll" in model && "hasExpandableRows" in model && "hasExpandableColumns" in model;
10189
10212
  }
@@ -10194,13 +10217,9 @@ class IrisGridPivotModel extends irisGrid.IrisGridModel {
10194
10217
  }
10195
10218
  super(dh);
10196
10219
  __publicField(this, "pivotTable");
10197
- __publicField(this, "keyColumns");
10220
+ __publicField(this, "showExtraGroupCol", true);
10198
10221
  __publicField(this, "_layoutHints");
10199
- __publicField(this, "_columnHeaderGroupMap", /* @__PURE__ */ new Map());
10200
- __publicField(this, "columnHeaderParentMap", /* @__PURE__ */ new Map());
10201
- __publicField(this, "_columnHeaderMaxDepth", null);
10202
- __publicField(this, "_columnHeaderGroups", []);
10203
- __publicField(this, "_isColumnHeaderGroupsInitialized", false);
10222
+ __publicField(this, "_sorts", EMPTY_ARRAY);
10204
10223
  __publicField(this, "viewportData", null);
10205
10224
  __publicField(this, "formattedStringData", []);
10206
10225
  __publicField(this, "snapshotColumns", null);
@@ -10217,73 +10236,80 @@ class IrisGridPivotModel extends irisGrid.IrisGridModel {
10217
10236
  __publicField(this, "dh");
10218
10237
  __publicField(this, "getCachedColumns", memoizeOne(
10219
10238
  (snapshotColumns, virtualColumns, valueSources) => {
10239
+ const columns = [];
10240
+ this.pivotTable.columnSources.forEach((source, col) => {
10241
+ const index = -this.pivotTable.columnSources.length + col;
10242
+ columns[index] = makeColumnFromSource(source, index);
10243
+ });
10244
+ columns.push(...virtualColumns);
10220
10245
  if (snapshotColumns == null) {
10221
- log$3.debug2("getCachedColumns", {
10222
- snapshotColumns,
10223
- valueSources
10224
- });
10225
- return virtualColumns;
10246
+ return columns;
10226
10247
  }
10227
- const columns = [...virtualColumns];
10228
10248
  for (let i = 0; i < snapshotColumns.totalCount; i += 1) {
10229
10249
  const isColumnInViewport = i >= snapshotColumns.offset && i < snapshotColumns.offset + snapshotColumns.count;
10230
10250
  for (let v = 0; v < valueSources.length; v += 1) {
10231
10251
  columns.push(
10232
- isColumnInViewport ? makeExpandableDisplayColumn(
10252
+ isColumnInViewport ? makeColumnFromSnapshot(
10233
10253
  snapshotColumns,
10234
10254
  valueSources[v],
10235
10255
  i,
10236
10256
  virtualColumns.length
10237
- ) : makePlaceholderDisplayColumn(
10238
- valueSources[v],
10239
- i,
10240
- virtualColumns.length
10241
- )
10257
+ ) : makePlaceholderColumn(valueSources[v], i, virtualColumns.length)
10242
10258
  );
10243
10259
  }
10244
10260
  }
10245
- log$3.debug2("getCachedColumns", {
10246
- snapshotColumns,
10247
- valueSources,
10248
- columns: columns.map(({ name }) => name)
10249
- });
10250
10261
  return columns;
10251
10262
  }
10252
10263
  ));
10253
10264
  __publicField(this, "getCachedTotalsColumns", memoizeOne(
10254
- (pivotTable, valueSources) => valueSources.map(
10265
+ (pivotTable, valueSources, groupColumn) => valueSources.map(
10255
10266
  (source, col) => makeColumn({
10256
10267
  name: makeGrandTotalColumnName(source),
10257
10268
  displayName: source.name,
10258
10269
  description: source.description,
10259
10270
  type: source.type,
10260
- index: pivotTable.rowSources.length + col,
10271
+ index: pivotTable.rowSources.length + col + (groupColumn == null ? 0 : 1),
10261
10272
  depth: 2,
10262
10273
  isExpanded: true,
10263
10274
  hasChildren: true
10264
10275
  })
10265
10276
  )
10266
10277
  ));
10278
+ __publicField(this, "getCachedKeyColumns", memoizeOne(
10279
+ (pivotTable, groupColumn) => pivotTable.rowSources.map(
10280
+ (source, index) => makeColumnFromSource(source, index + (groupColumn == null ? 0 : 1))
10281
+ )
10282
+ ));
10267
10283
  __publicField(this, "getCachedVirtualColumns", memoizeOne(
10268
- (keyColumns, totalsColumns) => [...keyColumns, ...totalsColumns]
10284
+ (groupColumn, keyColumns, totalsColumns) => groupColumn ? [groupColumn, ...keyColumns, ...totalsColumns] : [...keyColumns, ...totalsColumns]
10269
10285
  ));
10270
10286
  /**
10271
- * Get the cached column header groups.
10287
+ * Get the cached header groups data, including groups array, max depth, parent map, and group map.
10272
10288
  * Returns groups for the key columns, totals, and the snapshot column in the current viewport.
10273
10289
  * Placeholder columns are not included in the groups.
10274
10290
  */
10275
- __publicField(this, "getCachedColumnHeaderGroups", memoizeOne(
10276
- (snapshotColumns, isRootColumnExpanded, formatValue) => getColumnGroups(
10277
- this.pivotTable,
10278
- snapshotColumns,
10279
- isRootColumnExpanded,
10280
- formatValue
10281
- )
10291
+ __publicField(this, "getCachedParsedColumnHeaderData", memoizeOne(
10292
+ (snapshotColumns, groupColumn, formatter, isRootColumnExpanded) => {
10293
+ const columnGroups = makeColumnGroups(
10294
+ this.pivotTable,
10295
+ snapshotColumns,
10296
+ isRootColumnExpanded,
10297
+ groupColumn != null,
10298
+ (value2, type) => this.getCachedFormattedString(formatter, value2, type, "")
10299
+ );
10300
+ return irisGrid.IrisGridUtils.parseColumnHeaderGroups(
10301
+ this,
10302
+ columnGroups,
10303
+ (args) => new PivotColumnHeaderGroup(args)
10304
+ );
10305
+ }
10282
10306
  ));
10283
10307
  __publicField(this, "getColumnIndicesByNameMap", memoizeOne(
10284
10308
  (columns) => {
10285
10309
  const indices = /* @__PURE__ */ new Map();
10286
- columns.forEach(({ name }, i) => indices.set(name, i));
10310
+ Object.entries(columns).forEach(
10311
+ ([i, { name }]) => indices.set(name, Number(i))
10312
+ );
10287
10313
  return indices;
10288
10314
  }
10289
10315
  ));
@@ -10415,9 +10441,6 @@ class IrisGridPivotModel extends irisGrid.IrisGridModel {
10415
10441
  this.snapshotValueSources = pivotTable.valueSources;
10416
10442
  this.rowBufferPages = config.rowBufferPages ?? ROW_BUFFER_PAGES;
10417
10443
  this.columnBufferPages = config.columnBufferPages ?? COLUMN_BUFFER_PAGES;
10418
- this.keyColumns = pivotTable.rowSources.map(
10419
- (source, col) => makeRowSourceColumn(source, col)
10420
- );
10421
10444
  this._layoutHints = {
10422
10445
  backColumns: [],
10423
10446
  hiddenColumns: [],
@@ -10434,10 +10457,38 @@ class IrisGridPivotModel extends irisGrid.IrisGridModel {
10434
10457
  }
10435
10458
  set filter(_) {
10436
10459
  }
10437
- get sort() {
10438
- return EMPTY_ARRAY;
10460
+ hydratePivotSort(sort) {
10461
+ const sourceIndex = this.getColumnIndexByName(sort.column.name);
10462
+ const source = this.columns[sourceIndex ?? -1];
10463
+ return (source == null ? void 0 : source.sort()[sort.direction === "ASC" ? "asc" : "desc"]()) ?? null;
10439
10464
  }
10440
- set sort(_) {
10465
+ get sort() {
10466
+ return this._sorts ?? EMPTY_ARRAY;
10467
+ }
10468
+ set sort(sorts) {
10469
+ log$3.debug("Setting sorts on pivot table", sorts);
10470
+ this._sorts = sorts;
10471
+ const columnBySorts = [];
10472
+ const rowBySorts = [];
10473
+ sorts.forEach((s) => {
10474
+ const sort = this.hydratePivotSort(s);
10475
+ if (sort == null) {
10476
+ log$3.warn(`Cannot hydrate sort for source: ${s.column.name}`, s);
10477
+ return;
10478
+ }
10479
+ const index = this.getColumnIndexByName(sort.name);
10480
+ if (index == null) {
10481
+ log$3.warn(`Cannot find index for source: ${s.column.name}`, s);
10482
+ return;
10483
+ }
10484
+ if (index < 0) {
10485
+ columnBySorts.push(sort);
10486
+ } else {
10487
+ rowBySorts.push(sort);
10488
+ }
10489
+ });
10490
+ this.pivotTable.applyRowSort(rowBySorts);
10491
+ this.pivotTable.applyColumnSort(columnBySorts);
10441
10492
  }
10442
10493
  get customColumns() {
10443
10494
  return EMPTY_ARRAY;
@@ -10482,68 +10533,69 @@ class IrisGridPivotModel extends irisGrid.IrisGridModel {
10482
10533
  async export() {
10483
10534
  throw new Error("Method not implemented.");
10484
10535
  }
10536
+ get showExtraGroupColumn() {
10537
+ return this.showExtraGroupCol;
10538
+ }
10539
+ set showExtraGroupColumn(showExtraGroupCol) {
10540
+ if (showExtraGroupCol === this.showExtraGroupCol) {
10541
+ return;
10542
+ }
10543
+ this.showExtraGroupCol = showExtraGroupCol;
10544
+ this.dispatchEvent(
10545
+ new EventShimCustomEvent(irisGrid.IrisGridModel.EVENT.COLUMNS_CHANGED, {
10546
+ detail: this.columns
10547
+ })
10548
+ );
10549
+ }
10550
+ get groupColumn() {
10551
+ return this.pivotTable.rowSources.length !== 1 && this.showExtraGroupCol ? VirtualGroupColumn : null;
10552
+ }
10553
+ get keyColumns() {
10554
+ return this.getCachedKeyColumns(this.pivotTable, this.groupColumn);
10555
+ }
10485
10556
  get totalsColumns() {
10486
10557
  return this.getCachedTotalsColumns(
10487
10558
  this.pivotTable,
10488
- this.snapshotValueSources
10559
+ this.snapshotValueSources,
10560
+ this.groupColumn
10489
10561
  );
10490
10562
  }
10491
10563
  get virtualColumns() {
10492
- return this.getCachedVirtualColumns(this.keyColumns, this.totalsColumns);
10564
+ return this.getCachedVirtualColumns(
10565
+ this.groupColumn,
10566
+ this.keyColumns,
10567
+ this.totalsColumns
10568
+ );
10493
10569
  }
10494
- get initialColumnHeaderGroups() {
10495
- const groups = this.getCachedColumnHeaderGroups(
10570
+ getParsedColumnHeaderData() {
10571
+ return this.getCachedParsedColumnHeaderData(
10496
10572
  this.snapshotColumns,
10497
- this.isRootColumnExpanded,
10498
- (value2, type) => (
10499
- // Ignore name based formatting, pass empty column name
10500
- this.getCachedFormattedString(this.formatter, value2, type, "")
10501
- )
10573
+ this.groupColumn,
10574
+ this.formatter,
10575
+ this.isRootColumnExpanded
10502
10576
  );
10503
- log$3.debug2("initialColumnHeaderGroups", groups);
10504
- return groups;
10577
+ }
10578
+ get initialColumnHeaderGroups() {
10579
+ return this.columnHeaderGroups;
10505
10580
  }
10506
10581
  get columnHeaderMaxDepth() {
10507
- return this._columnHeaderMaxDepth ?? 1;
10582
+ const { maxDepth } = this.getParsedColumnHeaderData();
10583
+ return maxDepth;
10508
10584
  }
10509
- set columnHeaderMaxDepth(depth) {
10510
- this._columnHeaderMaxDepth = depth;
10585
+ get columnHeaderParentMap() {
10586
+ const { parentMap } = this.getParsedColumnHeaderData();
10587
+ return parentMap;
10511
10588
  }
10512
10589
  get columnHeaderGroupMap() {
10513
- this.initializeColumnHeaderGroups();
10514
- return this._columnHeaderGroupMap;
10590
+ const { groupMap } = this.getParsedColumnHeaderData();
10591
+ return groupMap;
10515
10592
  }
10516
10593
  get columnHeaderGroups() {
10517
- this.initializeColumnHeaderGroups();
10518
- return this._columnHeaderGroups;
10594
+ const { groups } = this.getParsedColumnHeaderData();
10595
+ return groups;
10519
10596
  }
10520
10597
  set columnHeaderGroups(_groups) {
10521
10598
  }
10522
- setInternalColumnHeaderGroups(groups) {
10523
- if (groups === this._columnHeaderGroups) {
10524
- return;
10525
- }
10526
- const {
10527
- groups: newGroups,
10528
- maxDepth,
10529
- parentMap,
10530
- groupMap
10531
- } = irisGrid.IrisGridUtils.parseColumnHeaderGroups(
10532
- this,
10533
- groups,
10534
- (args) => new PivotColumnHeaderGroup(args)
10535
- );
10536
- this._columnHeaderGroups = newGroups;
10537
- this.columnHeaderMaxDepth = maxDepth;
10538
- this.columnHeaderParentMap = parentMap;
10539
- this._columnHeaderGroupMap = groupMap;
10540
- this._isColumnHeaderGroupsInitialized = true;
10541
- }
10542
- initializeColumnHeaderGroups() {
10543
- if (!this._isColumnHeaderGroupsInitialized) {
10544
- this.setInternalColumnHeaderGroups(this.initialColumnHeaderGroups);
10545
- }
10546
- }
10547
10599
  textForColumnHeader(x, depth = 0) {
10548
10600
  const header = this.columnAtDepth(x, depth);
10549
10601
  if (isPivotColumnHeaderGroup(header)) {
@@ -10602,6 +10654,10 @@ class IrisGridPivotModel extends irisGrid.IrisGridModel {
10602
10654
  get initialMovedColumns() {
10603
10655
  return EMPTY_ARRAY;
10604
10656
  }
10657
+ /**
10658
+ * Get the columns in the pivot model.
10659
+ * Returned array includes column sources with negative indexes.
10660
+ */
10605
10661
  get columns() {
10606
10662
  return this.getCachedColumns(
10607
10663
  this.snapshotColumns,
@@ -10631,7 +10687,8 @@ class IrisGridPivotModel extends irisGrid.IrisGridModel {
10631
10687
  return false;
10632
10688
  }
10633
10689
  isColumnSortable(columnIndex) {
10634
- return false;
10690
+ var _a;
10691
+ return ((_a = this.columns[columnIndex]) == null ? void 0 : _a.isSortable) ?? false;
10635
10692
  }
10636
10693
  get isTotalsAvailable() {
10637
10694
  return false;
@@ -10697,10 +10754,10 @@ class IrisGridPivotModel extends irisGrid.IrisGridModel {
10697
10754
  this.formattedStringData = [];
10698
10755
  this.viewportData = this.extractSnapshotData(snapshot);
10699
10756
  this.updatePendingExpandCollapseState();
10700
- this.setInternalColumnHeaderGroups(this.initialColumnHeaderGroups);
10701
10757
  log$3.debug2("Pivot updated", {
10702
10758
  columns: this.columns,
10703
- snapshot: this.snapshotColumns,
10759
+ snapshot,
10760
+ snapshotColumns: this.snapshotColumns,
10704
10761
  viewport: (_a = this.viewportData) == null ? void 0 : _a.rowTotalCount,
10705
10762
  columnCount: this.columnCount,
10706
10763
  rowCount: this.rowCount
@@ -10751,10 +10808,7 @@ class IrisGridPivotModel extends irisGrid.IrisGridModel {
10751
10808
  const keyData = /* @__PURE__ */ new Map();
10752
10809
  const totalsData = /* @__PURE__ */ new Map();
10753
10810
  for (let c = 0; c < keys2.length; c += 1) {
10754
- keyData.set(c, {
10755
- // Only render the value for the deepest level
10756
- value: c === depth - 1 ? keys2[c] : void 0
10757
- });
10811
+ keyData.set(c, { value: keys2[c] });
10758
10812
  }
10759
10813
  for (let v = 0; v < snapshot.valueSources.length; v += 1) {
10760
10814
  totalsData.set(v, {
@@ -10965,41 +11019,33 @@ class IrisGridPivotModel extends irisGrid.IrisGridModel {
10965
11019
  this.setColumnExpanded(this.keyColumns.length, false, true);
10966
11020
  }
10967
11021
  isColumnExpandable(x, depth) {
10968
- var _a, _b;
10969
- log$3.debug2("isColumnExpandable", {
10970
- x,
10971
- depth,
10972
- name: (_a = this.columns[x]) == null ? void 0 : _a.name,
10973
- v: this.virtualColumns,
10974
- cC: this.columnCount,
10975
- c: this.columns
10976
- });
10977
- if (x >= this.keyColumns.length && x < this.virtualColumns.length) {
11022
+ var _a;
11023
+ if (this.isGrandTotalsColumn(x)) {
10978
11024
  return !this.isRootColumnExpanded || this.columns.length > this.virtualColumns.length;
10979
11025
  }
10980
11026
  if (x < this.keyColumns.length) {
10981
11027
  return false;
10982
11028
  }
10983
- return ((_b = this.columns[x]) == null ? void 0 : _b.hasChildren) ?? false;
11029
+ return ((_a = this.columns[x]) == null ? void 0 : _a.hasChildren) ?? false;
11030
+ }
11031
+ isGrandTotalsColumn(x) {
11032
+ const totalsStartIndex = this.keyColumns.length + (this.groupColumn == null ? 0 : 1);
11033
+ return x >= totalsStartIndex && x < this.virtualColumns.length;
10984
11034
  }
10985
11035
  isColumnExpanded(x) {
10986
11036
  var _a;
10987
- if (x >= this.keyColumns.length && x < this.virtualColumns.length) {
11037
+ if (this.isGrandTotalsColumn(x)) {
10988
11038
  return this.isRootColumnExpanded;
10989
11039
  }
10990
11040
  return ((_a = this.columns[x]) == null ? void 0 : _a.isExpanded) ?? false;
10991
11041
  }
10992
11042
  setColumnExpanded(x, isExpanded, expandDescendants = false) {
10993
- var _a;
10994
- log$3.debug2("[0] setColumnExpanded", {
11043
+ log$3.debug2("setColumnExpanded", {
10995
11044
  x,
10996
11045
  isExpanded,
10997
- name: (_a = this.columns[x]) == null ? void 0 : _a.name,
10998
- v: this.virtualColumns,
10999
- cC: this.columnCount,
11000
- c: this.columns
11046
+ expandDescendants
11001
11047
  });
11002
- if (x >= this.keyColumns.length && x < this.virtualColumns.length) {
11048
+ if (this.isGrandTotalsColumn(x)) {
11003
11049
  this.pivotTable.setRootColumnExpanded(isExpanded, expandDescendants);
11004
11050
  this.isRootColumnExpanded = isExpanded;
11005
11051
  return;
@@ -11065,15 +11111,27 @@ class IrisGridPivotModel extends irisGrid.IrisGridModel {
11065
11111
  this.formattedStringData[x][y] = text;
11066
11112
  }
11067
11113
  dataForCell(x, y) {
11068
- var _a, _b, _c;
11114
+ var _a, _b, _c, _d, _e, _f;
11069
11115
  const keyCount = this.keyColumns.length;
11070
- if (x < keyCount) {
11071
- return (_a = this.row(y)) == null ? void 0 : _a.keyData.get(x);
11116
+ const groupOffset = this.groupColumn == null ? 0 : 1;
11117
+ if (groupOffset === 1 && x === 0) {
11118
+ const rowDepth = ((_a = this.row(y)) == null ? void 0 : _a.depth) ?? 2;
11119
+ return y === 0 ? (
11120
+ // Empty value for the group cell in the totals row
11121
+ { value: "" }
11122
+ ) : {
11123
+ // Render all key values except the last one in the group column
11124
+ // to match the Rollup UI
11125
+ value: rowDepth < keyCount ? (_c = (_b = this.row(y)) == null ? void 0 : _b.keyData.get(rowDepth - 1)) == null ? void 0 : _c.value : ""
11126
+ };
11127
+ }
11128
+ if (x < keyCount + groupOffset) {
11129
+ return (_d = this.row(y)) == null ? void 0 : _d.keyData.get(x - groupOffset);
11072
11130
  }
11073
11131
  if (x < this.virtualColumns.length) {
11074
- return (_b = this.row(y)) == null ? void 0 : _b.totalsData.get(x - keyCount);
11132
+ return (_e = this.row(y)) == null ? void 0 : _e.totalsData.get(x - keyCount - groupOffset);
11075
11133
  }
11076
- return (_c = this.row(y)) == null ? void 0 : _c.data.get(x - this.virtualColumns.length);
11134
+ return (_f = this.row(y)) == null ? void 0 : _f.data.get(x - this.virtualColumns.length);
11077
11135
  }
11078
11136
  formatForCell(x, y) {
11079
11137
  var _a;
@@ -11146,8 +11204,8 @@ function useIrisGridPivotModel(fetch) {
11146
11204
  [model]
11147
11205
  );
11148
11206
  const makeModel = React.useCallback(async () => {
11149
- const pivotWidget = await fetch();
11150
- return new IrisGridPivotModel(dh, pivotWidget);
11207
+ const pivotTable = await fetch();
11208
+ return new IrisGridPivotModel(dh, pivotTable);
11151
11209
  }, [dh, fetch]);
11152
11210
  const reload = React.useCallback(async () => {
11153
11211
  setIsLoading(true);
@@ -11195,6 +11253,22 @@ function useIrisGridPivotModel(fetch) {
11195
11253
  }
11196
11254
  throw new Error("Invalid state");
11197
11255
  }
11256
+ const log$2 = Log.module("@deephaven/js-plugin-pivot/usePivotTableFetch");
11257
+ function usePivotTableFetch(fetch) {
11258
+ const api = jsapiBootstrap.useApi();
11259
+ return React.useCallback(
11260
+ () => fetch().then((widget) => {
11261
+ log$2.debug("Pivot fetch result:", widget);
11262
+ if (!isCorePlusDh(api)) {
11263
+ throw new Error("CorePlus is not available");
11264
+ }
11265
+ const pivotTable = new api.coreplus.pivot.PivotTable(widget);
11266
+ log$2.debug("Created pivot table:", pivotTable);
11267
+ return pivotTable;
11268
+ }),
11269
+ [api, fetch]
11270
+ );
11271
+ }
11198
11272
  class PivotColumnGroupMouseHandler extends GridMouseHandler {
11199
11273
  constructor(irisGrid2) {
11200
11274
  super();
@@ -11238,162 +11312,71 @@ class PivotColumnGroupMouseHandler extends GridMouseHandler {
11238
11312
  onClick(gridPoint, grid, event) {
11239
11313
  const column = this.getColumnGroupFromGridPoint(gridPoint);
11240
11314
  if (column != null && column === this.column && this.isExpandableColumnGroup(column, gridPoint.columnHeaderDepth)) {
11241
- this.irisGrid.toggleExpandColumn(column);
11315
+ this.irisGrid.toggleExpandColumn(
11316
+ column,
11317
+ GridUtils.isModifierKeyDown(event)
11318
+ );
11242
11319
  return true;
11243
11320
  }
11244
11321
  return false;
11245
11322
  }
11246
11323
  }
11324
+ class PivotSortMouseHandler extends GridMouseHandler {
11325
+ constructor(irisGrid2) {
11326
+ super();
11327
+ __publicField(this, "columnSource");
11328
+ __publicField(this, "irisGrid");
11329
+ this.columnSource = null;
11330
+ this.irisGrid = irisGrid2;
11331
+ }
11332
+ /**
11333
+ * Get the column source from a grid point
11334
+ * @param gridPoint The grid point to check
11335
+ * @returns The column source index if the grid point is in a column source header, else null
11336
+ */
11337
+ getColumnSourceHeaderFromGridPoint(gridPoint) {
11338
+ const { column, row, columnHeaderDepth } = gridPoint;
11339
+ const { model } = this.irisGrid.props;
11340
+ assertNotNull(model);
11341
+ const sourceIndex = columnHeaderDepth != null ? -columnHeaderDepth : null;
11342
+ if (column == null || row !== null || columnHeaderDepth == null) {
11343
+ return null;
11344
+ }
11345
+ const group = model.getColumnHeaderGroup(column, columnHeaderDepth);
11346
+ if (sourceIndex != null && sourceIndex < 0 && isIrisGridPivotModel(model) && model.isColumnSortable(sourceIndex) && isPivotColumnHeaderGroup(group) && group.isKeyColumnGroup) {
11347
+ return sourceIndex;
11348
+ }
11349
+ return null;
11350
+ }
11351
+ // We need to remember where the down started, because the canvas element will trigger a click where mouseUp is
11352
+ onDown(gridPoint, grid, event) {
11353
+ this.columnSource = this.getColumnSourceHeaderFromGridPoint(gridPoint);
11354
+ return false;
11355
+ }
11356
+ onClick(gridPoint, grid, event) {
11357
+ const columnSource = this.getColumnSourceHeaderFromGridPoint(gridPoint);
11358
+ if (columnSource != null && columnSource === this.columnSource) {
11359
+ const addToExisting = components.ContextActionUtils.isModifierKeyDown(event);
11360
+ this.irisGrid.toggleSort(columnSource, addToExisting);
11361
+ return true;
11362
+ }
11363
+ return false;
11364
+ }
11365
+ }
11366
+ function usePivotMouseHandlers() {
11367
+ return React.useMemo(
11368
+ () => [
11369
+ (irisGrid2) => new PivotColumnGroupMouseHandler(irisGrid2),
11370
+ (irisGrid2) => new PivotSortMouseHandler(irisGrid2)
11371
+ ],
11372
+ []
11373
+ );
11374
+ }
11247
11375
  function getColumnGroupName(model, modelColumn, depth) {
11248
11376
  var _a;
11249
11377
  return (_a = model.getColumnHeaderGroup(modelColumn, depth ?? 0)) == null ? void 0 : _a.name;
11250
11378
  }
11251
11379
  class IrisGridPivotRenderer extends irisGrid.IrisGridRenderer {
11252
- drawColumnHeaders(context, state) {
11253
- const {
11254
- mouseX,
11255
- mouseY,
11256
- theme,
11257
- metrics,
11258
- draggingColumnSeparator,
11259
- isDragging,
11260
- model
11261
- } = state;
11262
- const {
11263
- columnHeaderHeight,
11264
- floatingColumns,
11265
- gridX,
11266
- width,
11267
- visibleColumns,
11268
- allColumnWidths,
11269
- allColumnXs,
11270
- floatingLeftColumnCount,
11271
- floatingLeftWidth,
11272
- floatingRightWidth,
11273
- modelColumns,
11274
- columnHeaderMaxDepth
11275
- } = metrics;
11276
- if (columnHeaderHeight <= 0) {
11277
- return;
11278
- }
11279
- const {
11280
- headerHiddenSeparatorSize,
11281
- headerHiddenSeparatorHoverColor,
11282
- headerSeparatorColor,
11283
- headerSeparatorHoverColor
11284
- } = theme;
11285
- const hiddenSeparatorHeight = columnHeaderHeight * 0.5;
11286
- const hiddenY = columnHeaderHeight * (columnHeaderMaxDepth - 1) + columnHeaderHeight * 0.5 - hiddenSeparatorHeight * 0.5;
11287
- const containsFrozenColumns = floatingLeftColumnCount > 0;
11288
- if (!isExpandableColumnGridModel(model)) {
11289
- throw new Error("Unsupported model type");
11290
- }
11291
- context.save();
11292
- this.drawColumnHeadersForRange(
11293
- context,
11294
- state,
11295
- [visibleColumns[0], visibleColumns[visibleColumns.length - 1]],
11296
- {
11297
- minX: gridX + floatingLeftWidth,
11298
- maxX: width - floatingRightWidth
11299
- }
11300
- );
11301
- if (containsFrozenColumns) {
11302
- this.drawColumnHeadersForRange(
11303
- context,
11304
- state,
11305
- [floatingColumns[0], floatingColumns[floatingColumns.length - 1]],
11306
- {
11307
- minX: gridX,
11308
- maxX: gridX + floatingLeftWidth
11309
- }
11310
- );
11311
- }
11312
- if (headerSeparatorColor) {
11313
- context.strokeStyle = headerSeparatorColor;
11314
- const hiddenColumns = [...allColumnWidths.entries()].filter(([_, w]) => w === 0).map(([index]) => index);
11315
- context.beginPath();
11316
- context.fillStyle = headerSeparatorColor;
11317
- for (let i = 0; i < hiddenColumns.length; i += 1) {
11318
- const column = hiddenColumns[i];
11319
- const columnX = getOrThrow(allColumnXs, column);
11320
- const columnWidth = getOrThrow(allColumnWidths, column);
11321
- const minX = gridX + columnX + columnWidth + 0.5 - headerHiddenSeparatorSize * 0.5;
11322
- context.rect(
11323
- minX,
11324
- hiddenY,
11325
- headerHiddenSeparatorSize,
11326
- hiddenSeparatorHeight
11327
- );
11328
- }
11329
- context.fill();
11330
- }
11331
- if (headerSeparatorHoverColor) {
11332
- let { index: highlightedSeparator, depth } = draggingColumnSeparator ?? {};
11333
- if (highlightedSeparator == null && mouseX != null && mouseY != null) {
11334
- const separator = GridColumnSeparatorMouseHandler$1.getColumnSeparator(
11335
- GridUtils.getGridPointFromXY(mouseX, mouseY, metrics),
11336
- metrics,
11337
- model,
11338
- theme
11339
- );
11340
- highlightedSeparator = separator == null ? void 0 : separator.index;
11341
- depth = separator == null ? void 0 : separator.depth;
11342
- }
11343
- let shouldDrawSeparator;
11344
- if (highlightedSeparator == null) {
11345
- shouldDrawSeparator = false;
11346
- } else {
11347
- const columnIndex = modelColumns.get(highlightedSeparator);
11348
- const nextColumnIndex = modelColumns.get(highlightedSeparator + 1);
11349
- if (columnIndex == null || nextColumnIndex == null) {
11350
- shouldDrawSeparator = false;
11351
- } else {
11352
- shouldDrawSeparator = getColumnGroupName(model, columnIndex, depth) !== getColumnGroupName(model, nextColumnIndex, depth);
11353
- }
11354
- }
11355
- if (shouldDrawSeparator && highlightedSeparator != null && depth != null && (!isDragging || draggingColumnSeparator != null)) {
11356
- context.strokeStyle = headerSeparatorHoverColor;
11357
- const columnX = getOrThrow(allColumnXs, highlightedSeparator);
11358
- const columnWidth = getOrThrow(allColumnWidths, highlightedSeparator);
11359
- const x = gridX + columnX + columnWidth + 0.5;
11360
- const visibleColumnIndex = visibleColumns.indexOf(highlightedSeparator);
11361
- const nextColumn = visibleColumnIndex < visibleColumns.length - 1 ? visibleColumns[visibleColumnIndex + 1] : null;
11362
- const nextColumnWidth = nextColumn != null ? allColumnWidths.get(nextColumn) : null;
11363
- const isColumnHidden = columnWidth === 0;
11364
- const isNextColumnHidden = nextColumnWidth != null && nextColumnWidth === 0;
11365
- if (isColumnHidden) {
11366
- context.strokeStyle = headerHiddenSeparatorHoverColor;
11367
- context.fillStyle = headerHiddenSeparatorHoverColor;
11368
- context.fillRect(
11369
- x,
11370
- hiddenY,
11371
- headerHiddenSeparatorSize * 0.5,
11372
- hiddenSeparatorHeight
11373
- );
11374
- } else if (isNextColumnHidden) {
11375
- context.fillStyle = headerSeparatorHoverColor;
11376
- context.fillRect(
11377
- x - headerHiddenSeparatorSize * 0.5,
11378
- hiddenY,
11379
- headerHiddenSeparatorSize * 0.5,
11380
- hiddenSeparatorHeight
11381
- );
11382
- }
11383
- context.beginPath();
11384
- context.moveTo(
11385
- x,
11386
- (columnHeaderMaxDepth - depth - 1) * columnHeaderHeight
11387
- );
11388
- context.lineTo(
11389
- x,
11390
- (columnHeaderMaxDepth - depth) * columnHeaderHeight - 1
11391
- );
11392
- context.stroke();
11393
- }
11394
- }
11395
- context.restore();
11396
- }
11397
11380
  drawColumnHeadersAtDepth(context, state, range, bounds, depth) {
11398
11381
  const { metrics, model, theme } = state;
11399
11382
  if (!isIrisGridPivotModel(model)) {
@@ -11485,7 +11468,8 @@ class IrisGridPivotRenderer extends irisGrid.IrisGridRenderer {
11485
11468
  },
11486
11469
  bounds,
11487
11470
  isExpandable,
11488
- isExpanded
11471
+ isExpanded,
11472
+ jsapiUtils.TableUtils.getSortForColumn(model.sort, columnGroupName)
11489
11473
  );
11490
11474
  }
11491
11475
  columnIndex += 1;
@@ -11493,7 +11477,7 @@ class IrisGridPivotRenderer extends irisGrid.IrisGridRenderer {
11493
11477
  }
11494
11478
  context.restore();
11495
11479
  }
11496
- drawColumnHeader(context, state, columnText, columnX, columnWidth, style, bounds, isExpandable = false, isExpanded = false) {
11480
+ drawColumnHeader(context, state, columnText, columnX, columnWidth, style, bounds, isExpandable = false, isExpanded = false, sort = null) {
11497
11481
  if (columnWidth <= 0) {
11498
11482
  return;
11499
11483
  }
@@ -11601,6 +11585,15 @@ class IrisGridPivotRenderer extends irisGrid.IrisGridRenderer {
11601
11585
  isExpanded
11602
11586
  );
11603
11587
  }
11588
+ this.drawColumnSourceSortIndicator(
11589
+ context,
11590
+ state,
11591
+ sort,
11592
+ columnText,
11593
+ columnX,
11594
+ columnWidth,
11595
+ { minX, maxX }
11596
+ );
11604
11597
  context.restore();
11605
11598
  }
11606
11599
  drawColumnHeaderTreeMarker(context, state, columnX, columnWidth, headerY, headerHeight, treeBox, isExpanded) {
@@ -11628,39 +11621,60 @@ class IrisGridPivotRenderer extends irisGrid.IrisGridRenderer {
11628
11621
  isExpanded
11629
11622
  );
11630
11623
  }
11624
+ drawColumnSourceSortIndicator(context, state, sort, columnText, columnX, columnWidth, bounds) {
11625
+ const { metrics, theme } = state;
11626
+ const { gridX, columnHeaderHeight } = metrics;
11627
+ const { headerHorizontalPadding, iconSize: themeIconSize } = theme;
11628
+ const iconSize = Math.round(themeIconSize * 0.75);
11629
+ if (sort == null) {
11630
+ return;
11631
+ }
11632
+ const icon = this.getSortIcon(sort, iconSize);
11633
+ if (!icon) {
11634
+ return;
11635
+ }
11636
+ const textWidth = this.getCachedHeaderWidth(context, columnText);
11637
+ const textRight = gridX + columnX + textWidth + headerHorizontalPadding;
11638
+ let { maxX } = bounds;
11639
+ maxX -= headerHorizontalPadding;
11640
+ const defaultX = gridX + columnX + columnWidth - iconSize;
11641
+ const x = textRight > maxX ? textRight + 1 : Math.min(maxX, defaultX);
11642
+ const y = (columnHeaderHeight - iconSize) * 0.5;
11643
+ context.save();
11644
+ context.fillStyle = theme.headerSortBarColor;
11645
+ context.translate(x, y);
11646
+ context.fill(icon);
11647
+ context.restore();
11648
+ }
11649
+ }
11650
+ function usePivotRenderer() {
11651
+ return React.useMemo(() => new IrisGridPivotRenderer(), []);
11631
11652
  }
11632
- const IrisGridPivotTheme = Object.freeze({
11653
+ const IrisGridPivotThemeColors = Object.freeze({
11633
11654
  columnSourceHeaderBackground: "var(--dh-color-grid-bg)",
11634
11655
  totalsHeaderBackground: "var(--dh-color-grid-bg)"
11635
11656
  });
11636
- const log$2 = Log.module("@deephaven/js-plugin-pivot/PivotWidget");
11657
+ function getIrisGridPivotTheme() {
11658
+ return Object.freeze({
11659
+ ...components.resolveCssVariablesInRecord(IrisGridPivotThemeColors)
11660
+ });
11661
+ }
11662
+ const log$1 = Log.module("@deephaven/js-plugin-pivot/usePivotTheme");
11663
+ function usePivotTheme() {
11664
+ const theme = components.useTheme();
11665
+ return React.useMemo(() => {
11666
+ log$1.debug("Theme changed, updating pivot theme", theme);
11667
+ return getIrisGridPivotTheme();
11668
+ }, [theme]);
11669
+ }
11637
11670
  function PivotWidget({
11638
11671
  fetch
11639
11672
  }) {
11640
- const dh = jsapiBootstrap.useApi();
11641
- const mouseHandlers = React.useMemo(
11642
- () => [(irisGrid2) => new PivotColumnGroupMouseHandler(irisGrid2)],
11643
- []
11644
- );
11645
- const renderer = React.useMemo(() => new IrisGridPivotRenderer(), []);
11646
- const theme = components.useTheme();
11647
- const pivotTheme = React.useMemo(() => {
11648
- log$2.debug("Theme changed, updating pivot theme", theme);
11649
- return components.resolveCssVariablesInRecord(IrisGridPivotTheme);
11650
- }, [theme]);
11651
- const pivotTableFetch = React.useCallback(
11652
- () => fetch().then((result) => {
11653
- log$2.debug("pivotWidget fetch result:", result);
11654
- if (!isCorePlusDh(dh)) {
11655
- throw new Error("CorePlus is not available");
11656
- }
11657
- const pivot = new dh.coreplus.pivot.PivotTable(result);
11658
- log$2.debug("Created pivot table:", pivot);
11659
- return pivot;
11660
- }),
11661
- [dh, fetch]
11662
- );
11663
- const fetchResult = useIrisGridPivotModel(pivotTableFetch);
11673
+ const pivotFetch = usePivotTableFetch(fetch);
11674
+ const mouseHandlers = usePivotMouseHandlers();
11675
+ const renderer = usePivotRenderer();
11676
+ const pivotTheme = usePivotTheme();
11677
+ const fetchResult = useIrisGridPivotModel(pivotFetch);
11664
11678
  if (fetchResult.status === "loading") {
11665
11679
  return /* @__PURE__ */ jsxRuntimeExports.jsx(components.LoadingOverlay, { isLoading: true });
11666
11680
  }
@@ -11684,67 +11698,77 @@ function PivotWidget({
11684
11698
  }
11685
11699
  );
11686
11700
  }
11687
- const log$1 = Log.module("@deephaven/js-plugin-pivot/useHydratePivotGrid");
11688
- function useHydratePivotGrid(fetch, id, metadata) {
11701
+ const log = Log.module("@deephaven/js-plugin-pivot/useHydratePivotGrid");
11702
+ function useHydratePivotGrid(id, metadata) {
11703
+ assertNotNull(metadata, "Missing Pivot metadata");
11704
+ const objectFetch = jsapiBootstrap.useObjectFetch(metadata);
11689
11705
  const api = jsapiBootstrap.useApi();
11690
11706
  const loadPlugin = dashboardCorePlugins.useLoadTablePlugin();
11691
- const fetchTable = React.useCallback(
11692
- () => fetch().then((result) => {
11693
- log$1.debug("Pivot fetch result:", result);
11694
- if (!isCorePlusDh(api)) {
11695
- throw new Error("CorePlus is not available");
11696
- }
11697
- const pivot = new api.coreplus.pivot.PivotTable(result);
11698
- log$1.debug("Created pivot table:", pivot);
11699
- return pivot;
11700
- }),
11701
- [api, fetch]
11702
- );
11703
- const mouseHandlers = React.useMemo(
11704
- () => [(irisGrid2) => new PivotColumnGroupMouseHandler(irisGrid2)],
11705
- []
11706
- );
11707
- const renderer = React.useMemo(() => new IrisGridPivotRenderer(), []);
11708
- const theme = components.useTheme();
11709
- const pivotTheme = React.useMemo(() => {
11710
- log$1.debug("Theme changed, updating pivot theme", theme);
11711
- return components.resolveCssVariablesInRecord(IrisGridPivotTheme);
11712
- }, [theme]);
11713
- const hydratedProps = React.useMemo(
11714
- () => ({
11707
+ const mouseHandlers = usePivotMouseHandlers();
11708
+ const renderer = usePivotRenderer();
11709
+ const theme = usePivotTheme();
11710
+ const { status } = objectFetch;
11711
+ if (status === "loading") {
11712
+ log.debug("Widget is loading");
11713
+ return { status: "loading" };
11714
+ }
11715
+ if (status === "error") {
11716
+ log.debug("Error fetching widget:", objectFetch.error);
11717
+ return {
11718
+ status: "error",
11719
+ error: objectFetch.error
11720
+ };
11721
+ }
11722
+ const { fetch } = objectFetch;
11723
+ return {
11724
+ status: "success",
11725
+ props: {
11715
11726
  loadPlugin,
11716
11727
  localDashboardId: id,
11717
- makeModel: async () => {
11718
- const pivotWidget = await fetchTable();
11719
- return new IrisGridPivotModel(api, pivotWidget);
11728
+ makeModel: async function makeModel() {
11729
+ log.debug("Fetching pivot widget");
11730
+ const widget = await fetch();
11731
+ log.debug("Pivot fetch result:", widget);
11732
+ if (!isCorePlusDh(api)) {
11733
+ throw new Error("CorePlus is not available");
11734
+ }
11735
+ const pivotTable = new api.coreplus.pivot.PivotTable(widget);
11736
+ log.debug("Created pivot table:", pivotTable);
11737
+ return new IrisGridPivotModel(api, pivotTable);
11720
11738
  },
11721
11739
  metadata,
11722
11740
  mouseHandlers,
11723
- renderer
11724
- }),
11725
- [api, fetchTable, id, loadPlugin, metadata, mouseHandlers, renderer]
11726
- );
11727
- const hydratedPropsWithTheme = React.useMemo(
11728
- () => ({ ...hydratedProps, theme: pivotTheme }),
11729
- [hydratedProps, pivotTheme]
11730
- );
11731
- return hydratedPropsWithTheme;
11741
+ renderer,
11742
+ theme
11743
+ }
11744
+ };
11732
11745
  }
11733
11746
  const PivotPanel = React.forwardRef(
11747
+ // Unconnected IrisGridPanel type is not exported from dashboard-core-plugins
11734
11748
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
11735
- (props, ref) => {
11736
- const { localDashboardId, fetch, metadata } = props;
11737
- const hydratedProps = useHydratePivotGrid(
11738
- fetch,
11739
- localDashboardId,
11740
- metadata
11741
- );
11749
+ (panelProps, ref) => {
11750
+ const { localDashboardId, metadata, panelState, ...props } = panelProps;
11751
+ const hydrateResult = useHydratePivotGrid(localDashboardId, metadata);
11752
+ if (hydrateResult.status === "loading") {
11753
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(components.LoadingOverlay, { isLoading: true });
11754
+ }
11755
+ if (hydrateResult.status === "error") {
11756
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
11757
+ components.LoadingOverlay,
11758
+ {
11759
+ errorMessage: getErrorMessage(hydrateResult.error),
11760
+ isLoading: false
11761
+ }
11762
+ );
11763
+ }
11764
+ const { props: hydratedProps } = hydrateResult;
11742
11765
  return /* @__PURE__ */ jsxRuntimeExports.jsx(
11743
11766
  dashboardCorePlugins.IrisGridPanel,
11744
11767
  {
11745
11768
  ref,
11746
11769
  ...props,
11747
- ...hydratedProps
11770
+ ...hydratedProps,
11771
+ panelState
11748
11772
  }
11749
11773
  );
11750
11774
  }
@@ -11759,63 +11783,15 @@ const PivotPlugin = {
11759
11783
  icon: icons.dhTable,
11760
11784
  title: "Pivot Table"
11761
11785
  };
11762
- const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
11763
- let nanoid = (size = 21) => {
11764
- let id = "";
11765
- let bytes = crypto.getRandomValues(new Uint8Array(size |= 0));
11766
- while (size--) {
11767
- id += urlAlphabet[bytes[size] & 63];
11768
- }
11769
- return id;
11770
- };
11771
11786
  const VARIABLE_TYPE = "PivotTable";
11772
- const log = Log.module("@deephaven/js-plugin-pivot/DashboardPlugin");
11773
- function DashboardPlugin({
11774
- id,
11775
- layout,
11776
- registerComponent
11777
- }) {
11778
- const handlePanelOpen = React.useCallback(
11779
- ({
11780
- dragEvent,
11781
- fetch,
11782
- metadata = {},
11783
- panelId = nanoid(),
11784
- widget
11785
- }) => {
11786
- const { name, type } = widget;
11787
- if (type !== VARIABLE_TYPE) {
11788
- return;
11789
- }
11790
- log.info("Panel opened of type", type);
11791
- const config = {
11792
- type: "react-component",
11793
- component: PivotPanel.displayName,
11794
- props: {
11795
- localDashboardId: id,
11796
- id: panelId,
11797
- metadata: {
11798
- ...metadata,
11799
- ...widget
11800
- },
11801
- fetch
11802
- },
11803
- title: name ?? void 0,
11804
- id: panelId
11805
- };
11806
- const { root: root2 } = layout;
11807
- dashboard.LayoutUtils.openComponent({ root: root2, config, dragEvent });
11808
- },
11809
- [id, layout]
11810
- );
11811
- React.useEffect(() => {
11812
- assertNotNull(PivotPanel.displayName);
11813
- const cleanups = [registerComponent(PivotPanel.displayName, PivotPanel)];
11814
- return () => {
11815
- cleanups.forEach((cleanup) => cleanup());
11816
- };
11817
- }, [registerComponent]);
11818
- dashboard.useListener(layout.eventHub, "PanelEvent.OPEN", handlePanelOpen);
11787
+ function DashboardPlugin(dashboardProps) {
11788
+ assertNotNull(PivotPanel.displayName);
11789
+ dashboard.useDashboardPanel({
11790
+ dashboardProps,
11791
+ componentName: PivotPanel.displayName,
11792
+ supportedTypes: VARIABLE_TYPE,
11793
+ component: PivotPanel
11794
+ });
11819
11795
  return null;
11820
11796
  }
11821
11797
  exports.DashboardPlugin = DashboardPlugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deephaven/js-plugin-pivot",
3
- "version": "0.1.0",
3
+ "version": "0.2.1-dev.1002+b73a329e",
4
4
  "description": "Pivot plugin for Deephaven",
5
5
  "keywords": [
6
6
  "Deephaven",
@@ -29,7 +29,6 @@
29
29
  "@types/react-dom": "^17.0.2",
30
30
  "@vitejs/plugin-react-swc": "^3.0.0",
31
31
  "react": "^17.0.2",
32
- "typescript": "^4.5.4",
33
32
  "vite": "~4.1.4"
34
33
  },
35
34
  "peerDependencies": {
@@ -38,15 +37,15 @@
38
37
  },
39
38
  "dependencies": {
40
39
  "@deephaven/components": "^0.85.35",
41
- "@deephaven/dashboard": "^0.85.35",
42
- "@deephaven/dashboard-core-plugins": "^0.85.35",
43
- "@deephaven/grid": "^0.85.35",
40
+ "@deephaven/dashboard": "^0.85.38",
41
+ "@deephaven/dashboard-core-plugins": "^0.85.37",
42
+ "@deephaven/grid": "^0.85.38",
44
43
  "@deephaven/icons": "^0.85.0",
45
- "@deephaven/iris-grid": "^0.85.35",
44
+ "@deephaven/iris-grid": "^0.85.39",
46
45
  "@deephaven/jsapi-bootstrap": "^0.85.35",
47
- "@deephaven/jsapi-utils": "^0.85.35",
46
+ "@deephaven/jsapi-utils": "^0.85.39",
48
47
  "@deephaven/log": "^0.85.19",
49
- "@deephaven/plugin": "^0.85.35",
48
+ "@deephaven/plugin": "^0.85.37",
50
49
  "@deephaven/utils": "^0.85.35",
51
50
  "lodash.clamp": "^4.0.3",
52
51
  "lodash.throttle": "^4.1.1",
@@ -54,10 +53,11 @@
54
53
  "nanoid": "^5.1.5"
55
54
  },
56
55
  "publishConfig": {
57
- "access": "public"
56
+ "access": "public",
57
+ "provenance": false
58
58
  },
59
59
  "files": [
60
60
  "dist/index.js"
61
61
  ],
62
- "gitHead": "457bb8bac2d812477ce1907e642b310c854a4e7e"
62
+ "gitHead": "b73a329e136e465fa21ed93ecfe9d759505e6734"
63
63
  }