Infrastructure to save app state

This commit is contained in:
Laurent Nguyen
2024-07-22 12:17:56 +02:00
parent 5871c1e2d0
commit 96b2ef728a
6 changed files with 212 additions and 22 deletions

View File

@@ -0,0 +1,74 @@
// Definitions of State data
import { TableColumnSizingOptions } from "@fluentui/react-components";
import { loadState, saveStateDebounced } from "Shared/AppStatePersistenceUtility";
import { userContext } from "UserContext";
// Component states
export interface DocumentsTabStateData {
leftPaneWidthPercent: number;
}
const defaultState: DocumentsTabStateData = {
leftPaneWidthPercent: 35,
};
const ComponentName = "DocumentsTab";
export const readDocumentsTabState = (): DocumentsTabStateData => {
const state = loadState({ componentName: ComponentName });
return (state as DocumentsTabStateData) || defaultState;
};
export const saveDocumentsTabState = (state: DocumentsTabStateData): void => {
saveStateDebounced({ componentName: ComponentName }, state);
};
type ColumnSizesMap = { [columnId: string]: WidthDefinition };
type WidthDefinition = { idealWidth?: number; minWidth?: number };
const defaultSize: WidthDefinition = {
idealWidth: 200,
minWidth: 50,
};
const ColumnSizesSubComponentName = "ColumnSizes";
export const readColumnSizes = (
databaseName: string,
containerName: string,
columnIds: string[],
): TableColumnSizingOptions => {
const globalAccountName = userContext.databaseAccount?.name;
// TODO what if databaseAccount doesn't exist?
const state = loadState({
globalAccountName,
databaseName,
containerName,
componentName: ComponentName,
subComponentName: ColumnSizesSubComponentName,
}) as ColumnSizesMap;
const columnSizesPx: ColumnSizesMap = {};
columnIds.forEach((columnId) => {
columnSizesPx[columnId] = (state && state[columnId]) || defaultSize;
});
return columnSizesPx;
};
export const saveColumnSizes = (databaseName: string, containerName: string, columnSizesMap: ColumnSizesMap): void => {
const globalAccountName = userContext.databaseAccount?.name;
// TODO what if databaseAccount doesn't exist?
saveStateDebounced(
{
componentName: ComponentName,
subComponentName: ColumnSizesSubComponentName,
globalAccountName,
databaseName,
containerName,
},
columnSizesMap,
);
};

View File

@@ -21,6 +21,11 @@ import { EditorReact } from "Explorer/Controls/Editor/EditorReact";
import Explorer from "Explorer/Explorer";
import { useCommandBar } from "Explorer/Menus/CommandBar/CommandBarComponentAdapter";
import { querySampleDocuments, readSampleDocument } from "Explorer/QueryCopilot/QueryCopilotUtilities";
import {
DocumentsTabStateData,
readDocumentsTabState,
saveDocumentsTabState,
} from "Explorer/Tabs/DocumentsTabV2/DocumentsTabStateUtil";
import { getPlatformTheme } from "Explorer/Theme/ThemeUtil";
import { useSelectedNode } from "Explorer/useSelectedNode";
import { KeyboardAction, KeyboardActionGroup, useKeyboardActionGroup } from "KeyboardShortcuts";
@@ -480,6 +485,9 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
ViewModels.DocumentExplorerState.noDocumentSelected,
);
// State
const [tabStateData, setTabStateData] = useState<DocumentsTabStateData>(() => readDocumentsTabState());
const isQueryCopilotSampleContainer =
_collection?.isSampleCollection &&
_collection?.databaseId === QueryCopilotSampleDatabaseId &&
@@ -1772,7 +1780,13 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
)}
{/* <Split> doesn't like to be a flex child */}
<div style={{ overflow: "hidden", height: "100%" }}>
<Split>
<Split
onDragEnd={(preSize: number) => {
tabStateData.leftPaneWidthPercent = Math.min(100, Math.max(0, Math.round(100 * preSize) / 100));
saveDocumentsTabState(tabStateData);
setTabStateData({ ...tabStateData });
}}
>
<div
style={{ minWidth: 120, width: "35%", overflow: "hidden", position: "relative" }}
ref={tableContainerRef}
@@ -1813,6 +1827,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
(partitionKey.systemKey && !isPreferredApiMongoDB) ||
(configContext.platform === Platform.Fabric && userContext.fabricContext?.isReadOnly)
}
collection={_collection}
/>
{tableItems.length > 0 && (
<a

View File

@@ -23,10 +23,12 @@ import {
useTableSelection,
} from "@fluentui/react-components";
import { NormalizedEventKey } from "Common/Constants";
import { readColumnSizes, saveColumnSizes } from "Explorer/Tabs/DocumentsTabV2/DocumentsTabStateUtil";
import { selectionHelper } from "Explorer/Tabs/DocumentsTabV2/SelectionHelper";
import { isEnvironmentCtrlPressed, isEnvironmentShiftPressed } from "Utils/KeyboardUtils";
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;
@@ -45,6 +47,7 @@ export interface IDocumentsTableComponentProps {
columnHeaders: ColumnHeaders;
style?: React.CSSProperties;
isSelectionDisabled?: boolean;
collection: ViewModels.CollectionBase;
}
interface TableRowData extends RowStateBase<DocumentsTableComponentItem> {
@@ -65,30 +68,26 @@ export const DocumentsTableComponent: React.FC<IDocumentsTableComponentProps> =
size,
columnHeaders,
isSelectionDisabled,
collection,
}: IDocumentsTableComponentProps) => {
const initialSizingOptions: TableColumnSizingOptions = {
id: {
idealWidth: 280,
minWidth: 50,
},
};
columnHeaders.partitionKeyHeaders.forEach((pkHeader) => {
initialSizingOptions[pkHeader] = {
idealWidth: 200,
minWidth: 50,
};
});
const [columnSizingOptions, setColumnSizingOptions] = React.useState<TableColumnSizingOptions>(initialSizingOptions);
const [columnSizingOptions, setColumnSizingOptions] = React.useState<TableColumnSizingOptions>(() =>
readColumnSizes(collection.databaseId, collection.id(), ["id"].concat(columnHeaders.partitionKeyHeaders)),
);
const onColumnResize = React.useCallback((_, { columnId, width }) => {
setColumnSizingOptions((state) => ({
...state,
[columnId]: {
...state[columnId],
idealWidth: width,
},
}));
setColumnSizingOptions((state) => {
const newSizingOptions = {
...state,
[columnId]: {
...state[columnId],
idealWidth: width,
},
};
saveColumnSizes(collection.databaseId, collection.id(), newSizingOptions);
return newSizingOptions;
});
}, []);
// Columns must be a static object and cannot change on re-renders otherwise React will complain about too many refreshes