Skip to content

Commit 9cfa2c3

Browse files
gzh2003mofojed
andauthored
feat: DH-10205: Add column text alignment to web (#2513)
For DH-10205. Allows users to override the default type-based alignment logic on a per column basis using a context menu. Text alignment is determined with the following priority order: 1. context menu, 2.ui.table, 3. column type. TODO: - [ ] Bump package version in ui plugins - [ ] Update `UITableModel` to use custom text alignment from the base model --------- Co-authored-by: Mike Bender <mikebender@deephaven.io>
1 parent a155da6 commit 9cfa2c3

17 files changed

Lines changed: 356 additions & 3 deletions

packages/code-studio/src/styleguide/MockIrisGridTreeModel.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,14 @@ class MockIrisGridTreeModel
237237
// Ignore for mock
238238
}
239239

240+
get columnAlignmentMap(): ReadonlyMap<string, CanvasTextAlign> {
241+
return new Map<string, CanvasTextAlign>();
242+
}
243+
244+
set columnAlignmentMap(columnAlignmentMap: Map<string, CanvasTextAlign>) {
245+
// Ignore for mock
246+
}
247+
240248
displayString(value: unknown): string {
241249
return `${value}`;
242250
}

packages/dashboard-core-plugins/src/panels/IrisGridPanel.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ interface IrisGridPanelState {
187187
advancedSettings: Map<AdvancedSettingsType, boolean>;
188188
customColumns: readonly ColumnName[];
189189
customColumnFormatMap: Map<string, FormattingRule>;
190+
columnAlignmentMap: Map<string, CanvasTextAlign>;
190191
isFilterBarShown: boolean;
191192
quickFilters: ReadonlyQuickFilterMap;
192193
sorts: readonly dh.Sort[];
@@ -297,6 +298,7 @@ export class IrisGridPanel extends PureComponent<
297298
advancedSettings: new Map(AdvancedSettings.DEFAULTS),
298299
customColumns: [],
299300
customColumnFormatMap: new Map(),
301+
columnAlignmentMap: new Map(),
300302
isFilterBarShown: false,
301303
quickFilters: new Map(),
302304
sorts: [],
@@ -1013,6 +1015,7 @@ export class IrisGridPanel extends PureComponent<
10131015
advancedFilters,
10141016
customColumns,
10151017
customColumnFormatMap,
1018+
columnAlignmentMap,
10161019
isFilterBarShown,
10171020
quickFilters,
10181021
reverse,
@@ -1047,6 +1050,7 @@ export class IrisGridPanel extends PureComponent<
10471050
conditionalFormats,
10481051
customColumns,
10491052
customColumnFormatMap,
1053+
columnAlignmentMap,
10501054
isFilterBarShown,
10511055
isSelectingPartition,
10521056
movedColumns,
@@ -1141,6 +1145,7 @@ export class IrisGridPanel extends PureComponent<
11411145
conditionalFormats,
11421146
customColumns,
11431147
customColumnFormatMap,
1148+
columnAlignmentMap,
11441149
error,
11451150
isDisconnected,
11461151
isFilterBarShown,
@@ -1222,6 +1227,7 @@ export class IrisGridPanel extends PureComponent<
12221227
copyCursor="copy"
12231228
customColumns={customColumns}
12241229
customColumnFormatMap={customColumnFormatMap}
1230+
columnAlignmentMap={columnAlignmentMap}
12251231
columnSelectionValidator={this.isColumnSelectionValid}
12261232
conditionalFormats={conditionalFormats}
12271233
inputFilters={this.getGridInputFilters(model.columns, inputFilters)}

packages/iris-grid/src/EmptyIrisGridModel.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@ class EmptyIrisGridModel extends IrisGridModel {
2121
super(dh);
2222

2323
this.modelFormatter = formatter;
24+
this.modelColumnAlignmentMap = new Map<string, CanvasTextAlign>();
2425
}
2526

2627
modelFormatter: Formatter;
2728

29+
modelColumnAlignmentMap: Map<string, CanvasTextAlign>;
30+
2831
get rowCount(): number {
2932
return 0;
3033
}
@@ -104,6 +107,14 @@ class EmptyIrisGridModel extends IrisGridModel {
104107
this.modelFormatter = formatter;
105108
}
106109

110+
get columnAlignmentMap(): ReadonlyMap<string, CanvasTextAlign> {
111+
return this.modelColumnAlignmentMap;
112+
}
113+
114+
set columnAlignmentMap(columnAlignmentMap: Map<string, CanvasTextAlign>) {
115+
this.modelColumnAlignmentMap = columnAlignmentMap;
116+
}
117+
107118
displayString(
108119
value: unknown,
109120
columnType: string,

packages/iris-grid/src/IrisGrid.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ export interface IrisGridProps {
284284
applyInputFiltersOnInit: boolean;
285285
conditionalFormats: readonly SidebarFormattingRule[];
286286
customColumnFormatMap: Map<ColumnName, FormattingRule>;
287+
columnAlignmentMap: Map<string, CanvasTextAlign>;
287288
movedColumns: readonly MoveOperation[];
288289
movedRows: readonly MoveOperation[];
289290
inputFilters: readonly InputFilter[];
@@ -408,6 +409,8 @@ export interface IrisGridState {
408409
isMenuShown: boolean;
409410
customColumnFormatMap: Map<ColumnName, FormattingRule>;
410411

412+
columnAlignmentMap: Map<string, CanvasTextAlign>;
413+
411414
conditionalFormats: readonly SidebarFormattingRule[];
412415
conditionalFormatEditIndex: number | null;
413416
conditionalFormatPreview?: SidebarFormattingRule;
@@ -484,6 +487,7 @@ class IrisGrid extends Component<IrisGridProps, IrisGridState> {
484487
alwaysFetchColumns: EMPTY_ARRAY,
485488
conditionalFormats: EMPTY_ARRAY,
486489
customColumnFormatMap: EMPTY_MAP,
490+
columnAlignmentMap: EMPTY_MAP,
487491
isFilterBarShown: false,
488492
applyInputFiltersOnInit: false,
489493
movedColumns: EMPTY_ARRAY,
@@ -591,6 +595,8 @@ class IrisGrid extends Component<IrisGridProps, IrisGridState> {
591595
this.handleTooltipRef = this.handleTooltipRef.bind(this);
592596
this.handleViewChanged = this.handleViewChanged.bind(this);
593597
this.handleFormatSelection = this.handleFormatSelection.bind(this);
598+
this.handleColumnAlignmentChange =
599+
this.handleColumnAlignmentChange.bind(this);
594600
this.handleConditionalFormatCreate =
595601
this.handleConditionalFormatCreate.bind(this);
596602
this.handleConditionalFormatEdit =
@@ -718,6 +724,7 @@ class IrisGrid extends Component<IrisGridProps, IrisGridState> {
718724
aggregationSettings,
719725
conditionalFormats,
720726
customColumnFormatMap,
727+
columnAlignmentMap,
721728
isFilterBarShown,
722729
isSelectingPartition,
723730
partitions,
@@ -841,6 +848,7 @@ class IrisGrid extends Component<IrisGridProps, IrisGridState> {
841848
formatter: new Formatter(dh),
842849
isMenuShown: false,
843850
customColumnFormatMap: new Map(customColumnFormatMap),
851+
columnAlignmentMap: new Map(columnAlignmentMap),
844852

845853
conditionalFormats,
846854
conditionalFormatEditIndex: null,
@@ -3129,6 +3137,24 @@ class IrisGrid extends Component<IrisGridProps, IrisGridState> {
31293137
this.updateFormatter({ customColumnFormatMap });
31303138
}
31313139

3140+
handleColumnAlignmentChange(
3141+
modelIndex: ModelIndex,
3142+
alignment: CanvasTextAlign | null
3143+
): void {
3144+
const { model } = this.props;
3145+
const column = model.columns[modelIndex];
3146+
3147+
this.setState(({ columnAlignmentMap = EMPTY_MAP }) => {
3148+
const newColumnAlignmentMap = new Map(columnAlignmentMap);
3149+
if (alignment != null) {
3150+
newColumnAlignmentMap.set(column.name, alignment);
3151+
} else {
3152+
newColumnAlignmentMap.delete(column.name);
3153+
}
3154+
return { columnAlignmentMap: newColumnAlignmentMap };
3155+
});
3156+
}
3157+
31323158
handleMenu(e: React.MouseEvent<HTMLButtonElement>): void {
31333159
e.stopPropagation();
31343160
this.setState({ isMenuShown: true });
@@ -4389,6 +4415,8 @@ class IrisGrid extends Component<IrisGridProps, IrisGridState> {
43894415
conditionalFormatPreview,
43904416
conditionalFormatEditIndex,
43914417

4418+
columnAlignmentMap,
4419+
43924420
sorts,
43934421
reverse,
43944422
customColumns,
@@ -4980,6 +5008,7 @@ class IrisGrid extends Component<IrisGridProps, IrisGridState> {
49805008
right={right}
49815009
filter={filter}
49825010
formatter={formatter}
5011+
columnAlignmentMap={columnAlignmentMap}
49835012
sorts={sorts}
49845013
reverse={reverse}
49855014
movedColumns={movedColumns}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const irisGridState = {
2727
showOnTop: false,
2828
},
2929
customColumnFormatMap: new Map(),
30+
columnAlignmentMap: new Map(),
3031
isFilterBarShown: false,
3132
quickFilters: new Map(),
3233
customColumns: [],

packages/iris-grid/src/IrisGridCacheUtils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ function areIrisGridStatesEqual(
4848
'advancedFilters',
4949
'aggregationSettings',
5050
'customColumnFormatMap',
51+
'columnAlignmentMap',
5152
'isFilterBarShown',
5253
'quickFilters',
5354
'customColumns',

packages/iris-grid/src/IrisGridModel.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,18 @@ abstract class IrisGridModel<
249249
*/
250250
abstract set formatter(formatter: Formatter);
251251

252+
/**
253+
* @returns The column alignment map
254+
*/
255+
abstract get columnAlignmentMap(): ReadonlyMap<string, CanvasTextAlign>;
256+
257+
/**
258+
* @param columnAlignmentMap The column alignment map to set
259+
*/
260+
abstract set columnAlignmentMap(
261+
columnAlignmentMap: Map<string, CanvasTextAlign>
262+
);
263+
252264
/**
253265
* @param value The value to format
254266
* @param columnType The column type to format

packages/iris-grid/src/IrisGridModelUpdater.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ interface IrisGridModelUpdaterProps {
3939
formatColumns: readonly dh.CustomColumn[];
4040
alwaysFetchColumns: readonly ColumnName[];
4141
formatter: Formatter;
42+
columnAlignmentMap: Map<string, CanvasTextAlign>;
4243
rollupConfig?: dh.RollupConfig | null;
4344
totalsConfig?: UITotalsTableConfig | null;
4445
selectDistinctColumns?: readonly ColumnName[];
@@ -59,6 +60,7 @@ function IrisGridModelUpdater({
5960
right,
6061
filter,
6162
formatter,
63+
columnAlignmentMap,
6264
reverse = false,
6365
sorts,
6466
customColumns,
@@ -126,6 +128,12 @@ function IrisGridModelUpdater({
126128
},
127129
[model, formatter]
128130
);
131+
useOnChange(
132+
function updateColumnAlignmentMap() {
133+
model.columnAlignmentMap = columnAlignmentMap;
134+
},
135+
[model, columnAlignmentMap]
136+
);
129137
useOnChange(
130138
function updateCustomColumns() {
131139
if (model.isCustomColumnsAvailable) {

packages/iris-grid/src/IrisGridProxyModel.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,14 @@ class IrisGridProxyModel extends IrisGridModel implements PartitionedGridModel {
457457
this.originalModel.formatter = formatter;
458458
}
459459

460+
get columnAlignmentMap(): ReadonlyMap<string, CanvasTextAlign> {
461+
return this.originalModel.columnAlignmentMap;
462+
}
463+
464+
set columnAlignmentMap(columnAlignmentMap: Map<string, CanvasTextAlign>) {
465+
this.originalModel.columnAlignmentMap = columnAlignmentMap;
466+
}
467+
460468
setViewport = (
461469
top: number,
462470
bottom: number,

packages/iris-grid/src/IrisGridTableModelTemplate.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ class IrisGridTableModelTemplate<
141141

142142
private irisFormatter: Formatter;
143143

144+
private irisColumnAlignmentMap: Map<string, CanvasTextAlign>;
145+
144146
inputTable: DhType.InputTable | null;
145147

146148
private subscription: DhType.TableViewportSubscription | null;
@@ -193,12 +195,14 @@ class IrisGridTableModelTemplate<
193195
* @param table Iris data table to be used in the model
194196
* @param formatter The formatter to use when getting formats
195197
* @param inputTable Iris input table associated with this table
198+
* @param columnAlignmentMap Map of column alignments
196199
*/
197200
constructor(
198201
dh: typeof DhType,
199202
table: T,
200203
formatter = new Formatter(dh),
201-
inputTable: DhType.InputTable | null = null
204+
inputTable: DhType.InputTable | null = null,
205+
columnAlignmentMap = new Map<string, CanvasTextAlign>()
202206
) {
203207
super(dh);
204208

@@ -212,6 +216,7 @@ class IrisGridTableModelTemplate<
212216

213217
this.dh = dh;
214218
this.irisFormatter = formatter;
219+
this.irisColumnAlignmentMap = columnAlignmentMap;
215220
this.irisGridUtils = new IrisGridUtils(dh);
216221
this.inputTable = inputTable;
217222
this.subscription = null;
@@ -656,6 +661,11 @@ class IrisGridTableModelTemplate<
656661
textAlignForCell(x: ModelIndex, y: ModelIndex): CanvasTextAlign {
657662
const column = this.sourceColumn(x, y);
658663

664+
const userTextAlignment = this.columnAlignmentMap.get(column.name);
665+
if (userTextAlignment != null) {
666+
return userTextAlignment;
667+
}
668+
659669
return IrisGridUtils.textAlignForValue(column.type, column.name);
660670
}
661671

@@ -1220,6 +1230,14 @@ class IrisGridTableModelTemplate<
12201230
);
12211231
}
12221232

1233+
get columnAlignmentMap(): ReadonlyMap<string, CanvasTextAlign> {
1234+
return this.irisColumnAlignmentMap;
1235+
}
1236+
1237+
set columnAlignmentMap(columnAlignmentMap: Map<string, CanvasTextAlign>) {
1238+
this.irisColumnAlignmentMap = columnAlignmentMap;
1239+
}
1240+
12231241
displayString(
12241242
value: unknown,
12251243
columnType: string,

0 commit comments

Comments
 (0)