Revert "Enable column selection and sorting in DocumentsTab (with persistence) (#1881)" (#1960)

This reverts commit 7e95f5d8c8.
This commit is contained in:
Laurent Nguyen
2024-09-05 21:44:33 +02:00
committed by GitHub
parent 7e95f5d8c8
commit fe9730206e
14 changed files with 1332 additions and 742 deletions

View File

@@ -1,48 +1,30 @@
import {
Button,
createTableColumn,
Menu,
MenuDivider,
MenuItem,
MenuList,
MenuPopover,
MenuTrigger,
TableRowData as RowStateBase,
SortDirection,
Table,
TableBody,
TableCell,
TableCellLayout,
TableColumnDefinition,
TableColumnId,
TableColumnSizingOptions,
TableHeader,
TableHeaderCell,
TableRow,
TableRowId,
TableSelectionCell,
tokens,
useArrowNavigationGroup,
useTableColumnSizing_unstable,
useTableFeatures,
useTableSelection,
useTableSort,
} from "@fluentui/react-components";
import {
ArrowClockwise16Regular,
ArrowResetRegular,
DeleteRegular,
EditRegular,
MoreHorizontalRegular,
TableResizeColumnRegular,
TextSortAscendingRegular,
TextSortDescendingRegular,
} from "@fluentui/react-icons";
import { NormalizedEventKey } from "Common/Constants";
import { TableColumnSelectionPane } from "Explorer/Panes/TableColumnSelectionPane/TableColumnSelectionPane";
import {
ColumnSizesMap,
ColumnSort,
deleteSubComponentState,
readSubComponentState,
saveSubComponentState,
SubComponentName,
@@ -50,37 +32,29 @@ import {
import { INITIAL_SELECTED_ROW_INDEX, useDocumentsTabStyles } from "Explorer/Tabs/DocumentsTabV2/DocumentsTabV2";
import { selectionHelper } from "Explorer/Tabs/DocumentsTabV2/SelectionHelper";
import { LayoutConstants } from "Explorer/Theme/ThemeUtil";
import { userContext } from "UserContext";
import { isEnvironmentCtrlPressed, isEnvironmentShiftPressed } from "Utils/KeyboardUtils";
import { useSidePanel } from "hooks/useSidePanel";
import React, { useCallback, useMemo } from "react";
import { FixedSizeList as List, ListChildComponentProps } from "react-window";
import * as ViewModels from "../../../Contracts/ViewModels";
export type DocumentsTableComponentItem = {
id: string;
} & Record<string, string | number>;
} & Record<string, string>;
export type ColumnDefinition = {
id: string;
label: string;
isPartitionKey: boolean;
export type ColumnHeaders = {
idHeader: string;
partitionKeyHeaders: string[];
};
export interface IDocumentsTableComponentProps {
onRefreshTable: () => void;
items: DocumentsTableComponentItem[];
onItemClicked: (index: number) => void;
onSelectedRowsChange: (selectedItemsIndices: Set<TableRowId>) => void;
selectedRows: Set<TableRowId>;
size: { height: number; width: number };
selectedColumnIds: string[];
columnDefinitions: ColumnDefinition[];
columnHeaders: ColumnHeaders;
style?: React.CSSProperties;
isRowSelectionDisabled?: boolean;
isSelectionDisabled?: boolean;
collection: ViewModels.CollectionBase;
onColumnSelectionChange?: (newSelectedColumnIds: string[]) => void;
defaultColumnSelection?: string[];
isColumnSelectionDisabled?: boolean;
}
interface TableRowData extends RowStateBase<DocumentsTableComponentItem> {
@@ -93,33 +67,25 @@ interface ReactWindowRenderFnProps extends ListChildComponentProps {
data: TableRowData[];
}
const COLUMNS_MENU_NAME = "columnsMenu";
const defaultSize = {
idealWidth: 200,
minWidth: 50,
};
export const DocumentsTableComponent: React.FC<IDocumentsTableComponentProps> = ({
onRefreshTable,
items,
onSelectedRowsChange,
selectedRows,
style,
size,
selectedColumnIds,
columnDefinitions,
isRowSelectionDisabled: isSelectionDisabled,
columnHeaders,
isSelectionDisabled,
collection,
onColumnSelectionChange,
defaultColumnSelection,
isColumnSelectionDisabled,
}: IDocumentsTableComponentProps) => {
const styles = useDocumentsTabStyles();
const [columnSizingOptions, setColumnSizingOptions] = React.useState<TableColumnSizingOptions>(() => {
const columnIds = ["id"].concat(columnHeaders.partitionKeyHeaders);
const columnSizesMap: ColumnSizesMap = readSubComponentState(SubComponentName.ColumnSizes, collection, {});
const columnSizesPx: TableColumnSizingOptions = {};
selectedColumnIds.forEach((columnId) => {
columnIds.forEach((columnId) => {
if (
!columnSizesMap ||
!columnSizesMap[columnId] ||
@@ -137,24 +103,7 @@ export const DocumentsTableComponent: React.FC<IDocumentsTableComponentProps> =
return columnSizesPx;
});
const [sortState, setSortState] = React.useState<{
sortDirection: "ascending" | "descending";
sortColumn: TableColumnId | undefined;
}>(() => {
const sort = readSubComponentState<ColumnSort>(SubComponentName.ColumnSort, collection, undefined);
if (!sort) {
return {
sortDirection: undefined,
sortColumn: undefined,
};
}
return {
sortDirection: sort.direction,
sortColumn: sort.columnId,
};
});
const styles = useDocumentsTabStyles();
const onColumnResize = React.useCallback((_, { columnId, width }: { columnId: string; width: number }) => {
setColumnSizingOptions((state) => {
@@ -173,123 +122,42 @@ export const DocumentsTableComponent: React.FC<IDocumentsTableComponentProps> =
return acc;
}, {} as ColumnSizesMap);
saveSubComponentState<ColumnSizesMap>(SubComponentName.ColumnSizes, collection, persistentSizes, true);
saveSubComponentState(SubComponentName.ColumnSizes, collection, persistentSizes, true);
return newSizingOptions;
});
}, []);
// const restoreFocusTargetAttribute = useRestoreFocusTarget();
const onSortClick = (event: React.SyntheticEvent, columnId: string, direction: SortDirection) => {
setColumnSort(event, columnId, direction);
if (columnId === undefined || direction === undefined) {
deleteSubComponentState(SubComponentName.ColumnSort, collection);
return;
}
saveSubComponentState<ColumnSort>(SubComponentName.ColumnSort, collection, { columnId, direction });
};
// Columns must be a static object and cannot change on re-renders otherwise React will complain about too many refreshes
const columns: TableColumnDefinition<DocumentsTableComponentItem>[] = useMemo(
() =>
columnDefinitions
.filter((column) => selectedColumnIds.includes(column.id))
.map((column) => ({
columnId: column.id,
compare: (a, b) => {
if (typeof a[column.id] === "string") {
return (a[column.id] as string).localeCompare(b[column.id] as string);
} else if (typeof a[column.id] === "number") {
return (a[column.id] as number) - (b[column.id] as number);
} else {
// Should not happen
return 0;
}
},
renderHeaderCell: () => (
<>
<span title={column.label}>{column.label}</span>
<Menu>
<MenuTrigger disableButtonEnhancement>
<Button
// {...restoreFocusTargetAttribute}
appearance="transparent"
aria-label="Select column"
size="small"
icon={<MoreHorizontalRegular />}
style={{ position: "absolute", right: 0, backgroundColor: tokens.colorNeutralBackground1 }}
/>
</MenuTrigger>
<MenuPopover>
<MenuList>
<MenuItem key="refresh" icon={<ArrowClockwise16Regular />} onClick={onRefreshTable}>
Refresh
</MenuItem>
{userContext.features.enableDocumentsTableColumnSelection && (
<>
<MenuItem
icon={<TextSortAscendingRegular />}
onClick={(e) => onSortClick(e, column.id, "ascending")}
>
Sort ascending
</MenuItem>
<MenuItem
icon={<TextSortDescendingRegular />}
onClick={(e) => onSortClick(e, column.id, "descending")}
>
Sort descending
</MenuItem>
<MenuItem icon={<ArrowResetRegular />} onClick={(e) => onSortClick(e, undefined, undefined)}>
Reset sorting
</MenuItem>
{!isColumnSelectionDisabled && (
<MenuItem key="editcolumns" icon={<EditRegular />} onClick={openColumnSelectionPane}>
Edit columns
</MenuItem>
)}
<MenuDivider />
<MenuItem
key="keyboardresize"
icon={<TableResizeColumnRegular />}
onClick={columnSizing.enableKeyboardMode(column.id)}
>
Resize with left/right arrow keys
</MenuItem>
{!isColumnSelectionDisabled && (
<MenuItem
key="remove"
icon={<DeleteRegular />}
onClick={() => {
// Remove column id from selectedColumnIds
const index = selectedColumnIds.indexOf(column.id);
if (index === -1) {
return;
}
const newSelectedColumnIds = [...selectedColumnIds];
newSelectedColumnIds.splice(index, 1);
onColumnSelectionChange(newSelectedColumnIds);
}}
>
Remove column
</MenuItem>
)}
</>
)}
</MenuList>
</MenuPopover>
</Menu>
</>
),
[
createTableColumn<DocumentsTableComponentItem>({
columnId: "id",
compare: (a, b) => a.id.localeCompare(b.id),
renderHeaderCell: () => columnHeaders.idHeader,
renderCell: (item) => (
<TableCellLayout truncate title={`${item[column.id]}`}>
{item[column.id]}
<TableCellLayout truncate title={item.id}>
{item.id}
</TableCellLayout>
),
})),
[columnDefinitions, onColumnSelectionChange, selectedColumnIds],
}),
].concat(
columnHeaders.partitionKeyHeaders.map((pkHeader) =>
createTableColumn<DocumentsTableComponentItem>({
columnId: pkHeader,
compare: (a, b) => a[pkHeader].localeCompare(b[pkHeader]),
// Show Refresh button on last column
renderHeaderCell: () => <span title={pkHeader}>{pkHeader}</span>,
renderCell: (item) => (
<TableCellLayout truncate title={item[pkHeader]}>
{item[pkHeader]}
</TableCellLayout>
),
}),
),
),
[columnHeaders],
);
const [selectionStartIndex, setSelectionStartIndex] = React.useState<number>(INITIAL_SELECTED_ROW_INDEX);
@@ -379,7 +247,6 @@ export const DocumentsTableComponent: React.FC<IDocumentsTableComponentProps> =
columnSizing_unstable: columnSizing,
tableRef,
selection: { allRowsSelected, someRowsSelected, toggleAllRows, toggleRow, isRowSelected },
sort: { getSortDirection, setColumnSort, sort },
} = useTableFeatures(
{
columns,
@@ -393,36 +260,25 @@ export const DocumentsTableComponent: React.FC<IDocumentsTableComponentProps> =
// eslint-disable-next-line react/prop-types
onSelectionChange: (e, data) => onSelectedRowsChange(data.selectedItems),
}),
useTableSort({
sortState,
onSortChange: (e, nextSortState) => setSortState(nextSortState),
}),
],
);
const headerSortProps = (columnId: TableColumnId) => ({
// onClick: (e: React.MouseEvent) => toggleColumnSort(e, columnId),
sortDirection: getSortDirection(columnId),
const rows: TableRowData[] = getRows((row) => {
const selected = isRowSelected(row.rowId);
return {
...row,
onClick: (e: React.MouseEvent) => toggleRow(e, row.rowId),
onKeyDown: (e: React.KeyboardEvent) => {
if (e.key === " ") {
e.preventDefault();
toggleRow(e, row.rowId);
}
},
selected,
appearance: selected ? ("brand" as const) : ("none" as const),
};
});
const rows: TableRowData[] = sort(
getRows((row) => {
const selected = isRowSelected(row.rowId);
return {
...row,
onClick: (e: React.MouseEvent) => toggleRow(e, row.rowId),
onKeyDown: (e: React.KeyboardEvent) => {
if (e.key === " ") {
e.preventDefault();
toggleRow(e, row.rowId);
}
},
selected,
appearance: selected ? ("brand" as const) : ("none" as const),
};
}),
);
const toggleAllKeydown = React.useCallback(
(e: React.KeyboardEvent<HTMLDivElement>) => {
if (e.key === " ") {
@@ -448,50 +304,37 @@ export const DocumentsTableComponent: React.FC<IDocumentsTableComponentProps> =
...style,
};
const checkedValues: { [COLUMNS_MENU_NAME]: string[] } = {
[COLUMNS_MENU_NAME]: [],
};
columnDefinitions.forEach(
(columnDefinition) =>
selectedColumnIds.includes(columnDefinition.id) && checkedValues[COLUMNS_MENU_NAME].push(columnDefinition.id),
);
const openColumnSelectionPane = (): void => {
useSidePanel
.getState()
.openSidePanel(
"Select columns",
<TableColumnSelectionPane
selectedColumnIds={selectedColumnIds}
columnDefinitions={columnDefinitions}
onSelectionChange={onColumnSelectionChange}
defaultSelection={defaultColumnSelection}
/>,
);
};
return (
<Table noNativeElements sortable {...tableProps}>
<Table noNativeElements {...tableProps}>
<TableHeader>
<TableRow className={styles.tableRow} style={{ width: size ? size.width - 15 : "100%" }}>
{!isSelectionDisabled && (
<TableSelectionCell
key="selectcell"
checked={allRowsSelected ? true : someRowsSelected ? "mixed" : false}
onClick={toggleAllRows}
onKeyDown={toggleAllKeydown}
checkboxIndicator={{ "aria-label": "Select all rows " }}
/>
)}
{columns.map((column) => (
<TableHeaderCell
className={styles.tableCell}
key={column.columnId}
{...columnSizing.getTableHeaderCellProps(column.columnId)}
{...headerSortProps(column.columnId)}
>
{column.renderHeaderCell()}
</TableHeaderCell>
{columns.map((column /* index */) => (
<Menu openOnContext key={column.columnId}>
<MenuTrigger>
<TableHeaderCell
className={styles.tableCell}
key={column.columnId}
{...columnSizing.getTableHeaderCellProps(column.columnId)}
>
{column.renderHeaderCell()}
</TableHeaderCell>
</MenuTrigger>
<MenuPopover>
<MenuList>
<MenuItem onClick={columnSizing.enableKeyboardMode(column.columnId)}>
Keyboard Column Resizing
</MenuItem>
</MenuList>
</MenuPopover>
</Menu>
))}
</TableRow>
</TableHeader>