Skip to content

Commit

Permalink
Proper select all
Browse files Browse the repository at this point in the history
  • Loading branch information
EmilyBonar committed Oct 21, 2024
1 parent 8e032be commit 84d9e0e
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 65 deletions.
28 changes: 24 additions & 4 deletions webui/react/src/components/Searches/Searches.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -266,14 +266,33 @@ const Searches: React.FC<Props> = ({ project }) => {

const selection = useMemo<GridSelection>(() => {
let rows = CompactSelection.empty();
loadedSelectedExperimentIds.forEach((info) => {
rows = rows.add(info.index);
});
if (settings.selection.type === 'ONLY_IN') {
loadedSelectedExperimentIds.forEach((exp) => {
rows = rows.add(exp.index);
});
} else if (settings.selection.type === 'ALL_EXCEPT') {
rows = rows.add([0, total.getOrElse(1) - 1]);
settings.selection.exclusions.forEach((exc) => {
const excIndex = loadedSelectedExperimentIds.get(exc)?.index;
if (excIndex !== undefined) {
rows = rows.remove(excIndex);
}
});
}
return {
columns: CompactSelection.empty(),
rows,
};
}, [loadedSelectedExperimentIds]);
}, [loadedSelectedExperimentIds, settings.selection, total]);

const selectionSize = useMemo(() => {
if (settings.selection.type === 'ONLY_IN') {
return settings.selection.selections.length;
} else if (settings.selection.type === 'ALL_EXCEPT') {
return total.getOrElse(0) - settings.selection.exclusions.length;
}
return 0;
}, [settings.selection, total]);

const colorMap = useGlasbey([...loadedSelectedExperimentIds.keys()]);

