From f296c00a1c094570683d1813a1fa07d071197a2d Mon Sep 17 00:00:00 2001 From: vaidankarswapnil <81285216+vaidankarswapnil@users.noreply.github.com> Date: Mon, 7 Jun 2021 21:08:13 +0530 Subject: [PATCH 01/42] Fixed graph style panel close issue (#858) --- src/Explorer/Panes/GraphStylingPanel/GraphStylingPanel.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Explorer/Panes/GraphStylingPanel/GraphStylingPanel.tsx b/src/Explorer/Panes/GraphStylingPanel/GraphStylingPanel.tsx index 9fc520693..e5835e731 100644 --- a/src/Explorer/Panes/GraphStylingPanel/GraphStylingPanel.tsx +++ b/src/Explorer/Panes/GraphStylingPanel/GraphStylingPanel.tsx @@ -19,7 +19,8 @@ export const GraphStylingPanel: FunctionComponent = ({ const buttonLabel = "Ok"; - const submit = () => { + const submit = (event: React.FormEvent) => { + event.preventDefault(); closeSidePanel(); }; From ee60f61cfe69457e249a9ee4ffc0aa4cb20632b4 Mon Sep 17 00:00:00 2001 From: Srinath Narayanan Date: Tue, 8 Jun 2021 00:17:55 +0530 Subject: [PATCH 02/42] Mongo tabs UX fixes (#851) * Fixed mongo tabs UX * changed logic for new tab index * moved index to tabs base * removed getIndex method --- src/Contracts/ViewModels.ts | 1 + src/Explorer/Explorer.tsx | 7 ++++++- src/Explorer/Tabs/TabsBase.ts | 2 ++ src/Explorer/Tabs/TerminalTab.tsx | 9 +++++++-- src/Explorer/Tree/Collection.ts | 13 +++++++++++-- 5 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/Contracts/ViewModels.ts b/src/Contracts/ViewModels.ts index c44a86041..38091f611 100644 --- a/src/Contracts/ViewModels.ts +++ b/src/Contracts/ViewModels.ts @@ -286,6 +286,7 @@ export interface TabOptions { rid?: string; node?: TreeNode; theme?: string; + index?: number; } export interface DocumentsTabOptions extends TabOptions { diff --git a/src/Explorer/Explorer.tsx b/src/Explorer/Explorer.tsx index f5368679b..3c93ee918 100644 --- a/src/Explorer/Explorer.tsx +++ b/src/Explorer/Explorer.tsx @@ -1394,7 +1394,11 @@ export default class Explorer { tab.hashLocation().startsWith(hashLocation) ) as TerminalTab[]; - const index = terminalTabs.length + 1; + let index = 1; + if (terminalTabs.length > 0) { + index = terminalTabs[terminalTabs.length - 1].index + 1; + } + const newTab = new TerminalTab({ account: userContext.databaseAccount, tabKind: ViewModels.CollectionTabKind.Terminal, @@ -1407,6 +1411,7 @@ export default class Explorer { onLoadStartKey: null, container: this, kind: kind, + index: index, }); this.tabsManager.activateNewTab(newTab); diff --git a/src/Explorer/Tabs/TabsBase.ts b/src/Explorer/Tabs/TabsBase.ts index 2130a6715..feb0d2e03 100644 --- a/src/Explorer/Tabs/TabsBase.ts +++ b/src/Explorer/Tabs/TabsBase.ts @@ -16,6 +16,7 @@ import { TabsManager } from "./TabsManager"; // TODO: Use specific actions for logging telemetry data export default class TabsBase extends WaitsForTemplateViewModel { private static id = 0; + public readonly index: number; public closeTabButton: ViewModels.Button; public node: ViewModels.TreeNode; public collection: ViewModels.CollectionBase; @@ -35,6 +36,7 @@ export default class TabsBase extends WaitsForTemplateViewModel { constructor(options: ViewModels.TabOptions) { super(); + this.index = options.index; this._theme = ThemeUtility.getMonacoTheme(options.theme); this.node = options.node; this.collection = options.collection; diff --git a/src/Explorer/Tabs/TerminalTab.tsx b/src/Explorer/Tabs/TerminalTab.tsx index b3126d790..c0c7bf8c6 100644 --- a/src/Explorer/Tabs/TerminalTab.tsx +++ b/src/Explorer/Tabs/TerminalTab.tsx @@ -1,3 +1,4 @@ +import { Spinner, SpinnerSize } from "@fluentui/react"; import * as ko from "knockout"; import * as React from "react"; import { ReactAdapter } from "../../Bindings/ReactBindingHandler"; @@ -33,7 +34,7 @@ class NotebookTerminalComponentAdapter implements ReactAdapter { databaseAccount={this.getDatabaseAccount()} /> ) : ( - <> + ); } } @@ -51,7 +52,11 @@ export default class TerminalTab extends TabsBase { () => userContext?.databaseAccount ); this.notebookTerminalComponentAdapter.parameters = ko.computed(() => { - if (this.isTemplateReady() && this.container.isNotebookEnabled()) { + if ( + this.isTemplateReady() && + this.container.isNotebookEnabled() && + this.container.notebookServerInfo().notebookServerEndpoint + ) { return true; } return false; diff --git a/src/Explorer/Tree/Collection.ts b/src/Explorer/Tree/Collection.ts index ffd236573..ac3cc06ca 100644 --- a/src/Explorer/Tree/Collection.ts +++ b/src/Explorer/Tree/Collection.ts @@ -690,14 +690,23 @@ export default class Collection implements ViewModels.Collection { } public onNewMongoShellClick() { - const id = this.container.tabsManager.getTabs(ViewModels.CollectionTabKind.MongoShell).length + 1; + const mongoShellTabs = this.container.tabsManager.getTabs( + ViewModels.CollectionTabKind.MongoShell + ) as MongoShellTab[]; + + let index = 1; + if (mongoShellTabs.length > 0) { + index = mongoShellTabs[mongoShellTabs.length - 1].index + 1; + } + const mongoShellTab: MongoShellTab = new MongoShellTab({ tabKind: ViewModels.CollectionTabKind.MongoShell, - title: "Shell " + id, + title: "Shell " + index, tabPath: "", collection: this, node: this, hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(this.databaseId, this.id())}/mongoShell`, + index: index, }); this.container.tabsManager.activateNewTab(mongoShellTab); From 16b09df5faffa5bdb313642452e4e265c174891d Mon Sep 17 00:00:00 2001 From: victor-meng <56978073+victor-meng@users.noreply.github.com> Date: Mon, 7 Jun 2021 21:05:41 -0700 Subject: [PATCH 03/42] Hide provision throughput checkbox for serverless account (#861) --- .../AddDatabasePanel/AddDatabasePanel.tsx | 60 ++++++++++--------- .../AddDatabasePanel.test.tsx.snap | 21 +++---- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.tsx b/src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.tsx index c57d8ec89..4194e820b 100644 --- a/src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.tsx +++ b/src/Explorer/Panes/AddDatabasePanel/AddDatabasePanel.tsx @@ -179,10 +179,12 @@ export const AddDatabasePanel: FunctionComponent = ({ /> )}
-
+ - * - {databaseIdLabel} + + + {databaseIdLabel} + {databaseIdTooltipText} @@ -203,32 +205,34 @@ export const AddDatabasePanel: FunctionComponent = ({ styles={{ root: { width: 300 } }} /> - - setDatabaseCreateNewShared(!databaseCreateNewShared)} - /> - {databaseLevelThroughputTooltipText} - - - {!isServerlessAccount() && databaseCreateNewShared && ( - (throughput = newThroughput)} - setIsAutoscale={(isAutoscale: boolean) => (isAutoscaleSelected = isAutoscale)} - onCostAcknowledgeChange={(isAcknowledged: boolean) => (isCostAcknowledged = isAcknowledged)} - /> + {!isServerlessAccount() && ( + + setDatabaseCreateNewShared(!databaseCreateNewShared)} + /> + {databaseLevelThroughputTooltipText} + )} -
+ + + {!isServerlessAccount() && databaseCreateNewShared && ( + (throughput = newThroughput)} + setIsAutoscale={(isAutoscale: boolean) => (isAutoscaleSelected = isAutoscale)} + onCostAcknowledgeChange={(isAcknowledged: boolean) => (isCostAcknowledged = isAcknowledged)} + /> + )}
); diff --git a/src/Explorer/Panes/AddDatabasePanel/__snapshots__/AddDatabasePanel.test.tsx.snap b/src/Explorer/Panes/AddDatabasePanel/__snapshots__/AddDatabasePanel.test.tsx.snap index 75e11242d..e89600bec 100644 --- a/src/Explorer/Panes/AddDatabasePanel/__snapshots__/AddDatabasePanel.test.tsx.snap +++ b/src/Explorer/Panes/AddDatabasePanel/__snapshots__/AddDatabasePanel.test.tsx.snap @@ -10,16 +10,17 @@ exports[`AddDatabasePane Pane should render Default properly 1`] = `
-
+ - * + *  Database id @@ -82,14 +83,14 @@ exports[`AddDatabasePane Pane should render Default properly 1`] = ` Provisioned throughput at the database level will be shared across all collections within the database. - -
+ +
`; From 2c296ede35a6491ddf098bb450ffef6a2444564a Mon Sep 17 00:00:00 2001 From: Steve Faulkner Date: Mon, 7 Jun 2021 21:14:05 -0700 Subject: [PATCH 04/42] Remove unused KO->React Adapters (#863) --- .eslintignore | 1 - .../GraphExplorerAdapter.tsx | 74 ------------------- .../Menus/NavBar/ControlBarComponent.tsx | 33 --------- .../NavBar/ControlBarComponentAdapter.tsx | 28 ------- 4 files changed, 136 deletions(-) delete mode 100644 src/Explorer/Graph/GraphExplorerComponent/GraphExplorerAdapter.tsx delete mode 100644 src/Explorer/Menus/NavBar/ControlBarComponent.tsx delete mode 100644 src/Explorer/Menus/NavBar/ControlBarComponentAdapter.tsx diff --git a/.eslintignore b/.eslintignore index 02b4d7eb7..6ad6058d4 100644 --- a/.eslintignore +++ b/.eslintignore @@ -263,7 +263,6 @@ src/Explorer/Graph/GraphExplorerComponent/EditorNodePropertiesComponent.test.tsx src/Explorer/Graph/GraphExplorerComponent/EditorNodePropertiesComponent.tsx src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.test.tsx src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.tsx -src/Explorer/Graph/GraphExplorerComponent/GraphExplorerAdapter.tsx src/Explorer/Graph/GraphExplorerComponent/GraphVizComponent.tsx src/Explorer/Graph/GraphExplorerComponent/LeftPaneComponent.tsx src/Explorer/Graph/GraphExplorerComponent/MiddlePaneComponent.tsx diff --git a/src/Explorer/Graph/GraphExplorerComponent/GraphExplorerAdapter.tsx b/src/Explorer/Graph/GraphExplorerComponent/GraphExplorerAdapter.tsx deleted file mode 100644 index 984419398..000000000 --- a/src/Explorer/Graph/GraphExplorerComponent/GraphExplorerAdapter.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import * as React from "react"; -import { ReactAdapter } from "../../../Bindings/ReactBindingHandler"; -import * as ViewModels from "../../../Contracts/ViewModels"; -import { IGraphConfig } from "../../Tabs/GraphTab"; -import { GraphAccessor, GraphExplorer } from "./GraphExplorer"; -interface Parameter { - onIsNewVertexDisabledChange: (isEnabled: boolean) => void; - onGraphAccessorCreated: (instance: GraphAccessor) => void; - onIsFilterQueryLoading: (isFilterQueryLoading: boolean) => void; - onIsValidQuery: (isValidQuery: boolean) => void; - onIsPropertyEditing: (isEditing: boolean) => void; - onIsGraphDisplayed: (isDisplayed: boolean) => void; - onResetDefaultGraphConfigValues: () => void; - - collectionPartitionKeyProperty: string; - graphBackendEndpoint: string; - databaseId: string; - collectionId: string; - masterKey: string; - - onLoadStartKey: number; - onLoadStartKeyChange: (newKey: number) => void; - resourceId: string; - - igraphConfigUiData: ViewModels.IGraphConfigUiData; - igraphConfig: IGraphConfig; - setIConfigUiData?: (data: string[]) => void; -} - -interface IGraphExplorerProps { - isChanged: boolean; -} - -interface IGraphExplorerStates { - isChangedState: boolean; -} - -export interface GraphExplorerAdapter - extends ReactAdapter, - React.Component {} -export class GraphExplorerAdapter implements ReactAdapter { - public params: Parameter; - public parameters = {}; - public isNewVertexDisabled: boolean; - - public constructor(params: Parameter, props?: IGraphExplorerProps) { - this.params = params; - } - - public renderComponent(): JSX.Element { - return ( - - ); - } -} diff --git a/src/Explorer/Menus/NavBar/ControlBarComponent.tsx b/src/Explorer/Menus/NavBar/ControlBarComponent.tsx deleted file mode 100644 index 26864cea5..000000000 --- a/src/Explorer/Menus/NavBar/ControlBarComponent.tsx +++ /dev/null @@ -1,33 +0,0 @@ -/** - * React component for control bar - */ - -import * as React from "react"; -import { - CommandButtonComponent, - CommandButtonComponentProps, -} from "../../Controls/CommandButton/CommandButtonComponent"; - -export interface ControlBarComponentProps { - buttons: CommandButtonComponentProps[]; -} - -export class ControlBarComponent extends React.Component { - private static renderButtons(commandButtonOptions: CommandButtonComponentProps[]): JSX.Element[] { - return commandButtonOptions.map( - (btn: CommandButtonComponentProps, index: number): JSX.Element => { - // Remove label - btn.commandButtonLabel = undefined; - return CommandButtonComponent.renderButton(btn, `${index}`); - } - ); - } - - public render(): JSX.Element { - if (!this.props.buttons || this.props.buttons.length < 1) { - return ; - } - - return {ControlBarComponent.renderButtons(this.props.buttons)}; - } -} diff --git a/src/Explorer/Menus/NavBar/ControlBarComponentAdapter.tsx b/src/Explorer/Menus/NavBar/ControlBarComponentAdapter.tsx deleted file mode 100644 index b6af77dbe..000000000 --- a/src/Explorer/Menus/NavBar/ControlBarComponentAdapter.tsx +++ /dev/null @@ -1,28 +0,0 @@ -/** - * This adapter is responsible to render the React component - * If the component signals a change through the callback passed in the properties, it must render the React component when appropriate - * and update any knockout observables passed from the parent. - */ - -import * as ko from "knockout"; -import * as React from "react"; -import { ReactAdapter } from "../../../Bindings/ReactBindingHandler"; -import { ControlBarComponent } from "./ControlBarComponent"; -import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent"; - -export class ControlBarComponentAdapter implements ReactAdapter { - public parameters: ko.Observable; - - constructor(private buttons: ko.ObservableArray) { - this.buttons.subscribe(() => this.forceRender()); - this.parameters = ko.observable(Date.now()); - } - - public renderComponent(): JSX.Element { - return ; - } - - public forceRender(): void { - window.requestAnimationFrame(() => this.parameters(Date.now())); - } -} From 8f6cac3d35f30e17902deb9a8e97e580ef4c40f6 Mon Sep 17 00:00:00 2001 From: Steve Faulkner Date: Wed, 9 Jun 2021 06:35:25 -0700 Subject: [PATCH 05/42] Remove Unused Splitter (#874) --- src/Common/Constants.ts | 10 ---- src/Common/Splitter.ts | 25 --------- .../SettingsComponent.test.tsx.snap | 52 ------------------- src/Explorer/Explorer.tsx | 16 ------ .../GitHubReposPanel.test.tsx.snap | 13 ----- .../StringInputPane.test.tsx.snap | 13 ----- ...eteDatabaseConfirmationPanel.test.tsx.snap | 13 ----- src/Main.tsx | 3 -- 8 files changed, 145 deletions(-) diff --git a/src/Common/Constants.ts b/src/Common/Constants.ts index 79edd0234..57b65c43e 100644 --- a/src/Common/Constants.ts +++ b/src/Common/Constants.ts @@ -158,16 +158,6 @@ export class DocumentsGridMetrics { public static DocumentEditorMaxWidthRatio: number = 0.4; } -export class ExplorerMetrics { - public static SplitterMinWidth: number = 240; - public static SplitterMaxWidth: number = 400; - public static CollapsedResourceTreeWidth: number = 36; -} - -export class SplitterMetrics { - public static CollapsedPositionLeft: number = ExplorerMetrics.CollapsedResourceTreeWidth; -} - export class Areas { public static ResourceTree: string = "Resource Tree"; public static ContextualPane: string = "Contextual Pane"; diff --git a/src/Common/Splitter.ts b/src/Common/Splitter.ts index cf2518812..1db6d3ba5 100644 --- a/src/Common/Splitter.ts +++ b/src/Common/Splitter.ts @@ -1,7 +1,3 @@ -import * as ko from "knockout"; - -import { SplitterMetrics } from "./Constants"; - export enum SplitterDirection { Horizontal = "horizontal", Vertical = "vertical", @@ -28,14 +24,12 @@ export class Splitter { public lastX!: number; public lastWidth!: number; - private isCollapsed: ko.Observable; private bounds: SplitterBounds; private direction: SplitterDirection; constructor(options: SplitterOptions) { this.splitterId = options.splitterId; this.leftSideId = options.leftId; - this.isCollapsed = ko.observable(false); this.bounds = options.bounds; this.direction = options.direction; this.initialize(); @@ -83,23 +77,4 @@ export class Splitter { }; private onResizeStop: JQueryUI.ResizableEvent = () => $("iframe").css("pointer-events", "auto"); - - public collapseLeft() { - this.lastX = $(this.splitter).position().left; - this.lastWidth = $(this.leftSide).width(); - $(this.splitter).css("left", SplitterMetrics.CollapsedPositionLeft); - $(this.leftSide).css("width", ""); - $(this.leftSide).resizable("option", "disabled", true).removeClass("ui-resizable-disabled"); // remove class so splitter is visible - $(this.splitter).removeClass("ui-resizable-e"); - this.isCollapsed(true); - } - - public expandLeft() { - $(this.splitter).addClass("ui-resizable-e"); - $(this.leftSide).css("width", this.lastWidth); - $(this.splitter).css("left", this.lastX); - $(this.splitter).css("left", ""); // this ensures the splitter's position is not fixed and enables movement during resizing - $(this.leftSide).resizable("enable"); - this.isCollapsed(false); - } } diff --git a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap index c5db2d2af..3451ec734 100644 --- a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap +++ b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap @@ -31,7 +31,6 @@ exports[`SettingsComponent renders 1`] = ` "_isInitializingNotebooks": false, "_resetNotebookWorkspace": [Function], "canSaveQueries": [Function], - "collapsedResourceTreeWidth": 36, "databases": [Function], "isAccountReady": [Function], "isFixedCollectionWithSharedThroughputSupported": [Function], @@ -75,18 +74,6 @@ exports[`SettingsComponent renders 1`] = ` "setInProgressConsoleDataIdToBeDeleted": undefined, "setNotificationConsoleData": undefined, "sparkClusterConnectionInfo": [Function], - "splitter": Splitter { - "bounds": Object { - "max": 400, - "min": 240, - }, - "direction": "vertical", - "isCollapsed": [Function], - "leftSideId": "resourcetree", - "onResizeStart": [Function], - "onResizeStop": [Function], - "splitterId": "h_splitter1", - }, "tabsManager": TabsManager { "activeTab": [Function], "openedTabs": [Function], @@ -115,7 +102,6 @@ exports[`SettingsComponent renders 1`] = ` "_isInitializingNotebooks": false, "_resetNotebookWorkspace": [Function], "canSaveQueries": [Function], - "collapsedResourceTreeWidth": 36, "databases": [Function], "isAccountReady": [Function], "isFixedCollectionWithSharedThroughputSupported": [Function], @@ -159,18 +145,6 @@ exports[`SettingsComponent renders 1`] = ` "setInProgressConsoleDataIdToBeDeleted": undefined, "setNotificationConsoleData": undefined, "sparkClusterConnectionInfo": [Function], - "splitter": Splitter { - "bounds": Object { - "max": 400, - "min": 240, - }, - "direction": "vertical", - "isCollapsed": [Function], - "leftSideId": "resourcetree", - "onResizeStart": [Function], - "onResizeStop": [Function], - "splitterId": "h_splitter1", - }, "tabsManager": TabsManager { "activeTab": [Function], "openedTabs": [Function], @@ -212,7 +186,6 @@ exports[`SettingsComponent renders 1`] = ` "_isInitializingNotebooks": false, "_resetNotebookWorkspace": [Function], "canSaveQueries": [Function], - "collapsedResourceTreeWidth": 36, "databases": [Function], "isAccountReady": [Function], "isFixedCollectionWithSharedThroughputSupported": [Function], @@ -256,18 +229,6 @@ exports[`SettingsComponent renders 1`] = ` "setInProgressConsoleDataIdToBeDeleted": undefined, "setNotificationConsoleData": undefined, "sparkClusterConnectionInfo": [Function], - "splitter": Splitter { - "bounds": Object { - "max": 400, - "min": 240, - }, - "direction": "vertical", - "isCollapsed": [Function], - "leftSideId": "resourcetree", - "onResizeStart": [Function], - "onResizeStop": [Function], - "splitterId": "h_splitter1", - }, "tabsManager": TabsManager { "activeTab": [Function], "openedTabs": [Function], @@ -296,7 +257,6 @@ exports[`SettingsComponent renders 1`] = ` "_isInitializingNotebooks": false, "_resetNotebookWorkspace": [Function], "canSaveQueries": [Function], - "collapsedResourceTreeWidth": 36, "databases": [Function], "isAccountReady": [Function], "isFixedCollectionWithSharedThroughputSupported": [Function], @@ -340,18 +300,6 @@ exports[`SettingsComponent renders 1`] = ` "setInProgressConsoleDataIdToBeDeleted": undefined, "setNotificationConsoleData": undefined, "sparkClusterConnectionInfo": [Function], - "splitter": Splitter { - "bounds": Object { - "max": 400, - "min": 240, - }, - "direction": "vertical", - "isCollapsed": [Function], - "leftSideId": "resourcetree", - "onResizeStart": [Function], - "onResizeStop": [Function], - "splitterId": "h_splitter1", - }, "tabsManager": TabsManager { "activeTab": [Function], "openedTabs": [Function], diff --git a/src/Explorer/Explorer.tsx b/src/Explorer/Explorer.tsx index 3c93ee918..1686267f2 100644 --- a/src/Explorer/Explorer.tsx +++ b/src/Explorer/Explorer.tsx @@ -6,14 +6,12 @@ import _ from "underscore"; import { AuthType } from "../AuthType"; import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer"; import * as Constants from "../Common/Constants"; -import { ExplorerMetrics } from "../Common/Constants"; import { readCollection } from "../Common/dataAccess/readCollection"; import { readDatabases } from "../Common/dataAccess/readDatabases"; import { isPublicInternetAccessAllowed } from "../Common/DatabaseAccountUtility"; import { getErrorMessage, getErrorStack, handleError } from "../Common/ErrorHandlingUtils"; import * as Logger from "../Common/Logger"; import { QueriesClient } from "../Common/QueriesClient"; -import { Splitter, SplitterBounds, SplitterDirection } from "../Common/Splitter"; import { configContext, Platform } from "../ConfigContext"; import * as DataModels from "../Contracts/DataModels"; import * as ViewModels from "../Contracts/ViewModels"; @@ -86,15 +84,12 @@ export interface ExplorerParams { } export default class Explorer { - public collapsedResourceTreeWidth: number = ExplorerMetrics.CollapsedResourceTreeWidth; - public isFixedCollectionWithSharedThroughputSupported: ko.Computed; public isServerlessEnabled: ko.Computed; public isAccountReady: ko.Observable; public canSaveQueries: ko.Computed; public queriesClient: QueriesClient; public tableDataClient: TableDataClient; - public splitter: Splitter; private setNotificationConsoleData: (consoleData: ConsoleData) => void; private setInProgressConsoleDataIdToBeDeleted: (id: string) => void; @@ -230,17 +225,6 @@ export default class Explorer { ); }); - const splitterBounds: SplitterBounds = { - min: ExplorerMetrics.SplitterMinWidth, - max: ExplorerMetrics.SplitterMaxWidth, - }; - this.splitter = new Splitter({ - splitterId: "h_splitter1", - leftId: "resourcetree", - bounds: splitterBounds, - direction: SplitterDirection.Vertical, - }); - this.isFixedCollectionWithSharedThroughputSupported = ko.computed(() => { if (userContext.features.enableFixedCollectionWithSharedThroughput) { return true; diff --git a/src/Explorer/Panes/GitHubReposPanel/__snapshots__/GitHubReposPanel.test.tsx.snap b/src/Explorer/Panes/GitHubReposPanel/__snapshots__/GitHubReposPanel.test.tsx.snap index 6ef9c40b0..29a547ba7 100644 --- a/src/Explorer/Panes/GitHubReposPanel/__snapshots__/GitHubReposPanel.test.tsx.snap +++ b/src/Explorer/Panes/GitHubReposPanel/__snapshots__/GitHubReposPanel.test.tsx.snap @@ -20,7 +20,6 @@ exports[`GitHub Repos Panel should render Default properly 1`] = ` "_isInitializingNotebooks": false, "_resetNotebookWorkspace": [Function], "canSaveQueries": [Function], - "collapsedResourceTreeWidth": 36, "databases": [Function], "isAccountReady": [Function], "isFixedCollectionWithSharedThroughputSupported": [Function], @@ -64,18 +63,6 @@ exports[`GitHub Repos Panel should render Default properly 1`] = ` "setInProgressConsoleDataIdToBeDeleted": undefined, "setNotificationConsoleData": undefined, "sparkClusterConnectionInfo": [Function], - "splitter": Splitter { - "bounds": Object { - "max": 400, - "min": 240, - }, - "direction": "vertical", - "isCollapsed": [Function], - "leftSideId": "resourcetree", - "onResizeStart": [Function], - "onResizeStop": [Function], - "splitterId": "h_splitter1", - }, "tabsManager": TabsManager { "activeTab": [Function], "openedTabs": [Function], diff --git a/src/Explorer/Panes/StringInputPane/__snapshots__/StringInputPane.test.tsx.snap b/src/Explorer/Panes/StringInputPane/__snapshots__/StringInputPane.test.tsx.snap index 6a5f4cf63..09e143e84 100644 --- a/src/Explorer/Panes/StringInputPane/__snapshots__/StringInputPane.test.tsx.snap +++ b/src/Explorer/Panes/StringInputPane/__snapshots__/StringInputPane.test.tsx.snap @@ -10,7 +10,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = ` "_isInitializingNotebooks": false, "_resetNotebookWorkspace": [Function], "canSaveQueries": [Function], - "collapsedResourceTreeWidth": 36, "databases": [Function], "isAccountReady": [Function], "isFixedCollectionWithSharedThroughputSupported": [Function], @@ -54,18 +53,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = ` "setInProgressConsoleDataIdToBeDeleted": undefined, "setNotificationConsoleData": undefined, "sparkClusterConnectionInfo": [Function], - "splitter": Splitter { - "bounds": Object { - "max": 400, - "min": 240, - }, - "direction": "vertical", - "isCollapsed": [Function], - "leftSideId": "resourcetree", - "onResizeStart": [Function], - "onResizeStop": [Function], - "splitterId": "h_splitter1", - }, "tabsManager": TabsManager { "activeTab": [Function], "openedTabs": [Function], diff --git a/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap b/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap index 8c41ea2b1..0f6e55256 100644 --- a/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap +++ b/src/Explorer/Panes/__snapshots__/DeleteDatabaseConfirmationPanel.test.tsx.snap @@ -8,7 +8,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database "_isInitializingNotebooks": false, "_resetNotebookWorkspace": [Function], "canSaveQueries": [Function], - "collapsedResourceTreeWidth": 36, "databases": [Function], "isAccountReady": [Function], "isFixedCollectionWithSharedThroughputSupported": [Function], @@ -56,18 +55,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database "setInProgressConsoleDataIdToBeDeleted": undefined, "setNotificationConsoleData": undefined, "sparkClusterConnectionInfo": [Function], - "splitter": Splitter { - "bounds": Object { - "max": 400, - "min": 240, - }, - "direction": "vertical", - "isCollapsed": [Function], - "leftSideId": "resourcetree", - "onResizeStart": [Function], - "onResizeStop": [Function], - "splitterId": "h_splitter1", - }, "tabsManager": TabsManager { "activeTab": [Function], "openedTabs": [Function], diff --git a/src/Main.tsx b/src/Main.tsx index bf6f1643f..a62ee3020 100644 --- a/src/Main.tsx +++ b/src/Main.tsx @@ -105,9 +105,6 @@ const App: React.FunctionComponent = () => { /> {/* Collections Tree Collapsed - End */} - {/* Splitter - Start */} -
- {/* Splitter - End */}
{/* Collections Tree - End */} {tabs.length === 0 && } From fc9f4c5583629975e33327feb101f0dd78a2e38c Mon Sep 17 00:00:00 2001 From: Steve Faulkner Date: Wed, 9 Jun 2021 13:08:10 -0700 Subject: [PATCH 06/42] Migrate notebooks workspaces to generated clients (#876) --- src/Common/MongoProxyClient.test.ts | 1 - src/Explorer/Explorer.tsx | 65 +++--- .../Notebook/NotebookContainerClient.ts | 13 +- .../SetupNotebooksPanel.tsx | 7 +- .../NotebookWorkspaceManager.ts | 98 -------- .../IResourceProviderClient.test.ts | 163 ------------- .../IResourceProviderClient.ts | 30 --- .../ResourceProviderClient.ts | 217 ------------------ .../ResourceProviderClientFactory.ts | 22 -- .../cosmosNotebooks/notebookWorkspaces.ts | 5 +- .../generatedClients/cosmosNotebooks/types.ts | 4 +- src/Utils/arm/request.ts | 6 +- tsconfig.strict.json | 1 - 13 files changed, 49 insertions(+), 583 deletions(-) delete mode 100644 src/NotebookWorkspaceManager/NotebookWorkspaceManager.ts delete mode 100644 src/ResourceProvider/IResourceProviderClient.test.ts delete mode 100644 src/ResourceProvider/IResourceProviderClient.ts delete mode 100644 src/ResourceProvider/ResourceProviderClient.ts delete mode 100644 src/ResourceProvider/ResourceProviderClientFactory.ts diff --git a/src/Common/MongoProxyClient.test.ts b/src/Common/MongoProxyClient.test.ts index 8f7e033f9..3a5a02365 100644 --- a/src/Common/MongoProxyClient.test.ts +++ b/src/Common/MongoProxyClient.test.ts @@ -5,7 +5,6 @@ import { Collection } from "../Contracts/ViewModels"; import DocumentId from "../Explorer/Tree/DocumentId"; import { updateUserContext } from "../UserContext"; import { deleteDocument, getEndpoint, queryDocuments, readDocument, updateDocument } from "./MongoProxyClient"; -jest.mock("../ResourceProvider/ResourceProviderClient.ts"); const databaseId = "testDB"; diff --git a/src/Explorer/Explorer.tsx b/src/Explorer/Explorer.tsx index 1686267f2..52535b3c5 100644 --- a/src/Explorer/Explorer.tsx +++ b/src/Explorer/Explorer.tsx @@ -18,7 +18,6 @@ import * as ViewModels from "../Contracts/ViewModels"; import { GitHubOAuthService } from "../GitHub/GitHubOAuthService"; import { useSidePanel } from "../hooks/useSidePanel"; import { IGalleryItem, JunoClient } from "../Juno/JunoClient"; -import { NotebookWorkspaceManager } from "../NotebookWorkspaceManager/NotebookWorkspaceManager"; import { RouteHandler } from "../RouteHandlers/RouteHandler"; import { ExplorerSettings } from "../Shared/ExplorerSettings"; import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants"; @@ -26,6 +25,12 @@ import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor"; import { userContext } from "../UserContext"; import { getCollectionName, getDatabaseName, getUploadName } from "../Utils/APITypeUtils"; import { update } from "../Utils/arm/generatedClients/cosmos/databaseAccounts"; +import { + get as getWorkspace, + listByDatabaseAccount, + listConnectionInfo, + start, +} from "../Utils/arm/generatedClients/cosmosNotebooks/notebookWorkspaces"; import { getAuthorizationHeader } from "../Utils/AuthorizationUtils"; import { stringToBlob } from "../Utils/BlobUtils"; import { isCapabilityEnabled } from "../Utils/CapabilityUtils"; @@ -123,7 +128,6 @@ export default class Explorer { public isNotebookEnabled: ko.Observable; public isNotebooksEnabledForAccount: ko.Observable; public notebookServerInfo: ko.Observable; - public notebookWorkspaceManager: NotebookWorkspaceManager; public sparkClusterConnectionInfo: ko.Observable; public isSynapseLinkUpdating: ko.Observable; public memoryUsageInfo: ko.Observable; @@ -159,7 +163,6 @@ export default class Explorer { ? this.refreshDatabaseForResourceToken() : this.refreshAllDatabases(true); RouteHandler.getInstance().initHandler(); - this.notebookWorkspaceManager = new NotebookWorkspaceManager(); await this._refreshNotebooksEnabledStateForAccount(); this.isNotebookEnabled( userContext.authType !== AuthType.ResourceToken && @@ -581,37 +584,19 @@ export default class Explorer { this._isInitializingNotebooks = true; await this.ensureNotebookWorkspaceRunning(); - let connectionInfo: DataModels.NotebookWorkspaceConnectionInfo = { - authToken: undefined, - notebookServerEndpoint: undefined, - }; - try { - connectionInfo = await this.notebookWorkspaceManager.getNotebookConnectionInfoAsync( - databaseAccount.id, - "default" - ); - } catch (error) { - this._isInitializingNotebooks = false; - handleError( - error, - "initNotebooks/getNotebookConnectionInfoAsync", - `Failed to get notebook workspace connection info: ${getErrorMessage(error)}` - ); - throw error; - } finally { - // Overwrite with feature flags - if (userContext.features.notebookServerUrl) { - connectionInfo.notebookServerEndpoint = userContext.features.notebookServerUrl; - } + const connectionInfo = await listConnectionInfo( + userContext.subscriptionId, + userContext.resourceGroup, + databaseAccount.name, + "default" + ); - if (userContext.features.notebookServerToken) { - connectionInfo.authToken = userContext.features.notebookServerToken; - } - - this.notebookServerInfo(connectionInfo); - this.notebookServerInfo.valueHasMutated(); - this.refreshNotebookList(); - } + this.notebookServerInfo({ + notebookServerEndpoint: userContext.features.notebookServerUrl || connectionInfo.notebookServerEndpoint, + authToken: userContext.features.notebookServerToken || connectionInfo.authToken, + }); + this.notebookServerInfo.valueHasMutated(); + this.refreshNotebookList(); this._isInitializingNotebooks = false; } @@ -643,7 +628,11 @@ export default class Explorer { } try { - const workspaces = await this.notebookWorkspaceManager.getNotebookWorkspacesAsync(databaseAccount?.id); + const { value: workspaces } = await listByDatabaseAccount( + userContext.subscriptionId, + userContext.resourceGroup, + userContext.databaseAccount.name + ); return workspaces && workspaces.length > 0 && workspaces.some((workspace) => workspace.name === "default"); } catch (error) { Logger.logError(getErrorMessage(error), "Explorer/_containsDefaultNotebookWorkspace"); @@ -658,8 +647,10 @@ export default class Explorer { let clearMessage; try { - const notebookWorkspace = await this.notebookWorkspaceManager.getNotebookWorkspaceAsync( - userContext.databaseAccount.id, + const notebookWorkspace = await getWorkspace( + userContext.subscriptionId, + userContext.resourceGroup, + userContext.databaseAccount.name, "default" ); if ( @@ -669,7 +660,7 @@ export default class Explorer { notebookWorkspace.properties.status.toLowerCase() === "stopped" ) { clearMessage = NotificationConsoleUtils.logConsoleProgress("Initializing notebook workspace"); - await this.notebookWorkspaceManager.startNotebookWorkspaceAsync(userContext.databaseAccount.id, "default"); + await start(userContext.subscriptionId, userContext.resourceGroup, userContext.databaseAccount.name, "default"); } } catch (error) { handleError(error, "Explorer/ensureNotebookWorkspaceRunning", "Failed to initialize notebook workspace"); diff --git a/src/Explorer/Notebook/NotebookContainerClient.ts b/src/Explorer/Notebook/NotebookContainerClient.ts index 8b961450f..3764360ef 100644 --- a/src/Explorer/Notebook/NotebookContainerClient.ts +++ b/src/Explorer/Notebook/NotebookContainerClient.ts @@ -6,6 +6,7 @@ import { getErrorMessage } from "../../Common/ErrorHandlingUtils"; import * as Logger from "../../Common/Logger"; import * as DataModels from "../../Contracts/DataModels"; import { userContext } from "../../UserContext"; +import { createOrUpdate, destroy } from "../../Utils/arm/generatedClients/cosmosNotebooks/notebookWorkspaces"; import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils"; export class NotebookContainerClient { @@ -130,16 +131,18 @@ export class NotebookContainerClient { } private async recreateNotebookWorkspaceAsync(): Promise { - const explorer = window.dataExplorer; const { databaseAccount } = userContext; if (!databaseAccount?.id) { throw new Error("DataExplorer not initialized"); } - - const notebookWorkspaceManager = explorer.notebookWorkspaceManager; try { - await notebookWorkspaceManager.deleteNotebookWorkspaceAsync(databaseAccount?.id, "default"); - await notebookWorkspaceManager.createNotebookWorkspaceAsync(databaseAccount?.id, "default"); + await destroy(userContext.subscriptionId, userContext.resourceGroup, userContext.databaseAccount.name, "default"); + await createOrUpdate( + userContext.subscriptionId, + userContext.resourceGroup, + userContext.databaseAccount.name, + "default" + ); } catch (error) { Logger.logError(getErrorMessage(error), "NotebookContainerClient/recreateNotebookWorkspaceAsync"); return Promise.reject(error); diff --git a/src/Explorer/Panes/SetupNotebooksPanel/SetupNotebooksPanel.tsx b/src/Explorer/Panes/SetupNotebooksPanel/SetupNotebooksPanel.tsx index d465bb7d4..75a17d89a 100644 --- a/src/Explorer/Panes/SetupNotebooksPanel/SetupNotebooksPanel.tsx +++ b/src/Explorer/Panes/SetupNotebooksPanel/SetupNotebooksPanel.tsx @@ -7,6 +7,7 @@ import { useSidePanel } from "../../../hooks/useSidePanel"; import { Action } from "../../../Shared/Telemetry/TelemetryConstants"; import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor"; import { userContext } from "../../../UserContext"; +import { createOrUpdate } from "../../../Utils/arm/generatedClients/cosmosNotebooks/notebookWorkspaces"; import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils"; import Explorer from "../../Explorer"; import { PanelInfoErrorComponent } from "../PanelInfoErrorComponent"; @@ -56,8 +57,10 @@ export const SetupNoteBooksPanel: FunctionComponent = try { setLoadingTrue(); - await explorer.notebookWorkspaceManager.createNotebookWorkspaceAsync( - userContext.databaseAccount && userContext.databaseAccount.id, + await createOrUpdate( + userContext.subscriptionId, + userContext.resourceGroup, + userContext.databaseAccount.name, "default" ); explorer.isAccountReady.valueHasMutated(); // re-trigger init notebooks diff --git a/src/NotebookWorkspaceManager/NotebookWorkspaceManager.ts b/src/NotebookWorkspaceManager/NotebookWorkspaceManager.ts deleted file mode 100644 index 171cb5cf4..000000000 --- a/src/NotebookWorkspaceManager/NotebookWorkspaceManager.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { ArmApiVersions } from "../Common/Constants"; -import { IResourceProviderClient, IResourceProviderClientFactory } from "../ResourceProvider/IResourceProviderClient"; -import * as Logger from "../Common/Logger"; -import { - NotebookWorkspace, - NotebookWorkspaceConnectionInfo, - NotebookWorkspaceFeedResponse, -} from "../Contracts/DataModels"; -import { ResourceProviderClientFactory } from "../ResourceProvider/ResourceProviderClientFactory"; -import { getErrorMessage } from "../Common/ErrorHandlingUtils"; - -export class NotebookWorkspaceManager { - private resourceProviderClientFactory: IResourceProviderClientFactory; - - constructor() { - this.resourceProviderClientFactory = new ResourceProviderClientFactory(); - } - - public async getNotebookWorkspacesAsync(cosmosdbResourceId: string): Promise { - const uri = `${cosmosdbResourceId}/notebookWorkspaces`; - try { - const response = (await this.rpClient(uri).getAsync( - uri, - ArmApiVersions.documentDB - )) as NotebookWorkspaceFeedResponse; - return response && response.value; - } catch (error) { - Logger.logError(getErrorMessage(error), "NotebookWorkspaceManager/getNotebookWorkspacesAsync"); - throw error; - } - } - - public async getNotebookWorkspaceAsync( - cosmosdbResourceId: string, - notebookWorkspaceId: string - ): Promise { - const uri = `${cosmosdbResourceId}/notebookWorkspaces/${notebookWorkspaceId}`; - try { - return (await this.rpClient(uri).getAsync(uri, ArmApiVersions.documentDB)) as NotebookWorkspace; - } catch (error) { - Logger.logError(getErrorMessage(error), "NotebookWorkspaceManager/getNotebookWorkspaceAsync"); - throw error; - } - } - - public async createNotebookWorkspaceAsync(cosmosdbResourceId: string, notebookWorkspaceId: string): Promise { - const uri = `${cosmosdbResourceId}/notebookWorkspaces/${notebookWorkspaceId}`; - try { - await this.rpClient(uri).putAsync(uri, ArmApiVersions.documentDB, { name: notebookWorkspaceId }); - } catch (error) { - Logger.logError(getErrorMessage(error), "NotebookWorkspaceManager/createNotebookWorkspaceAsync"); - throw error; - } - } - - public async deleteNotebookWorkspaceAsync(cosmosdbResourceId: string, notebookWorkspaceId: string): Promise { - const uri = `${cosmosdbResourceId}/notebookWorkspaces/${notebookWorkspaceId}`; - try { - await this.rpClient(uri).deleteAsync(uri, ArmApiVersions.documentDB); - } catch (error) { - Logger.logError(getErrorMessage(error), "NotebookWorkspaceManager/deleteNotebookWorkspaceAsync"); - throw error; - } - } - - public async getNotebookConnectionInfoAsync( - cosmosdbResourceId: string, - notebookWorkspaceId: string - ): Promise { - const uri = `${cosmosdbResourceId}/notebookWorkspaces/${notebookWorkspaceId}/listConnectionInfo`; - try { - return await this.rpClient(uri).postAsync( - uri, - ArmApiVersions.documentDB, - undefined - ); - } catch (error) { - Logger.logError(getErrorMessage(error), "NotebookWorkspaceManager/getNotebookConnectionInfoAsync"); - throw error; - } - } - - public async startNotebookWorkspaceAsync(cosmosdbResourceId: string, notebookWorkspaceId: string): Promise { - const uri = `${cosmosdbResourceId}/notebookWorkspaces/${notebookWorkspaceId}/start`; - try { - return await this.rpClient(uri).postAsync(uri, ArmApiVersions.documentDB, undefined, { - skipResourceValidation: true, - }); - } catch (error) { - Logger.logError(getErrorMessage(error), "NotebookWorkspaceManager/startNotebookWorkspaceAsync"); - throw error; - } - } - - private rpClient(uri: string): IResourceProviderClient { - return this.resourceProviderClientFactory.getOrCreate(uri); - } -} diff --git a/src/ResourceProvider/IResourceProviderClient.test.ts b/src/ResourceProvider/IResourceProviderClient.test.ts deleted file mode 100644 index b775564c1..000000000 --- a/src/ResourceProvider/IResourceProviderClient.test.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { IResourceProviderClient, IResourceProviderClientFactory } from "./IResourceProviderClient"; - -describe("IResourceProviderClient", () => { - interface TestResource { - id: string; - } - - const expectedResult: TestResource = { id: "a" }; - const expectedReason: any = "error"; - - class SuccessClient implements IResourceProviderClient { - public deleteAsync(url: string, apiVersion?: string): Promise { - return new Promise((resolve, reject) => { - resolve(); - }); - } - - public getAsync(url: string, apiVersion?: string): Promise { - return new Promise((resolve, reject) => { - resolve(expectedResult); - }); - } - - public postAsync(url: string, apiVersion: string, body: TestResource): Promise { - return new Promise((resolve, reject) => { - resolve(expectedResult); - }); - } - - public putAsync(url: string, apiVersion: string, body: TestResource): Promise { - return new Promise((resolve, reject) => { - resolve(expectedResult); - }); - } - - public patchAsync(url: string, apiVersion: string, body: TestResource): Promise { - return new Promise((resolve, reject) => { - resolve(expectedResult); - }); - } - } - - class ErrorClient implements IResourceProviderClient { - public patchAsync(url: string, apiVersion: string, body: TestResource): Promise { - return new Promise((resolve, reject) => { - reject(expectedReason); - }); - } - - public putAsync(url: string, apiVersion: string, body: TestResource): Promise { - return new Promise((resolve, reject) => { - reject(expectedReason); - }); - } - - public postAsync(url: string, apiVersion: string, body: TestResource): Promise { - return new Promise((resolve, reject) => { - reject(expectedReason); - }); - } - - public getAsync(url: string, apiVersion?: string): Promise { - return new Promise((resolve, reject) => { - reject(expectedReason); - }); - } - - public deleteAsync(url: string, apiVersion?: string): Promise { - return new Promise((resolve, reject) => { - reject(expectedReason); - }); - } - } - - class TestResourceProviderClientFactory implements IResourceProviderClientFactory { - public getOrCreate(url: string): IResourceProviderClient { - switch (url) { - case "reject": - return new ErrorClient(); - case "fulfill": - default: - return new SuccessClient(); - } - } - } - - const factory = new TestResourceProviderClientFactory(); - const fulfillClient = factory.getOrCreate("fulfill"); - const rejectClient = factory.getOrCreate("reject"); - const testApiVersion = "apiversion"; - - describe("deleteAsync", () => { - it("returns a fulfilled promise on success", async () => { - const result = await fulfillClient.deleteAsync("/foo", testApiVersion); - expect(result).toEqual(undefined); - }); - - it("returns a rejected promise with a reason on error", async () => { - let result: any; - try { - result = await rejectClient.deleteAsync("/foo", testApiVersion); - } catch (reason) { - result = reason; - } - - expect(result).toEqual(expectedReason); - }); - }); - - describe("getAsync", () => { - it("returns a fulfilled promise with a value on success", async () => { - const result = await fulfillClient.getAsync("/foo", testApiVersion); - expect(result).toEqual(expectedResult); - }); - - it("returns a rejected promise with a reason on error", async () => { - let result: any; - try { - result = await rejectClient.getAsync("/foo", testApiVersion); - } catch (reason) { - result = reason; - } - - expect(result).toEqual(expectedReason); - }); - }); - - describe("postAsync", () => { - it("returns a fulfilled promise with a value on success", async () => { - const result = await fulfillClient.postAsync("/foo", testApiVersion, {}); - expect(result).toEqual(expectedResult); - }); - - it("returns a rejected promise with a reason on error", async () => { - let result: any; - try { - result = await rejectClient.postAsync("/foo", testApiVersion, {}); - } catch (reason) { - result = reason; - } - - expect(result).toEqual(expectedReason); - }); - }); - - describe("putAsync", () => { - it("returns a fulfilled promise with a value on success", async () => { - const result = await fulfillClient.putAsync("/foo", testApiVersion, {}); - expect(result).toEqual(expectedResult); - }); - - it("returns a rejected promise with a reason on error", async () => { - let result: any; - try { - result = await rejectClient.putAsync("/foo", testApiVersion, {}); - } catch (reason) { - result = reason; - } - - expect(result).toEqual(expectedReason); - }); - }); -}); diff --git a/src/ResourceProvider/IResourceProviderClient.ts b/src/ResourceProvider/IResourceProviderClient.ts deleted file mode 100644 index b9205be4b..000000000 --- a/src/ResourceProvider/IResourceProviderClient.ts +++ /dev/null @@ -1,30 +0,0 @@ -export interface IResourceProviderClient { - deleteAsync(url: string, apiVersion: string, requestOptions?: IResourceProviderRequestOptions): Promise; - getAsync( - url: string, - apiVersion: string, - queryString?: string, - requestOptions?: IResourceProviderRequestOptions - ): Promise; - postAsync(url: string, apiVersion: string, body: any, requestOptions?: IResourceProviderRequestOptions): Promise; - putAsync( - url: string, - apiVersion: string, - body: any, - requestOptions?: IResourceProviderRequestOptions - ): Promise; - patchAsync( - url: string, - apiVersion: string, - body: any, - requestOptions?: IResourceProviderRequestOptions - ): Promise; -} - -export interface IResourceProviderRequestOptions { - skipResourceValidation: boolean; -} - -export interface IResourceProviderClientFactory { - getOrCreate(url: string): IResourceProviderClient; -} diff --git a/src/ResourceProvider/ResourceProviderClient.ts b/src/ResourceProvider/ResourceProviderClient.ts deleted file mode 100644 index 10f3c8fae..000000000 --- a/src/ResourceProvider/ResourceProviderClient.ts +++ /dev/null @@ -1,217 +0,0 @@ -import * as ViewModels from "../Contracts/ViewModels"; -import { HttpStatusCodes } from "../Common/Constants"; -import { IResourceProviderClient, IResourceProviderRequestOptions } from "./IResourceProviderClient"; -import { OperationStatus } from "../Contracts/DataModels"; -import { TokenProviderFactory } from "../TokenProviders/TokenProviderFactory"; -import * as UrlUtility from "../Common/UrlUtility"; - -export class ResourceProviderClient implements IResourceProviderClient { - private httpClient: HttpClient; - - constructor(private armEndpoint: string) { - this.httpClient = new HttpClient(); - } - - public async getAsync( - url: string, - apiVersion: string, - queryString?: string, - requestOptions?: IResourceProviderRequestOptions - ): Promise { - let uri = `${this.armEndpoint}${url}?api-version=${apiVersion}`; - if (queryString) { - uri += `&${queryString}`; - } - return await this.httpClient.getAsync( - uri, - Object.assign({}, { skipResourceValidation: false }, requestOptions) - ); - } - - public async postAsync( - url: string, - apiVersion: string, - body: any, - requestOptions?: IResourceProviderRequestOptions - ): Promise { - const fullUrl = UrlUtility.createUri(this.armEndpoint, url); - return await this.httpClient.postAsync( - `${fullUrl}?api-version=${apiVersion}`, - body, - Object.assign({}, { skipResourceValidation: false }, requestOptions) - ); - } - - public async putAsync( - url: string, - apiVersion: string, - body: any, - requestOptions?: IResourceProviderRequestOptions - ): Promise { - const fullUrl = UrlUtility.createUri(this.armEndpoint, url); - return await this.httpClient.putAsync( - `${fullUrl}?api-version=${apiVersion}`, - body, - Object.assign({}, { skipResourceValidation: false }, requestOptions) - ); - } - - public async patchAsync( - url: string, - apiVersion: string, - body: any, - requestOptions?: IResourceProviderRequestOptions - ): Promise { - const fullUrl = UrlUtility.createUri(this.armEndpoint, url); - return await this.httpClient.patchAsync( - `${fullUrl}?api-version=${apiVersion}`, - body, - Object.assign({}, { skipResourceValidation: false }, requestOptions) - ); - } - - public async deleteAsync( - url: string, - apiVersion: string, - requestOptions?: IResourceProviderRequestOptions - ): Promise { - const fullUrl = UrlUtility.createUri(this.armEndpoint, url); - return await this.httpClient.deleteAsync( - `${fullUrl}?api-version=${apiVersion}`, - Object.assign({}, { skipResourceValidation: true }, requestOptions) - ); - } -} - -class HttpClient { - private static readonly SUCCEEDED_STATUS = "Succeeded"; - private static readonly FAILED_STATUS = "Failed"; - private static readonly CANCELED_STATUS = "Canceled"; - private static readonly AZURE_ASYNC_OPERATION_HEADER = "azure-asyncoperation"; - private static readonly RETRY_AFTER_HEADER = "Retry-After"; - private static readonly DEFAULT_THROTTLE_WAIT_TIME_SECONDS = 5; - - private tokenProvider: ViewModels.TokenProvider; - - constructor() { - this.tokenProvider = TokenProviderFactory.create(); - } - - public async getAsync(url: string, requestOptions: IResourceProviderRequestOptions): Promise { - const args: RequestInit = { method: "GET" }; - const response = await this.httpRequest(new Request(url, args), requestOptions); - return (await response.json()) as T; - } - - public async postAsync(url: string, body: any, requestOptions: IResourceProviderRequestOptions): Promise { - body = typeof body !== "string" && body !== undefined ? JSON.stringify(body) : body; - const args: RequestInit = { method: "POST", headers: { "Content-Type": "application/json" }, body }; - const response = await this.httpRequest(new Request(url, args), requestOptions); - return await response.json(); - } - - public async putAsync(url: string, body: any, requestOptions: IResourceProviderRequestOptions): Promise { - body = typeof body !== "string" && body !== undefined ? JSON.stringify(body) : body; - const args: RequestInit = { method: "PUT", headers: { "Content-Type": "application/json" }, body }; - const response = await this.httpRequest(new Request(url, args), requestOptions); - return (await response.json()) as T; - } - - public async patchAsync(url: string, body: any, requestOptions: IResourceProviderRequestOptions): Promise { - body = typeof body !== "string" && body !== undefined ? JSON.stringify(body) : body; - const args: RequestInit = { method: "PATCH", headers: { "Content-Type": "application/json" }, body }; - const response = await this.httpRequest(new Request(url, args), requestOptions); - return (await response.json()) as T; - } - - public async deleteAsync(url: string, requestOptions: IResourceProviderRequestOptions): Promise { - const args: RequestInit = { method: "DELETE" }; - await this.httpRequest(new Request(url, args), requestOptions); - return null; - } - - public async httpRequest( - request: RequestInfo, - requestOptions: IResourceProviderRequestOptions, - numRetries: number = 12 - ): Promise { - const authHeader = await this.tokenProvider.getAuthHeader(); - authHeader && - authHeader.forEach((value: string, header: string) => { - (request as Request).headers.append(header, value); - }); - const response = await fetch(request); - - if (response.status === HttpStatusCodes.Accepted) { - const operationStatusUrl: string = - response.headers && response.headers.get(HttpClient.AZURE_ASYNC_OPERATION_HEADER); - const resource = await this.pollOperationAndGetResultAsync(request, operationStatusUrl, requestOptions); - return new Response(resource && JSON.stringify(resource)); - } - - if (response.status === HttpStatusCodes.TooManyRequests && numRetries > 0) { - // retry on throttles - let waitTimeInSeconds = response.headers.has(HttpClient.RETRY_AFTER_HEADER) - ? parseInt(response.headers.get(HttpClient.RETRY_AFTER_HEADER)) - : HttpClient.DEFAULT_THROTTLE_WAIT_TIME_SECONDS; - - return new Promise((resolve: (value: Response) => void, reject: (error: any) => void) => { - setTimeout(async () => { - try { - const response = await this.httpRequest(request, requestOptions, numRetries - 1); - resolve(response); - } catch (error) { - reject(error); - throw error; - } - }, waitTimeInSeconds * 1000); - }); - } - - if (response.ok) { - // RP sometimes returns HTTP 200 for async operations instead of HTTP 202 (e.g., on PATCH operations), so we need to check - const operationStatusUrl: string = - response.headers && response.headers.get(HttpClient.AZURE_ASYNC_OPERATION_HEADER); - - if (operationStatusUrl) { - const resource = await this.pollOperationAndGetResultAsync(request, operationStatusUrl, requestOptions); - return new Response(resource && JSON.stringify(resource)); - } - - return response; - } - - return Promise.reject({ code: response.status, message: await response.text() }); - } - - private async pollOperationAndGetResultAsync( - originalRequest: RequestInfo, - operationStatusUrl: string, - requestOptions: IResourceProviderRequestOptions - ): Promise { - const getOperationResult = async (resolve: (value: T) => void, reject: (error: any) => void) => { - const operationStatus: OperationStatus = await this.getAsync(operationStatusUrl, requestOptions); - if (!operationStatus) { - return reject("Could not retrieve operation status"); - } else if (operationStatus.status === HttpClient.SUCCEEDED_STATUS) { - let result; - if (requestOptions?.skipResourceValidation === false) { - result = await this.getAsync((originalRequest as Request).url, requestOptions); - } - return resolve(result); - } else if ( - operationStatus.status === HttpClient.CANCELED_STATUS || - operationStatus.status === HttpClient.FAILED_STATUS - ) { - const errorMessage = operationStatus.error - ? JSON.stringify(operationStatus.error) - : "Operation could not be completed"; - return reject(errorMessage); - } - // TODO: add exponential backup and timeout threshold - setTimeout(getOperationResult, 1000, resolve, reject); - }; - - return new Promise(getOperationResult); - } -} diff --git a/src/ResourceProvider/ResourceProviderClientFactory.ts b/src/ResourceProvider/ResourceProviderClientFactory.ts deleted file mode 100644 index 4ecc128d1..000000000 --- a/src/ResourceProvider/ResourceProviderClientFactory.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { configContext } from "../ConfigContext"; -import { IResourceProviderClientFactory, IResourceProviderClient } from "./IResourceProviderClient"; -import { ResourceProviderClient } from "./ResourceProviderClient"; - -export class ResourceProviderClientFactory implements IResourceProviderClientFactory { - private armEndpoint: string; - private cachedClients: { [url: string]: IResourceProviderClient } = {}; - - constructor() { - this.armEndpoint = configContext.ARM_ENDPOINT; - } - - public getOrCreate(url: string): IResourceProviderClient { - if (!url) { - throw new Error("No resource provider client factory params specified"); - } - if (!this.cachedClients[url]) { - this.cachedClients[url] = new ResourceProviderClient(this.armEndpoint); - } - return this.cachedClients[url]; - } -} diff --git a/src/Utils/arm/generatedClients/cosmosNotebooks/notebookWorkspaces.ts b/src/Utils/arm/generatedClients/cosmosNotebooks/notebookWorkspaces.ts index c08e79855..a46b9aab0 100644 --- a/src/Utils/arm/generatedClients/cosmosNotebooks/notebookWorkspaces.ts +++ b/src/Utils/arm/generatedClients/cosmosNotebooks/notebookWorkspaces.ts @@ -37,11 +37,10 @@ export async function createOrUpdate( subscriptionId: string, resourceGroupName: string, accountName: string, - notebookWorkspaceName: string, - body: Types.NotebookWorkspaceCreateUpdateParameters + notebookWorkspaceName: string ): Promise { const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}`; - return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "PUT", apiVersion, body }); + return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "PUT", apiVersion, body: {} }); } /* Deletes the notebook workspace for a Cosmos DB account. */ diff --git a/src/Utils/arm/generatedClients/cosmosNotebooks/types.ts b/src/Utils/arm/generatedClients/cosmosNotebooks/types.ts index ecc745703..9704f399a 100644 --- a/src/Utils/arm/generatedClients/cosmosNotebooks/types.ts +++ b/src/Utils/arm/generatedClients/cosmosNotebooks/types.ts @@ -6,6 +6,8 @@ Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2021-04-15/notebook.json */ +import { ARMResourceProperties } from "../cosmos/types"; + /* Parameters to create a notebook workspace resource */ export type NotebookWorkspaceCreateUpdateParameters = unknown; @@ -16,7 +18,7 @@ export interface NotebookWorkspaceListResult { } /* A notebook workspace resource */ -export type NotebookWorkspace = unknown & { +export type NotebookWorkspace = ARMResourceProperties & { /* Resource properties. */ properties?: NotebookWorkspaceProperties; }; diff --git a/src/Utils/arm/request.ts b/src/Utils/arm/request.ts index 2d733cac4..e593633ac 100644 --- a/src/Utils/arm/request.ts +++ b/src/Utils/arm/request.ts @@ -144,13 +144,13 @@ async function getOperationStatus(operationStatusUrl: string) { const body = await response.json(); const status = body.status; - if (!status && response.status === 200) { - return body; - } if (status === "Canceled" || status === "Failed") { const errorMessage = body.error ? JSON.stringify(body.error) : "Operation could not be completed"; const error = new Error(errorMessage); throw new AbortError(error); } + if (response.status === 200) { + return body; + } throw new Error(`Operation Response: ${JSON.stringify(body)}. Retrying.`); } diff --git a/tsconfig.strict.json b/tsconfig.strict.json index 3693d539c..b10fa0ac6 100644 --- a/tsconfig.strict.json +++ b/tsconfig.strict.json @@ -85,7 +85,6 @@ "./src/Platform/Hosted/extractFeatures.test.ts", "./src/Platform/Hosted/extractFeatures.ts", "./src/ReactDevTools.ts", - "./src/ResourceProvider/IResourceProviderClient.ts", "./src/SelfServe/Example/SelfServeExample.types.ts", "./src/SelfServe/SelfServeStyles.tsx", "./src/SelfServe/SqlX/SqlxTypes.ts", From bcc9f8dd32938abb472b5f1ac64e2e53c1deb32a Mon Sep 17 00:00:00 2001 From: Steve Faulkner Date: Wed, 9 Jun 2021 13:11:12 -0700 Subject: [PATCH 07/42] Migrate remaining notification console methods to zustand (#873) --- src/Contracts/ViewModels.ts | 2 +- .../SettingsComponent.test.tsx.snap | 8 ----- src/Explorer/Explorer.tsx | 17 ---------- .../GraphExplorer.test.tsx | 2 +- .../GraphExplorerComponent/GraphExplorer.tsx | 2 +- .../NodePropertiesComponent.tsx | 31 ++++++++++------- .../Menus/NotificationConsole/ConsoleData.tsx | 16 +++++++++ .../NotificationConsoleComponent.test.tsx | 7 ++-- .../NotificationConsoleComponent.tsx | 31 ++++------------- ...teCollectionConfirmationPane.test.tsx.snap | 26 +++++++------- .../GitHubReposPanel.test.tsx.snap | 2 -- .../StringInputPane.test.tsx.snap | 2 -- ...eteDatabaseConfirmationPanel.test.tsx.snap | 34 +++++++++---------- src/GitHub/GitHubOAuthService.test.ts | 3 -- src/Main.tsx | 11 +----- src/Utils/NotificationConsoleUtils.ts | 26 ++++++-------- src/hooks/useNotificationConsole.ts | 11 ++++++ 17 files changed, 96 insertions(+), 135 deletions(-) create mode 100644 src/Explorer/Menus/NotificationConsole/ConsoleData.tsx diff --git a/src/Contracts/ViewModels.ts b/src/Contracts/ViewModels.ts index 38091f611..c851ea8aa 100644 --- a/src/Contracts/ViewModels.ts +++ b/src/Contracts/ViewModels.ts @@ -6,7 +6,7 @@ import { UserDefinedFunctionDefinition, } from "@azure/cosmos"; import Explorer from "../Explorer/Explorer"; -import { ConsoleData } from "../Explorer/Menus/NotificationConsole/NotificationConsoleComponent"; +import { ConsoleData } from "../Explorer/Menus/NotificationConsole/ConsoleData"; import { CassandraTableKey, CassandraTableKeys } from "../Explorer/Tables/TableDataClient"; import ConflictId from "../Explorer/Tree/ConflictId"; import DocumentId from "../Explorer/Tree/DocumentId"; diff --git a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap index 3451ec734..18c2e4c7c 100644 --- a/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap +++ b/src/Explorer/Controls/Settings/__snapshots__/SettingsComponent.test.tsx.snap @@ -71,8 +71,6 @@ exports[`SettingsComponent renders 1`] = ` }, "selectedDatabaseId": [Function], "selectedNode": [Function], - "setInProgressConsoleDataIdToBeDeleted": undefined, - "setNotificationConsoleData": undefined, "sparkClusterConnectionInfo": [Function], "tabsManager": TabsManager { "activeTab": [Function], @@ -142,8 +140,6 @@ exports[`SettingsComponent renders 1`] = ` }, "selectedDatabaseId": [Function], "selectedNode": [Function], - "setInProgressConsoleDataIdToBeDeleted": undefined, - "setNotificationConsoleData": undefined, "sparkClusterConnectionInfo": [Function], "tabsManager": TabsManager { "activeTab": [Function], @@ -226,8 +222,6 @@ exports[`SettingsComponent renders 1`] = ` }, "selectedDatabaseId": [Function], "selectedNode": [Function], - "setInProgressConsoleDataIdToBeDeleted": undefined, - "setNotificationConsoleData": undefined, "sparkClusterConnectionInfo": [Function], "tabsManager": TabsManager { "activeTab": [Function], @@ -297,8 +291,6 @@ exports[`SettingsComponent renders 1`] = ` }, "selectedDatabaseId": [Function], "selectedNode": [Function], - "setInProgressConsoleDataIdToBeDeleted": undefined, - "setNotificationConsoleData": undefined, "sparkClusterConnectionInfo": [Function], "tabsManager": TabsManager { "activeTab": [Function], diff --git a/src/Explorer/Explorer.tsx b/src/Explorer/Explorer.tsx index 52535b3c5..b1999e7fa 100644 --- a/src/Explorer/Explorer.tsx +++ b/src/Explorer/Explorer.tsx @@ -41,7 +41,6 @@ import * as ComponentRegisterer from "./ComponentRegisterer"; import { DialogProps, TextFieldProps, useDialog } from "./Controls/Dialog"; import { GalleryTab as GalleryTabKind } from "./Controls/NotebookGallery/GalleryViewerComponent"; import { useCommandBar } from "./Menus/CommandBar/CommandBarComponentAdapter"; -import { ConsoleData } from "./Menus/NotificationConsole/NotificationConsoleComponent"; import * as FileSystemUtil from "./Notebook/FileSystemUtil"; import { SnapshotRequest } from "./Notebook/NotebookComponent/types"; import { NotebookContentItem, NotebookContentItemType } from "./Notebook/NotebookContentItem"; @@ -83,8 +82,6 @@ BindingHandlersRegisterer.registerBindingHandlers(); var tmp = ComponentRegisterer; export interface ExplorerParams { - setNotificationConsoleData: (consoleData: ConsoleData) => void; - setInProgressConsoleDataIdToBeDeleted: (id: string) => void; tabsManager: TabsManager; } @@ -96,9 +93,6 @@ export default class Explorer { public queriesClient: QueriesClient; public tableDataClient: TableDataClient; - private setNotificationConsoleData: (consoleData: ConsoleData) => void; - private setInProgressConsoleDataIdToBeDeleted: (id: string) => void; - // Resource Tree public databases: ko.ObservableArray; public selectedDatabaseId: ko.Computed; @@ -145,9 +139,6 @@ export default class Explorer { private static readonly MaxNbDatabasesToAutoExpand = 5; constructor(params?: ExplorerParams) { - this.setNotificationConsoleData = params?.setNotificationConsoleData; - this.setInProgressConsoleDataIdToBeDeleted = params?.setInProgressConsoleDataIdToBeDeleted; - const startKey: number = TelemetryProcessor.traceStart(Action.InitializeDataExplorer, { dataExplorerArea: Constants.Areas.ResourceTree, }); @@ -444,14 +435,6 @@ export default class Explorer { return this.selectedNode() == null; } - public logConsoleData(consoleData: ConsoleData): void { - this.setNotificationConsoleData(consoleData); - } - - public deleteInProgressConsoleDataWithId(id: string): void { - this.setInProgressConsoleDataIdToBeDeleted(id); - } - public refreshDatabaseForResourceToken(): Q.Promise { const databaseId = this.resourceTokenDatabaseId(); const collectionId = this.resourceTokenCollectionId(); diff --git a/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.test.tsx b/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.test.tsx index 1954186c8..6ce0a11bf 100644 --- a/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.test.tsx +++ b/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.test.tsx @@ -10,7 +10,7 @@ import { queryDocumentsPage } from "../../../Common/dataAccess/queryDocumentsPag import * as DataModels from "../../../Contracts/DataModels"; import * as StorageUtility from "../../../Shared/StorageUtility"; import { TabComponent } from "../../Controls/Tabs/TabComponent"; -import { ConsoleDataType } from "../../Menus/NotificationConsole/NotificationConsoleComponent"; +import { ConsoleDataType } from "../../Menus/NotificationConsole/ConsoleData"; import GraphTab from "../../Tabs/GraphTab"; import * as D3ForceGraph from "./D3ForceGraph"; import { GraphData } from "./GraphData"; diff --git a/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.tsx b/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.tsx index 5b2441e40..cf2fbbb3a 100644 --- a/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.tsx +++ b/src/Explorer/Graph/GraphExplorerComponent/GraphExplorer.tsx @@ -18,7 +18,7 @@ import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../../Ut import { EditorReact } from "../../Controls/Editor/EditorReact"; import * as InputTypeaheadComponent from "../../Controls/InputTypeahead/InputTypeaheadComponent"; import * as TabComponent from "../../Controls/Tabs/TabComponent"; -import { ConsoleDataType } from "../../Menus/NotificationConsole/NotificationConsoleComponent"; +import { ConsoleDataType } from "../../Menus/NotificationConsole/ConsoleData"; import { IGraphConfig } from "../../Tabs/GraphTab"; import { ArraysByKeyCache } from "./ArraysByKeyCache"; import * as D3ForceGraph from "./D3ForceGraph"; diff --git a/src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.tsx b/src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.tsx index e308d7ece..3314bf9eb 100644 --- a/src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.tsx +++ b/src/Explorer/Graph/GraphExplorerComponent/NodePropertiesComponent.tsx @@ -5,21 +5,26 @@ */ import * as React from "react"; -import { GraphHighlightedNodeData, EditedProperties, EditedEdges, PossibleVertex } from "./GraphExplorer"; -import { CollapsiblePanel } from "../../Controls/CollapsiblePanel/CollapsiblePanel"; -import { ReadOnlyNodePropertiesComponent } from "./ReadOnlyNodePropertiesComponent"; -import { EditorNodePropertiesComponent } from "./EditorNodePropertiesComponent"; -import { ReadOnlyNeighborsComponent } from "./ReadOnlyNeighborsComponent"; -import * as ViewModels from "../../../Contracts/ViewModels"; -import { Item } from "../../Controls/InputTypeahead/InputTypeaheadComponent"; -import * as EditorNeighbors from "./EditorNeighborsComponent"; -import EditIcon from "../../../../images/edit.svg"; -import DeleteIcon from "../../../../images/delete.svg"; -import CheckIcon from "../../../../images/check.svg"; import CancelIcon from "../../../../images/cancel.svg"; -import { GraphExplorer } from "./GraphExplorer"; -import { ConsoleDataType } from "../../Menus/NotificationConsole/NotificationConsoleComponent"; +import CheckIcon from "../../../../images/check.svg"; +import DeleteIcon from "../../../../images/delete.svg"; +import EditIcon from "../../../../images/edit.svg"; +import * as ViewModels from "../../../Contracts/ViewModels"; import { AccessibleElement } from "../../Controls/AccessibleElement/AccessibleElement"; +import { CollapsiblePanel } from "../../Controls/CollapsiblePanel/CollapsiblePanel"; +import { Item } from "../../Controls/InputTypeahead/InputTypeaheadComponent"; +import { ConsoleDataType } from "../../Menus/NotificationConsole/ConsoleData"; +import * as EditorNeighbors from "./EditorNeighborsComponent"; +import { EditorNodePropertiesComponent } from "./EditorNodePropertiesComponent"; +import { + EditedEdges, + EditedProperties, + GraphExplorer, + GraphHighlightedNodeData, + PossibleVertex, +} from "./GraphExplorer"; +import { ReadOnlyNeighborsComponent } from "./ReadOnlyNeighborsComponent"; +import { ReadOnlyNodePropertiesComponent } from "./ReadOnlyNodePropertiesComponent"; export enum Mode { READONLY_PROP, diff --git a/src/Explorer/Menus/NotificationConsole/ConsoleData.tsx b/src/Explorer/Menus/NotificationConsole/ConsoleData.tsx new file mode 100644 index 000000000..2ede2f003 --- /dev/null +++ b/src/Explorer/Menus/NotificationConsole/ConsoleData.tsx @@ -0,0 +1,16 @@ +/** + * Interface for the data/content that will be recorded + */ + +export interface ConsoleData { + type: ConsoleDataType; + date: string; + message: string; + id?: string; +} + +export enum ConsoleDataType { + Info = 0, + Error = 1, + InProgress = 2, +} diff --git a/src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.test.tsx b/src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.test.tsx index 05df0f46f..711e0db35 100644 --- a/src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.test.tsx +++ b/src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.test.tsx @@ -1,10 +1,7 @@ import { shallow } from "enzyme"; import React from "react"; -import { - ConsoleDataType, - NotificationConsoleComponent, - NotificationConsoleComponentProps, -} from "./NotificationConsoleComponent"; +import { ConsoleDataType } from "./ConsoleData"; +import { NotificationConsoleComponent, NotificationConsoleComponentProps } from "./NotificationConsoleComponent"; describe("NotificationConsoleComponent", () => { const createBlankProps = (): NotificationConsoleComponentProps => { diff --git a/src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.tsx b/src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.tsx index 218bd4893..c715159ca 100644 --- a/src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.tsx +++ b/src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.tsx @@ -17,25 +17,7 @@ import ChevronUpIcon from "../../../../images/QueryBuilder/CollapseChevronUp_16x import { ClientDefaults, KeyCodes } from "../../../Common/Constants"; import { useNotificationConsole } from "../../../hooks/useNotificationConsole"; import { userContext } from "../../../UserContext"; - -/** - * Log levels - */ -export enum ConsoleDataType { - Info = 0, - Error = 1, - InProgress = 2, -} - -/** - * Interface for the data/content that will be recorded - */ -export interface ConsoleData { - type: ConsoleDataType; - date: string; - message: string; - id?: string; -} +import { ConsoleData, ConsoleDataType } from "./ConsoleData"; export interface NotificationConsoleComponentProps { isConsoleExpanded: boolean; @@ -323,14 +305,13 @@ const PrPreview = (props: { pr: string }) => { ); }; -export const NotificationConsole: React.FC< - Pick -> = ({ - consoleData, - inProgressConsoleDataIdToBeDeleted, -}: Pick) => { +export const NotificationConsole: React.FC = () => { const setIsExpanded = useNotificationConsole((state) => state.setIsExpanded); const isExpanded = useNotificationConsole((state) => state.isExpanded); + const consoleData = useNotificationConsole((state) => state.consoleData); + const inProgressConsoleDataIdToBeDeleted = useNotificationConsole( + (state) => state.inProgressConsoleDataIdToBeDeleted + ); // TODO Refactor NotificationConsoleComponent into a functional component and remove this wrapper // This component only exists so we can use hooks and pass them down to a non-functional component return ( diff --git a/src/Explorer/Panes/DeleteCollectionConfirmationPane/__snapshots__/DeleteCollectionConfirmationPane.test.tsx.snap b/src/Explorer/Panes/DeleteCollectionConfirmationPane/__snapshots__/DeleteCollectionConfirmationPane.test.tsx.snap index 5032adad2..59e62296b 100644 --- a/src/Explorer/Panes/DeleteCollectionConfirmationPane/__snapshots__/DeleteCollectionConfirmationPane.test.tsx.snap +++ b/src/Explorer/Panes/DeleteCollectionConfirmationPane/__snapshots__/DeleteCollectionConfirmationPane.test.tsx.snap @@ -43,7 +43,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect variant="small" > Confirm by typing the container @@ -347,18 +347,18 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect value="" >
Help us improve Azure Cosmos DB! @@ -391,7 +391,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect variant="small" > What is the reason why you are deleting this container @@ -697,17 +697,17 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect value="" >