mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-04-30 13:35:07 +01:00
Implement new menu for column selection with search.
This commit is contained in:
parent
b096fa9bf8
commit
0ce9acdfdf
@ -1,5 +1,6 @@
|
|||||||
import { SearchBox } from "@fluentui/react";
|
|
||||||
import {
|
import {
|
||||||
|
Button,
|
||||||
|
InputOnChangeData,
|
||||||
Menu,
|
Menu,
|
||||||
MenuCheckedValueChangeData,
|
MenuCheckedValueChangeData,
|
||||||
MenuCheckedValueChangeEvent,
|
MenuCheckedValueChangeEvent,
|
||||||
@ -10,8 +11,12 @@ import {
|
|||||||
MenuItemCheckbox,
|
MenuItemCheckbox,
|
||||||
MenuList,
|
MenuList,
|
||||||
MenuPopover,
|
MenuPopover,
|
||||||
|
MenuProps,
|
||||||
MenuTrigger,
|
MenuTrigger,
|
||||||
|
PositioningImperativeRef,
|
||||||
TableRowData as RowStateBase,
|
TableRowData as RowStateBase,
|
||||||
|
SearchBox,
|
||||||
|
SearchBoxChangeEvent,
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
TableCell,
|
TableCell,
|
||||||
@ -24,14 +29,16 @@ import {
|
|||||||
TableRowId,
|
TableRowId,
|
||||||
TableSelectionCell,
|
TableSelectionCell,
|
||||||
useArrowNavigationGroup,
|
useArrowNavigationGroup,
|
||||||
|
useRestoreFocusTarget,
|
||||||
useTableColumnSizing_unstable,
|
useTableColumnSizing_unstable,
|
||||||
useTableFeatures,
|
useTableFeatures,
|
||||||
useTableSelection
|
useTableSelection,
|
||||||
} from "@fluentui/react-components";
|
} from "@fluentui/react-components";
|
||||||
|
import { Add16Regular, Dismiss12Regular } from "@fluentui/react-icons";
|
||||||
import { NormalizedEventKey } from "Common/Constants";
|
import { NormalizedEventKey } from "Common/Constants";
|
||||||
import { selectionHelper } from "Explorer/Tabs/DocumentsTabV2/SelectionHelper";
|
import { selectionHelper } from "Explorer/Tabs/DocumentsTabV2/SelectionHelper";
|
||||||
import { isEnvironmentCtrlPressed, isEnvironmentShiftPressed } from "Utils/KeyboardUtils";
|
import { isEnvironmentCtrlPressed, isEnvironmentShiftPressed } from "Utils/KeyboardUtils";
|
||||||
import React, { ChangeEvent, useCallback, useMemo } from "react";
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { FixedSizeList as List, ListChildComponentProps } from "react-window";
|
import { FixedSizeList as List, ListChildComponentProps } from "react-window";
|
||||||
|
|
||||||
export type DocumentsTableComponentItem = {
|
export type DocumentsTableComponentItem = {
|
||||||
@ -93,7 +100,33 @@ export const DocumentsTableComponent: React.FC<IDocumentsTableComponentProps> =
|
|||||||
});
|
});
|
||||||
|
|
||||||
const [columnSizingOptions, setColumnSizingOptions] = React.useState<TableColumnSizingOptions>(initialSizingOptions);
|
const [columnSizingOptions, setColumnSizingOptions] = React.useState<TableColumnSizingOptions>(initialSizingOptions);
|
||||||
const [columnSearchText, setColumnSearchText] = React.useState<string>("");
|
|
||||||
|
// This is for the menu to select columns
|
||||||
|
const [columnSearchText, setColumnSearchText] = useState<string>("");
|
||||||
|
const [isColumnSelectionMenuOpen, setIsColumnSelectionMenuOpen] = useState<boolean>(false);
|
||||||
|
const columnSelectionMenuButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
|
const columnSelectionMenuPositionRef = useRef<HTMLDivElement>(null);
|
||||||
|
const positioningRef = React.useRef<PositioningImperativeRef>(null);
|
||||||
|
const onColumnSelectionMenuOpenChange: MenuProps["onOpenChange"] = (e, data) => {
|
||||||
|
// do not close menu as an outside click if clicking on the custom trigger/target
|
||||||
|
// this prevents it from closing & immediately re-opening when clicking custom triggers
|
||||||
|
if (
|
||||||
|
data.type === "clickOutside" &&
|
||||||
|
(e.target === columnSelectionMenuButtonRef.current || e.target === columnSelectionMenuPositionRef.current)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsColumnSelectionMenuOpen(data.open);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (columnSelectionMenuPositionRef.current) {
|
||||||
|
positioningRef.current?.setTarget(columnSelectionMenuPositionRef.current);
|
||||||
|
}
|
||||||
|
}, [columnSelectionMenuPositionRef, positioningRef]);
|
||||||
|
|
||||||
|
const restoreFocusTargetAttribute = useRestoreFocusTarget();
|
||||||
|
|
||||||
const onColumnResize = React.useCallback(
|
const onColumnResize = React.useCallback(
|
||||||
(_, { columnId, width }) => {
|
(_, { columnId, width }) => {
|
||||||
@ -117,7 +150,28 @@ export const DocumentsTableComponent: React.FC<IDocumentsTableComponentProps> =
|
|||||||
.map((column) => ({
|
.map((column) => ({
|
||||||
columnId: column.id,
|
columnId: column.id,
|
||||||
compare: (a, b) => a[column.id].localeCompare(b[column.id]),
|
compare: (a, b) => a[column.id].localeCompare(b[column.id]),
|
||||||
renderHeaderCell: () => <span title={column.label}>{column.label}</span>,
|
renderHeaderCell: () => (
|
||||||
|
<>
|
||||||
|
<span title={column.label}>{column.label}</span>
|
||||||
|
<Button
|
||||||
|
appearance="transparent"
|
||||||
|
aria-label="De-select column"
|
||||||
|
size="small"
|
||||||
|
icon={<Dismiss12Regular />}
|
||||||
|
style={{ position: "absolute", right: 0 }}
|
||||||
|
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);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
),
|
||||||
renderCell: (item) => (
|
renderCell: (item) => (
|
||||||
<TableCellLayout truncate title={item[column.id]}>
|
<TableCellLayout truncate title={item[column.id]}>
|
||||||
{item[column.id]}
|
{item[column.id]}
|
||||||
@ -280,8 +334,8 @@ export const DocumentsTableComponent: React.FC<IDocumentsTableComponentProps> =
|
|||||||
onColumnSelectionChange(data.checkedItems);
|
onColumnSelectionChange(data.checkedItems);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSearchChange: (event?: ChangeEvent<HTMLInputElement>, newValue?: string) => void = (_, newValue) =>
|
const onSearchChange: (event: SearchBoxChangeEvent, data: InputOnChangeData) => void = (_, data) =>
|
||||||
setColumnSearchText(newValue);
|
setColumnSearchText(data.value);
|
||||||
|
|
||||||
const getMenuList = (columnDefinitions: ColumnDefinition[]): JSX.Element => {
|
const getMenuList = (columnDefinitions: ColumnDefinition[]): JSX.Element => {
|
||||||
// Group by group. Unnamed group first
|
// Group by group. Unnamed group first
|
||||||
@ -299,10 +353,12 @@ export const DocumentsTableComponent: React.FC<IDocumentsTableComponentProps> =
|
|||||||
});
|
});
|
||||||
|
|
||||||
const menuList: JSX.Element[] = [];
|
const menuList: JSX.Element[] = [];
|
||||||
menuList.push(<SearchBox key="search" value={columnSearchText} onChange={onSearchChange} />)
|
menuList.push(<SearchBox key="search" size="small" value={columnSearchText} onChange={onSearchChange} />);
|
||||||
if (unnamedGroup.length > 0) {
|
if (unnamedGroup.length > 0) {
|
||||||
menuList.push(
|
menuList.push(
|
||||||
...unnamedGroup.filter(def => !columnSearchText || def.label.startsWith(columnSearchText)).map((column) => (
|
...unnamedGroup
|
||||||
|
.filter((def) => !columnSearchText || def.label.startsWith(columnSearchText))
|
||||||
|
.map((column) => (
|
||||||
<MenuItemCheckbox key={column.id} name={COLUMNS_MENU_NAME} value={column.id}>
|
<MenuItemCheckbox key={column.id} name={COLUMNS_MENU_NAME} value={column.id}>
|
||||||
{column.label}
|
{column.label}
|
||||||
</MenuItemCheckbox>
|
</MenuItemCheckbox>
|
||||||
@ -338,13 +394,8 @@ export const DocumentsTableComponent: React.FC<IDocumentsTableComponentProps> =
|
|||||||
checkboxIndicator={{ "aria-label": "Select all rows " }}
|
checkboxIndicator={{ "aria-label": "Select all rows " }}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{columns.map((column /* index */) => (
|
{columns.map((column) => (
|
||||||
<Menu
|
<Menu openOnContext key={column.columnId}>
|
||||||
openOnContext
|
|
||||||
key={column.columnId}
|
|
||||||
checkedValues={checkedValues}
|
|
||||||
onCheckedValueChange={onCheckedValueChange}
|
|
||||||
>
|
|
||||||
<MenuTrigger>
|
<MenuTrigger>
|
||||||
<TableHeaderCell
|
<TableHeaderCell
|
||||||
className="documentsTableCell"
|
className="documentsTableCell"
|
||||||
@ -355,16 +406,41 @@ export const DocumentsTableComponent: React.FC<IDocumentsTableComponentProps> =
|
|||||||
</TableHeaderCell>
|
</TableHeaderCell>
|
||||||
</MenuTrigger>
|
</MenuTrigger>
|
||||||
<MenuPopover>
|
<MenuPopover>
|
||||||
<MenuList style={{ maxHeight: size?.height, overflowY: "auto", overflowX: "hidden" }}>
|
<MenuList>
|
||||||
{getMenuList(columnDefinitions)}
|
|
||||||
<MenuDivider />
|
|
||||||
<MenuItem onClick={columnSizing.enableKeyboardMode(column.columnId)}>
|
<MenuItem onClick={columnSizing.enableKeyboardMode(column.columnId)}>
|
||||||
Use Left/Right Arrow keys to resize
|
Enable Left/Right Arrow keys to resize
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
</MenuList>
|
</MenuList>
|
||||||
</MenuPopover>
|
</MenuPopover>
|
||||||
</Menu>
|
</Menu>
|
||||||
))}
|
))}
|
||||||
|
<Button
|
||||||
|
{...restoreFocusTargetAttribute}
|
||||||
|
appearance="transparent"
|
||||||
|
aria-label="Select column"
|
||||||
|
size="small"
|
||||||
|
icon={<Add16Regular />}
|
||||||
|
style={{ position: "absolute", right: 25 }}
|
||||||
|
onClick={() => setIsColumnSelectionMenuOpen((s) => !s)}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
{...restoreFocusTargetAttribute}
|
||||||
|
ref={columnSelectionMenuPositionRef}
|
||||||
|
style={{ height: 0, position: "absolute", right: 20, top: 0 }}
|
||||||
|
/>
|
||||||
|
<Menu
|
||||||
|
checkedValues={checkedValues}
|
||||||
|
onCheckedValueChange={onCheckedValueChange}
|
||||||
|
open={isColumnSelectionMenuOpen}
|
||||||
|
onOpenChange={onColumnSelectionMenuOpenChange}
|
||||||
|
positioning={{ positioningRef }}
|
||||||
|
>
|
||||||
|
<MenuPopover>
|
||||||
|
<MenuList style={{ maxHeight: size?.height, overflowY: "auto", overflowX: "hidden" }}>
|
||||||
|
{getMenuList(columnDefinitions)}
|
||||||
|
</MenuList>
|
||||||
|
</MenuPopover>
|
||||||
|
</Menu>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user