Expand Down Expand Up @@ -885,6 +904,7 @@ const Searches: React.FC<Props> = ({ project }) => {
projectColumns={projectColumns}
rowHeight={globalSettings.rowHeight}
selectedExperimentIds={allSelectedExperimentIds}
selectionSize={selectionSize}
sorts={sorts}
total={total}
onActionComplete={handleActionComplete}
Expand Down
8 changes: 4 additions & 4 deletions webui/react/src/components/TableActionBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ interface Props {
projectColumns: Loadable<ProjectColumn[]>;
rowHeight: RowHeight;
selectedExperimentIds: number[];
selectionSize: number;
sorts: Sort[];
pinnedColumnsCount?: number;
total: Loadable<number>;
Expand Down Expand Up @@ -150,6 +151,7 @@ const TableActionBar: React.FC<Props> = ({
bannedFilterColumns,
bannedSortColumns,
entityCopy,
selectionSize,
}) => {
const permissions = usePermissions();
const [batchAction, setBatchAction] = useState<BatchAction>();
Expand Down Expand Up @@ -382,8 +384,6 @@ const TableActionBar: React.FC<Props> = ({
}, [] as MenuItem[]);
}, [availableBatchActions]);

const handleAction = useCallback((key: string) => handleBatchAction(key), [handleBatchAction]);

return (
<div className={css.base} data-test-component="tableActionBar">
<Row>
Expand Down Expand Up @@ -420,7 +420,7 @@ const TableActionBar: React.FC<Props> = ({
/>
<OptionsMenu rowHeight={rowHeight} onRowHeightChange={onRowHeightChange} />
{selectedExperimentIds.length > 0 && (
<Dropdown menu={editMenuItems} onClick={handleAction}>
<Dropdown menu={editMenuItems} onClick={handleBatchAction}>
<Button data-test="actionsDropdown" hideChildren={isMobile}>
Actions
</Button>
Expand All @@ -430,7 +430,7 @@ const TableActionBar: React.FC<Props> = ({
labelPlural={labelPlural}
labelSingular={labelSingular}
pageSize={pageSize}
selectedCount={selectedExperimentIds.length}
selectedCount={selectionSize}
total={total}
onActualSelectAll={onActualSelectAll}
onClearSelect={onClearSelect}
Expand Down
84 changes: 53 additions & 31 deletions webui/react/src/pages/F_ExpList/F_ExperimentList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -270,14 +270,33 @@ const F_ExperimentList: React.FC<Props> = ({ project }) => {

const selection = useMemo<GridSelection>(() => {
let rows = CompactSelection.empty();
loadedSelectedExperimentIds.forEach((info) => {
rows = rows.add(info.index);
});
if (settings.selection.type === 'ONLY_IN') {
loadedSelectedExperimentIds.forEach((exp) => {
rows = rows.add(exp.index);
});
} else if (settings.selection.type === 'ALL_EXCEPT') {
rows = rows.add([0, total.getOrElse(1) - 1]);
settings.selection.exclusions.forEach((exc) => {
const excIndex = loadedSelectedExperimentIds.get(exc)?.index;
if (excIndex !== undefined) {
rows = rows.remove(excIndex);
}
});
}
return {
columns: CompactSelection.empty(),
rows,
};
}, [loadedSelectedExperimentIds]);
}, [loadedSelectedExperimentIds, settings.selection, total]);

const selectionSize = useMemo(() => {
if (settings.selection.type === 'ONLY_IN') {
return settings.selection.selections.length;
} else if (settings.selection.type === 'ALL_EXCEPT') {
return total.getOrElse(0) - settings.selection.exclusions.length;
}
return 0;
}, [settings.selection, total]);

const colorMap = useGlasbey([...loadedSelectedExperimentIds.keys()]);
const { width: containerWidth } = useResize(contentRef);
Expand Down Expand Up @@ -906,35 +925,36 @@ const F_ExperimentList: React.FC<Props> = ({ project }) => {
users,
]);

const isRangeSelected = useCallback(
(range: [number, number]): boolean => {
if (settings.selection.type === 'ONLY_IN') {
const includedSet = new Set(settings.selection.selections);
return rowRangeToIds(range).every((id) => includedSet.has(id));
} else if (settings.selection.type === 'ALL_EXCEPT') {
const excludedSet = new Set(settings.selection.exclusions);
return rowRangeToIds(range).every((id) => !excludedSet.has(id));
}
return false; // should never be reached
},
[rowRangeToIds, settings.selection],
);

const handleHeaderClick = useCallback(
(columnId: string): void => {
if (columnId === MULTISELECT) {
if (isRangeSelected([0, settings.pageLimit])) {
handleSelectionChange?.('remove', [0, settings.pageLimit]);
} else {
handleSelectionChange?.('add', [0, settings.pageLimit]);
}
}
},
[handleSelectionChange, isRangeSelected, settings.pageLimit],
);

const getHeaderMenuItems = (columnId: string, colIdx: number): MenuItem[] => {
if (columnId === MULTISELECT) {
const items: MenuItem[] = [
settings.selection.type === 'ALL_EXCEPT' || settings.selection.selections.length > 0
? {
key: 'select-none',
label: 'Clear selected',
onClick: () => {
handleSelectionChange?.('remove-all');
},
}
: null,
...[5, 10, 25].map((n) => ({
key: `select-${n}`,
label: `Select first ${n}`,
onClick: () => {
handleSelectionChange?.('set', [0, n]);
dataGridRef.current?.scrollToTop();
},
})),
{
key: 'select-all',
label: 'Select all',
onClick: () => {
handleSelectionChange?.('add', [0, settings.pageLimit]);
},
},
];
return items;
return [];
}
const column = Loadable.getOrElse([], projectColumns).find((c) => c.column === columnId);
if (!column) {
Expand Down Expand Up @@ -1097,6 +1117,7 @@ const F_ExperimentList: React.FC<Props> = ({ project }) => {
projectColumns={projectColumns}
rowHeight={globalSettings.rowHeight}
selectedExperimentIds={allSelectedExperimentIds}
selectionSize={selectionSize}
sorts={sorts}
total={total}
onActionComplete={handleActionComplete}
Expand Down Expand Up @@ -1172,6 +1193,7 @@ const F_ExperimentList: React.FC<Props> = ({ project }) => {
onColumnResize={handleColumnWidthChange}
onColumnsOrderChange={handleColumnsOrderChange}
onContextMenuComplete={handleContextMenuComplete}
onHeaderClicked={handleHeaderClick}
onPinnedColumnsCountChange={handlePinnedColumnsCountChange}
onSelectionChange={handleSelectionChange}
/>
Expand Down
79 changes: 53 additions & 26 deletions webui/react/src/pages/FlatRuns/FlatRuns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -290,19 +290,38 @@ const FlatRuns: React.FC<Props> = ({ projectId, workspaceId, searchId }) => {

const selection = useMemo<GridSelection>(() => {
let rows = CompactSelection.empty();
loadedSelectedRunIds.forEach((info) => {
rows = rows.add(info.index);
});
if (settings.selection.type === 'ONLY_IN') {
loadedSelectedRunIds.forEach((info) => {
rows = rows.add(info.index);
});
} else if (settings.selection.type === 'ALL_EXCEPT') {
rows = rows.add([0, total.getOrElse(1) - 1]);
settings.selection.exclusions.forEach((exc) => {
const excIndex = loadedSelectedRunIds.get(exc)?.index;
if (excIndex !== undefined) {
rows = rows.remove(excIndex);
}
});
}
return {
columns: CompactSelection.empty(),
rows,
};
}, [loadedSelectedRunIds]);
}, [loadedSelectedRunIds, settings.selection, total]);

const selectedRuns: FlatRun[] = useMemo(() => {
return Loadable.filterNotLoaded(runs, (run) => selectedRunIdSet.has(run.id));
}, [runs, selectedRunIdSet]);

const selectionSize = useMemo(() => {
if (settings.selection.type === 'ONLY_IN') {
return settings.selection.selections.length;
} else if (settings.selection.type === 'ALL_EXCEPT') {
return total.getOrElse(0) - settings.selection.exclusions.length;
}
return 0;
}, [settings.selection, total]);

const handleIsOpenFilterChange = useCallback((newOpen: boolean) => {
setIsOpenFilter(newOpen);
if (!newOpen) {
Expand Down Expand Up @@ -882,28 +901,37 @@ const FlatRuns: React.FC<Props> = ({ projectId, workspaceId, searchId }) => {
handleSelectionChange?.('remove-all');
}, [handleSelectionChange]);

const isRangeSelected = useCallback(
(range: [number, number]): boolean => {
if (settings.selection.type === 'ONLY_IN') {
const includedSet = new Set(settings.selection.selections);
return rowRangeToIds(range).every((id) => includedSet.has(id));
} else if (settings.selection.type === 'ALL_EXCEPT') {
const excludedSet = new Set(settings.selection.exclusions);
return rowRangeToIds(range).every((id) => !excludedSet.has(id));
}
return false; // should never be reached
},
[rowRangeToIds, settings.selection],
);

const handleHeaderClick = useCallback(
(columnId: string): void => {
if (columnId === MULTISELECT) {
if (isRangeSelected([0, settings.pageLimit])) {
handleSelectionChange?.('remove', [0, settings.pageLimit]);
} else {
handleSelectionChange?.('add', [0, settings.pageLimit]);
}
}
},
[handleSelectionChange, isRangeSelected, settings.pageLimit],
);

const getHeaderMenuItems = useCallback(
(columnId: string, colIdx: number): MenuItem[] => {
if (columnId === MULTISELECT) {
const items: MenuItem[] = [
settings.selection.type === 'ALL_EXCEPT' || settings.selection.selections.length > 0
? {
key: 'select-none',
label: 'Clear selected',
onClick: () => {
handleSelectionChange?.('remove-all');
},
}
: null,
{
key: 'select-all',
label: 'Select all',
onClick: () => {
handleSelectionChange?.('add-all');
},
},
];
return items;
return [];
}

const column = Loadable.getOrElse([], projectColumns).find((c) => c.column === columnId);
Expand Down Expand Up @@ -1055,11 +1083,9 @@ const FlatRuns: React.FC<Props> = ({ projectId, workspaceId, searchId }) => {
bannedSortColumns,
projectColumns,
settings.pinnedColumnsCount,
settings.selection,
settings.heatmapOn,
settings.heatmapSkipped,
isMobile,
handleSelectionChange,
columnsIfLoaded,
handleColumnsOrderChange,
rootFilterChildren,
Expand Down Expand Up @@ -1131,7 +1157,7 @@ const FlatRuns: React.FC<Props> = ({ projectId, workspaceId, searchId }) => {
labelPlural="runs"
labelSingular="run"
pageSize={settings.pageLimit}
selectedCount={selectedRunIdSet.size}
selectedCount={selectionSize}
total={total}
onActualSelectAll={handleActualSelectAll}
onClearSelect={handleClearSelect}
Expand Down Expand Up @@ -1222,6 +1248,7 @@ const FlatRuns: React.FC<Props> = ({ projectId, workspaceId, searchId }) => {
onColumnResize={handleColumnWidthChange}
onColumnsOrderChange={handleColumnsOrderChange}
onContextMenuComplete={handleContextMenuComplete}
onHeaderClicked={handleHeaderClick}
onPinnedColumnsCountChange={handlePinnedColumnsCountChange}
onSelectionChange={handleSelectionChange}
/>
Expand Down

0 comments on commit 84d9e0e

Please sign in to comment.