From fa460bfba2062920dc118131a458e3fdf46f94ab Mon Sep 17 00:00:00 2001 From: Laurent Nguyen Date: Wed, 10 Jul 2024 17:20:24 +0200 Subject: [PATCH] Rework column selection UI --- .../TableColumnSelectionPane.less | 3 + .../TableColumnSelectionPane.tsx | 108 ++++++++ .../Tabs/DocumentsTabV2/DocumentsTabV2.tsx | 37 +-- .../DocumentsTableComponent.tsx | 232 ++++++------------ 4 files changed, 196 insertions(+), 184 deletions(-) create mode 100644 src/Explorer/Panes/TableColumnSelectionPane/TableColumnSelectionPane.less create mode 100644 src/Explorer/Panes/TableColumnSelectionPane/TableColumnSelectionPane.tsx diff --git a/src/Explorer/Panes/TableColumnSelectionPane/TableColumnSelectionPane.less b/src/Explorer/Panes/TableColumnSelectionPane/TableColumnSelectionPane.less new file mode 100644 index 000000000..9cd95cb6e --- /dev/null +++ b/src/Explorer/Panes/TableColumnSelectionPane/TableColumnSelectionPane.less @@ -0,0 +1,3 @@ +.tableColumnSelectionCheckbox label { + padding: 4px 8px; +} diff --git a/src/Explorer/Panes/TableColumnSelectionPane/TableColumnSelectionPane.tsx b/src/Explorer/Panes/TableColumnSelectionPane/TableColumnSelectionPane.tsx new file mode 100644 index 000000000..e7e97636f --- /dev/null +++ b/src/Explorer/Panes/TableColumnSelectionPane/TableColumnSelectionPane.tsx @@ -0,0 +1,108 @@ +import { Checkbox } from "@fluentui/react"; +import { + Button, + FluentProvider, + InputOnChangeData, + SearchBox, + SearchBoxChangeEvent, + Text, +} from "@fluentui/react-components"; +import { configContext } from "ConfigContext"; +import { ColumnDefinition } from "Explorer/Tabs/DocumentsTabV2/DocumentsTableComponent"; +import { getPlatformTheme } from "Explorer/Theme/ThemeUtil"; +import React from "react"; +import { useSidePanel } from "../../../hooks/useSidePanel"; +import "./TableColumnSelectionPane.less"; + +export interface TableColumnSelectionPaneProps { + columnDefinitions: ColumnDefinition[]; + selectedColumnIds: string[]; + onSelectionChange: (newSelectedColumnIds: string[]) => void; +} + +export const TableColumnSelectionPane: React.FC = ({ + columnDefinitions, + selectedColumnIds, + onSelectionChange, +}: TableColumnSelectionPaneProps): JSX.Element => { + const closeSidePanel = useSidePanel((state) => state.closeSidePanel); + const originalSelectedColumnIds = React.useMemo(() => selectedColumnIds, []); + const [columnSearchText, setColumnSearchText] = React.useState(""); + const [newSelectedColumnIds, setNewSelectedColumnIds] = React.useState(originalSelectedColumnIds); + + const selectedColumnIdsSet = new Set(newSelectedColumnIds); + const onCheckedValueChange = (id: string, checked?: boolean): void => { + if (checked) { + selectedColumnIdsSet.add(id); + } else { + selectedColumnIdsSet.delete(id); + } + setNewSelectedColumnIds([...selectedColumnIdsSet]); + }; + + const onSave = (): void => { + onSelectionChange(newSelectedColumnIds); + closeSidePanel(); + }; + + const onSearchChange: (event: SearchBoxChangeEvent, data: InputOnChangeData) => void = (_, data) => + // eslint-disable-next-line react/prop-types + setColumnSearchText(data.value); + + const theme = getPlatformTheme(configContext.platform); + + // Filter and move partition keys to the top + const columnDefinitionList = columnDefinitions + .filter((def) => !columnSearchText || def.label.toLowerCase().includes(columnSearchText.toLowerCase())) + .sort((a, b) => { + const ID = "id"; + // "id" always at the top, then partition keys, then everything else sorted + if (a.id === ID) { + return b.id === ID ? 0 : -1; + } else if (b.id === ID) { + return a.id === ID ? 0 : 1; + } else if (a.isPartitionKey && !b.isPartitionKey) { + return -1; + } else if (b.isPartitionKey && !a.isPartitionKey) { + return 1; + } else { + return a.label.localeCompare(b.label); + } + }); + + return ( + +
+
+ Select which columns to display in your view of items in your container. +
to avoid margin-bottom set by panelMainContent css */> + +
+ + {columnDefinitionList.map((columnDefinition) => ( + onCheckedValueChange(columnDefinition.id, checked)} + /> + ))} +
+
+ + +
+
+
+ ); +}; diff --git a/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.tsx b/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.tsx index 9a376103d..d5491fb71 100644 --- a/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.tsx +++ b/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.tsx @@ -1,11 +1,10 @@ import { Item, ItemDefinition, PartitionKey, PartitionKeyDefinition, QueryIterator, Resource } from "@azure/cosmos"; import { Button, FluentProvider, Input, TableRowId } from "@fluentui/react-components"; -import { ArrowClockwise16Filled, Dismiss16Filled } from "@fluentui/react-icons"; +import { Dismiss16Filled } from "@fluentui/react-icons"; import Split from "@uiw/react-split"; import { KeyCodes, QueryCopilotSampleContainerId, QueryCopilotSampleDatabaseId } from "Common/Constants"; import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils"; import MongoUtility from "Common/MongoUtility"; -import { StyleConstants } from "Common/StyleConstants"; import { createDocument } from "Common/dataAccess/createDocument"; import { deleteDocuments as deleteNoSqlDocuments } from "Common/dataAccess/deleteDocument"; import { queryDocuments } from "Common/dataAccess/queryDocuments"; @@ -1184,16 +1183,6 @@ export const DocumentsTabComponent: React.FunctionComponent = (event) => { - if (event.key === " " || event.key === "Enter") { - const focusElement = event.target as HTMLElement; - refreshDocumentsGrid(false); - focusElement && focusElement.focus(); - event.stopPropagation(); - event.preventDefault(); - } - }; - const onLoadMoreKeyInput: KeyboardEventHandler = (event) => { if (event.key === " " || event.key === "Enter") { const focusElement = event.target as HTMLElement; @@ -1242,13 +1231,13 @@ export const DocumentsTabComponent: React.FunctionComponent typeof (document as any)[key] === "string" || typeof (document as any)[key] === "number") // Only allow safe types for displayable React children .map((key) => key === "id" - ? { id: key, label: isPreferredApiMongoDB ? "_id" : "id", group: undefined } - : { id: key, label: key, group: undefined }, + ? { id: key, label: isPreferredApiMongoDB ? "_id" : "id", isPartitionKey: false } + : { id: key, label: key, isPartitionKey: false }, ); if (showPartitionKey(_collection, isPreferredApiMongoDB)) { columnDefinitions.push( - ...partitionKeyPropertyHeaders.map((key) => ({ id: key, label: key, group: "Partition Key" })), + ...partitionKeyPropertyHeaders.map((key) => ({ id: key, label: key, isPartitionKey: true })), ); // Remove properties that are the partition keys, since they are already included @@ -1908,23 +1897,6 @@ export const DocumentsTabComponent: React.FunctionComponent -