(originalSelectedColumnIds);
- const styles = useColumnSelectionStyles();
-
- const selectedColumnIdsSet = new Set(newSelectedColumnIds);
- const onCheckedValueChange = (id: string, checkedData?: CheckboxOnChangeData): void => {
- const checked = checkedData?.checked;
- if (checked === "mixed" || checked === undefined) {
- return;
- }
-
- if (checked) {
- selectedColumnIdsSet.add(id);
- } else {
- if (selectedColumnIdsSet.size === 1 && selectedColumnIdsSet.has(id)) {
- // Don't allow unchecking the last column
- return;
- }
- 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, data)}
- />
- ))}
-
-
-
-
-
-
-
-
-
-
- );
-};
diff --git a/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabStateUtil.ts b/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabStateUtil.ts
index 6c63ab446..aaccfa3ac 100644
--- a/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabStateUtil.ts
+++ b/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabStateUtil.ts
@@ -1,6 +1,5 @@
// Definitions of State data
-import { ColumnDefinition } from "Explorer/Tabs/DocumentsTabV2/DocumentsTableComponent";
import { deleteState, loadState, saveState, saveStateDebounced } from "Shared/AppStatePersistenceUtility";
import { userContext } from "UserContext";
import * as ViewModels from "../../../Contracts/ViewModels";
@@ -12,16 +11,11 @@ export enum SubComponentName {
ColumnSizes = "ColumnSizes",
FilterHistory = "FilterHistory",
MainTabDivider = "MainTabDivider",
- ColumnsSelection = "ColumnsSelection",
- ColumnSort = "ColumnSort",
}
export type ColumnSizesMap = { [columnId: string]: WidthDefinition };
-export type FilterHistory = string[];
export type WidthDefinition = { widthPx: number };
export type TabDivider = { leftPaneWidthPercent: number };
-export type ColumnsSelection = { selectedColumnIds: string[]; columnDefinitions: ColumnDefinition[] };
-export type ColumnSort = { columnId: string; direction: "ascending" | "descending" };
/**
*
diff --git a/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.test.tsx b/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.test.tsx
index ab6c8ee70..59ae9052a 100644
--- a/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.test.tsx
+++ b/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.test.tsx
@@ -92,13 +92,7 @@ async function waitForComponentToPaint(wrapper: ReactWrapper
| S
describe("Documents tab (noSql API)", () => {
describe("buildQuery", () => {
it("should generate the right select query for SQL API", () => {
- expect(
- buildQuery(false, "", ["pk"], {
- paths: ["pk"],
- kind: "Hash",
- version: 2,
- }),
- ).toContain("select");
+ expect(buildQuery(false, "")).toContain("select");
});
});
diff --git a/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.tsx b/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.tsx
index 09f4a3487..b0b76b377 100644
--- a/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.tsx
+++ b/src/Explorer/Tabs/DocumentsTabV2/DocumentsTabV2.tsx
@@ -1,9 +1,10 @@
import { Item, ItemDefinition, PartitionKey, PartitionKeyDefinition, QueryIterator, Resource } from "@azure/cosmos";
import { Button, Input, TableRowId, makeStyles, shorthands } from "@fluentui/react-components";
-import { Dismiss16Filled } from "@fluentui/react-icons";
+import { ArrowClockwise16Filled, Dismiss16Filled } from "@fluentui/react-icons";
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 {
deleteDocument as deleteNoSqlDocument,
@@ -20,14 +21,11 @@ import Explorer from "Explorer/Explorer";
import { useCommandBar } from "Explorer/Menus/CommandBar/CommandBarComponentAdapter";
import { querySampleDocuments, readSampleDocument } from "Explorer/QueryCopilot/QueryCopilotUtilities";
import {
- ColumnsSelection,
- FilterHistory,
SubComponentName,
TabDivider,
readSubComponentState,
saveSubComponentState,
} from "Explorer/Tabs/DocumentsTabV2/DocumentsTabStateUtil";
-import { usePrevious } from "Explorer/Tabs/DocumentsTabV2/SelectionHelper";
import { CosmosFluentProvider, LayoutConstants, cosmosShorthands, tokens } from "Explorer/Theme/ThemeUtil";
import { useSelectedNode } from "Explorer/useSelectedNode";
import { KeyboardAction, KeyboardActionGroup, useKeyboardActionGroup } from "KeyboardShortcuts";
@@ -53,11 +51,11 @@ import * as ViewModels from "../../../Contracts/ViewModels";
import { CollectionBase } from "../../../Contracts/ViewModels";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import * as QueryUtils from "../../../Utils/QueryUtils";
-import { defaultQueryFields, extractPartitionKeyValues } from "../../../Utils/QueryUtils";
+import { extractPartitionKeyValues } from "../../../Utils/QueryUtils";
import DocumentId from "../../Tree/DocumentId";
import ObjectId from "../../Tree/ObjectId";
import TabsBase from "../TabsBase";
-import { ColumnDefinition, DocumentsTableComponent, DocumentsTableComponentItem } from "./DocumentsTableComponent";
+import { DocumentsTableComponent, DocumentsTableComponentItem } from "./DocumentsTableComponent";
const MAX_FILTER_HISTORY_COUNT = 100; // Datalist will become scrollable, so we can afford to keep more items than fit on the screen
@@ -103,6 +101,17 @@ export const useDocumentsTabStyles = makeStyles({
...shorthands.outline("1px", "dotted"),
},
},
+ floatingControlsContainer: {
+ position: "relative",
+ },
+ floatingControls: {
+ position: "absolute",
+ top: "6px",
+ right: 0,
+ float: "right",
+ backgroundColor: "white",
+ zIndex: 1,
+ },
});
export class DocumentsTabV2 extends TabsBase {
@@ -272,7 +281,7 @@ const createUploadButton = (container: Explorer): CommandButtonComponentProps =>
iconAlt: label,
onCommandClick: () => {
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
- selectedCollection && container.openUploadItemsPane();
+ selectedCollection && container.openUploadItemsPanePane();
},
commandButtonLabel: label,
ariaLabel: label,
@@ -460,33 +469,17 @@ export const showPartitionKey = (collection: ViewModels.CollectionBase, isPrefer
};
// Export to expose to unit tests
-/**
- * Build default query
- * @param isMongo true if mongo api
- * @param filter
- * @param partitionKeyProperties optional for mongo
- * @param partitionKey optional for mongo
- * @param additionalField
- * @returns
- */
export const buildQuery = (
isMongo: boolean,
filter: string,
partitionKeyProperties?: string[],
partitionKey?: DataModels.PartitionKey,
- additionalField?: string[],
): string => {
if (isMongo) {
return filter || "{}";
}
- // Filter out fields starting with "/" (partition keys)
- return QueryUtils.buildDocumentsQuery(
- filter,
- partitionKeyProperties,
- partitionKey,
- additionalField?.filter((f) => !f.startsWith("/")) || [],
- );
+ return QueryUtils.buildDocumentsQuery(filter, partitionKeyProperties, partitionKey);
};
/**
@@ -529,12 +522,6 @@ const getDefaultSqlFilters = (partitionKeys: string[]) =>
);
const defaultMongoFilters = ['{"id":"foo"}', "{ qty: { $gte: 20 } }"];
-// Extend DocumentId to include fields displayed in the table
-type ExtendedDocumentId = DocumentId & { tableFields?: DocumentsTableComponentItem };
-
-// This is based on some heuristics
-const calculateOffset = (columnNumber: number): number => columnNumber * 16 - 29;
-
// Export to expose to unit tests
export const DocumentsTabComponent: React.FunctionComponent = ({
isPreferredApiMongoDB,
@@ -553,7 +540,7 @@ export const DocumentsTabComponent: React.FunctionComponent(false);
const [appliedFilter, setAppliedFilter] = useState("");
const [filterContent, setFilterContent] = useState("");
- const [documentIds, setDocumentIds] = useState([]);
+ const [documentIds, setDocumentIds] = useState([]);
const [isExecuting, setIsExecuting] = useState(false);
const filterInput = useRef(null);
const styles = useDocumentsTabStyles();
@@ -584,7 +571,7 @@ export const DocumentsTabComponent: React.FunctionComponent(() =>
- readSubComponentState(SubComponentName.MainTabDivider, _collection, {
+ readSubComponentState(SubComponentName.MainTabDivider, _collection, {
leftPaneWidthPercent: 35,
}),
);
@@ -598,8 +585,8 @@ export const DocumentsTabComponent: React.FunctionComponent(undefined);
// User's filter history
- const [lastFilterContents, setLastFilterContents] = useState(() =>
- readSubComponentState(SubComponentName.FilterHistory, _collection, [] as FilterHistory),
+ const [lastFilterContents, setLastFilterContents] = useState(() =>
+ readSubComponentState(SubComponentName.FilterHistory, _collection, []),
);
const setKeyboardActions = useKeyboardActionGroup(KeyboardActionGroup.ACTIVE_TAB);
@@ -648,37 +635,10 @@ export const DocumentsTabComponent: React.FunctionComponent {
- const defaultColumnsIds = ["id"];
- if (showPartitionKey(_collection, isPreferredApiMongoDB)) {
- defaultColumnsIds.push(...partitionKeyPropertyHeaders);
- }
-
- return defaultColumnsIds;
- };
-
- const [selectedColumnIds, setSelectedColumnIds] = useState(() => {
- const persistedColumnsSelection = readSubComponentState(
- SubComponentName.ColumnsSelection,
- _collection,
- undefined,
- );
-
- if (!persistedColumnsSelection) {
- return getInitialColumnSelection();
- }
-
- return persistedColumnsSelection.selectedColumnIds;
- });
-
// new DocumentId() requires a DocumentTab which we mock with only the required properties
const newDocumentId = useCallback(
- (
- rawDocument: DataModels.DocumentId,
- partitionKeyProperties: string[],
- partitionKeyValue: string[],
- ): ExtendedDocumentId => {
- const extendedDocumentId = new DocumentId(
+ (rawDocument: DataModels.DocumentId, partitionKeyProperties: string[], partitionKeyValue: string[]) =>
+ new DocumentId(
{
partitionKey,
partitionKeyProperties,
@@ -688,10 +648,7 @@ export const DocumentsTabComponent: React.FunctionComponent {
onExecutionErrorChange(true);
@@ -1144,13 +1093,7 @@ export const DocumentsTabComponent: React.FunctionComponent {
@@ -1319,6 +1261,16 @@ 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;
@@ -1350,7 +1302,9 @@ export const DocumentsTabComponent: React.FunctionComponent {
- const item: DocumentsTableComponentItem = documentId.tableFields || { id: documentId.id() };
+ const item: Record & { id: string } = {
+ id: documentId.id(),
+ };
if (partitionKeyPropertyHeaders && documentId.stringPartitionKeyValues) {
for (let i = 0; i < partitionKeyPropertyHeaders.length; i++) {
@@ -1361,44 +1315,6 @@ export const DocumentsTabComponent: React.FunctionComponent {
- let columnDefinitions: ColumnDefinition[] = Object.keys(document)
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- .filter((key) => 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", isPartitionKey: false }
- : { id: key, label: key, isPartitionKey: false },
- );
-
- if (showPartitionKey(_collection, isPreferredApiMongoDB)) {
- columnDefinitions.push(
- ...partitionKeyPropertyHeaders.map((key) => ({ id: key, label: key, isPartitionKey: true })),
- );
-
- // Remove properties that are the partition keys, since they are already included
- columnDefinitions = columnDefinitions.filter(
- (columnDefinition) => !partitionKeyProperties.includes(columnDefinition.id),
- );
- }
-
- return columnDefinitions;
- };
-
- /**
- * Extract column definitions from document and add to the definitions
- * @param document
- */
- const setColumnDefinitionsFromDocument = (document: unknown): void => {
- const currentIds = new Set(columnDefinitions.map((columnDefinition) => columnDefinition.id));
- extractColumnDefinitionsFromDocument(document).forEach((columnDefinition) => {
- if (!currentIds.has(columnDefinition.id)) {
- columnDefinitions.push(columnDefinition);
- }
- });
- setColumnDefinitions([...columnDefinitions]);
- };
-
/**
* replicate logic of selectedDocument.click();
* Document has been clicked on in table
@@ -1414,9 +1330,6 @@ export const DocumentsTabComponent: React.FunctionComponent {
initDocumentEditor(documentId, content);
-
- // Update columns
- setColumnDefinitionsFromDocument(content);
},
);
@@ -1507,22 +1420,10 @@ export const DocumentsTabComponent: React.FunctionComponent resizeObserver.disconnect(); // clean up
}, []);
- // Column definition is a map to garantee uniqueness
- const [columnDefinitions, setColumnDefinitions] = useState(() => {
- const persistedColumnsSelection = readSubComponentState(
- SubComponentName.ColumnsSelection,
- _collection,
- undefined,
- );
-
- if (!persistedColumnsSelection) {
- return extractColumnDefinitionsFromDocument({
- id: "id",
- });
- }
-
- return persistedColumnsSelection.columnDefinitions;
- });
+ const columnHeaders = {
+ idHeader: isPreferredApiMongoDB ? "_id" : "id",
+ partitionKeyHeaders: (showPartitionKey(_collection, isPreferredApiMongoDB) && partitionKeyPropertyHeaders) || [],
+ };
const onSelectedRowsChange = (selectedRows: Set) => {
confirmDiscardingChange(() => {
@@ -1754,7 +1655,7 @@ export const DocumentsTabComponent: React.FunctionComponent(SubComponentName.FilterHistory, _collection, lastFilterContents);
+ saveSubComponentState(SubComponentName.FilterHistory, _collection, lastFilterContents);
};
const refreshDocumentsGrid = useCallback(
@@ -1853,41 +1754,6 @@ export const DocumentsTabComponent: React.FunctionComponent {
- // Do not allow to unselecting all columns
- if (newSelectedColumnIds.length === 0) {
- return;
- }
-
- setSelectedColumnIds(newSelectedColumnIds);
-
- saveSubComponentState(SubComponentName.ColumnsSelection, _collection, {
- selectedColumnIds: newSelectedColumnIds,
- columnDefinitions,
- });
- };
-
- const prevSelectedColumnIds = usePrevious({ selectedColumnIds, setSelectedColumnIds });
-
- useEffect(() => {
- // If we are adding a field, let's refresh to include the field in the query
- let addedField = false;
- for (const field of selectedColumnIds) {
- if (
- !defaultQueryFields.includes(field) &&
- prevSelectedColumnIds &&
- !prevSelectedColumnIds.selectedColumnIds.includes(field)
- ) {
- addedField = true;
- break;
- }
- }
-
- if (addedField) {
- refreshDocumentsGrid(false);
- }
- }, [prevSelectedColumnIds, refreshDocumentsGrid, selectedColumnIds]);
-
return (
@@ -1982,40 +1848,42 @@ export const DocumentsTabComponent: React.FunctionComponent
{
tabStateData.leftPaneWidthPercent = (100 * sizes[0]) / (sizes[0] + sizes[1]);
- saveSubComponentState(SubComponentName.MainTabDivider, _collection, tabStateData);
+ saveSubComponentState(SubComponentName.MainTabDivider, _collection, tabStateData);
setTabStateData(tabStateData);
}}
>
-
-
-
refreshDocumentsGrid(false)}
- items={tableItems}
- onItemClicked={(index) => onDocumentClicked(index, documentIds)}
- onSelectedRowsChange={onSelectedRowsChange}
- selectedRows={selectedRows}
- size={tableContainerSizePx}
- selectedColumnIds={selectedColumnIds}
- columnDefinitions={columnDefinitions}
- isRowSelectionDisabled={
- configContext.platform === Platform.Fabric && userContext.fabricContext?.isReadOnly
- }
- onColumnSelectionChange={onColumnSelectionChange}
- defaultColumnSelection={getInitialColumnSelection()}
- collection={_collection}
- isColumnSelectionDisabled={isPreferredApiMongoDB}
+
+
+ }
+ style={{
+ color: StyleConstants.AccentMedium,
+ }}
+ onClick={() => refreshDocumentsGrid(false)}
+ onKeyDown={onRefreshKeyInput}
/>
+
+ onDocumentClicked(index, documentIds)}
+ onSelectedRowsChange={onSelectedRowsChange}
+ selectedRows={selectedRows}
+ size={tableContainerSizePx}
+ columnHeaders={columnHeaders}
+ isSelectionDisabled={
+ (partitionKey.systemKey && !isPreferredApiMongoDB) ||
+ (configContext.platform === Platform.Fabric && userContext.fabricContext?.isReadOnly)
+ }
+ collection={_collection}
+ />
+
{tableItems.length > 0 && (
{
height: 0,
width: 0,
},
- columnDefinitions: [
- { id: ID_HEADER, label: "ID", isPartitionKey: false },
- { id: PARTITION_KEY_HEADER, label: "Partition Key", isPartitionKey: true },
- ],
- isRowSelectionDisabled: false,
+ columnHeaders: {
+ idHeader: ID_HEADER,
+ partitionKeyHeaders: [PARTITION_KEY_HEADER],
+ },
+ isSelectionDisabled: false,
collection: {
databaseId: "db",
id: ((): string => "coll") as ko.Observable,
} as ViewModels.CollectionBase,
- onRefreshTable: (): void => {
- throw new Error("Function not implemented.");
- },
- selectedColumnIds: [],
});
it("should render documents and partition keys in header", () => {
@@ -44,7 +40,7 @@ describe("DocumentsTableComponent", () => {
it("should not render selection column when isSelectionDisabled is true", () => {
const props: IDocumentsTableComponentProps = createMockProps();
- props.isRowSelectionDisabled = true;
+ props.isSelectionDisabled = true;
const wrapper = mount();
expect(wrapper).toMatchSnapshot();
});
diff --git a/src/Explorer/Tabs/DocumentsTabV2/DocumentsTableComponent.tsx b/src/Explorer/Tabs/DocumentsTabV2/DocumentsTableComponent.tsx
index df68a2c0d..127c5d6d9 100644
--- a/src/Explorer/Tabs/DocumentsTabV2/DocumentsTableComponent.tsx
+++ b/src/Explorer/Tabs/DocumentsTabV2/DocumentsTableComponent.tsx
@@ -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;
+} & Record;
-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) => void;
selectedRows: Set;
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 {
@@ -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 = ({
- 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(() => {
+ 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 =
return columnSizesPx;
});
- const [sortState, setSortState] = React.useState<{
- sortDirection: "ascending" | "descending";
- sortColumn: TableColumnId | undefined;
- }>(() => {
- const sort = readSubComponentState(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 =
return acc;
}, {} as ColumnSizesMap);
- saveSubComponentState(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(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[] = 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: () => (
- <>
- {column.label}
-
- >
- ),
+ [
+ createTableColumn({
+ columnId: "id",
+ compare: (a, b) => a.id.localeCompare(b.id),
+ renderHeaderCell: () => columnHeaders.idHeader,
renderCell: (item) => (
-
- {item[column.id]}
+
+ {item.id}
),
- })),
- [columnDefinitions, onColumnSelectionChange, selectedColumnIds],
+ }),
+ ].concat(
+ columnHeaders.partitionKeyHeaders.map((pkHeader) =>
+ createTableColumn({
+ columnId: pkHeader,
+ compare: (a, b) => a[pkHeader].localeCompare(b[pkHeader]),
+ // Show Refresh button on last column
+ renderHeaderCell: () => {pkHeader},
+ renderCell: (item) => (
+
+ {item[pkHeader]}
+
+ ),
+ }),
+ ),
+ ),
+ [columnHeaders],
);
const [selectionStartIndex, setSelectionStartIndex] = React.useState(INITIAL_SELECTED_ROW_INDEX);
@@ -379,7 +247,6 @@ export const DocumentsTableComponent: React.FC =
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 =
// 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) => {
if (e.key === " ") {
@@ -448,50 +304,37 @@ export const DocumentsTableComponent: React.FC =
...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",
- ,
- );
- };
-
return (
-
+
{!isSelectionDisabled && (
)}
- {columns.map((column) => (
-
- {column.renderHeaderCell()}
-
+ {columns.map((column /* index */) => (
+
))}
diff --git a/src/Explorer/Tabs/DocumentsTabV2/SelectionHelper.ts b/src/Explorer/Tabs/DocumentsTabV2/SelectionHelper.ts
index 25d0d3270..fe4426d4e 100644
--- a/src/Explorer/Tabs/DocumentsTabV2/SelectionHelper.ts
+++ b/src/Explorer/Tabs/DocumentsTabV2/SelectionHelper.ts
@@ -1,5 +1,3 @@
-import { useEffect, useRef } from "react";
-
/**
* Utility class to help with selection.
* This emulates File Explorer selection behavior.
@@ -92,12 +90,3 @@ export const selectionHelper = (
}
}
};
-
-// To get previous values of a state in useEffect
-export const usePrevious = (value: T): T | undefined => {
- const ref = useRef();
- useEffect(() => {
- ref.current = value;
- });
- return ref.current;
-};
diff --git a/src/Explorer/Tabs/DocumentsTabV2/__snapshots__/DocumentsTabV2.test.tsx.snap b/src/Explorer/Tabs/DocumentsTabV2/__snapshots__/DocumentsTabV2.test.tsx.snap
index 15dae99d7..93719e55c 100644
--- a/src/Explorer/Tabs/DocumentsTabV2/__snapshots__/DocumentsTabV2.test.tsx.snap
+++ b/src/Explorer/Tabs/DocumentsTabV2/__snapshots__/DocumentsTabV2.test.tsx.snap
@@ -55,57 +55,53 @@ exports[`Documents tab (noSql API) when rendered should render the page 1`] = `
}
>
- }
+ onClick={[Function]}
+ onKeyDown={[Function]}
+ size="small"
+ style={
{
- "databaseId": "databaseId",
- "id": [Function],
- }
- }
- columnDefinitions={
- [
- {
- "id": "id",
- "isPartitionKey": false,
- "label": "id",
- },
- ]
- }
- defaultColumnSelection={
- [
- "id",
- ]
- }
- isColumnSelectionDisabled={false}
- isRowSelectionDisabled={true}
- items={[]}
- onColumnSelectionChange={[Function]}
- onItemClicked={[Function]}
- onRefreshTable={[Function]}
- onSelectedRowsChange={[Function]}
- selectedColumnIds={
- [
- "id",
- ]
- }
- selectedRows={
- Set {
- 0,
+ "color": undefined,
}
}
/>
+
+
+
+ >
+
+
+
@@ -268,7 +509,106 @@ exports[`DocumentsTableComponent should not render selection column when isSelec
"width": "100%",
}
}
- />
+ >
+
+
+
+
+
+
+
+ >
+
+
+
+
+
+
+
+ >
+
+
+
+
+
+
+
@@ -469,21 +1007,15 @@ exports[`DocumentsTableComponent should render documents and partition keys in h
"id": [Function],
}
}
- columnDefinitions={
- [
- {
- "id": "id",
- "isPartitionKey": false,
- "label": "ID",
- },
- {
- "id": "partitionKey",
- "isPartitionKey": true,
- "label": "Partition Key",
- },
- ]
+ columnHeaders={
+ {
+ "idHeader": "id",
+ "partitionKeyHeaders": [
+ "partitionKey",
+ ],
+ }
}
- isRowSelectionDisabled={false}
+ isSelectionDisabled={false}
items={
[
{
@@ -501,9 +1033,7 @@ exports[`DocumentsTableComponent should render documents and partition keys in h
]
}
onItemClicked={[Function]}
- onRefreshTable={[Function]}
onSelectedRowsChange={[Function]}
- selectedColumnIds={[]}
selectedRows={Set {}}
size={
{
@@ -518,7 +1048,6 @@ exports[`DocumentsTableComponent should render documents and partition keys in h
noNativeElements={true}
role="grid"
size="small"
- sortable={true}
style={
{
"minWidth": "fit-content",
@@ -565,7 +1094,6 @@ exports[`DocumentsTableComponent should render documents and partition keys in h
}
}
checked={false}
- key="selectcell"
onClick={[Function]}
onKeyDown={[Function]}
>
@@ -599,6 +1127,255 @@ exports[`DocumentsTableComponent should render documents and partition keys in h
+
+
@@ -800,7 +1577,7 @@ exports[`DocumentsTableComponent should render documents and partition keys in h
aria-label="Select row"
checked={false}
className="fui-Checkbox__input ruo9svu ___qlal8r0_1xrlghj f1vgc2s3"
- id="checkbox-10"
+ id="checkbox-12"
onChange={[Function]}
type="checkbox"
/>
@@ -812,6 +1589,104 @@ exports[`DocumentsTableComponent should render documents and partition keys in h
+
+
+
+
+
+
@@ -931,7 +1806,7 @@ exports[`DocumentsTableComponent should render documents and partition keys in h
aria-label="Select row"
checked={false}
className="fui-Checkbox__input ruo9svu ___qlal8r0_1xrlghj f1vgc2s3"
- id="checkbox-12"
+ id="checkbox-14"
onChange={[Function]}
type="checkbox"
/>
@@ -943,6 +1818,104 @@ exports[`DocumentsTableComponent should render documents and partition keys in h
+
+
+
+
+
+
@@ -1062,7 +2035,7 @@ exports[`DocumentsTableComponent should render documents and partition keys in h
aria-label="Select row"
checked={false}
className="fui-Checkbox__input ruo9svu ___qlal8r0_1xrlghj f1vgc2s3"
- id="checkbox-14"
+ id="checkbox-16"
onChange={[Function]}
type="checkbox"
/>
@@ -1074,6 +2047,104 @@ exports[`DocumentsTableComponent should render documents and partition keys in h
+
+
+
+
+
+
diff --git a/src/Platform/Hosted/extractFeatures.ts b/src/Platform/Hosted/extractFeatures.ts
index 2ae14e59e..5bd84516e 100644
--- a/src/Platform/Hosted/extractFeatures.ts
+++ b/src/Platform/Hosted/extractFeatures.ts
@@ -38,7 +38,6 @@ export type Features = {
readonly copilotChatFixedMonacoEditorHeight: boolean;
readonly enablePriorityBasedExecution: boolean;
readonly disableConnectionStringLogin: boolean;
- readonly enableDocumentsTableColumnSelection: boolean;
// can be set via both flight and feature flag
autoscaleDefault: boolean;
@@ -109,7 +108,6 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
copilotChatFixedMonacoEditorHeight: "true" === get("copilotchatfixedmonacoeditorheight"),
enablePriorityBasedExecution: "true" === get("enableprioritybasedexecution"),
disableConnectionStringLogin: "true" === get("disableconnectionstringlogin"),
- enableDocumentsTableColumnSelection: "true" === get("enabledocumentstablecolumnselection"),
};
}
diff --git a/src/Shared/StorageUtility.ts b/src/Shared/StorageUtility.ts
index 7a55513ed..1cea30145 100644
--- a/src/Shared/StorageUtility.ts
+++ b/src/Shared/StorageUtility.ts
@@ -29,7 +29,6 @@ export enum StorageKey {
GalleryCalloutDismissed,
VisitedAccounts,
PriorityLevel,
- DocumentsTabPrefs,
DefaultQueryResultsView,
AppState,
}
diff --git a/src/Utils/QueryUtils.ts b/src/Utils/QueryUtils.ts
index 5706d4eac..5c621b2fb 100644
--- a/src/Utils/QueryUtils.ts
+++ b/src/Utils/QueryUtils.ts
@@ -2,28 +2,18 @@ import { PartitionKey, PartitionKeyDefinition } from "@azure/cosmos";
import * as DataModels from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels";
-export const defaultQueryFields = ["id", "_self", "_rid", "_ts"];
-
export function buildDocumentsQuery(
filter: string,
partitionKeyProperties: string[],
partitionKey: DataModels.PartitionKey,
- additionalField: string[] = [],
): string {
- const fieldSet = new Set(defaultQueryFields);
- additionalField.forEach((prop) => fieldSet.add(prop));
-
- const objectListSpec = [...fieldSet]
- .filter((f) => !partitionKeyProperties.includes(f))
- .map((prop) => `c.${prop}`)
- .join(",");
let query =
partitionKeyProperties && partitionKeyProperties.length > 0
- ? `select ${objectListSpec}, [${buildDocumentsQueryPartitionProjections(
+ ? `select c.id, c._self, c._rid, c._ts, [${buildDocumentsQueryPartitionProjections(
"c",
partitionKey,
)}] as _partitionKeyValue from c`
- : `select ${objectListSpec} from c`;
+ : `select c.id, c._self, c._rid, c._ts from c`;
if (filter) {
query += " " + filter;