Skip to content

Commit 5f3d5f3

Browse files
vbabichmofojed
andauthored
feat: Pivot sort UI (#1272)
- Add Sort functionality for RowBy and ColumnBy sources - Add Group column matching the Rollup UI --------- Co-authored-by: Mike Bender <[email protected]>
1 parent 910d174 commit 5f3d5f3

13 files changed

+1312
-1109
lines changed

package-lock.json

Lines changed: 503 additions & 675 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/pivot/src/js/package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,15 @@
3737
},
3838
"dependencies": {
3939
"@deephaven/components": "^0.85.35",
40-
"@deephaven/dashboard": "^0.85.35",
41-
"@deephaven/dashboard-core-plugins": "^0.85.35",
42-
"@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",
4343
"@deephaven/icons": "^0.85.0",
44-
"@deephaven/iris-grid": "^0.85.35",
44+
"@deephaven/iris-grid": "^0.85.39",
4545
"@deephaven/jsapi-bootstrap": "^0.85.35",
46-
"@deephaven/jsapi-utils": "^0.85.35",
46+
"@deephaven/jsapi-utils": "^0.85.39",
4747
"@deephaven/log": "^0.85.19",
48-
"@deephaven/plugin": "^0.85.35",
48+
"@deephaven/plugin": "^0.85.37",
4949
"@deephaven/utils": "^0.85.35",
5050
"lodash.clamp": "^4.0.3",
5151
"lodash.throttle": "^4.1.1",

plugins/pivot/src/js/src/IrisGridPivotModel.test.ts

Lines changed: 86 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ describe('IrisGridPivotModel', () => {
329329
model.startListening();
330330

331331
expect(model.rowCount).toBe(0); // Initially, no rows. We get the count from the snapshot in the update event.
332-
expect(model.columns.length).toBe(3); // Only the virtual columns initially. RowBy sources and the totals.
332+
expect(model.columns.length).toBe(4); // Group column + 2 row sources + totals column
333333

334334
model.setViewport(0, 10);
335335

@@ -339,11 +339,12 @@ describe('IrisGridPivotModel', () => {
339339
asMock(pivotTable.addEventListener).mock.calls[0][1](updateEvent);
340340

341341
expect(model.rowCount).toBe(4); // 3 rows + 1 totals
342-
expect(model.columns.length).toBe(8); // 3 virtual columns (row source labels, totals) + 2 actual columns (C0, C1) + 3 children columns (D0, D1, D2)
342+
expect(model.columns.length).toBe(9); // 4 virtual columns (Group + 2 row sources + totals) + 2 actual columns (C0, C1) + 3 children columns (D0, D1, D2)
343343

344344
expect(
345345
getModelRowText(model, 0) // Totals row
346346
).toEqual([
347+
'', // Group
347348
'', // R
348349
'', // O
349350
`${DEFAULT_GRAND_TOTAL}`, // Grand total
@@ -357,6 +358,7 @@ describe('IrisGridPivotModel', () => {
357358
expect(
358359
getModelRowText(model, 1) // R0
359360
).toEqual([
361+
'R0', // Group
360362
'R0',
361363
'', // O
362364
`${DEFAULT_ROW_TOTAL}`, // Total for R0
@@ -379,41 +381,86 @@ describe('IrisGridPivotModel', () => {
379381

380382
// Expandable columns
381383

382-
// Virtual columns are not expandable
384+
// Virtual columns are not expandable (Group, R, O)
383385
expect(model.isColumnExpandable(0)).toBe(false);
384386
expect(model.isColumnExpandable(1)).toBe(false);
387+
expect(model.isColumnExpandable(2)).toBe(false);
385388

386389
// Totals column is expandable and expanded by default
387-
expect(model.isColumnExpandable(2)).toBe(true);
388-
expect(model.isColumnExpanded(2)).toBe(true);
389-
390-
// C0
391390
expect(model.isColumnExpandable(3)).toBe(true);
392391
expect(model.isColumnExpanded(3)).toBe(true);
393-
expect(model.depthForColumn(3)).toBe(2);
394-
expect(model.columns[3].name).toBe('C0/Count');
395392

396-
// C0 children - D0, D1, D2
397-
expect(model.isColumnExpandable(4)).toBe(false);
398-
expect(model.isColumnExpanded(4)).toBe(false);
399-
expect(model.depthForColumn(4)).toBe(3);
400-
expect(model.columns[4].name).toBe('C0/D0/Count');
393+
// C0
394+
expect(model.isColumnExpandable(4)).toBe(true);
395+
expect(model.isColumnExpanded(4)).toBe(true);
396+
expect(model.depthForColumn(4)).toBe(2);
397+
expect(model.columns[4].name).toBe('C0/Count');
401398

399+
// C0 children - D0, D1, D2
402400
expect(model.isColumnExpandable(5)).toBe(false);
403401
expect(model.isColumnExpanded(5)).toBe(false);
404402
expect(model.depthForColumn(5)).toBe(3);
405-
expect(model.columns[5].name).toBe('C0/D2/Count');
403+
expect(model.columns[5].name).toBe('C0/D0/Count');
406404

407405
expect(model.isColumnExpandable(6)).toBe(false);
408406
expect(model.isColumnExpanded(6)).toBe(false);
409407
expect(model.depthForColumn(6)).toBe(3);
410-
expect(model.columns[6].name).toBe('C0/D1/Count');
408+
expect(model.columns[6].name).toBe('C0/D2/Count');
411409

412-
// C1
413-
expect(model.isColumnExpandable(7)).toBe(true);
410+
expect(model.isColumnExpandable(7)).toBe(false);
414411
expect(model.isColumnExpanded(7)).toBe(false);
415-
expect(model.depthForColumn(7)).toBe(2);
416-
expect(model.columns[7].name).toBe('C1/Count');
412+
expect(model.depthForColumn(7)).toBe(3);
413+
expect(model.columns[7].name).toBe('C0/D1/Count');
414+
415+
// C1
416+
expect(model.isColumnExpandable(8)).toBe(true);
417+
expect(model.isColumnExpanded(8)).toBe(false);
418+
expect(model.depthForColumn(8)).toBe(2);
419+
expect(model.columns[8].name).toBe('C1/Count');
420+
});
421+
422+
it('handles showExtraGroupColumn changes', () => {
423+
const pivotTable = makePivotTable(['R', 'O'], ['C'], ['Count']);
424+
425+
const model = new IrisGridPivotModel(
426+
mockDh,
427+
pivotTable,
428+
formatter,
429+
DEFAULT_CONFIG
430+
);
431+
model.startListening();
432+
433+
const mockColumnsChangedListener = jest.fn();
434+
model.addEventListener(
435+
IrisGridModel.EVENT.COLUMNS_CHANGED,
436+
mockColumnsChangedListener
437+
);
438+
439+
// Initially with 2 row sources, should have Group column
440+
expect(model.columns.length).toBe(4); // Group + 2 row sources + totals
441+
expect(model.columns[0].name).toBe('__GROUP__');
442+
expect(model.showExtraGroupColumn).toBe(true);
443+
444+
// Disable the extra group column
445+
model.showExtraGroupColumn = false;
446+
447+
expect(model.columns.length).toBe(3); // 2 row sources + totals (no Group)
448+
expect(model.columns[0].name).toBe('R'); // First row source is now first column
449+
expect(mockColumnsChangedListener).toHaveBeenCalledTimes(1);
450+
451+
// Re-enable the extra group column
452+
mockColumnsChangedListener.mockClear();
453+
model.showExtraGroupColumn = true;
454+
455+
expect(model.columns.length).toBe(4); // Group + 2 row sources + totals
456+
expect(model.columns[0].name).toBe('__GROUP__');
457+
expect(mockColumnsChangedListener).toHaveBeenCalledTimes(1);
458+
459+
// Setting to same value should not trigger event
460+
mockColumnsChangedListener.mockClear();
461+
model.showExtraGroupColumn = true;
462+
463+
expect(mockColumnsChangedListener).not.toHaveBeenCalled();
417464
});
418465

419466
it('returns correct data for the viewport with just the totals row', () => {
@@ -848,19 +895,19 @@ describe('IrisGridPivotModel', () => {
848895
);
849896
model.startListening();
850897

851-
expect(model.columnCount).toBe(3);
898+
expect(model.columnCount).toBe(4);
852899
expect(model.columnHeaderGroups).toEqual([
853900
expect.objectContaining({
854901
name: 'C',
855-
children: ['R', 'O'],
902+
children: ['__GROUP__', 'R', 'O'],
856903
depth: 1,
857-
childIndexes: [0, 1],
904+
childIndexes: [0, 1, 2],
858905
}),
859906
expect.objectContaining({
860907
name: `__GRAND_TOTAL/C`,
861908
children: [makeGrandTotalColumnName(pivotTable.valueSources[0])],
862909
depth: 1,
863-
childIndexes: [2],
910+
childIndexes: [3],
864911
}),
865912
]);
866913
});
@@ -876,7 +923,7 @@ describe('IrisGridPivotModel', () => {
876923
);
877924
model.startListening();
878925

879-
model.setViewport(0, 0, model.columns.slice(5, 8)); // Viewport with 3 columns starting from index 5
926+
model.setViewport(0, 0, model.columns.slice(7, 10)); // Viewport with 3 columns at indices 7, 8, 9 (data columns C3, C4, C5)
880927
jest.runOnlyPendingTimers();
881928

882929
// Pivot responds with the update event, 3 columns starting from adjusted index 3
@@ -888,41 +935,41 @@ describe('IrisGridPivotModel', () => {
888935
})
889936
);
890937

891-
expect(model.columnCount).toBe(10);
938+
expect(model.columnCount).toBe(11);
892939
expect(model.columnHeaderGroups).toEqual([
893940
expect.objectContaining({
894941
name: 'C',
895-
children: ['R', 'O'],
942+
children: ['__GROUP__', 'R', 'O'],
896943
depth: 1,
897-
childIndexes: [0, 1],
944+
childIndexes: [0, 1, 2],
898945
}),
899946
expect.objectContaining({
900947
name: '__GRAND_TOTAL/C',
901948
children: [makeGrandTotalColumnName(pivotTable.valueSources[0])],
902949
depth: 1,
903-
childIndexes: [2],
950+
childIndexes: [3],
904951
}),
905952

906953
// groups for columns in the viewport
907954
expect.objectContaining({
908955
name: 'C3',
909956
children: ['C3/Count'],
910957
depth: 1,
911-
childIndexes: [6],
958+
childIndexes: [7],
912959
}),
913960

914961
expect.objectContaining({
915962
name: 'C4',
916963
children: ['C4/Count'],
917964
depth: 1,
918-
childIndexes: [7],
965+
childIndexes: [8],
919966
}),
920967

921968
expect.objectContaining({
922969
name: 'C5',
923970
children: ['C5/Count'],
924971
depth: 1,
925-
childIndexes: [8],
972+
childIndexes: [9],
926973
}),
927974
]);
928975
});
@@ -938,13 +985,13 @@ describe('IrisGridPivotModel', () => {
938985
);
939986
model.startListening();
940987

941-
expect(model.columnCount).toBe(3);
988+
expect(model.columnCount).toBe(4);
942989
expect(model.columnHeaderGroups).toEqual([
943990
expect.objectContaining({
944991
name: 'D',
945-
children: ['R', 'O'],
992+
children: ['__GROUP__', 'R', 'O'],
946993
depth: 1,
947-
childIndexes: [0, 1],
994+
childIndexes: [0, 1, 2],
948995
parent: 'C',
949996
}),
950997
// Parent for the group D above
@@ -953,20 +1000,20 @@ describe('IrisGridPivotModel', () => {
9531000
children: ['D'],
9541001
depth: 2,
9551002
// Same as group D
956-
childIndexes: [0, 1],
1003+
childIndexes: [0, 1, 2],
9571004
}),
9581005
expect.objectContaining({
9591006
name: '__GRAND_TOTAL/D',
9601007
children: [makeGrandTotalColumnName(pivotTable.valueSources[0])],
9611008
depth: 1,
9621009
parent: '__GRAND_TOTAL/C',
963-
childIndexes: [2],
1010+
childIndexes: [3],
9641011
}),
9651012
expect.objectContaining({
9661013
name: '__GRAND_TOTAL/C',
9671014
children: ['__GRAND_TOTAL/D'],
9681015
depth: 2,
969-
childIndexes: [2],
1016+
childIndexes: [3],
9701017
}),
9711018
]);
9721019

@@ -998,7 +1045,7 @@ describe('IrisGridPivotModel', () => {
9981045
// Simulate the update event with the data
9991046
asMock(pivotTable.addEventListener).mock.calls[0][1](updateEvent);
10001047

1001-
expect(model.columnCount).toBe(8);
1048+
expect(model.columnCount).toBe(9);
10021049
});
10031050
});
10041051
});

0 commit comments

Comments
 (0)