diff --git a/webui/react/src/components/Searches/Searches.settings.ts b/webui/react/src/components/Searches/Searches.settings.ts index 46e86cfab97..db0f578637e 100644 --- a/webui/react/src/components/Searches/Searches.settings.ts +++ b/webui/react/src/components/Searches/Searches.settings.ts @@ -1,4 +1,5 @@ import * as t from 'io-ts'; +import { pick } from 'lodash'; import { INIT_FORMSET } from 'components/FilterForm/components/FilterFormStore'; import { RegularSelectionType, SelectionType } from 'types'; @@ -10,24 +11,26 @@ export const DEFAULT_SELECTION: t.TypeOf = { type: 'ONLY_IN', }; -// have to intersect with an empty object bc of settings store type issue -export const ProjectSettings = t.intersection([ - t.type({}), - t.partial({ - columns: t.array(t.string), - columnWidths: t.record(t.string, t.number), - compare: t.boolean, - filterset: t.string, // save FilterFormSet as string - heatmapOn: t.boolean, - heatmapSkipped: t.array(t.string), - pageLimit: t.number, - pinnedColumnsCount: t.number, - selection: SelectionType, - sortString: t.string, - }), -]); +export const ProjectSettings = t.partial({ + columns: t.array(t.string), + columnWidths: t.record(t.string, t.number), + compare: t.boolean, + filterset: t.string, // save FilterFormSet as string + heatmapOn: t.boolean, + heatmapSkipped: t.array(t.string), + pageLimit: t.number, + pinnedColumnsCount: t.number, + selection: SelectionType, + sortString: t.string, +}); export type ProjectSettings = t.TypeOf; +/** + * Slice of ProjectSettings that concerns column widths -- this is extracted to + * allow updates to it to be debounced. + */ +export const ColumnWidthsSlice = t.exact(t.partial(pick(ProjectSettings.props, ['columnWidths']))); + export const ProjectUrlSettings = t.partial({ compare: t.boolean, page: t.number, diff --git a/webui/react/src/components/Searches/Searches.tsx b/webui/react/src/components/Searches/Searches.tsx index 32b27f96c8f..03eb57c7cee 100644 --- a/webui/react/src/components/Searches/Searches.tsx +++ b/webui/react/src/components/Searches/Searches.tsx @@ -8,6 +8,7 @@ import { defaultNumberColumn, defaultSelectionColumn, defaultTextColumn, + MIN_COLUMN_WIDTH, MULTISELECT, } from 'hew/DataGrid/columns'; import DataGrid, { @@ -51,6 +52,7 @@ import { DataGridGlobalSettings, settingsConfigGlobal } from 'components/Options import TableActionBar from 'components/TableActionBar'; import useUI from 'components/ThemeProvider'; import { useAsync } from 'hooks/useAsync'; +import { useDebouncedSettings } from 'hooks/useDebouncedSettings'; import { useGlasbey } from 'hooks/useGlasbey'; import useMobile from 'hooks/useMobile'; import usePolling from 'hooks/usePolling'; @@ -83,6 +85,7 @@ import { pluralizer } from 'utils/string'; import { getColumnDefs, searcherMetricsValColumn } from './columns'; import css from './Searches.module.scss'; import { + ColumnWidthsSlice, DEFAULT_SELECTION, defaultProjectSettings, ProjectSettings, @@ -145,12 +148,13 @@ const Searches: React.FC = ({ project }) => { (p: Partial) => userSettings.setPartial(ProjectSettings, settingsPath, p), [settingsPath], ); + const [columnWidths, setColumnWidths] = useDebouncedSettings(ColumnWidthsSlice, settingsPath); const settings = useMemo( () => - projectSettings - .map((s) => ({ ...defaultProjectSettings, ...s })) + Loadable.all([projectSettings, columnWidths]) + .map(([s, cw]) => ({ ...defaultProjectSettings, ...s, ...cw })) .getOrElse(defaultProjectSettings), - [projectSettings], + [projectSettings, columnWidths], ); const { params, updateParams } = useTypedParams(ProjectUrlSettings, {}); @@ -540,16 +544,18 @@ const Searches: React.FC = ({ project }) => { acc[col] = DEFAULT_COLUMN_WIDTH; return acc; }, {}); - updateSettings({ - columns: newColumnsOrder, + setColumnWidths({ columnWidths: { ...settings.columnWidths, ...newColumnWidths, }, + }); + updateSettings({ + columns: newColumnsOrder, pinnedColumnsCount: isUndefined(pinnedCount) ? settings.pinnedColumnsCount : pinnedCount, }); }, - [updateSettings, settings.pinnedColumnsCount, settings.columnWidths], + [setColumnWidths, updateSettings, settings.pinnedColumnsCount, settings.columnWidths], ); const handleRowHeightChange = useCallback( @@ -586,14 +592,14 @@ const Searches: React.FC = ({ project }) => { const handleColumnWidthChange = useCallback( (columnId: string, width: number) => { - updateSettings({ + setColumnWidths({ columnWidths: { ...settings.columnWidths, - [columnId]: width, + [columnId]: Math.max(MIN_COLUMN_WIDTH, width), }, }); }, - [updateSettings, settings.columnWidths], + [setColumnWidths, settings.columnWidths], ); const columnsIfLoaded = useMemo(