Skip to content

Commit 6161def

Browse files
feat: add metadata column type badge
1 parent 85a5d22 commit 6161def

File tree

6 files changed

+92
-63
lines changed

6 files changed

+92
-63
lines changed

webui/react/src/components/ColumnPickerMenu.tsx

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import Badge from 'hew/Badge';
12
import Button from 'hew/Button';
23
import Checkbox, { CheckboxChangeEvent } from 'hew/Checkbox';
34
import Dropdown from 'hew/Dropdown';
@@ -10,9 +11,11 @@ import { Loadable } from 'hew/utils/loadable';
1011
import React, { ChangeEvent, useCallback, useMemo, useState } from 'react';
1112
import { FixedSizeList as List } from 'react-window';
1213

13-
import { V1LocationType } from 'services/api-ts-sdk';
14+
import { runColumns } from 'pages/FlatRuns/columns';
15+
import { V1ColumnType, V1LocationType } from 'services/api-ts-sdk';
1416
import { ProjectColumn } from 'types';
1517
import { ensureArray } from 'utils/data';
18+
import { formatColumnKey, removeColumnTypePrefix } from 'utils/flatRun';
1619

1720
import css from './ColumnPickerMenu.module.scss';
1821

@@ -75,7 +78,7 @@ const ColumnPickerTab: React.FC<ColumnTabProps> = ({
7578
onVisibleColumnChange,
7679
onHeatmapSelectionRemove,
7780
}) => {
78-
const checkedColumns = useMemo(
81+
const checkedColumnNames = useMemo(
7982
() => (compare ? new Set(columnState.slice(0, pinnedColumnsCount)) : new Set(columnState)),
8083
[columnState, compare, pinnedColumnsCount],
8184
);
@@ -95,18 +98,21 @@ const ColumnPickerTab: React.FC<ColumnTabProps> = ({
9598
}, [searchString, totalColumns, tab]);
9699

97100
const allFilteredColumnsChecked = useMemo(() => {
98-
return filteredColumns.every((col) => columnState.includes(col.column));
101+
return filteredColumns.every((col) => columnState.includes(formatColumnKey(col)));
99102
}, [columnState, filteredColumns]);
100103

101104
const handleShowHideAll = useCallback(() => {
102105
const filteredColumnMap: Record<string, boolean> = filteredColumns.reduce(
103-
(acc, col) => ({ ...acc, [col.column]: columnState.includes(col.column) }),
106+
(acc, col) => ({
107+
...acc,
108+
[formatColumnKey(col)]: columnState.includes(formatColumnKey(col)),
109+
}),
104110
{},
105111
);
106112

107113
const newColumns = allFilteredColumnsChecked
108114
? columnState.filter((col) => !filteredColumnMap[col])
109-
: [...new Set([...columnState, ...filteredColumns.map((col) => col.column)])];
115+
: [...new Set([...columnState, ...filteredColumns.map((col) => formatColumnKey(col))])];
110116
const pinnedCount = allFilteredColumnsChecked
111117
? // If uncheck something pinned, reduce the pinnedColumnsCount
112118
newColumns.filter((col) => columnState.indexOf(col) < pinnedColumnsCount).length
@@ -123,32 +129,34 @@ const ColumnPickerTab: React.FC<ColumnTabProps> = ({
123129

124130
const handleColumnChange = useCallback(
125131
(event: CheckboxChangeEvent) => {
126-
const { id, checked } = event.target;
127-
if (id === undefined) return;
132+
const { id: targetCol, checked } = event.target;
133+
134+
if (targetCol === undefined) return;
135+
128136
if (compare) {
129137
// pin or unpin column
130-
const newColumns = columnState.filter((c) => c !== id);
138+
const newColumns = columnState.filter((c) => c !== targetCol);
131139
let pinnedCount = pinnedColumnsCount;
132140
if (checked) {
133-
newColumns.splice(pinnedColumnsCount, 0, id);
141+
newColumns.splice(pinnedColumnsCount, 0, targetCol);
134142
pinnedCount = Math.max(pinnedColumnsCount + 1, 0);
135143
} else {
136-
newColumns.splice(pinnedColumnsCount - 1, 0, id);
144+
newColumns.splice(pinnedColumnsCount - 1, 0, targetCol);
137145
pinnedCount = Math.max(pinnedColumnsCount - 1, 0);
138146
}
139147
onVisibleColumnChange?.(newColumns, pinnedCount);
140148
} else {
141149
let pinnedCount = pinnedColumnsCount;
142150
// If uncheck something pinned, reduce the pinnedColumnsCount
143-
if (!checked && columnState.indexOf(id) < pinnedColumnsCount) {
151+
if (!checked && columnState.indexOf(targetCol) < pinnedColumnsCount) {
144152
pinnedCount = Math.max(pinnedColumnsCount - 1, 0);
145153
}
146154
// If uncheck something had heatmap skipped, reset to heatmap visible
147155
if (!checked) {
148-
onHeatmapSelectionRemove?.(id);
156+
onHeatmapSelectionRemove?.(targetCol);
149157
}
150158
const newColumnSet = new Set(columnState);
151-
checked ? newColumnSet.add(id) : newColumnSet.delete(id);
159+
checked ? newColumnSet.add(targetCol) : newColumnSet.delete(targetCol);
152160
onVisibleColumnChange?.([...newColumnSet], pinnedCount);
153161
}
154162
},
@@ -165,24 +173,48 @@ const ColumnPickerTab: React.FC<ColumnTabProps> = ({
165173
const rows = useCallback(
166174
({ index, style }: { index: number; style: React.CSSProperties }) => {
167175
const col = filteredColumns[index];
176+
const colType =
177+
(runColumns as readonly string[]).includes(col.column) &&
178+
col.type === V1ColumnType.UNSPECIFIED
179+
? 'BOOLEAN'
180+
: removeColumnTypePrefix(col.type);
181+
const getColDisplayName = (col: ProjectColumn) => {
182+
return (
183+
<>
184+
{col.displayName || col.column} <Badge text={colType} />
185+
</>
186+
);
187+
};
188+
const getId = () => {
189+
if (col.location === V1LocationType.RUNMETADATA) return formatColumnKey(col);
190+
191+
return col.column;
192+
};
193+
const getChecked = () => {
194+
if (col.location === V1LocationType.RUNMETADATA)
195+
return checkedColumnNames.has(formatColumnKey(col));
196+
197+
return checkedColumnNames.has(col.column);
198+
};
199+
168200
return (
169201
<div
170202
className={css.rows}
171203
data-test="row"
172-
data-test-id={col.column}
173-
key={col.column}
204+
data-test-id={getId()}
205+
key={getId()}
174206
style={style}>
175207
<Checkbox
176-
checked={checkedColumns.has(col.column)}
208+
checked={getChecked()}
177209
data-test="checkbox"
178-
id={col.column}
210+
id={getId()}
179211
onChange={handleColumnChange}>
180-
{col.displayName || col.column}
212+
{getColDisplayName(col)}
181213
</Checkbox>
182214
</div>
183215
);
184216
},
185-
[filteredColumns, checkedColumns, handleColumnChange],
217+
[filteredColumns, checkedColumnNames, handleColumnChange],
186218
);
187219

188220
return (

webui/react/src/components/Searches/columns.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ export const getColumnDefs = ({
130130
},
131131
checkpointCount: {
132132
id: 'checkpointCount',
133-
isNumerical: true,
134133
renderer: (record: ExperimentWithTrial) => ({
135134
allowOverlay: false,
136135
data: Number(record.experiment.checkpoints),
@@ -143,7 +142,6 @@ export const getColumnDefs = ({
143142
},
144143
checkpointSize: {
145144
id: 'checkpointSize',
146-
isNumerical: true,
147145
renderer: (record: ExperimentWithTrial) =>
148146
handleEmptyCell(record.experiment.checkpointSize, (data) => ({
149147
allowOverlay: false,
@@ -174,7 +172,6 @@ export const getColumnDefs = ({
174172
},
175173
duration: {
176174
id: 'duration',
177-
isNumerical: true,
178175
renderer: (record: ExperimentWithTrial) =>
179176
handleEmptyCell(record.experiment.duration, () => ({
180177
allowOverlay: false,
@@ -297,7 +294,6 @@ export const getColumnDefs = ({
297294
},
298295
numTrials: {
299296
id: 'numTrials',
300-
isNumerical: true,
301297
renderer: (record: ExperimentWithTrial) => ({
302298
allowOverlay: false,
303299
data: record.experiment.numTrials,
@@ -335,7 +331,6 @@ export const getColumnDefs = ({
335331
},
336332
searcherMetric: {
337333
id: 'searcherMetric',
338-
isNumerical: false,
339334
renderer: (record: ExperimentWithTrial) =>
340335
handleEmptyCell(record.experiment.searcherMetric, (data) => ({
341336
allowOverlay: false,
@@ -361,7 +356,6 @@ export const getColumnDefs = ({
361356
},
362357
startTime: {
363358
id: 'startTime',
364-
isNumerical: true,
365359
renderer: (record: ExperimentWithTrial) => ({
366360
allowOverlay: false,
367361
copyData: getTimeInEnglish(new Date(record.experiment.startTime)),
@@ -440,7 +434,6 @@ export const getColumnDefs = ({
440434
export const searcherMetricsValColumn = (columnWidth?: number): ColumnDef<ExperimentWithTrial> => {
441435
return {
442436
id: 'searcherMetricsVal',
443-
isNumerical: true,
444437
renderer: (record: ExperimentWithTrial) =>
445438
handleEmptyCell(record.bestTrial?.searcherMetricsVal, (data) => ({
446439
allowOverlay: false,

webui/react/src/pages/F_ExpList/expListColumns.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ export const getColumnDefs = ({
136136
},
137137
checkpointCount: {
138138
id: 'checkpointCount',
139-
isNumerical: true,
140139
renderer: (record: ExperimentWithTrial) => ({
141140
allowOverlay: false,
142141
data: Number(record.experiment.checkpoints),
@@ -149,7 +148,6 @@ export const getColumnDefs = ({
149148
},
150149
checkpointSize: {
151150
id: 'checkpointSize',
152-
isNumerical: true,
153151
renderer: (record: ExperimentWithTrial) => ({
154152
allowOverlay: false,
155153
copyData: record.experiment.checkpointSize
@@ -176,7 +174,6 @@ export const getColumnDefs = ({
176174
},
177175
duration: {
178176
id: 'duration',
179-
isNumerical: true,
180177
renderer: (record: ExperimentWithTrial) => ({
181178
allowOverlay: false,
182179
copyData: getDurationInEnglish(record.experiment),
@@ -305,7 +302,6 @@ export const getColumnDefs = ({
305302
},
306303
numTrials: {
307304
id: 'numTrials',
308-
isNumerical: true,
309305
renderer: (record: ExperimentWithTrial) => ({
310306
allowOverlay: false,
311307
data: record.experiment.numTrials,
@@ -346,7 +342,6 @@ export const getColumnDefs = ({
346342
},
347343
searcherMetric: {
348344
id: 'searcherMetric',
349-
isNumerical: false,
350345
renderer: (record: ExperimentWithTrial) => {
351346
const sMetric = record.experiment.searcherMetric ?? '';
352347
return {
@@ -374,7 +369,6 @@ export const getColumnDefs = ({
374369
},
375370
startTime: {
376371
id: 'startTime',
377-
isNumerical: true,
378372
renderer: (record: ExperimentWithTrial) => ({
379373
allowOverlay: false,
380374
copyData: getTimeInEnglish(new Date(record.experiment.startTime)),
@@ -456,7 +450,6 @@ export const searcherMetricsValColumn = (
456450
): ColumnDef<ExperimentWithTrial> => {
457451
return {
458452
id: 'searcherMetricsVal',
459-
isNumerical: true,
460453
renderer: (record: ExperimentWithTrial) => {
461454
const sMetricValue = record.bestTrial?.searcherMetricsVal;
462455

webui/react/src/pages/FlatRuns/FlatRuns.tsx

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ import userSettings from 'stores/userSettings';
7575
import { DetailedUser, FlatRun, FlatRunAction, ProjectColumn, RunState } from 'types';
7676
import handleError from 'utils/error';
7777
import { combine } from 'utils/filterFormSet';
78+
import { formatColumnKey } from 'utils/flatRun';
7879
import { eagerSubscribe } from 'utils/observable';
7980
import { pluralizer } from 'utils/string';
8081

@@ -295,7 +296,7 @@ const FlatRuns: React.FC<Props> = ({ projectId, workspaceId, searchId }) => {
295296
const projectColumnsMap: Loadable<Record<string, ProjectColumn>> = Loadable.map(
296297
projectColumns,
297298
(columns) => {
298-
return columns.reduce((acc, col) => ({ ...acc, [col.column]: col }), {});
299+
return columns.reduce((acc, col) => ({ ...acc, [formatColumnKey(col)]: col }), {});
299300
},
300301
);
301302
const columnDefs = getColumnDefs({
@@ -333,6 +334,7 @@ const FlatRuns: React.FC<Props> = ({ projectId, workspaceId, searchId }) => {
333334
};
334335

335336
let dataPath: string | undefined = undefined;
337+
const columnDefKey = formatColumnKey(currentColumn);
336338
switch (currentColumn.location) {
337339
case V1LocationType.EXPERIMENT:
338340
dataPath = `experiment.${currentColumn.column}`;
@@ -373,11 +375,11 @@ const FlatRuns: React.FC<Props> = ({ projectId, workspaceId, searchId }) => {
373375
settings.heatmapOn &&
374376
!settings.heatmapSkipped.includes(currentColumn.column)
375377
) {
376-
columnDefs[currentColumn.column] = defaultNumberColumn(
377-
currentColumn.column,
378+
columnDefs[columnDefKey] = defaultNumberColumn(
379+
columnDefKey,
378380
currentColumn.displayName || currentColumn.column,
379-
settings.columnWidths[currentColumn.column] ??
380-
defaultColumnWidths[currentColumn.column as RunColumn] ??
381+
settings.columnWidths[columnDefKey] ??
382+
defaultColumnWidths[columnDefKey as RunColumn] ??
381383
MIN_COLUMN_WIDTH,
382384
dataPath,
383385
{
@@ -386,45 +388,46 @@ const FlatRuns: React.FC<Props> = ({ projectId, workspaceId, searchId }) => {
386388
},
387389
);
388390
} else {
389-
columnDefs[currentColumn.column] = defaultNumberColumn(
390-
currentColumn.column,
391+
columnDefs[columnDefKey] = defaultNumberColumn(
392+
columnDefKey,
391393
currentColumn.displayName || currentColumn.column,
392-
settings.columnWidths[currentColumn.column] ??
393-
defaultColumnWidths[currentColumn.column as RunColumn] ??
394+
settings.columnWidths[columnDefKey] ??
395+
defaultColumnWidths[columnDefKey as RunColumn] ??
394396
MIN_COLUMN_WIDTH,
395397
dataPath,
398+
undefined,
396399
);
397400
}
398401
break;
399402
}
400403
case V1ColumnType.DATE:
401-
columnDefs[currentColumn.column] = defaultDateColumn(
402-
currentColumn.column,
404+
columnDefs[columnDefKey] = defaultDateColumn(
405+
columnDefKey,
403406
currentColumn.displayName || currentColumn.column,
404-
settings.columnWidths[currentColumn.column] ??
405-
defaultColumnWidths[currentColumn.column as RunColumn] ??
407+
settings.columnWidths[columnDefKey] ??
408+
defaultColumnWidths[columnDefKey as RunColumn] ??
406409
MIN_COLUMN_WIDTH,
407410
dataPath,
408411
);
409412
break;
410413
case V1ColumnType.ARRAY:
411-
columnDefs[currentColumn.column] = defaultArrayColumn(
412-
currentColumn.column,
414+
columnDefs[columnDefKey] = defaultArrayColumn(
415+
columnDefKey,
413416
currentColumn.displayName || currentColumn.column,
414-
settings.columnWidths[currentColumn.column] ??
415-
defaultColumnWidths[currentColumn.column as RunColumn] ??
417+
settings.columnWidths[columnDefKey] ??
418+
defaultColumnWidths[columnDefKey as RunColumn] ??
416419
MIN_COLUMN_WIDTH,
417420
dataPath,
418421
);
419422
break;
420423
case V1ColumnType.TEXT:
421424
case V1ColumnType.UNSPECIFIED:
422425
default:
423-
columnDefs[currentColumn.column] = defaultTextColumn(
424-
currentColumn.column,
426+
columnDefs[columnDefKey] = defaultTextColumn(
427+
columnDefKey,
425428
currentColumn.displayName || currentColumn.column,
426-
settings.columnWidths[currentColumn.column] ??
427-
defaultColumnWidths[currentColumn.column as RunColumn] ??
429+
settings.columnWidths[columnDefKey] ??
430+
defaultColumnWidths[columnDefKey as RunColumn] ??
428431
MIN_COLUMN_WIDTH,
429432
dataPath,
430433
);
@@ -434,7 +437,7 @@ const FlatRuns: React.FC<Props> = ({ projectId, workspaceId, searchId }) => {
434437
.getOrElse([])
435438
.find((h) => h.metricsName === currentColumn.column);
436439

437-
columnDefs[currentColumn.column] = searcherMetricsValColumn(
440+
columnDefs[columnDefKey] = searcherMetricsValColumn(
438441
settings.columnWidths[currentColumn.column],
439442
heatmap && settings.heatmapOn && !settings.heatmapSkipped.includes(currentColumn.column)
440443
? {
@@ -444,7 +447,7 @@ const FlatRuns: React.FC<Props> = ({ projectId, workspaceId, searchId }) => {
444447
: undefined,
445448
);
446449
}
447-
return columnDefs[currentColumn.column];
450+
return columnDefs[columnDefKey];
448451
})
449452
.flatMap((col) => (col ? [col] : []));
450453
return gridColumns;

0 commit comments

Comments
 (0)