Skip to content

Commit 0c1f05f

Browse files
committed
Store model columns in IrisGridMetricCalculator
1 parent a3a913c commit 0c1f05f

File tree

3 files changed

+145
-44
lines changed

3 files changed

+145
-44
lines changed

packages/iris-grid/src/IrisGrid.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ import {
125125
} from './mousehandlers';
126126
import ToastBottomBar from './ToastBottomBar';
127127
import IrisGridMetricCalculator, {
128-
getColumnNameMap,
129128
IrisGridMetricState,
130129
} from './IrisGridMetricCalculator';
131130
import IrisGridModelUpdater from './IrisGridModelUpdater';

packages/iris-grid/src/IrisGridMetricCalculator.test.ts

Lines changed: 13 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { GridMetricCalculator } from '@deephaven/grid';
22
import { dh } from '@deephaven/jsapi-types';
33
import { TestUtils } from '@deephaven/utils';
44
import {
5-
getColumnNameMap,
65
IrisGridMetricCalculator,
76
type IrisGridMetricState,
87
} from './IrisGridMetricCalculator';
@@ -49,9 +48,7 @@ describe('IrisGridMetricCalculator', () => {
4948
return index !== -1 ? index : undefined;
5049
},
5150
});
52-
calculator = new IrisGridMetricCalculator({
53-
columnNameMap: getColumnNameMap(model),
54-
});
51+
calculator = new IrisGridMetricCalculator();
5552
state = makeGridMetricState(model);
5653
});
5754

