diff --git a/webui/react/src/components/ColumnPickerMenu.tsx b/webui/react/src/components/ColumnPickerMenu.tsx index 9cfd63c33ff..6838723479b 100644 --- a/webui/react/src/components/ColumnPickerMenu.tsx +++ b/webui/react/src/components/ColumnPickerMenu.tsx @@ -11,7 +11,6 @@ import { Loadable } from 'hew/utils/loadable'; import React, { ChangeEvent, useCallback, useMemo, useState } from 'react'; import { FixedSizeList as List } from 'react-window'; -import { runColumns } from 'pages/FlatRuns/columns'; import { V1ColumnType, V1LocationType } from 'services/api-ts-sdk'; import { ProjectColumn } from 'types'; import { ensureArray } from 'utils/data'; @@ -66,6 +65,8 @@ interface ColumnTabProps { onHeatmapSelectionRemove?: (id: string) => void; } +const KNOWN_BOOLEAN_COLUMNS = ['archived', 'isExpMultitrial', 'parentArchived']; + const ColumnPickerTab: React.FC = ({ columnState, compare, @@ -115,7 +116,7 @@ const ColumnPickerTab: React.FC = ({ : [...new Set([...columnState, ...filteredColumns.map((col) => formatColumnKey(col))])]; const pinnedCount = allFilteredColumnsChecked ? // If uncheck something pinned, reduce the pinnedColumnsCount - newColumns.filter((col) => columnState.indexOf(col) < pinnedColumnsCount).length + newColumns.filter((col) => columnState.indexOf(col) < pinnedColumnsCount).length : pinnedColumnsCount; onVisibleColumnChange?.(newColumns, pinnedCount); @@ -174,8 +175,7 @@ const ColumnPickerTab: React.FC = ({ ({ index, style }: { index: number; style: React.CSSProperties }) => { const col = filteredColumns[index]; const colType = - (runColumns as readonly string[]).includes(col.column) && - col.type === V1ColumnType.UNSPECIFIED + KNOWN_BOOLEAN_COLUMNS.includes(col.column) && col.type === V1ColumnType.UNSPECIFIED ? 'BOOLEAN' : removeColumnTypePrefix(col.type); const getColDisplayName = (col: ProjectColumn) => { diff --git a/webui/react/src/components/FilterForm/TableFilter.tsx b/webui/react/src/components/FilterForm/TableFilter.tsx index 62a91c42109..6fd3f42ef74 100644 --- a/webui/react/src/components/FilterForm/TableFilter.tsx +++ b/webui/react/src/components/FilterForm/TableFilter.tsx @@ -9,6 +9,7 @@ import FilterForm from 'components/FilterForm/components/FilterForm'; import { FilterFormStore } from 'components/FilterForm/components/FilterFormStore'; import { FormKind } from 'components/FilterForm/components/type'; import { V1ProjectColumn } from 'services/api-ts-sdk'; +import { formatColumnKey } from 'utils/flatRun'; interface Props { loadableColumns: Loadable; @@ -32,7 +33,7 @@ const TableFilter = ({ onIsOpenFilterChange, }: Props): JSX.Element => { const columns: V1ProjectColumn[] = Loadable.getOrElse([], loadableColumns).filter( - (column) => !bannedFilterColumns?.has(column.column), + (column) => !bannedFilterColumns?.has(formatColumnKey(column)), ); const fieldCount = useObservable(formStore.fieldCount); const formset = useObservable(formStore.formset); diff --git a/webui/react/src/components/FilterForm/components/FilterField.tsx b/webui/react/src/components/FilterForm/components/FilterField.tsx index eda8536a474..5512e925781 100644 --- a/webui/react/src/components/FilterForm/components/FilterField.tsx +++ b/webui/react/src/components/FilterForm/components/FilterField.tsx @@ -1,4 +1,5 @@ import dayjs from 'dayjs'; +import Badge from 'hew/Badge'; import Button from 'hew/Button'; import DatePicker, { DatePickerProps } from 'hew/DatePicker'; import Icon from 'hew/Icon'; @@ -32,6 +33,7 @@ import { getMetadataValues } from 'services/api'; import { V1ColumnType, V1LocationType, V1ProjectColumn } from 'services/api-ts-sdk'; import clusterStore from 'stores/cluster'; import userStore from 'stores/users'; +import { formatColumnKey, METADATA_SEPARATOR, removeColumnTypePrefix } from 'utils/flatRun'; import { alphaNumericSorter } from 'utils/sort'; import css from './FilterField.module.scss'; @@ -69,7 +71,10 @@ const FilterField = ({ }: Props): JSX.Element => { const users = Loadable.getOrElse([], useObservable(userStore.getUsers())); const resourcePools = Loadable.getOrElse([], useObservable(clusterStore.resourcePools)); - const currentColumn = columns.find((c) => c.column === field.columnName); + const currentColumn = useMemo( + () => columns.find((c) => c.type === field.type && c.column === field.columnName), + [columns, field.columnName, field.type], + ); const columnType = useMemo(() => { if (field.location === V1LocationType.RUNMETADATA && field.type === V1ColumnType.TEXT) { @@ -96,19 +101,18 @@ const FilterField = ({ }; const onChangeColumnName = (value: SelectValue) => { - const prevType = currentColumn?.type; - const newColName = value?.toString() ?? ''; - const newCol = columns.find((c) => c.column === newColName); + const prevType = field.type; + const [type, newColName] = (value?.toString() ?? '').split(METADATA_SEPARATOR, 2); + const newCol = columns.find((c) => c.column === newColName && type === c.type); if (newCol) { Observable.batch(() => { formStore.setFieldColumnName(field.id, newCol); - if ((SpecialColumnNames as ReadonlyArray).includes(newColName)) { formStore.setFieldOperator(field.id, Operator.Eq); updateFieldValue(field.id, null); - } else if (prevType !== newCol?.type) { + } else if (prevType !== newCol.type) { const defaultOperator: Operator = - AvailableOperators[newCol?.type ?? V1ColumnType.UNSPECIFIED][0]; + AvailableOperators[newCol.type ?? V1ColumnType.UNSPECIFIED][0]; formStore.setFieldOperator(field.id, defaultOperator); updateFieldValue(field.id, null); } @@ -218,6 +222,16 @@ const FilterField = ({ [columnType, field.type, formStore, index, inputOpen, parentId], ); + const getColDisplayName = (col: V1ProjectColumn) => { + const colType = removeColumnTypePrefix(col.type); + + return ( + <> + {col.displayName || col.column} + + ); + }; + return (
drop(node)}> ({ - key: `${col.column} ${idx}`, - label: col.displayName || col.column, - value: col.column, + options={columns.map((col) => ({ + key: formatColumnKey(col, true), + label: getColDisplayName(col), + title: col.displayName || col.column, + value: formatColumnKey(col, true), }))} - value={field.columnName} + value={`${field.type}${METADATA_SEPARATOR}${field.columnName}`} width={'100%'} onChange={onChangeColumnName} /> diff --git a/webui/react/src/components/FilterForm/components/FilterFormStore.ts b/webui/react/src/components/FilterForm/components/FilterFormStore.ts index 9bb61000a04..880c1421701 100644 --- a/webui/react/src/components/FilterForm/components/FilterFormStore.ts +++ b/webui/react/src/components/FilterForm/components/FilterFormStore.ts @@ -242,7 +242,8 @@ export class FilterFormStore { col: Pick, ): void { return this.#updateField(id, (form) => { - if (form.columnName === col.column && form.location === col.location) { + const isSameColumn = form.columnName === col.column && form.type === col.type; + if (isSameColumn && form.location === col.location) { return form; } return { diff --git a/webui/react/src/components/MultiSortMenu.tsx b/webui/react/src/components/MultiSortMenu.tsx index 68916cb3fd6..1b677894876 100644 --- a/webui/react/src/components/MultiSortMenu.tsx +++ b/webui/react/src/components/MultiSortMenu.tsx @@ -1,12 +1,17 @@ +import Badge from 'hew/Badge'; import Button from 'hew/Button'; import { DirectionType, Sort, validSort } from 'hew/DataGrid/DataGrid'; import Dropdown, { MenuItem } from 'hew/Dropdown'; import Icon from 'hew/Icon'; import Select, { Option } from 'hew/Select'; import { Loadable } from 'hew/utils/loadable'; +import { groupBy, mapValues } from 'lodash'; +import { Fragment, useMemo } from 'react'; +import { runColumns } from 'pages/FlatRuns/columns'; import { V1ColumnType } from 'services/api-ts-sdk'; import { ProjectColumn } from 'types'; +import { removeColumnTypePrefix } from 'utils/flatRun'; import css from './MultiSortMenu.module.scss'; @@ -25,6 +30,7 @@ interface MultiSortRowProps { onChange?: (sort: Sort) => void; onRemove?: () => void; bannedSortColumns: Set; + typeMap: Record; } interface DirectionOptionsProps { onChange?: (direction: DirectionType) => void; @@ -36,6 +42,7 @@ interface ColumnOptionsProps { onChange?: (column: string) => void; value?: string; bannedSortColumns: Set; + typeMap: Record; } export const optionsByColumnType = { @@ -153,6 +160,7 @@ const ColumnOptions: React.FC = ({ columns, value, bannedSortColumns, + typeMap, }) => (