@@ -60,29 +57,22 @@ describe('IrisGridMetricCalculator', () => {
6057

6158
expect(model.getColumnIndexByName('Column1')).toBe(0);
6259

63-
calculator.setColumnWidth(
64-
state,
65-
model.getColumnIndexByName('Column1'),
66-
100
67-
);
68-
calculator.setColumnWidth(
69-
state,
70-
model.getColumnIndexByName('Column2'),
71-
200
72-
);
73-
calculator.setColumnWidth(
74-
state,
75-
model.getColumnIndexByName('Column3'),
76-
300
77-
);
60+
// setColumnWidth requires getMetrics call
61+
calculator.getMetrics(state);
62+
calculator.setColumnWidth(model.getColumnIndexByName('Column1'), 100);
63+
calculator.setColumnWidth(model.getColumnIndexByName('Column2'), 200);
64+
calculator.setColumnWidth(model.getColumnIndexByName('Column3'), 300);
7865

66+
// Calling getMetrics to update user column widths
67+
calculator.getMetrics(state);
7968
expect(calculator.getUserColumnWidths().size).toBe(3);
8069

8170
// Delete Column2
8271
columns = columns.filter(col => col.name !== 'Column2');
8372

8473
expect(state.model.columns[1].name).toBe('Column3');
8574

75+
calculator.getMetrics(state);
8676
expect([...calculator.getUserColumnWidths().entries()]).toEqual([
8777
[0, 100],
8878
[1, 300],
@@ -98,6 +88,7 @@ describe('IrisGridMetricCalculator', () => {
9888
...columns.slice(1),
9989
];
10090

91+
calculator.getMetrics(state);
10192
expect([...calculator.getUserColumnWidths().entries()]).toEqual([
10293
[0, 100],
10394
[1, 200],
@@ -106,20 +97,13 @@ describe('IrisGridMetricCalculator', () => {
10697
});
10798

10899
it('setColumnWidth updates user column width', () => {
109-
calculator.setColumnWidth(
110-
state,
111-
model.getColumnIndexByName('Column1'),
112-
100
113-
);
100+
calculator.getMetrics(state);
101+
calculator.setColumnWidth(model.getColumnIndexByName('Column1'), 100);
114102

115103
expect(calculator.getUserColumnWidths().size).toBe(1);
116104
expect(calculator.getUserColumnWidths().get(0)).toBe(100);
117105

118-
calculator.setColumnWidth(
119-
state,
120-
model.getColumnIndexByName('Column1'),
121-
150
122-
);
106+
calculator.setColumnWidth(model.getColumnIndexByName('Column1'), 150);
123107
expect(calculator.getUserColumnWidths().get(0)).toBe(150);
124108
});
125109
});

packages/iris-grid/src/IrisGridMetricCalculator.ts

Lines changed: 132 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,87 @@
1-
import { GridMetricCalculator, ModelSizeMap } from '@deephaven/grid';
1+
import {
2+
GridMetricCalculator,
3+
GridMetrics,
4+
ModelIndex,
5+
ModelSizeMap,
6+
trimMap,
7+
} from '@deephaven/grid';
28
import type { GridMetricState } from '@deephaven/grid';
39
import type { dh } from '@deephaven/jsapi-types';
10+
import { assertNotNull } from '@deephaven/utils';
411
import type IrisGridModel from './IrisGridModel';
512
import { IrisGridThemeType } from './IrisGridTheme';
13+
import {
14+
ColumnName,
15+
ReadonlyAdvancedFilterMap,
16+
ReadonlyQuickFilterMap,
17+
} from './CommonTypes';
618

719
export interface IrisGridMetricState extends GridMetricState {
820
model: IrisGridModel;
921
theme: IrisGridThemeType;
1022
isFilterBarShown: boolean;
11-
advancedFilters: Map<
12-
string,
13-
{ options: unknown; filter: dh.FilterCondition | null }
14-
>;
15-
quickFilters: Map<
16-
string,
17-
{ text: string; filter: dh.FilterCondition | null }
18-
>;
19-
sorts: dh.Sort[];
23+
advancedFilters: ReadonlyAdvancedFilterMap;
24+
quickFilters: ReadonlyQuickFilterMap;
25+
sorts: readonly dh.Sort[];
2026
reverse: boolean;
2127
}
2228

23-
/**
24-
* Class to calculate all the metrics for a grid.
25-
* Call getMetrics() with the state to get metrics
26-
*/
2729
export class IrisGridMetricCalculator extends GridMetricCalculator {
30+
// Column widths by name to keep track of columns going in and out of viewport
31+
userColumnWidthsByName: Map<ColumnName, number> = new Map();
32+
33+
private cachedModelColumns: readonly dh.Column[] | undefined;
34+
35+
// constructor(...args: IrisGridMetricCalculatorParameters) {
36+
// super(...args);
37+
// const [config] = args;
38+
// const { model, userColumnWidths } = config;
39+
40+
// this.model = model;
41+
42+
// // Populate userColumnWidthsByName from index-based userColumnWidths arg
43+
// // and the map of existing column names.
44+
// // We need to persist widths for all columns, even the ones that are not currently present because the model can expand and collapse
45+
// // TODO: this will be problematic for user width persistence since the model can initialize with partial set of columns
46+
// // and populates the rest on model update.
47+
// // TODO: change the arg type to Map<ColumnName, number>?
48+
// this.userColumnWidthsByName = new Map<ColumnName, number>();
49+
// userColumnWidths?.forEach((width, modelIndex) => {
50+
// const name = model.columns[modelIndex]?.name;
51+
// if (name != null) {
52+
// this.userColumnWidthsByName.set(name, width);
53+
// }
54+
// });
55+
// }
56+
57+
/**
58+
* Updates the user column widths based on the current model state
59+
* @param model The current IrisGridModel
60+
*/
61+
private updateUserColumnWidths(model: IrisGridModel): void {
62+
this.userColumnWidths = new Map<ModelIndex, number>();
63+
this.userColumnWidthsByName.forEach((width, name) => {
64+
const modelIndex = model.getColumnIndexByName(name);
65+
if (modelIndex != null) {
66+
super.setColumnWidth(modelIndex, width);
67+
}
68+
});
69+
}
70+
71+
/**
72+
* Updates the user and calculated column widths if the model columns have changed
73+
* @param model The current IrisGridModel
74+
*/
75+
private updateColumnWidthsIfNecessary(model: IrisGridModel): void {
76+
if (model.columns !== this.cachedModelColumns) {
77+
this.resetCalculatedColumnWidths();
78+
this.updateUserColumnWidths(model);
79+
}
80+
}
81+
2882
getGridY(state: IrisGridMetricState): number {
83+
// The state here seems to be a GridMetricState with stateOverrides passed from IrisGrid in the props,
84+
// not guaranteed to be IrisGridMetricState
2985
let gridY = super.getGridY(state);
3086
const {
3187
isFilterBarShown,
@@ -50,7 +106,69 @@ export class IrisGridMetricCalculator extends GridMetricCalculator {
50106
return gridY;
51107
}
52108

109+
/**
110+
* Gets the metrics for the current state. This method has to be called to update cachedModelColumns on model columns change.
111+
* @param state The current IrisGridMetricState
112+
* @returns The metrics for the current state
113+
*/
114+
getMetrics(state: IrisGridMetricState): GridMetrics {
115+
const { model } = state;
116+
// Update column widths if columns in the cached model don't match the current model passed in the state
117+
this.updateColumnWidthsIfNecessary(model);
118+
119+
this.cachedModelColumns = model.columns;
120+
return super.getMetrics(state);
121+
}
122+
123+
/**
124+
* Sets the width for a specific column by index
125+
* @param column The index of the column to set
126+
* @param size The new width for the column
127+
*/
128+
setColumnWidth(column: number, size: number): void {
129+
super.setColumnWidth(column, size);
130+
assertNotNull(
131+
this.cachedModelColumns,
132+
'setColumnWidth should be called after getMetrics'
133+
);
134+
const name = this.cachedModelColumns[column]?.name;
135+
if (name != null) {
136+
this.userColumnWidthsByName.set(name, size);
137+
trimMap(this.userColumnWidthsByName);
138+
}
139+
}
140+
141+
/**
142+
* Resets the width for a specific column by index
143+
* @param column The index of the column to reset
144+
*/
145+
resetColumnWidth(column: number): void {
146+
super.resetColumnWidth(column);
147+
assertNotNull(
148+
this.cachedModelColumns,
149+
'resetColumnWidth should be called after getMetrics'
150+
);
151+
const name = this.cachedModelColumns[column]?.name;
152+
if (name != null) {
153+
this.userColumnWidthsByName.delete(name);
154+
}
155+
}
156+
157+
/**
158+
* Resets all user column widths
159+
*/
160+
resetAllColumnWidths(): void {
161+
this.userColumnWidths = new Map<ModelIndex, number>();
162+
this.userColumnWidthsByName = new Map<ColumnName, number>();
163+
}
164+
165+
/**
166+
* Gets the user column widths for the current state
167+
* @param state The current IrisGridMetricState
168+
* @returns A map of user column widths
169+
*/
53170
getUserColumnWidths(): ModelSizeMap {
171+
// This might return stale data if getMetrics hasn't been called
54172
return this.userColumnWidths;
55173
}
56174
}

0 commit comments

Comments
 (0)