Move selectedNode to zustand (#903)
This commit is contained in:
parent
a7239c7579
commit
4d2a6999d4
|
@ -89,7 +89,6 @@ export interface Database extends TreeNode {
|
||||||
|
|
||||||
selectedSubnodeKind: ko.Observable<CollectionTabKind>;
|
selectedSubnodeKind: ko.Observable<CollectionTabKind>;
|
||||||
|
|
||||||
selectDatabase(): void;
|
|
||||||
expandDatabase(): Promise<void>;
|
expandDatabase(): Promise<void>;
|
||||||
collapseDatabase(): void;
|
collapseDatabase(): void;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { DeleteDatabaseConfirmationPanel } from "./Panes/DeleteDatabaseConfirmat
|
||||||
import StoredProcedure from "./Tree/StoredProcedure";
|
import StoredProcedure from "./Tree/StoredProcedure";
|
||||||
import Trigger from "./Tree/Trigger";
|
import Trigger from "./Tree/Trigger";
|
||||||
import UserDefinedFunction from "./Tree/UserDefinedFunction";
|
import UserDefinedFunction from "./Tree/UserDefinedFunction";
|
||||||
|
import { useSelectedNode } from "./useSelectedNode";
|
||||||
|
|
||||||
export interface CollectionContextMenuButtonParams {
|
export interface CollectionContextMenuButtonParams {
|
||||||
databaseId: string;
|
databaseId: string;
|
||||||
|
@ -48,10 +49,7 @@ export const createDatabaseContextMenu = (container: Explorer, databaseId: strin
|
||||||
onClick: () =>
|
onClick: () =>
|
||||||
useSidePanel
|
useSidePanel
|
||||||
.getState()
|
.getState()
|
||||||
.openSidePanel(
|
.openSidePanel("Delete " + getDatabaseName(), <DeleteDatabaseConfirmationPanel explorer={container} />),
|
||||||
"Delete " + getDatabaseName(),
|
|
||||||
<DeleteDatabaseConfirmationPanel explorer={container} selectedDatabase={container.findSelectedDatabase()} />
|
|
||||||
),
|
|
||||||
label: `Delete ${getDatabaseName()}`,
|
label: `Delete ${getDatabaseName()}`,
|
||||||
styleClass: "deleteDatabaseMenuItem",
|
styleClass: "deleteDatabaseMenuItem",
|
||||||
});
|
});
|
||||||
|
@ -82,7 +80,7 @@ export const createCollectionContextMenuButton = (
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: HostedTerminalIcon,
|
iconSrc: HostedTerminalIcon,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||||
if (container.isShellEnabled()) {
|
if (container.isShellEnabled()) {
|
||||||
container.openNotebookTerminal(ViewModels.TerminalKind.Mongo);
|
container.openNotebookTerminal(ViewModels.TerminalKind.Mongo);
|
||||||
} else {
|
} else {
|
||||||
|
@ -97,7 +95,7 @@ export const createCollectionContextMenuButton = (
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: AddStoredProcedureIcon,
|
iconSrc: AddStoredProcedureIcon,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||||
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection, undefined);
|
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection, undefined);
|
||||||
},
|
},
|
||||||
label: "New Stored Procedure",
|
label: "New Stored Procedure",
|
||||||
|
@ -106,7 +104,7 @@ export const createCollectionContextMenuButton = (
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: AddUdfIcon,
|
iconSrc: AddUdfIcon,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||||
selectedCollection && selectedCollection.onNewUserDefinedFunctionClick(selectedCollection, undefined);
|
selectedCollection && selectedCollection.onNewUserDefinedFunctionClick(selectedCollection, undefined);
|
||||||
},
|
},
|
||||||
label: "New UDF",
|
label: "New UDF",
|
||||||
|
@ -115,7 +113,7 @@ export const createCollectionContextMenuButton = (
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: AddTriggerIcon,
|
iconSrc: AddTriggerIcon,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||||
selectedCollection && selectedCollection.onNewTriggerClick(selectedCollection, undefined);
|
selectedCollection && selectedCollection.onNewTriggerClick(selectedCollection, undefined);
|
||||||
},
|
},
|
||||||
label: "New Trigger",
|
label: "New Trigger",
|
||||||
|
|
|
@ -126,7 +126,6 @@ describe("SettingsComponent", () => {
|
||||||
isDatabaseExpanded: undefined,
|
isDatabaseExpanded: undefined,
|
||||||
isDatabaseShared: ko.computed(() => true),
|
isDatabaseShared: ko.computed(() => true),
|
||||||
selectedSubnodeKind: undefined,
|
selectedSubnodeKind: undefined,
|
||||||
selectDatabase: undefined,
|
|
||||||
expandDatabase: undefined,
|
expandDatabase: undefined,
|
||||||
collapseDatabase: undefined,
|
collapseDatabase: undefined,
|
||||||
loadCollections: undefined,
|
loadCollections: undefined,
|
||||||
|
|
|
@ -36,7 +36,6 @@ describe("SettingsUtils", () => {
|
||||||
isDatabaseExpanded: ko.observable(false),
|
isDatabaseExpanded: ko.observable(false),
|
||||||
isDatabaseShared: ko.computed(() => true),
|
isDatabaseShared: ko.computed(() => true),
|
||||||
selectedSubnodeKind: ko.observable(undefined),
|
selectedSubnodeKind: ko.observable(undefined),
|
||||||
selectDatabase: undefined,
|
|
||||||
expandDatabase: undefined,
|
expandDatabase: undefined,
|
||||||
collapseDatabase: undefined,
|
collapseDatabase: undefined,
|
||||||
loadCollections: undefined,
|
loadCollections: undefined,
|
||||||
|
|
|
@ -34,7 +34,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||||
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
||||||
"isNotebookEnabled": [Function],
|
"isNotebookEnabled": [Function],
|
||||||
"isNotebooksEnabledForAccount": [Function],
|
"isNotebooksEnabledForAccount": [Function],
|
||||||
"isResourceTokenCollectionNodeSelected": [Function],
|
|
||||||
"isSchemaEnabled": [Function],
|
"isSchemaEnabled": [Function],
|
||||||
"isShellEnabled": [Function],
|
"isShellEnabled": [Function],
|
||||||
"isSynapseLinkUpdating": [Function],
|
"isSynapseLinkUpdating": [Function],
|
||||||
|
@ -59,8 +58,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
"parameters": [Function],
|
"parameters": [Function],
|
||||||
},
|
},
|
||||||
"selectedDatabaseId": [Function],
|
|
||||||
"selectedNode": [Function],
|
|
||||||
"sparkClusterConnectionInfo": [Function],
|
"sparkClusterConnectionInfo": [Function],
|
||||||
"tabsManager": TabsManager {
|
"tabsManager": TabsManager {
|
||||||
"activeTab": [Function],
|
"activeTab": [Function],
|
||||||
|
@ -123,7 +120,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||||
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
||||||
"isNotebookEnabled": [Function],
|
"isNotebookEnabled": [Function],
|
||||||
"isNotebooksEnabledForAccount": [Function],
|
"isNotebooksEnabledForAccount": [Function],
|
||||||
"isResourceTokenCollectionNodeSelected": [Function],
|
|
||||||
"isSchemaEnabled": [Function],
|
"isSchemaEnabled": [Function],
|
||||||
"isShellEnabled": [Function],
|
"isShellEnabled": [Function],
|
||||||
"isSynapseLinkUpdating": [Function],
|
"isSynapseLinkUpdating": [Function],
|
||||||
|
@ -148,8 +144,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
"parameters": [Function],
|
"parameters": [Function],
|
||||||
},
|
},
|
||||||
"selectedDatabaseId": [Function],
|
|
||||||
"selectedNode": [Function],
|
|
||||||
"sparkClusterConnectionInfo": [Function],
|
"sparkClusterConnectionInfo": [Function],
|
||||||
"tabsManager": TabsManager {
|
"tabsManager": TabsManager {
|
||||||
"activeTab": [Function],
|
"activeTab": [Function],
|
||||||
|
|
|
@ -67,6 +67,7 @@ import { ResourceTreeAdapter } from "./Tree/ResourceTreeAdapter";
|
||||||
import { ResourceTreeAdapterForResourceToken } from "./Tree/ResourceTreeAdapterForResourceToken";
|
import { ResourceTreeAdapterForResourceToken } from "./Tree/ResourceTreeAdapterForResourceToken";
|
||||||
import StoredProcedure from "./Tree/StoredProcedure";
|
import StoredProcedure from "./Tree/StoredProcedure";
|
||||||
import { useDatabases } from "./useDatabases";
|
import { useDatabases } from "./useDatabases";
|
||||||
|
import { useSelectedNode } from "./useSelectedNode";
|
||||||
|
|
||||||
BindingHandlersRegisterer.registerBindingHandlers();
|
BindingHandlersRegisterer.registerBindingHandlers();
|
||||||
// Hold a reference to ComponentRegisterer to prevent transpiler to ignore import
|
// Hold a reference to ComponentRegisterer to prevent transpiler to ignore import
|
||||||
|
@ -83,14 +84,10 @@ export default class Explorer {
|
||||||
public tableDataClient: TableDataClient;
|
public tableDataClient: TableDataClient;
|
||||||
|
|
||||||
// Resource Tree
|
// Resource Tree
|
||||||
public selectedDatabaseId: ko.Computed<string>;
|
|
||||||
public selectedCollectionId: ko.Computed<string>;
|
|
||||||
public selectedNode: ko.Observable<ViewModels.TreeNode>;
|
|
||||||
private resourceTree: ResourceTreeAdapter;
|
private resourceTree: ResourceTreeAdapter;
|
||||||
|
|
||||||
// Resource Token
|
// Resource Token
|
||||||
public resourceTokenCollection: ko.Observable<ViewModels.CollectionBase>;
|
public resourceTokenCollection: ko.Observable<ViewModels.CollectionBase>;
|
||||||
public isResourceTokenCollectionNodeSelected: ko.Computed<boolean>;
|
|
||||||
public resourceTreeForResourceToken: ResourceTreeAdapterForResourceToken;
|
public resourceTreeForResourceToken: ResourceTreeAdapterForResourceToken;
|
||||||
|
|
||||||
// Tabs
|
// Tabs
|
||||||
|
@ -163,18 +160,10 @@ export default class Explorer {
|
||||||
this.resourceTokenCollection = ko.observable<ViewModels.CollectionBase>();
|
this.resourceTokenCollection = ko.observable<ViewModels.CollectionBase>();
|
||||||
this.isSchemaEnabled = ko.computed<boolean>(() => userContext.features.enableSchema);
|
this.isSchemaEnabled = ko.computed<boolean>(() => userContext.features.enableSchema);
|
||||||
|
|
||||||
this.selectedNode = ko.observable<ViewModels.TreeNode>();
|
useSelectedNode.subscribe(() => {
|
||||||
this.selectedNode.subscribe((nodeSelected: ViewModels.TreeNode) => {
|
|
||||||
// Make sure switching tabs restores tabs display
|
// Make sure switching tabs restores tabs display
|
||||||
this.isTabsContentExpanded(false);
|
this.isTabsContentExpanded(false);
|
||||||
});
|
});
|
||||||
this.isResourceTokenCollectionNodeSelected = ko.computed<boolean>(() => {
|
|
||||||
return (
|
|
||||||
this.selectedNode() &&
|
|
||||||
this.resourceTokenCollection() &&
|
|
||||||
this.selectedNode().id() === this.resourceTokenCollection().id()
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.isFixedCollectionWithSharedThroughputSupported = ko.computed(() => {
|
this.isFixedCollectionWithSharedThroughputSupported = ko.computed(() => {
|
||||||
if (userContext.features.enableFixedCollectionWithSharedThroughput) {
|
if (userContext.features.enableFixedCollectionWithSharedThroughput) {
|
||||||
|
@ -187,31 +176,11 @@ export default class Explorer {
|
||||||
|
|
||||||
return isCapabilityEnabled("EnableMongo");
|
return isCapabilityEnabled("EnableMongo");
|
||||||
});
|
});
|
||||||
this.selectedDatabaseId = ko.computed<string>(() => {
|
|
||||||
const selectedNode = this.selectedNode();
|
|
||||||
if (!selectedNode) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (selectedNode.nodeKind) {
|
|
||||||
case "Collection":
|
|
||||||
return (selectedNode as ViewModels.CollectionBase).databaseId || "";
|
|
||||||
case "Database":
|
|
||||||
return selectedNode.id() || "";
|
|
||||||
case "DocumentId":
|
|
||||||
case "StoredProcedure":
|
|
||||||
case "Trigger":
|
|
||||||
case "UserDefinedFunction":
|
|
||||||
return selectedNode.collection.databaseId || "";
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.tabsManager = params?.tabsManager ?? new TabsManager();
|
this.tabsManager = params?.tabsManager ?? new TabsManager();
|
||||||
this.tabsManager.openedTabs.subscribe((tabs) => {
|
this.tabsManager.openedTabs.subscribe((tabs) => {
|
||||||
if (tabs.length === 0) {
|
if (tabs.length === 0) {
|
||||||
this.selectedNode(undefined);
|
useSelectedNode.getState().setSelectedNode(undefined);
|
||||||
useCommandBar.getState().setContextButtons([]);
|
useCommandBar.getState().setContextButtons([]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -363,22 +332,6 @@ export default class Explorer {
|
||||||
// TODO: return result
|
// TODO: return result
|
||||||
}
|
}
|
||||||
|
|
||||||
public isDatabaseNodeOrNoneSelected(): boolean {
|
|
||||||
return this.isNoneSelected() || this.isDatabaseNodeSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
public isDatabaseNodeSelected(): boolean {
|
|
||||||
return (this.selectedNode() && this.selectedNode().nodeKind === "Database") || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isNodeKindSelected(nodeKind: string): boolean {
|
|
||||||
return (this.selectedNode() && this.selectedNode().nodeKind === nodeKind) || false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isNoneSelected(): boolean {
|
|
||||||
return this.selectedNode() == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public refreshDatabaseForResourceToken(): Promise<void> {
|
public refreshDatabaseForResourceToken(): Promise<void> {
|
||||||
const databaseId = userContext.parsedResourceToken?.databaseId;
|
const databaseId = userContext.parsedResourceToken?.databaseId;
|
||||||
const collectionId = userContext.parsedResourceToken?.collectionId;
|
const collectionId = userContext.parsedResourceToken?.collectionId;
|
||||||
|
@ -388,7 +341,7 @@ export default class Explorer {
|
||||||
|
|
||||||
return readCollection(databaseId, collectionId).then((collection: DataModels.Collection) => {
|
return readCollection(databaseId, collectionId).then((collection: DataModels.Collection) => {
|
||||||
this.resourceTokenCollection(new ResourceTokenCollection(this, databaseId, collection));
|
this.resourceTokenCollection(new ResourceTokenCollection(this, databaseId, collection));
|
||||||
this.selectedNode(this.resourceTokenCollection());
|
useSelectedNode.getState().setSelectedNode(this.resourceTokenCollection());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,11 +367,9 @@ export default class Explorer {
|
||||||
},
|
},
|
||||||
startKey
|
startKey
|
||||||
);
|
);
|
||||||
const currentlySelectedNode: ViewModels.TreeNode = this.selectedNode();
|
|
||||||
const deltaDatabases = this.getDeltaDatabases(databases);
|
const deltaDatabases = this.getDeltaDatabases(databases);
|
||||||
this.addDatabasesToList(deltaDatabases.toAdd);
|
this.addDatabasesToList(deltaDatabases.toAdd);
|
||||||
this.deleteDatabasesFromList(deltaDatabases.toDelete);
|
this.deleteDatabasesFromList(deltaDatabases.toDelete);
|
||||||
this.selectedNode(currentlySelectedNode);
|
|
||||||
this.refreshAndExpandNewDatabases(deltaDatabases.toAdd).then(
|
this.refreshAndExpandNewDatabases(deltaDatabases.toAdd).then(
|
||||||
() => {
|
() => {
|
||||||
deferred.resolve();
|
deferred.resolve();
|
||||||
|
@ -611,34 +562,6 @@ export default class Explorer {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public findSelectedDatabase(): ViewModels.Database {
|
|
||||||
if (!this.selectedNode()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (this.selectedNode().nodeKind === "Database") {
|
|
||||||
return _.find(
|
|
||||||
useDatabases.getState().databases,
|
|
||||||
(database: ViewModels.Database) => database.id() === this.selectedNode().id()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return this.findSelectedCollection().database;
|
|
||||||
}
|
|
||||||
|
|
||||||
public isSelectedDatabaseShared(): boolean {
|
|
||||||
const database = this.findSelectedDatabase();
|
|
||||||
if (!!database) {
|
|
||||||
return database.offer && !!database.offer();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public findSelectedCollection(): ViewModels.Collection {
|
|
||||||
return (this.selectedNode().nodeKind === "Collection"
|
|
||||||
? this.selectedNode()
|
|
||||||
: this.selectedNode().collection) as ViewModels.Collection;
|
|
||||||
}
|
|
||||||
|
|
||||||
private refreshAndExpandNewDatabases(newDatabases: ViewModels.Database[]): Q.Promise<void> {
|
private refreshAndExpandNewDatabases(newDatabases: ViewModels.Database[]): Q.Promise<void> {
|
||||||
// we reload collections for all databases so the resource tree reflects any collection-level changes
|
// we reload collections for all databases so the resource tree reflects any collection-level changes
|
||||||
// i.e addition of stored procedures, etc.
|
// i.e addition of stored procedures, etc.
|
||||||
|
@ -1331,7 +1254,7 @@ export default class Explorer {
|
||||||
}
|
}
|
||||||
|
|
||||||
public openUploadItemsPanePane(): void {
|
public openUploadItemsPanePane(): void {
|
||||||
useSidePanel.getState().openSidePanel("Upload " + getUploadName(), <UploadItemsPane explorer={this} />);
|
useSidePanel.getState().openSidePanel("Upload " + getUploadName(), <UploadItemsPane />);
|
||||||
}
|
}
|
||||||
public openExecuteSprocParamsPanel(storedProcedure: StoredProcedure): void {
|
public openExecuteSprocParamsPanel(storedProcedure: StoredProcedure): void {
|
||||||
useSidePanel
|
useSidePanel
|
||||||
|
|
|
@ -8,9 +8,9 @@ import * as React from "react";
|
||||||
import create, { UseStore } from "zustand";
|
import create, { UseStore } from "zustand";
|
||||||
import { StyleConstants } from "../../../Common/Constants";
|
import { StyleConstants } from "../../../Common/Constants";
|
||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
import { useObservable } from "../../../hooks/useObservable";
|
|
||||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
|
import { useSelectedNode } from "../../useSelectedNode";
|
||||||
import * as CommandBarComponentButtonFactory from "./CommandBarComponentButtonFactory";
|
import * as CommandBarComponentButtonFactory from "./CommandBarComponentButtonFactory";
|
||||||
import * as CommandBarUtil from "./CommandBarUtil";
|
import * as CommandBarUtil from "./CommandBarUtil";
|
||||||
|
|
||||||
|
@ -29,13 +29,13 @@ export const useCommandBar: UseStore<CommandBarStore> = create((set) => ({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const CommandBar: React.FC<Props> = ({ container }: Props) => {
|
export const CommandBar: React.FC<Props> = ({ container }: Props) => {
|
||||||
useObservable(container.selectedNode);
|
const selectedNodeState = useSelectedNode();
|
||||||
const buttons = useCommandBar((state) => state.contextButtons);
|
const buttons = useCommandBar((state) => state.contextButtons);
|
||||||
const backgroundColor = StyleConstants.BaseLight;
|
const backgroundColor = StyleConstants.BaseLight;
|
||||||
|
|
||||||
const staticButtons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(container);
|
const staticButtons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(container, selectedNodeState);
|
||||||
const contextButtons = (buttons || []).concat(
|
const contextButtons = (buttons || []).concat(
|
||||||
CommandBarComponentButtonFactory.createContextCommandBarButtons(container)
|
CommandBarComponentButtonFactory.createContextCommandBarButtons(container, selectedNodeState)
|
||||||
);
|
);
|
||||||
const controlButtons = CommandBarComponentButtonFactory.createControlCommandBarButtons(container);
|
const controlButtons = CommandBarComponentButtonFactory.createControlCommandBarButtons(container);
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,22 @@
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import { AuthType } from "../../../AuthType";
|
import { AuthType } from "../../../AuthType";
|
||||||
import { DatabaseAccount } from "../../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../../Contracts/DataModels";
|
||||||
|
import { CollectionBase } from "../../../Contracts/ViewModels";
|
||||||
import { GitHubOAuthService } from "../../../GitHub/GitHubOAuthService";
|
import { GitHubOAuthService } from "../../../GitHub/GitHubOAuthService";
|
||||||
import { updateUserContext } from "../../../UserContext";
|
import { updateUserContext } from "../../../UserContext";
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
import NotebookManager from "../../Notebook/NotebookManager";
|
import NotebookManager from "../../Notebook/NotebookManager";
|
||||||
|
import { useSelectedNode } from "../../useSelectedNode";
|
||||||
import * as CommandBarComponentButtonFactory from "./CommandBarComponentButtonFactory";
|
import * as CommandBarComponentButtonFactory from "./CommandBarComponentButtonFactory";
|
||||||
|
|
||||||
describe("CommandBarComponentButtonFactory tests", () => {
|
describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
let mockExplorer: Explorer;
|
let mockExplorer: Explorer;
|
||||||
|
|
||||||
|
afterEach(() => useSelectedNode.getState().setSelectedNode(undefined));
|
||||||
|
|
||||||
describe("Enable Azure Synapse Link Button", () => {
|
describe("Enable Azure Synapse Link Button", () => {
|
||||||
const enableAzureSynapseLinkBtnLabel = "Enable Azure Synapse Link";
|
const enableAzureSynapseLinkBtnLabel = "Enable Azure Synapse Link";
|
||||||
|
const selectedNodeState = useSelectedNode.getState();
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
mockExplorer = {} as Explorer;
|
mockExplorer = {} as Explorer;
|
||||||
|
@ -23,14 +28,12 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
});
|
});
|
||||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||||
|
|
||||||
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
|
|
||||||
mockExplorer.isNotebookEnabled = ko.observable(false);
|
mockExplorer.isNotebookEnabled = ko.observable(false);
|
||||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
|
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Account is not serverless - button should be visible", () => {
|
it("Account is not serverless - button should be visible", () => {
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const enableAzureSynapseLinkBtn = buttons.find(
|
const enableAzureSynapseLinkBtn = buttons.find(
|
||||||
(button) => button.commandButtonLabel === enableAzureSynapseLinkBtnLabel
|
(button) => button.commandButtonLabel === enableAzureSynapseLinkBtnLabel
|
||||||
);
|
);
|
||||||
|
@ -45,7 +48,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
},
|
},
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
});
|
});
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const enableAzureSynapseLinkBtn = buttons.find(
|
const enableAzureSynapseLinkBtn = buttons.find(
|
||||||
(button) => button.commandButtonLabel === enableAzureSynapseLinkBtnLabel
|
(button) => button.commandButtonLabel === enableAzureSynapseLinkBtnLabel
|
||||||
);
|
);
|
||||||
|
@ -55,6 +58,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
|
|
||||||
describe("Enable notebook button", () => {
|
describe("Enable notebook button", () => {
|
||||||
const enableNotebookBtnLabel = "Enable Notebooks (Preview)";
|
const enableNotebookBtnLabel = "Enable Notebooks (Preview)";
|
||||||
|
const selectedNodeState = useSelectedNode.getState();
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
mockExplorer = {} as Explorer;
|
mockExplorer = {} as Explorer;
|
||||||
|
@ -67,9 +71,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
});
|
});
|
||||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
|
||||||
|
|
||||||
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
@ -82,7 +83,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
mockExplorer.isNotebookEnabled = ko.observable(true);
|
mockExplorer.isNotebookEnabled = ko.observable(true);
|
||||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const enableNotebookBtn = buttons.find((button) => button.commandButtonLabel === enableNotebookBtnLabel);
|
const enableNotebookBtn = buttons.find((button) => button.commandButtonLabel === enableNotebookBtnLabel);
|
||||||
expect(enableNotebookBtn).toBeUndefined();
|
expect(enableNotebookBtn).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
@ -94,7 +95,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
portalEnv: "mooncake",
|
portalEnv: "mooncake",
|
||||||
});
|
});
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const enableNotebookBtn = buttons.find((button) => button.commandButtonLabel === enableNotebookBtnLabel);
|
const enableNotebookBtn = buttons.find((button) => button.commandButtonLabel === enableNotebookBtnLabel);
|
||||||
expect(enableNotebookBtn).toBeUndefined();
|
expect(enableNotebookBtn).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
@ -103,7 +104,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
mockExplorer.isNotebookEnabled = ko.observable(false);
|
mockExplorer.isNotebookEnabled = ko.observable(false);
|
||||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const enableNotebookBtn = buttons.find((button) => button.commandButtonLabel === enableNotebookBtnLabel);
|
const enableNotebookBtn = buttons.find((button) => button.commandButtonLabel === enableNotebookBtnLabel);
|
||||||
expect(enableNotebookBtn).toBeDefined();
|
expect(enableNotebookBtn).toBeDefined();
|
||||||
expect(enableNotebookBtn.disabled).toBe(false);
|
expect(enableNotebookBtn.disabled).toBe(false);
|
||||||
|
@ -114,7 +115,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
mockExplorer.isNotebookEnabled = ko.observable(false);
|
mockExplorer.isNotebookEnabled = ko.observable(false);
|
||||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
|
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const enableNotebookBtn = buttons.find((button) => button.commandButtonLabel === enableNotebookBtnLabel);
|
const enableNotebookBtn = buttons.find((button) => button.commandButtonLabel === enableNotebookBtnLabel);
|
||||||
expect(enableNotebookBtn).toBeDefined();
|
expect(enableNotebookBtn).toBeDefined();
|
||||||
expect(enableNotebookBtn.disabled).toBe(true);
|
expect(enableNotebookBtn.disabled).toBe(true);
|
||||||
|
@ -126,6 +127,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
|
|
||||||
describe("Open Mongo Shell button", () => {
|
describe("Open Mongo Shell button", () => {
|
||||||
const openMongoShellBtnLabel = "Open Mongo Shell";
|
const openMongoShellBtnLabel = "Open Mongo Shell";
|
||||||
|
const selectedNodeState = useSelectedNode.getState();
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
mockExplorer = {} as Explorer;
|
mockExplorer = {} as Explorer;
|
||||||
|
@ -137,9 +139,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
});
|
});
|
||||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||||
|
|
||||||
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
|
|
||||||
|
|
||||||
mockExplorer.isShellEnabled = ko.observable(true);
|
mockExplorer.isShellEnabled = ko.observable(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -163,7 +162,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
apiType: "SQL",
|
apiType: "SQL",
|
||||||
});
|
});
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
||||||
expect(openMongoShellBtn).toBeUndefined();
|
expect(openMongoShellBtn).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
@ -173,13 +172,13 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
portalEnv: "mooncake",
|
portalEnv: "mooncake",
|
||||||
});
|
});
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
||||||
expect(openMongoShellBtn).toBeUndefined();
|
expect(openMongoShellBtn).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Notebooks is not enabled and is unavailable - button should be hidden", () => {
|
it("Notebooks is not enabled and is unavailable - button should be hidden", () => {
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
||||||
expect(openMongoShellBtn).toBeUndefined();
|
expect(openMongoShellBtn).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
@ -187,7 +186,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
it("Notebooks is not enabled and is available - button should be hidden", () => {
|
it("Notebooks is not enabled and is available - button should be hidden", () => {
|
||||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
||||||
expect(openMongoShellBtn).toBeUndefined();
|
expect(openMongoShellBtn).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
@ -195,7 +194,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
it("Notebooks is enabled and is unavailable - button should be shown and enabled", () => {
|
it("Notebooks is enabled and is unavailable - button should be shown and enabled", () => {
|
||||||
mockExplorer.isNotebookEnabled = ko.observable(true);
|
mockExplorer.isNotebookEnabled = ko.observable(true);
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
||||||
expect(openMongoShellBtn).toBeDefined();
|
expect(openMongoShellBtn).toBeDefined();
|
||||||
expect(openMongoShellBtn.disabled).toBe(false);
|
expect(openMongoShellBtn.disabled).toBe(false);
|
||||||
|
@ -206,7 +205,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
mockExplorer.isNotebookEnabled = ko.observable(true);
|
mockExplorer.isNotebookEnabled = ko.observable(true);
|
||||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
||||||
expect(openMongoShellBtn).toBeDefined();
|
expect(openMongoShellBtn).toBeDefined();
|
||||||
expect(openMongoShellBtn.disabled).toBe(false);
|
expect(openMongoShellBtn.disabled).toBe(false);
|
||||||
|
@ -218,7 +217,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
||||||
mockExplorer.isShellEnabled = ko.observable(false);
|
mockExplorer.isShellEnabled = ko.observable(false);
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
const openMongoShellBtn = buttons.find((button) => button.commandButtonLabel === openMongoShellBtnLabel);
|
||||||
expect(openMongoShellBtn).toBeUndefined();
|
expect(openMongoShellBtn).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
@ -226,6 +225,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
|
|
||||||
describe("Open Cassandra Shell button", () => {
|
describe("Open Cassandra Shell button", () => {
|
||||||
const openCassandraShellBtnLabel = "Open Cassandra Shell";
|
const openCassandraShellBtnLabel = "Open Cassandra Shell";
|
||||||
|
const selectedNodeState = useSelectedNode.getState();
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
mockExplorer = {} as Explorer;
|
mockExplorer = {} as Explorer;
|
||||||
|
@ -237,8 +237,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
});
|
});
|
||||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||||
|
|
||||||
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -262,7 +260,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
});
|
});
|
||||||
console.log(mockExplorer);
|
console.log(mockExplorer);
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const openCassandraShellBtn = buttons.find((button) => button.commandButtonLabel === openCassandraShellBtnLabel);
|
const openCassandraShellBtn = buttons.find((button) => button.commandButtonLabel === openCassandraShellBtnLabel);
|
||||||
expect(openCassandraShellBtn).toBeUndefined();
|
expect(openCassandraShellBtn).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
@ -272,13 +270,13 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
portalEnv: "mooncake",
|
portalEnv: "mooncake",
|
||||||
});
|
});
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const openCassandraShellBtn = buttons.find((button) => button.commandButtonLabel === openCassandraShellBtnLabel);
|
const openCassandraShellBtn = buttons.find((button) => button.commandButtonLabel === openCassandraShellBtnLabel);
|
||||||
expect(openCassandraShellBtn).toBeUndefined();
|
expect(openCassandraShellBtn).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Notebooks is not enabled and is unavailable - button should be shown and disabled", () => {
|
it("Notebooks is not enabled and is unavailable - button should be shown and disabled", () => {
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const openCassandraShellBtn = buttons.find((button) => button.commandButtonLabel === openCassandraShellBtnLabel);
|
const openCassandraShellBtn = buttons.find((button) => button.commandButtonLabel === openCassandraShellBtnLabel);
|
||||||
expect(openCassandraShellBtn).toBeUndefined();
|
expect(openCassandraShellBtn).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
@ -286,7 +284,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
it("Notebooks is not enabled and is available - button should be shown and enabled", () => {
|
it("Notebooks is not enabled and is available - button should be shown and enabled", () => {
|
||||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const openCassandraShellBtn = buttons.find((button) => button.commandButtonLabel === openCassandraShellBtnLabel);
|
const openCassandraShellBtn = buttons.find((button) => button.commandButtonLabel === openCassandraShellBtnLabel);
|
||||||
expect(openCassandraShellBtn).toBeUndefined();
|
expect(openCassandraShellBtn).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
@ -294,7 +292,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
it("Notebooks is enabled and is unavailable - button should be shown and enabled", () => {
|
it("Notebooks is enabled and is unavailable - button should be shown and enabled", () => {
|
||||||
mockExplorer.isNotebookEnabled = ko.observable(true);
|
mockExplorer.isNotebookEnabled = ko.observable(true);
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const openCassandraShellBtn = buttons.find((button) => button.commandButtonLabel === openCassandraShellBtnLabel);
|
const openCassandraShellBtn = buttons.find((button) => button.commandButtonLabel === openCassandraShellBtnLabel);
|
||||||
expect(openCassandraShellBtn).toBeDefined();
|
expect(openCassandraShellBtn).toBeDefined();
|
||||||
expect(openCassandraShellBtn.disabled).toBe(false);
|
expect(openCassandraShellBtn.disabled).toBe(false);
|
||||||
|
@ -305,7 +303,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
mockExplorer.isNotebookEnabled = ko.observable(true);
|
mockExplorer.isNotebookEnabled = ko.observable(true);
|
||||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const openCassandraShellBtn = buttons.find((button) => button.commandButtonLabel === openCassandraShellBtnLabel);
|
const openCassandraShellBtn = buttons.find((button) => button.commandButtonLabel === openCassandraShellBtnLabel);
|
||||||
expect(openCassandraShellBtn).toBeDefined();
|
expect(openCassandraShellBtn).toBeDefined();
|
||||||
expect(openCassandraShellBtn.disabled).toBe(false);
|
expect(openCassandraShellBtn.disabled).toBe(false);
|
||||||
|
@ -316,6 +314,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
describe("GitHub buttons", () => {
|
describe("GitHub buttons", () => {
|
||||||
const connectToGitHubBtnLabel = "Connect to GitHub";
|
const connectToGitHubBtnLabel = "Connect to GitHub";
|
||||||
const manageGitHubSettingsBtnLabel = "Manage GitHub settings";
|
const manageGitHubSettingsBtnLabel = "Manage GitHub settings";
|
||||||
|
const selectedNodeState = useSelectedNode.getState();
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
mockExplorer = {} as Explorer;
|
mockExplorer = {} as Explorer;
|
||||||
|
@ -328,7 +327,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
mockExplorer.isSynapseLinkUpdating = ko.observable(false);
|
||||||
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
|
|
||||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
|
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
|
||||||
|
|
||||||
mockExplorer.notebookManager = new NotebookManager();
|
mockExplorer.notebookManager = new NotebookManager();
|
||||||
|
@ -346,7 +344,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
it("Notebooks is enabled and GitHubOAuthService is not logged in - connect to github button should be visible", () => {
|
it("Notebooks is enabled and GitHubOAuthService is not logged in - connect to github button should be visible", () => {
|
||||||
mockExplorer.isNotebookEnabled = ko.observable(true);
|
mockExplorer.isNotebookEnabled = ko.observable(true);
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const connectToGitHubBtn = buttons.find((button) => button.commandButtonLabel === connectToGitHubBtnLabel);
|
const connectToGitHubBtn = buttons.find((button) => button.commandButtonLabel === connectToGitHubBtnLabel);
|
||||||
expect(connectToGitHubBtn).toBeDefined();
|
expect(connectToGitHubBtn).toBeDefined();
|
||||||
});
|
});
|
||||||
|
@ -355,7 +353,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
mockExplorer.isNotebookEnabled = ko.observable(true);
|
mockExplorer.isNotebookEnabled = ko.observable(true);
|
||||||
mockExplorer.notebookManager.gitHubOAuthService.isLoggedIn = jest.fn().mockReturnValue(true);
|
mockExplorer.notebookManager.gitHubOAuthService.isLoggedIn = jest.fn().mockReturnValue(true);
|
||||||
|
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
const manageGitHubSettingsBtn = buttons.find(
|
const manageGitHubSettingsBtn = buttons.find(
|
||||||
(button) => button.commandButtonLabel === manageGitHubSettingsBtnLabel
|
(button) => button.commandButtonLabel === manageGitHubSettingsBtnLabel
|
||||||
);
|
);
|
||||||
|
@ -363,7 +361,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Notebooks is not enabled - connect to github and manage github settings buttons should be hidden", () => {
|
it("Notebooks is not enabled - connect to github and manage github settings buttons should be hidden", () => {
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
|
|
||||||
const connectToGitHubBtn = buttons.find((button) => button.commandButtonLabel === connectToGitHubBtnLabel);
|
const connectToGitHubBtn = buttons.find((button) => button.commandButtonLabel === connectToGitHubBtnLabel);
|
||||||
expect(connectToGitHubBtn).toBeUndefined();
|
expect(connectToGitHubBtn).toBeUndefined();
|
||||||
|
@ -376,10 +374,12 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Resource token", () => {
|
describe("Resource token", () => {
|
||||||
|
const mockCollection = { id: ko.observable("test") } as CollectionBase;
|
||||||
|
useSelectedNode.getState().setSelectedNode(mockCollection);
|
||||||
|
const selectedNodeState = useSelectedNode.getState();
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
mockExplorer = {} as Explorer;
|
mockExplorer = {} as Explorer;
|
||||||
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
|
mockExplorer.resourceTokenCollection = ko.observable(mockCollection);
|
||||||
mockExplorer.isResourceTokenCollectionNodeSelected = ko.computed(() => true);
|
|
||||||
|
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
authType: AuthType.ResourceToken,
|
authType: AuthType.ResourceToken,
|
||||||
|
@ -392,7 +392,7 @@ describe("CommandBarComponentButtonFactory tests", () => {
|
||||||
kind: "DocumentDB",
|
kind: "DocumentDB",
|
||||||
} as DatabaseAccount,
|
} as DatabaseAccount,
|
||||||
});
|
});
|
||||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer, selectedNodeState);
|
||||||
expect(buttons.length).toBe(2);
|
expect(buttons.length).toBe(2);
|
||||||
expect(buttons[0].commandButtonLabel).toBe("New SQL Query");
|
expect(buttons[0].commandButtonLabel).toBe("New SQL Query");
|
||||||
expect(buttons[0].disabled).toBe(false);
|
expect(buttons[0].disabled).toBe(false);
|
||||||
|
|
|
@ -31,12 +31,16 @@ import Explorer from "../../Explorer";
|
||||||
import { OpenFullScreen } from "../../OpenFullScreen";
|
import { OpenFullScreen } from "../../OpenFullScreen";
|
||||||
import { LoadQueryPane } from "../../Panes/LoadQueryPane/LoadQueryPane";
|
import { LoadQueryPane } from "../../Panes/LoadQueryPane/LoadQueryPane";
|
||||||
import { SettingsPane } from "../../Panes/SettingsPane/SettingsPane";
|
import { SettingsPane } from "../../Panes/SettingsPane/SettingsPane";
|
||||||
|
import { SelectedNodeState } from "../../useSelectedNode";
|
||||||
|
|
||||||
let counter = 0;
|
let counter = 0;
|
||||||
|
|
||||||
export function createStaticCommandBarButtons(container: Explorer): CommandButtonComponentProps[] {
|
export function createStaticCommandBarButtons(
|
||||||
|
container: Explorer,
|
||||||
|
selectedNodeState: SelectedNodeState
|
||||||
|
): CommandButtonComponentProps[] {
|
||||||
if (userContext.authType === AuthType.ResourceToken) {
|
if (userContext.authType === AuthType.ResourceToken) {
|
||||||
return createStaticCommandBarButtonsForResourceToken(container);
|
return createStaticCommandBarButtonsForResourceToken(container, selectedNodeState);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newCollectionBtn = createNewCollectionGroup(container);
|
const newCollectionBtn = createNewCollectionGroup(container);
|
||||||
|
@ -71,7 +75,9 @@ export function createStaticCommandBarButtons(container: Explorer): CommandButto
|
||||||
|
|
||||||
buttons.push(createNotebookWorkspaceResetButton(container));
|
buttons.push(createNotebookWorkspaceResetButton(container));
|
||||||
if (
|
if (
|
||||||
(userContext.apiType === "Mongo" && container.isShellEnabled() && container.isDatabaseNodeOrNoneSelected()) ||
|
(userContext.apiType === "Mongo" &&
|
||||||
|
container.isShellEnabled() &&
|
||||||
|
selectedNodeState.isDatabaseNodeOrNoneSelected()) ||
|
||||||
userContext.apiType === "Cassandra"
|
userContext.apiType === "Cassandra"
|
||||||
) {
|
) {
|
||||||
buttons.push(createDivider());
|
buttons.push(createDivider());
|
||||||
|
@ -87,18 +93,18 @@ export function createStaticCommandBarButtons(container: Explorer): CommandButto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!container.isDatabaseNodeOrNoneSelected()) {
|
if (!selectedNodeState.isDatabaseNodeOrNoneSelected()) {
|
||||||
const isQuerySupported = userContext.apiType === "SQL" || userContext.apiType === "Gremlin";
|
const isQuerySupported = userContext.apiType === "SQL" || userContext.apiType === "Gremlin";
|
||||||
|
|
||||||
if (isQuerySupported) {
|
if (isQuerySupported) {
|
||||||
buttons.push(createDivider());
|
buttons.push(createDivider());
|
||||||
const newSqlQueryBtn = createNewSQLQueryButton(container);
|
const newSqlQueryBtn = createNewSQLQueryButton(selectedNodeState);
|
||||||
buttons.push(newSqlQueryBtn);
|
buttons.push(newSqlQueryBtn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isQuerySupported && container.selectedNode() && container.findSelectedCollection()) {
|
if (isQuerySupported && selectedNodeState.findSelectedCollection()) {
|
||||||
const openQueryBtn = createOpenQueryButton(container);
|
const openQueryBtn = createOpenQueryButton(container);
|
||||||
openQueryBtn.children = [createOpenQueryButton(container), createOpenQueryFromDiskButton(container)];
|
openQueryBtn.children = [createOpenQueryButton(container), createOpenQueryFromDiskButton()];
|
||||||
buttons.push(openQueryBtn);
|
buttons.push(openQueryBtn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,16 +114,16 @@ export function createStaticCommandBarButtons(container: Explorer): CommandButto
|
||||||
iconSrc: AddStoredProcedureIcon,
|
iconSrc: AddStoredProcedureIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () => {
|
onCommandClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = selectedNodeState.findSelectedCollection();
|
||||||
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection);
|
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection);
|
||||||
},
|
},
|
||||||
commandButtonLabel: label,
|
commandButtonLabel: label,
|
||||||
ariaLabel: label,
|
ariaLabel: label,
|
||||||
hasPopup: true,
|
hasPopup: true,
|
||||||
disabled: container.isDatabaseNodeOrNoneSelected(),
|
disabled: selectedNodeState.isDatabaseNodeOrNoneSelected(),
|
||||||
};
|
};
|
||||||
|
|
||||||
newStoredProcedureBtn.children = createScriptCommandButtons(container);
|
newStoredProcedureBtn.children = createScriptCommandButtons(selectedNodeState);
|
||||||
buttons.push(newStoredProcedureBtn);
|
buttons.push(newStoredProcedureBtn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,16 +131,19 @@ export function createStaticCommandBarButtons(container: Explorer): CommandButto
|
||||||
return buttons;
|
return buttons;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createContextCommandBarButtons(container: Explorer): CommandButtonComponentProps[] {
|
export function createContextCommandBarButtons(
|
||||||
|
container: Explorer,
|
||||||
|
selectedNodeState: SelectedNodeState
|
||||||
|
): CommandButtonComponentProps[] {
|
||||||
const buttons: CommandButtonComponentProps[] = [];
|
const buttons: CommandButtonComponentProps[] = [];
|
||||||
|
|
||||||
if (!container.isDatabaseNodeOrNoneSelected() && userContext.apiType === "Mongo") {
|
if (!selectedNodeState.isDatabaseNodeOrNoneSelected() && userContext.apiType === "Mongo") {
|
||||||
const label = container.isShellEnabled() ? "Open Mongo Shell" : "New Shell";
|
const label = container.isShellEnabled() ? "Open Mongo Shell" : "New Shell";
|
||||||
const newMongoShellBtn: CommandButtonComponentProps = {
|
const newMongoShellBtn: CommandButtonComponentProps = {
|
||||||
iconSrc: HostedTerminalIcon,
|
iconSrc: HostedTerminalIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () => {
|
onCommandClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = selectedNodeState.findSelectedCollection();
|
||||||
if (container.isShellEnabled()) {
|
if (container.isShellEnabled()) {
|
||||||
container.openNotebookTerminal(ViewModels.TerminalKind.Mongo);
|
container.openNotebookTerminal(ViewModels.TerminalKind.Mongo);
|
||||||
} else {
|
} else {
|
||||||
|
@ -144,7 +153,7 @@ export function createContextCommandBarButtons(container: Explorer): CommandButt
|
||||||
commandButtonLabel: label,
|
commandButtonLabel: label,
|
||||||
ariaLabel: label,
|
ariaLabel: label,
|
||||||
hasPopup: true,
|
hasPopup: true,
|
||||||
disabled: container.isDatabaseNodeOrNoneSelected() && userContext.apiType === "Mongo",
|
disabled: selectedNodeState.isDatabaseNodeOrNoneSelected() && userContext.apiType === "Mongo",
|
||||||
};
|
};
|
||||||
buttons.push(newMongoShellBtn);
|
buttons.push(newMongoShellBtn);
|
||||||
}
|
}
|
||||||
|
@ -279,20 +288,20 @@ function createNewDatabase(container: Explorer): CommandButtonComponentProps {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createNewSQLQueryButton(container: Explorer): CommandButtonComponentProps {
|
function createNewSQLQueryButton(selectedNodeState: SelectedNodeState): CommandButtonComponentProps {
|
||||||
if (userContext.apiType === "SQL" || userContext.apiType === "Gremlin") {
|
if (userContext.apiType === "SQL" || userContext.apiType === "Gremlin") {
|
||||||
const label = "New SQL Query";
|
const label = "New SQL Query";
|
||||||
return {
|
return {
|
||||||
iconSrc: AddSqlQueryIcon,
|
iconSrc: AddSqlQueryIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () => {
|
onCommandClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = selectedNodeState.findSelectedCollection();
|
||||||
selectedCollection && selectedCollection.onNewQueryClick(selectedCollection);
|
selectedCollection && selectedCollection.onNewQueryClick(selectedCollection);
|
||||||
},
|
},
|
||||||
commandButtonLabel: label,
|
commandButtonLabel: label,
|
||||||
ariaLabel: label,
|
ariaLabel: label,
|
||||||
hasPopup: true,
|
hasPopup: true,
|
||||||
disabled: container.isDatabaseNodeOrNoneSelected(),
|
disabled: selectedNodeState.isDatabaseNodeOrNoneSelected(),
|
||||||
};
|
};
|
||||||
} else if (userContext.apiType === "Mongo") {
|
} else if (userContext.apiType === "Mongo") {
|
||||||
const label = "New Query";
|
const label = "New Query";
|
||||||
|
@ -300,23 +309,24 @@ function createNewSQLQueryButton(container: Explorer): CommandButtonComponentPro
|
||||||
iconSrc: AddSqlQueryIcon,
|
iconSrc: AddSqlQueryIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () => {
|
onCommandClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = selectedNodeState.findSelectedCollection();
|
||||||
selectedCollection && selectedCollection.onNewMongoQueryClick(selectedCollection);
|
selectedCollection && selectedCollection.onNewMongoQueryClick(selectedCollection);
|
||||||
},
|
},
|
||||||
commandButtonLabel: label,
|
commandButtonLabel: label,
|
||||||
ariaLabel: label,
|
ariaLabel: label,
|
||||||
hasPopup: true,
|
hasPopup: true,
|
||||||
disabled: container.isDatabaseNodeOrNoneSelected(),
|
disabled: selectedNodeState.isDatabaseNodeOrNoneSelected(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createScriptCommandButtons(container: Explorer): CommandButtonComponentProps[] {
|
export function createScriptCommandButtons(selectedNodeState: SelectedNodeState): CommandButtonComponentProps[] {
|
||||||
const buttons: CommandButtonComponentProps[] = [];
|
const buttons: CommandButtonComponentProps[] = [];
|
||||||
|
|
||||||
const shouldEnableScriptsCommands: boolean = !container.isDatabaseNodeOrNoneSelected() && areScriptsSupported();
|
const shouldEnableScriptsCommands: boolean =
|
||||||
|
!selectedNodeState.isDatabaseNodeOrNoneSelected() && areScriptsSupported();
|
||||||
|
|
||||||
if (shouldEnableScriptsCommands) {
|
if (shouldEnableScriptsCommands) {
|
||||||
const label = "New Stored Procedure";
|
const label = "New Stored Procedure";
|
||||||
|
@ -324,13 +334,13 @@ export function createScriptCommandButtons(container: Explorer): CommandButtonCo
|
||||||
iconSrc: AddStoredProcedureIcon,
|
iconSrc: AddStoredProcedureIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () => {
|
onCommandClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = selectedNodeState.findSelectedCollection();
|
||||||
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection);
|
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection);
|
||||||
},
|
},
|
||||||
commandButtonLabel: label,
|
commandButtonLabel: label,
|
||||||
ariaLabel: label,
|
ariaLabel: label,
|
||||||
hasPopup: true,
|
hasPopup: true,
|
||||||
disabled: container.isDatabaseNodeOrNoneSelected(),
|
disabled: selectedNodeState.isDatabaseNodeOrNoneSelected(),
|
||||||
};
|
};
|
||||||
buttons.push(newStoredProcedureBtn);
|
buttons.push(newStoredProcedureBtn);
|
||||||
}
|
}
|
||||||
|
@ -341,13 +351,13 @@ export function createScriptCommandButtons(container: Explorer): CommandButtonCo
|
||||||
iconSrc: AddUdfIcon,
|
iconSrc: AddUdfIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () => {
|
onCommandClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = selectedNodeState.findSelectedCollection();
|
||||||
selectedCollection && selectedCollection.onNewUserDefinedFunctionClick(selectedCollection);
|
selectedCollection && selectedCollection.onNewUserDefinedFunctionClick(selectedCollection);
|
||||||
},
|
},
|
||||||
commandButtonLabel: label,
|
commandButtonLabel: label,
|
||||||
ariaLabel: label,
|
ariaLabel: label,
|
||||||
hasPopup: true,
|
hasPopup: true,
|
||||||
disabled: container.isDatabaseNodeOrNoneSelected(),
|
disabled: selectedNodeState.isDatabaseNodeOrNoneSelected(),
|
||||||
};
|
};
|
||||||
buttons.push(newUserDefinedFunctionBtn);
|
buttons.push(newUserDefinedFunctionBtn);
|
||||||
}
|
}
|
||||||
|
@ -358,13 +368,13 @@ export function createScriptCommandButtons(container: Explorer): CommandButtonCo
|
||||||
iconSrc: AddTriggerIcon,
|
iconSrc: AddTriggerIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () => {
|
onCommandClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = selectedNodeState.findSelectedCollection();
|
||||||
selectedCollection && selectedCollection.onNewTriggerClick(selectedCollection);
|
selectedCollection && selectedCollection.onNewTriggerClick(selectedCollection);
|
||||||
},
|
},
|
||||||
commandButtonLabel: label,
|
commandButtonLabel: label,
|
||||||
ariaLabel: label,
|
ariaLabel: label,
|
||||||
hasPopup: true,
|
hasPopup: true,
|
||||||
disabled: container.isDatabaseNodeOrNoneSelected(),
|
disabled: selectedNodeState.isDatabaseNodeOrNoneSelected(),
|
||||||
};
|
};
|
||||||
buttons.push(newTriggerBtn);
|
buttons.push(newTriggerBtn);
|
||||||
}
|
}
|
||||||
|
@ -411,12 +421,12 @@ function createOpenQueryButton(container: Explorer): CommandButtonComponentProps
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createOpenQueryFromDiskButton(container: Explorer): CommandButtonComponentProps {
|
function createOpenQueryFromDiskButton(): CommandButtonComponentProps {
|
||||||
const label = "Open Query From Disk";
|
const label = "Open Query From Disk";
|
||||||
return {
|
return {
|
||||||
iconSrc: OpenQueryFromDiskIcon,
|
iconSrc: OpenQueryFromDiskIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () => useSidePanel.getState().openSidePanel("Load Query", <LoadQueryPane explorer={container} />),
|
onCommandClick: () => useSidePanel.getState().openSidePanel("Load Query", <LoadQueryPane />),
|
||||||
commandButtonLabel: label,
|
commandButtonLabel: label,
|
||||||
ariaLabel: label,
|
ariaLabel: label,
|
||||||
hasPopup: true,
|
hasPopup: true,
|
||||||
|
@ -537,19 +547,25 @@ function createManageGitHubAccountButton(container: Explorer): CommandButtonComp
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function createStaticCommandBarButtonsForResourceToken(container: Explorer): CommandButtonComponentProps[] {
|
function createStaticCommandBarButtonsForResourceToken(
|
||||||
const newSqlQueryBtn = createNewSQLQueryButton(container);
|
container: Explorer,
|
||||||
|
selectedNodeState: SelectedNodeState
|
||||||
|
): CommandButtonComponentProps[] {
|
||||||
|
const newSqlQueryBtn = createNewSQLQueryButton(selectedNodeState);
|
||||||
const openQueryBtn = createOpenQueryButton(container);
|
const openQueryBtn = createOpenQueryButton(container);
|
||||||
|
|
||||||
newSqlQueryBtn.disabled = !container.isResourceTokenCollectionNodeSelected();
|
const isResourceTokenCollectionNodeSelected: boolean =
|
||||||
|
container.resourceTokenCollection() &&
|
||||||
|
container.resourceTokenCollection().id() === selectedNodeState.selectedNode?.id();
|
||||||
|
newSqlQueryBtn.disabled = !isResourceTokenCollectionNodeSelected;
|
||||||
newSqlQueryBtn.onCommandClick = () => {
|
newSqlQueryBtn.onCommandClick = () => {
|
||||||
const resourceTokenCollection: ViewModels.CollectionBase = container.resourceTokenCollection();
|
const resourceTokenCollection: ViewModels.CollectionBase = container.resourceTokenCollection();
|
||||||
resourceTokenCollection && resourceTokenCollection.onNewQueryClick(resourceTokenCollection, undefined);
|
resourceTokenCollection && resourceTokenCollection.onNewQueryClick(resourceTokenCollection, undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
openQueryBtn.disabled = !container.isResourceTokenCollectionNodeSelected();
|
openQueryBtn.disabled = !isResourceTokenCollectionNodeSelected;
|
||||||
if (!openQueryBtn.disabled) {
|
if (!openQueryBtn.disabled) {
|
||||||
openQueryBtn.children = [createOpenQueryButton(container), createOpenQueryFromDiskButton(container)];
|
openQueryBtn.children = [createOpenQueryButton(container), createOpenQueryFromDiskButton()];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [newSqlQueryBtn, openQueryBtn];
|
return [newSqlQueryBtn, openQueryBtn];
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
import { NewQueryTab } from "../../Tabs/QueryTab/QueryTab";
|
import { NewQueryTab } from "../../Tabs/QueryTab/QueryTab";
|
||||||
import { useDatabases } from "../../useDatabases";
|
import { useDatabases } from "../../useDatabases";
|
||||||
|
import { useSelectedNode } from "../../useSelectedNode";
|
||||||
|
|
||||||
interface BrowseQueriesPaneProps {
|
interface BrowseQueriesPaneProps {
|
||||||
explorer: Explorer;
|
explorer: Explorer;
|
||||||
|
@ -24,7 +25,7 @@ export const BrowseQueriesPane: FunctionComponent<BrowseQueriesPaneProps> = ({
|
||||||
}: BrowseQueriesPaneProps): JSX.Element => {
|
}: BrowseQueriesPaneProps): JSX.Element => {
|
||||||
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
|
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
|
||||||
const loadSavedQuery = (savedQuery: Query): void => {
|
const loadSavedQuery = (savedQuery: Query): void => {
|
||||||
const selectedCollection: Collection = explorer && explorer.findSelectedCollection();
|
const selectedCollection: Collection = useSelectedNode.getState().findSelectedCollection();
|
||||||
if (!selectedCollection) {
|
if (!selectedCollection) {
|
||||||
// should never get into this state because this pane is only accessible through the query tab
|
// should never get into this state because this pane is only accessible through the query tab
|
||||||
logError("No collection was selected", "BrowseQueriesPane.loadSavedQuery");
|
logError("No collection was selected", "BrowseQueriesPane.loadSavedQuery");
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
jest.mock("../../../Common/dataAccess/deleteCollection");
|
jest.mock("../../../Common/dataAccess/deleteCollection");
|
||||||
jest.mock("../../../Shared/Telemetry/TelemetryProcessor");
|
jest.mock("../../../Shared/Telemetry/TelemetryProcessor");
|
||||||
import { mount, ReactWrapper, shallow } from "enzyme";
|
import { mount, shallow } from "enzyme";
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { deleteCollection } from "../../../Common/dataAccess/deleteCollection";
|
import { deleteCollection } from "../../../Common/dataAccess/deleteCollection";
|
||||||
import DeleteFeedback from "../../../Common/DeleteFeedback";
|
import DeleteFeedback from "../../../Common/DeleteFeedback";
|
||||||
import { ApiKind, DatabaseAccount } from "../../../Contracts/DataModels";
|
import { ApiKind, DatabaseAccount } from "../../../Contracts/DataModels";
|
||||||
import { Collection, Database, TreeNode } from "../../../Contracts/ViewModels";
|
import { Collection, Database } from "../../../Contracts/ViewModels";
|
||||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||||
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { updateUserContext } from "../../../UserContext";
|
import { updateUserContext } from "../../../UserContext";
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
import { useDatabases } from "../../useDatabases";
|
import { useDatabases } from "../../useDatabases";
|
||||||
|
import { useSelectedNode } from "../../useSelectedNode";
|
||||||
import { DeleteCollectionConfirmationPane } from "./DeleteCollectionConfirmationPane";
|
import { DeleteCollectionConfirmationPane } from "./DeleteCollectionConfirmationPane";
|
||||||
|
|
||||||
describe("Delete Collection Confirmation Pane", () => {
|
describe("Delete Collection Confirmation Pane", () => {
|
||||||
|
@ -54,47 +55,39 @@ describe("Delete Collection Confirmation Pane", () => {
|
||||||
it("should return true if last collection and database does not have shared throughput else false", () => {
|
it("should return true if last collection and database does not have shared throughput else false", () => {
|
||||||
const fakeExplorer = new Explorer();
|
const fakeExplorer = new Explorer();
|
||||||
fakeExplorer.refreshAllDatabases = () => undefined;
|
fakeExplorer.refreshAllDatabases = () => undefined;
|
||||||
fakeExplorer.isSelectedDatabaseShared = () => false;
|
|
||||||
|
|
||||||
const props = {
|
const wrapper = shallow(<DeleteCollectionConfirmationPane explorer={fakeExplorer} />);
|
||||||
explorer: fakeExplorer,
|
|
||||||
closePanel: (): void => undefined,
|
|
||||||
collectionName: "container",
|
|
||||||
};
|
|
||||||
const wrapper = shallow(<DeleteCollectionConfirmationPane {...props} />);
|
|
||||||
expect(wrapper.exists(".deleteCollectionFeedback")).toBe(false);
|
expect(wrapper.exists(".deleteCollectionFeedback")).toBe(false);
|
||||||
|
|
||||||
const database = { id: ko.observable("testDB") } as Database;
|
const database = { id: ko.observable("testDB") } as Database;
|
||||||
database.collections = ko.observableArray<Collection>([{ id: ko.observable("testCollection") } as Collection]);
|
database.collections = ko.observableArray<Collection>([{ id: ko.observable("testCollection") } as Collection]);
|
||||||
|
database.nodeKind = "Database";
|
||||||
|
database.isDatabaseShared = ko.computed(() => false);
|
||||||
useDatabases.getState().addDatabases([database]);
|
useDatabases.getState().addDatabases([database]);
|
||||||
wrapper.setProps(props);
|
useSelectedNode.getState().setSelectedNode(database);
|
||||||
|
wrapper.setProps({ explorer: fakeExplorer });
|
||||||
expect(wrapper.exists(".deleteCollectionFeedback")).toBe(true);
|
expect(wrapper.exists(".deleteCollectionFeedback")).toBe(true);
|
||||||
|
|
||||||
props.explorer.isSelectedDatabaseShared = () => true;
|
database.isDatabaseShared = ko.computed(() => true);
|
||||||
wrapper.setProps(props);
|
wrapper.setProps({ explorer: fakeExplorer });
|
||||||
expect(wrapper.exists(".deleteCollectionFeedback")).toBe(false);
|
expect(wrapper.exists(".deleteCollectionFeedback")).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("submit()", () => {
|
describe("submit()", () => {
|
||||||
let wrapper: ReactWrapper;
|
|
||||||
const selectedCollectionId = "testCol";
|
const selectedCollectionId = "testCol";
|
||||||
const databaseId = "testDatabase";
|
const databaseId = "testDatabase";
|
||||||
const fakeExplorer = {} as Explorer;
|
const fakeExplorer = {} as Explorer;
|
||||||
fakeExplorer.findSelectedCollection = () => {
|
|
||||||
return {
|
|
||||||
id: ko.observable<string>(selectedCollectionId),
|
|
||||||
databaseId,
|
|
||||||
rid: "test",
|
|
||||||
} as Collection;
|
|
||||||
};
|
|
||||||
fakeExplorer.selectedCollectionId = ko.computed<string>(() => selectedCollectionId);
|
|
||||||
fakeExplorer.selectedNode = ko.observable<TreeNode>();
|
|
||||||
fakeExplorer.refreshAllDatabases = () => undefined;
|
fakeExplorer.refreshAllDatabases = () => undefined;
|
||||||
fakeExplorer.isSelectedDatabaseShared = () => false;
|
const database = { id: ko.observable(databaseId) } as Database;
|
||||||
const database = { id: ko.observable("testDB") } as Database;
|
const collection = {
|
||||||
database.collections = ko.observableArray<Collection>([{ id: ko.observable("testCollection") } as Collection]);
|
id: ko.observable(selectedCollectionId),
|
||||||
useDatabases.getState().addDatabases([database]);
|
nodeKind: "Collection",
|
||||||
|
database,
|
||||||
|
databaseId,
|
||||||
|
} as Collection;
|
||||||
|
database.collections = ko.observableArray<Collection>([collection]);
|
||||||
|
database.isDatabaseShared = ko.computed(() => false);
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
|
@ -112,15 +105,17 @@ describe("Delete Collection Confirmation Pane", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
const props = {
|
useDatabases.getState().addDatabases([database]);
|
||||||
explorer: fakeExplorer,
|
useSelectedNode.getState().setSelectedNode(collection);
|
||||||
closePanel: (): void => undefined,
|
});
|
||||||
collectionName: "container",
|
|
||||||
};
|
afterEach(() => {
|
||||||
wrapper = mount(<DeleteCollectionConfirmationPane {...props} />);
|
useDatabases.getState().clearDatabases();
|
||||||
|
useSelectedNode.getState().setSelectedNode(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should call delete collection", () => {
|
it("should call delete collection", () => {
|
||||||
|
const wrapper = mount(<DeleteCollectionConfirmationPane explorer={fakeExplorer} />);
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
|
||||||
expect(wrapper.exists("#confirmCollectionId")).toBe(true);
|
expect(wrapper.exists("#confirmCollectionId")).toBe(true);
|
||||||
|
@ -137,6 +132,7 @@ describe("Delete Collection Confirmation Pane", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should record feedback", async () => {
|
it("should record feedback", async () => {
|
||||||
|
const wrapper = mount(<DeleteCollectionConfirmationPane explorer={fakeExplorer} />);
|
||||||
expect(wrapper.exists("#confirmCollectionId")).toBe(true);
|
expect(wrapper.exists("#confirmCollectionId")).toBe(true);
|
||||||
wrapper
|
wrapper
|
||||||
.find("#confirmCollectionId")
|
.find("#confirmCollectionId")
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { getCollectionName } from "../../../Utils/APITypeUtils";
|
||||||
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
|
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
import { useDatabases } from "../../useDatabases";
|
import { useDatabases } from "../../useDatabases";
|
||||||
|
import { useSelectedNode } from "../../useSelectedNode";
|
||||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||||
|
|
||||||
export interface DeleteCollectionConfirmationPaneProps {
|
export interface DeleteCollectionConfirmationPaneProps {
|
||||||
|
@ -24,19 +25,19 @@ export const DeleteCollectionConfirmationPane: FunctionComponent<DeleteCollectio
|
||||||
explorer,
|
explorer,
|
||||||
}: DeleteCollectionConfirmationPaneProps) => {
|
}: DeleteCollectionConfirmationPaneProps) => {
|
||||||
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
|
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
|
||||||
const isLastCollection = useDatabases((state) => state.isLastCollection);
|
|
||||||
const [deleteCollectionFeedback, setDeleteCollectionFeedback] = useState<string>("");
|
const [deleteCollectionFeedback, setDeleteCollectionFeedback] = useState<string>("");
|
||||||
const [inputCollectionName, setInputCollectionName] = useState<string>("");
|
const [inputCollectionName, setInputCollectionName] = useState<string>("");
|
||||||
const [formError, setFormError] = useState<string>("");
|
const [formError, setFormError] = useState<string>("");
|
||||||
const [isExecuting, setIsExecuting] = useState(false);
|
const [isExecuting, setIsExecuting] = useState(false);
|
||||||
|
|
||||||
const shouldRecordFeedback = (): boolean => {
|
const shouldRecordFeedback = (): boolean =>
|
||||||
return isLastCollection() && !explorer.isSelectedDatabaseShared();
|
useDatabases.getState().isLastCollection() &&
|
||||||
};
|
!useSelectedNode.getState().findSelectedDatabase()?.isDatabaseShared();
|
||||||
|
|
||||||
const collectionName = getCollectionName().toLocaleLowerCase();
|
const collectionName = getCollectionName().toLocaleLowerCase();
|
||||||
const paneTitle = "Delete " + collectionName;
|
const paneTitle = "Delete " + collectionName;
|
||||||
const onSubmit = async (): Promise<void> => {
|
const onSubmit = async (): Promise<void> => {
|
||||||
const collection = explorer.findSelectedCollection();
|
const collection = useSelectedNode.getState().findSelectedCollection();
|
||||||
if (!collection || inputCollectionName !== collection.id()) {
|
if (!collection || inputCollectionName !== collection.id()) {
|
||||||
const errorMessage = "Input " + collectionName + " name does not match the selected " + collectionName;
|
const errorMessage = "Input " + collectionName + " name does not match the selected " + collectionName;
|
||||||
setFormError(errorMessage);
|
setFormError(errorMessage);
|
||||||
|
@ -61,7 +62,7 @@ export const DeleteCollectionConfirmationPane: FunctionComponent<DeleteCollectio
|
||||||
await deleteCollection(collection.databaseId, collection.id());
|
await deleteCollection(collection.databaseId, collection.id());
|
||||||
|
|
||||||
setIsExecuting(false);
|
setIsExecuting(false);
|
||||||
explorer.selectedNode(collection.database);
|
useSelectedNode.getState().setSelectedNode(collection.database);
|
||||||
explorer.tabsManager?.closeTabsByComparator(
|
explorer.tabsManager?.closeTabsByComparator(
|
||||||
(tab) => tab.node?.id() === collection.id() && (tab.node as Collection).databaseId === collection.databaseId
|
(tab) => tab.node?.id() === collection.id() && (tab.node as Collection).databaseId === collection.databaseId
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,15 +2,9 @@
|
||||||
|
|
||||||
exports[`Delete Collection Confirmation Pane submit() should call delete collection 1`] = `
|
exports[`Delete Collection Confirmation Pane submit() should call delete collection 1`] = `
|
||||||
<DeleteCollectionConfirmationPane
|
<DeleteCollectionConfirmationPane
|
||||||
closePanel={[Function]}
|
|
||||||
collectionName="container"
|
|
||||||
explorer={
|
explorer={
|
||||||
Object {
|
Object {
|
||||||
"findSelectedCollection": [Function],
|
|
||||||
"isSelectedDatabaseShared": [Function],
|
|
||||||
"refreshAllDatabases": [Function],
|
"refreshAllDatabases": [Function],
|
||||||
"selectedCollectionId": [Function],
|
|
||||||
"selectedNode": [Function],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -372,355 +366,6 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
||||||
</TextFieldBase>
|
</TextFieldBase>
|
||||||
</StyledTextFieldBase>
|
</StyledTextFieldBase>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
className="deleteCollectionFeedback"
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
block={true}
|
|
||||||
variant="small"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="css-66"
|
|
||||||
>
|
|
||||||
Help us improve Azure Cosmos DB!
|
|
||||||
</span>
|
|
||||||
</Text>
|
|
||||||
<Text
|
|
||||||
block={true}
|
|
||||||
variant="small"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="css-66"
|
|
||||||
>
|
|
||||||
What is the reason why you are deleting this
|
|
||||||
container
|
|
||||||
?
|
|
||||||
</span>
|
|
||||||
</Text>
|
|
||||||
<StyledTextFieldBase
|
|
||||||
id="deleteCollectionFeedbackInput"
|
|
||||||
multiline={true}
|
|
||||||
onChange={[Function]}
|
|
||||||
rows={3}
|
|
||||||
styles={
|
|
||||||
Object {
|
|
||||||
"fieldGroup": Object {
|
|
||||||
"width": 300,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value=""
|
|
||||||
>
|
|
||||||
<TextFieldBase
|
|
||||||
deferredValidationTime={200}
|
|
||||||
id="deleteCollectionFeedbackInput"
|
|
||||||
multiline={true}
|
|
||||||
onChange={[Function]}
|
|
||||||
resizable={true}
|
|
||||||
rows={3}
|
|
||||||
styles={[Function]}
|
|
||||||
theme={
|
|
||||||
Object {
|
|
||||||
"disableGlobalClassNames": false,
|
|
||||||
"effects": Object {
|
|
||||||
"elevation16": "0 6.4px 14.4px 0 rgba(0, 0, 0, 0.132), 0 1.2px 3.6px 0 rgba(0, 0, 0, 0.108)",
|
|
||||||
"elevation4": "0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132), 0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108)",
|
|
||||||
"elevation64": "0 25.6px 57.6px 0 rgba(0, 0, 0, 0.22), 0 4.8px 14.4px 0 rgba(0, 0, 0, 0.18)",
|
|
||||||
"elevation8": "0 3.2px 7.2px 0 rgba(0, 0, 0, 0.132), 0 0.6px 1.8px 0 rgba(0, 0, 0, 0.108)",
|
|
||||||
"roundedCorner2": "2px",
|
|
||||||
"roundedCorner4": "4px",
|
|
||||||
"roundedCorner6": "6px",
|
|
||||||
},
|
|
||||||
"fonts": Object {
|
|
||||||
"large": Object {
|
|
||||||
"MozOsxFontSmoothing": "grayscale",
|
|
||||||
"WebkitFontSmoothing": "antialiased",
|
|
||||||
"fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif",
|
|
||||||
"fontSize": "18px",
|
|
||||||
"fontWeight": 400,
|
|
||||||
},
|
|
||||||
"medium": Object {
|
|
||||||
"MozOsxFontSmoothing": "grayscale",
|
|
||||||
"WebkitFontSmoothing": "antialiased",
|
|
||||||
"fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif",
|
|
||||||
"fontSize": "14px",
|
|
||||||
"fontWeight": 400,
|
|
||||||
},
|
|
||||||
"mediumPlus": Object {
|
|
||||||
"MozOsxFontSmoothing": "grayscale",
|
|
||||||
"WebkitFontSmoothing": "antialiased",
|
|
||||||
"fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif",
|
|
||||||
"fontSize": "16px",
|
|
||||||
"fontWeight": 400,
|
|
||||||
},
|
|
||||||
"mega": Object {
|
|
||||||
"MozOsxFontSmoothing": "grayscale",
|
|
||||||
"WebkitFontSmoothing": "antialiased",
|
|
||||||
"fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif",
|
|
||||||
"fontSize": "68px",
|
|
||||||
"fontWeight": 600,
|
|
||||||
},
|
|
||||||
"small": Object {
|
|
||||||
"MozOsxFontSmoothing": "grayscale",
|
|
||||||
"WebkitFontSmoothing": "antialiased",
|
|
||||||
"fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif",
|
|
||||||
"fontSize": "12px",
|
|
||||||
"fontWeight": 400,
|
|
||||||
},
|
|
||||||
"smallPlus": Object {
|
|
||||||
"MozOsxFontSmoothing": "grayscale",
|
|
||||||
"WebkitFontSmoothing": "antialiased",
|
|
||||||
"fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif",
|
|
||||||
"fontSize": "12px",
|
|
||||||
"fontWeight": 400,
|
|
||||||
},
|
|
||||||
"superLarge": Object {
|
|
||||||
"MozOsxFontSmoothing": "grayscale",
|
|
||||||
"WebkitFontSmoothing": "antialiased",
|
|
||||||
"fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif",
|
|
||||||
"fontSize": "42px",
|
|
||||||
"fontWeight": 600,
|
|
||||||
},
|
|
||||||
"tiny": Object {
|
|
||||||
"MozOsxFontSmoothing": "grayscale",
|
|
||||||
"WebkitFontSmoothing": "antialiased",
|
|
||||||
"fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif",
|
|
||||||
"fontSize": "10px",
|
|
||||||
"fontWeight": 400,
|
|
||||||
},
|
|
||||||
"xLarge": Object {
|
|
||||||
"MozOsxFontSmoothing": "grayscale",
|
|
||||||
"WebkitFontSmoothing": "antialiased",
|
|
||||||
"fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif",
|
|
||||||
"fontSize": "20px",
|
|
||||||
"fontWeight": 600,
|
|
||||||
},
|
|
||||||
"xLargePlus": Object {
|
|
||||||
"MozOsxFontSmoothing": "grayscale",
|
|
||||||
"WebkitFontSmoothing": "antialiased",
|
|
||||||
"fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif",
|
|
||||||
"fontSize": "24px",
|
|
||||||
"fontWeight": 600,
|
|
||||||
},
|
|
||||||
"xSmall": Object {
|
|
||||||
"MozOsxFontSmoothing": "grayscale",
|
|
||||||
"WebkitFontSmoothing": "antialiased",
|
|
||||||
"fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif",
|
|
||||||
"fontSize": "10px",
|
|
||||||
"fontWeight": 400,
|
|
||||||
},
|
|
||||||
"xxLarge": Object {
|
|
||||||
"MozOsxFontSmoothing": "grayscale",
|
|
||||||
"WebkitFontSmoothing": "antialiased",
|
|
||||||
"fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif",
|
|
||||||
"fontSize": "28px",
|
|
||||||
"fontWeight": 600,
|
|
||||||
},
|
|
||||||
"xxLargePlus": Object {
|
|
||||||
"MozOsxFontSmoothing": "grayscale",
|
|
||||||
"WebkitFontSmoothing": "antialiased",
|
|
||||||
"fontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif",
|
|
||||||
"fontSize": "32px",
|
|
||||||
"fontWeight": 600,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"isInverted": false,
|
|
||||||
"palette": Object {
|
|
||||||
"accent": "#0078d4",
|
|
||||||
"black": "#000000",
|
|
||||||
"blackTranslucent40": "rgba(0,0,0,.4)",
|
|
||||||
"blue": "#0078d4",
|
|
||||||
"blueDark": "#002050",
|
|
||||||
"blueLight": "#00bcf2",
|
|
||||||
"blueMid": "#00188f",
|
|
||||||
"green": "#107c10",
|
|
||||||
"greenDark": "#004b1c",
|
|
||||||
"greenLight": "#bad80a",
|
|
||||||
"magenta": "#b4009e",
|
|
||||||
"magentaDark": "#5c005c",
|
|
||||||
"magentaLight": "#e3008c",
|
|
||||||
"neutralDark": "#201f1e",
|
|
||||||
"neutralLight": "#edebe9",
|
|
||||||
"neutralLighter": "#f3f2f1",
|
|
||||||
"neutralLighterAlt": "#faf9f8",
|
|
||||||
"neutralPrimary": "#323130",
|
|
||||||
"neutralPrimaryAlt": "#3b3a39",
|
|
||||||
"neutralQuaternary": "#d2d0ce",
|
|
||||||
"neutralQuaternaryAlt": "#e1dfdd",
|
|
||||||
"neutralSecondary": "#605e5c",
|
|
||||||
"neutralSecondaryAlt": "#8a8886",
|
|
||||||
"neutralTertiary": "#a19f9d",
|
|
||||||
"neutralTertiaryAlt": "#c8c6c4",
|
|
||||||
"orange": "#d83b01",
|
|
||||||
"orangeLight": "#ea4300",
|
|
||||||
"orangeLighter": "#ff8c00",
|
|
||||||
"purple": "#5c2d91",
|
|
||||||
"purpleDark": "#32145a",
|
|
||||||
"purpleLight": "#b4a0ff",
|
|
||||||
"red": "#e81123",
|
|
||||||
"redDark": "#a4262c",
|
|
||||||
"teal": "#008272",
|
|
||||||
"tealDark": "#004b50",
|
|
||||||
"tealLight": "#00b294",
|
|
||||||
"themeDark": "#005a9e",
|
|
||||||
"themeDarkAlt": "#106ebe",
|
|
||||||
"themeDarker": "#004578",
|
|
||||||
"themeLight": "#c7e0f4",
|
|
||||||
"themeLighter": "#deecf9",
|
|
||||||
"themeLighterAlt": "#eff6fc",
|
|
||||||
"themePrimary": "#0078d4",
|
|
||||||
"themeSecondary": "#2b88d8",
|
|
||||||
"themeTertiary": "#71afe5",
|
|
||||||
"white": "#ffffff",
|
|
||||||
"whiteTranslucent40": "rgba(255,255,255,.4)",
|
|
||||||
"yellow": "#ffb900",
|
|
||||||
"yellowDark": "#d29200",
|
|
||||||
"yellowLight": "#fff100",
|
|
||||||
},
|
|
||||||
"rtl": undefined,
|
|
||||||
"semanticColors": Object {
|
|
||||||
"accentButtonBackground": "#0078d4",
|
|
||||||
"accentButtonText": "#ffffff",
|
|
||||||
"actionLink": "#323130",
|
|
||||||
"actionLinkHovered": "#201f1e",
|
|
||||||
"blockingBackground": "#FDE7E9",
|
|
||||||
"blockingIcon": "#FDE7E9",
|
|
||||||
"bodyBackground": "#ffffff",
|
|
||||||
"bodyBackgroundChecked": "#edebe9",
|
|
||||||
"bodyBackgroundHovered": "#f3f2f1",
|
|
||||||
"bodyDivider": "#edebe9",
|
|
||||||
"bodyFrameBackground": "#ffffff",
|
|
||||||
"bodyFrameDivider": "#edebe9",
|
|
||||||
"bodyStandoutBackground": "#faf9f8",
|
|
||||||
"bodySubtext": "#605e5c",
|
|
||||||
"bodyText": "#323130",
|
|
||||||
"bodyTextChecked": "#000000",
|
|
||||||
"buttonBackground": "#ffffff",
|
|
||||||
"buttonBackgroundChecked": "#c8c6c4",
|
|
||||||
"buttonBackgroundCheckedHovered": "#edebe9",
|
|
||||||
"buttonBackgroundDisabled": "#f3f2f1",
|
|
||||||
"buttonBackgroundHovered": "#f3f2f1",
|
|
||||||
"buttonBackgroundPressed": "#edebe9",
|
|
||||||
"buttonBorder": "#8a8886",
|
|
||||||
"buttonBorderDisabled": "#f3f2f1",
|
|
||||||
"buttonText": "#323130",
|
|
||||||
"buttonTextChecked": "#201f1e",
|
|
||||||
"buttonTextCheckedHovered": "#000000",
|
|
||||||
"buttonTextDisabled": "#a19f9d",
|
|
||||||
"buttonTextHovered": "#201f1e",
|
|
||||||
"buttonTextPressed": "#201f1e",
|
|
||||||
"cardShadow": "0 1.6px 3.6px 0 rgba(0, 0, 0, 0.132), 0 0.3px 0.9px 0 rgba(0, 0, 0, 0.108)",
|
|
||||||
"cardShadowHovered": "0 3.2px 7.2px 0 rgba(0, 0, 0, 0.132), 0 0.6px 1.8px 0 rgba(0, 0, 0, 0.108)",
|
|
||||||
"cardStandoutBackground": "#ffffff",
|
|
||||||
"defaultStateBackground": "#faf9f8",
|
|
||||||
"disabledBackground": "#f3f2f1",
|
|
||||||
"disabledBodySubtext": "#c8c6c4",
|
|
||||||
"disabledBodyText": "#a19f9d",
|
|
||||||
"disabledBorder": "#c8c6c4",
|
|
||||||
"disabledSubtext": "#d2d0ce",
|
|
||||||
"disabledText": "#a19f9d",
|
|
||||||
"errorBackground": "#FDE7E9",
|
|
||||||
"errorIcon": "#A80000",
|
|
||||||
"errorText": "#a4262c",
|
|
||||||
"focusBorder": "#605e5c",
|
|
||||||
"infoBackground": "#f3f2f1",
|
|
||||||
"infoIcon": "#605e5c",
|
|
||||||
"inputBackground": "#ffffff",
|
|
||||||
"inputBackgroundChecked": "#0078d4",
|
|
||||||
"inputBackgroundCheckedHovered": "#005a9e",
|
|
||||||
"inputBorder": "#605e5c",
|
|
||||||
"inputBorderHovered": "#323130",
|
|
||||||
"inputFocusBorderAlt": "#0078d4",
|
|
||||||
"inputForegroundChecked": "#ffffff",
|
|
||||||
"inputIcon": "#0078d4",
|
|
||||||
"inputIconDisabled": "#a19f9d",
|
|
||||||
"inputIconHovered": "#005a9e",
|
|
||||||
"inputPlaceholderBackgroundChecked": "#deecf9",
|
|
||||||
"inputPlaceholderText": "#605e5c",
|
|
||||||
"inputText": "#323130",
|
|
||||||
"inputTextHovered": "#201f1e",
|
|
||||||
"link": "#0078d4",
|
|
||||||
"linkHovered": "#004578",
|
|
||||||
"listBackground": "#ffffff",
|
|
||||||
"listHeaderBackgroundHovered": "#f3f2f1",
|
|
||||||
"listHeaderBackgroundPressed": "#edebe9",
|
|
||||||
"listItemBackgroundChecked": "#edebe9",
|
|
||||||
"listItemBackgroundCheckedHovered": "#e1dfdd",
|
|
||||||
"listItemBackgroundHovered": "#f3f2f1",
|
|
||||||
"listText": "#323130",
|
|
||||||
"listTextColor": "#323130",
|
|
||||||
"menuBackground": "#ffffff",
|
|
||||||
"menuDivider": "#c8c6c4",
|
|
||||||
"menuHeader": "#0078d4",
|
|
||||||
"menuIcon": "#0078d4",
|
|
||||||
"menuItemBackgroundChecked": "#edebe9",
|
|
||||||
"menuItemBackgroundHovered": "#f3f2f1",
|
|
||||||
"menuItemBackgroundPressed": "#edebe9",
|
|
||||||
"menuItemText": "#323130",
|
|
||||||
"menuItemTextHovered": "#201f1e",
|
|
||||||
"messageLink": "#005A9E",
|
|
||||||
"messageLinkHovered": "#004578",
|
|
||||||
"messageText": "#323130",
|
|
||||||
"primaryButtonBackground": "#0078d4",
|
|
||||||
"primaryButtonBackgroundDisabled": "#f3f2f1",
|
|
||||||
"primaryButtonBackgroundHovered": "#106ebe",
|
|
||||||
"primaryButtonBackgroundPressed": "#005a9e",
|
|
||||||
"primaryButtonBorder": "transparent",
|
|
||||||
"primaryButtonText": "#ffffff",
|
|
||||||
"primaryButtonTextDisabled": "#d2d0ce",
|
|
||||||
"primaryButtonTextHovered": "#ffffff",
|
|
||||||
"primaryButtonTextPressed": "#ffffff",
|
|
||||||
"severeWarningBackground": "#FED9CC",
|
|
||||||
"severeWarningIcon": "#D83B01",
|
|
||||||
"smallInputBorder": "#605e5c",
|
|
||||||
"successBackground": "#DFF6DD",
|
|
||||||
"successIcon": "#107C10",
|
|
||||||
"successText": "#107C10",
|
|
||||||
"variantBorder": "#edebe9",
|
|
||||||
"variantBorderHovered": "#a19f9d",
|
|
||||||
"warningBackground": "#FFF4CE",
|
|
||||||
"warningHighlight": "#ffb900",
|
|
||||||
"warningIcon": "#797775",
|
|
||||||
"warningText": "#323130",
|
|
||||||
},
|
|
||||||
"spacing": Object {
|
|
||||||
"l1": "20px",
|
|
||||||
"l2": "32px",
|
|
||||||
"m": "16px",
|
|
||||||
"s1": "8px",
|
|
||||||
"s2": "4px",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
validateOnLoad={true}
|
|
||||||
value=""
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="ms-TextField ms-TextField--multiline root-55"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="ms-TextField-wrapper"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="ms-TextField-fieldGroup fieldGroup-67"
|
|
||||||
>
|
|
||||||
<textarea
|
|
||||||
aria-invalid={false}
|
|
||||||
className="ms-TextField-field field-68"
|
|
||||||
id="deleteCollectionFeedbackInput"
|
|
||||||
onBlur={[Function]}
|
|
||||||
onChange={[Function]}
|
|
||||||
onFocus={[Function]}
|
|
||||||
onInput={[Function]}
|
|
||||||
rows={3}
|
|
||||||
value=""
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</TextFieldBase>
|
|
||||||
</StyledTextFieldBase>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<PanelFooterComponent
|
<PanelFooterComponent
|
||||||
|
@ -2433,7 +2078,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
aria-label="OK"
|
aria-label="OK"
|
||||||
className="ms-Button ms-Button--primary root-70"
|
className="ms-Button ms-Button--primary root-66"
|
||||||
data-is-focusable={true}
|
data-is-focusable={true}
|
||||||
id="sidePanelOkButton"
|
id="sidePanelOkButton"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
|
@ -2445,16 +2090,16 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="ms-Button-flexContainer flexContainer-71"
|
className="ms-Button-flexContainer flexContainer-67"
|
||||||
data-automationid="splitbuttonprimary"
|
data-automationid="splitbuttonprimary"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="ms-Button-textContainer textContainer-72"
|
className="ms-Button-textContainer textContainer-68"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="ms-Button-label label-74"
|
className="ms-Button-label label-70"
|
||||||
id="id__6"
|
id="id__3"
|
||||||
key="id__6"
|
key="id__3"
|
||||||
>
|
>
|
||||||
OK
|
OK
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
jest.mock("../../Common/dataAccess/deleteDatabase");
|
jest.mock("../../Common/dataAccess/deleteDatabase");
|
||||||
jest.mock("../../Shared/Telemetry/TelemetryProcessor");
|
jest.mock("../../Shared/Telemetry/TelemetryProcessor");
|
||||||
import { mount, ReactWrapper, shallow } from "enzyme";
|
import { mount, shallow } from "enzyme";
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { deleteDatabase } from "../../Common/dataAccess/deleteDatabase";
|
import { deleteDatabase } from "../../Common/dataAccess/deleteDatabase";
|
||||||
|
@ -13,121 +13,102 @@ import { updateUserContext } from "../../UserContext";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import { TabsManager } from "../Tabs/TabsManager";
|
import { TabsManager } from "../Tabs/TabsManager";
|
||||||
import { useDatabases } from "../useDatabases";
|
import { useDatabases } from "../useDatabases";
|
||||||
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
import { DeleteDatabaseConfirmationPanel } from "./DeleteDatabaseConfirmationPanel";
|
import { DeleteDatabaseConfirmationPanel } from "./DeleteDatabaseConfirmationPanel";
|
||||||
|
|
||||||
describe("Delete Database Confirmation Pane", () => {
|
describe("Delete Database Confirmation Pane", () => {
|
||||||
describe("shouldRecordFeedback()", () => {
|
const selectedDatabaseId = "testDatabase";
|
||||||
it("should return true if last non empty database or is last database that has shared throughput, else false", () => {
|
let fakeExplorer: Explorer;
|
||||||
const fakeExplorer = {} as Explorer;
|
let database: Database;
|
||||||
fakeExplorer.refreshAllDatabases = () => undefined;
|
|
||||||
fakeExplorer.isSelectedDatabaseShared = () => false;
|
|
||||||
|
|
||||||
const database = {} as Database;
|
beforeAll(() => {
|
||||||
database.collections = ko.observableArray<Collection>([{ id: ko.observable("testCollection") } as Collection]);
|
updateUserContext({
|
||||||
database.id = ko.observable<string>("testDatabase");
|
databaseAccount: {
|
||||||
|
name: "testDatabaseAccountName",
|
||||||
const props = {
|
properties: {
|
||||||
explorer: fakeExplorer,
|
cassandraEndpoint: "testEndpoint",
|
||||||
closePanel: (): void => undefined,
|
},
|
||||||
openNotificationConsole: (): void => undefined,
|
id: "testDatabaseAccountId",
|
||||||
selectedDatabase: database,
|
} as DatabaseAccount,
|
||||||
};
|
apiType: "SQL",
|
||||||
|
|
||||||
const wrapper = shallow(<DeleteDatabaseConfirmationPanel {...props} />);
|
|
||||||
expect(wrapper.exists(".deleteDatabaseFeedback")).toBe(false);
|
|
||||||
|
|
||||||
useDatabases.getState().addDatabases([database]);
|
|
||||||
|
|
||||||
wrapper.setProps(props);
|
|
||||||
expect(wrapper.exists(".deleteDatabaseFeedback")).toBe(true);
|
|
||||||
useDatabases.getState().clearDatabases();
|
|
||||||
});
|
});
|
||||||
|
(deleteDatabase as jest.Mock).mockResolvedValue(undefined);
|
||||||
|
(TelemetryProcessor.trace as jest.Mock).mockReturnValue(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("submit()", () => {
|
beforeEach(() => {
|
||||||
const selectedDatabaseId = "testDatabse";
|
fakeExplorer = {} as Explorer;
|
||||||
const database = { id: ko.observable("testDatabase") } as Database;
|
fakeExplorer.refreshAllDatabases = () => undefined;
|
||||||
|
fakeExplorer.tabsManager = new TabsManager();
|
||||||
|
|
||||||
|
database = {} as Database;
|
||||||
database.collections = ko.observableArray<Collection>([{ id: ko.observable("testCollection") } as Collection]);
|
database.collections = ko.observableArray<Collection>([{ id: ko.observable("testCollection") } as Collection]);
|
||||||
database.id = ko.observable<string>(selectedDatabaseId);
|
database.id = ko.observable<string>(selectedDatabaseId);
|
||||||
const fakeExplorer = {} as Explorer;
|
database.nodeKind = "Database";
|
||||||
fakeExplorer.refreshAllDatabases = () => undefined;
|
|
||||||
fakeExplorer.isSelectedDatabaseShared = () => false;
|
|
||||||
fakeExplorer.tabsManager = new TabsManager();
|
|
||||||
fakeExplorer.selectedNode = ko.observable();
|
|
||||||
|
|
||||||
let wrapper: ReactWrapper;
|
useDatabases.getState().addDatabases([database]);
|
||||||
beforeAll(() => {
|
useSelectedNode.getState().setSelectedNode(database);
|
||||||
updateUserContext({
|
});
|
||||||
databaseAccount: {
|
|
||||||
name: "testDatabaseAccountName",
|
afterEach(() => {
|
||||||
properties: {
|
useDatabases.getState().clearDatabases();
|
||||||
cassandraEndpoint: "testEndpoint",
|
useSelectedNode.getState().setSelectedNode(undefined);
|
||||||
},
|
});
|
||||||
id: "testDatabaseAccountId",
|
|
||||||
} as DatabaseAccount,
|
it("shouldRecordFeedback() should return true if last non empty database or is last database that has shared throughput", () => {
|
||||||
apiType: "SQL",
|
const wrapper = shallow(<DeleteDatabaseConfirmationPanel explorer={fakeExplorer} />);
|
||||||
});
|
expect(wrapper.exists(".deleteDatabaseFeedback")).toBe(true);
|
||||||
(deleteDatabase as jest.Mock).mockResolvedValue(undefined);
|
|
||||||
(TelemetryProcessor.trace as jest.Mock).mockReturnValue(undefined);
|
useDatabases.getState().addDatabases([database]);
|
||||||
useDatabases.getState().addDatabases([database]);
|
wrapper.setProps({ explorer: fakeExplorer });
|
||||||
});
|
expect(wrapper.exists(".deleteDatabaseFeedback")).toBe(false);
|
||||||
|
useDatabases.getState().clearDatabases();
|
||||||
beforeEach(() => {
|
});
|
||||||
const props = {
|
|
||||||
explorer: fakeExplorer,
|
it("Should call delete database", () => {
|
||||||
closePanel: (): void => undefined,
|
const wrapper = mount(<DeleteDatabaseConfirmationPanel explorer={fakeExplorer} />);
|
||||||
openNotificationConsole: (): void => undefined,
|
expect(wrapper).toMatchSnapshot();
|
||||||
selectedDatabase: database,
|
expect(wrapper.exists("#confirmDatabaseId")).toBe(true);
|
||||||
};
|
|
||||||
|
wrapper
|
||||||
wrapper = mount(<DeleteDatabaseConfirmationPanel {...props} />);
|
.find("#confirmDatabaseId")
|
||||||
});
|
.hostNodes()
|
||||||
|
.simulate("change", { target: { value: selectedDatabaseId } });
|
||||||
afterAll(() => useDatabases.getState().clearDatabases());
|
expect(wrapper.exists("button")).toBe(true);
|
||||||
|
wrapper.find("button").hostNodes().simulate("submit");
|
||||||
it("Should call delete database", () => {
|
expect(deleteDatabase).toHaveBeenCalledWith(selectedDatabaseId);
|
||||||
expect(wrapper).toMatchSnapshot();
|
wrapper.unmount();
|
||||||
expect(wrapper.exists("#confirmDatabaseId")).toBe(true);
|
});
|
||||||
|
|
||||||
wrapper
|
it("should record feedback", async () => {
|
||||||
.find("#confirmDatabaseId")
|
const wrapper = mount(<DeleteDatabaseConfirmationPanel explorer={fakeExplorer} />);
|
||||||
.hostNodes()
|
expect(wrapper.exists("#confirmDatabaseId")).toBe(true);
|
||||||
.simulate("change", { target: { value: selectedDatabaseId } });
|
wrapper
|
||||||
expect(wrapper.exists("button")).toBe(true);
|
.find("#confirmDatabaseId")
|
||||||
wrapper.find("button").hostNodes().simulate("submit");
|
.hostNodes()
|
||||||
expect(deleteDatabase).toHaveBeenCalledWith(selectedDatabaseId);
|
.simulate("change", { target: { value: selectedDatabaseId } });
|
||||||
wrapper.unmount();
|
|
||||||
});
|
expect(wrapper.exists("#deleteDatabaseFeedbackInput")).toBe(true);
|
||||||
|
const feedbackText = "Test delete Database feedback text";
|
||||||
it("should record feedback", async () => {
|
wrapper
|
||||||
expect(wrapper.exists("#confirmDatabaseId")).toBe(true);
|
.find("#deleteDatabaseFeedbackInput")
|
||||||
wrapper
|
.hostNodes()
|
||||||
.find("#confirmDatabaseId")
|
.simulate("change", { target: { value: feedbackText } });
|
||||||
.hostNodes()
|
|
||||||
.simulate("change", { target: { value: selectedDatabaseId } });
|
expect(wrapper.exists("#sidePanelOkButton")).toBe(true);
|
||||||
|
wrapper.find("#sidePanelOkButton").hostNodes().simulate("submit");
|
||||||
expect(wrapper.exists("#deleteDatabaseFeedbackInput")).toBe(true);
|
expect(deleteDatabase).toHaveBeenCalledWith(selectedDatabaseId);
|
||||||
const feedbackText = "Test delete Database feedback text";
|
|
||||||
wrapper
|
const deleteFeedback = new DeleteFeedback(
|
||||||
.find("#deleteDatabaseFeedbackInput")
|
"testDatabaseAccountId",
|
||||||
.hostNodes()
|
"testDatabaseAccountName",
|
||||||
.simulate("change", { target: { value: feedbackText } });
|
ApiKind.SQL,
|
||||||
|
feedbackText
|
||||||
expect(wrapper.exists("#sidePanelOkButton")).toBe(true);
|
);
|
||||||
wrapper.find("#sidePanelOkButton").hostNodes().simulate("submit");
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
||||||
expect(deleteDatabase).toHaveBeenCalledWith(selectedDatabaseId);
|
expect(TelemetryProcessor.trace).toHaveBeenCalledWith(Action.DeleteDatabase, ActionModifiers.Mark, {
|
||||||
|
message: JSON.stringify(deleteFeedback, Object.getOwnPropertyNames(deleteFeedback)),
|
||||||
const deleteFeedback = new DeleteFeedback(
|
|
||||||
"testDatabaseAccountId",
|
|
||||||
"testDatabaseAccountName",
|
|
||||||
ApiKind.SQL,
|
|
||||||
feedbackText
|
|
||||||
);
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
||||||
expect(TelemetryProcessor.trace).toHaveBeenCalledWith(Action.DeleteDatabase, ActionModifiers.Mark, {
|
|
||||||
message: JSON.stringify(deleteFeedback, Object.getOwnPropertyNames(deleteFeedback)),
|
|
||||||
});
|
|
||||||
wrapper.unmount();
|
|
||||||
});
|
});
|
||||||
|
wrapper.unmount();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,17 +14,16 @@ import { userContext } from "../../UserContext";
|
||||||
import { logConsoleError } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleError } from "../../Utils/NotificationConsoleUtils";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import { useDatabases } from "../useDatabases";
|
import { useDatabases } from "../useDatabases";
|
||||||
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
import { PanelInfoErrorComponent, PanelInfoErrorProps } from "./PanelInfoErrorComponent";
|
import { PanelInfoErrorComponent, PanelInfoErrorProps } from "./PanelInfoErrorComponent";
|
||||||
import { RightPaneForm, RightPaneFormProps } from "./RightPaneForm/RightPaneForm";
|
import { RightPaneForm, RightPaneFormProps } from "./RightPaneForm/RightPaneForm";
|
||||||
|
|
||||||
interface DeleteDatabaseConfirmationPanelProps {
|
interface DeleteDatabaseConfirmationPanelProps {
|
||||||
explorer: Explorer;
|
explorer: Explorer;
|
||||||
selectedDatabase: Database;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DeleteDatabaseConfirmationPanel: FunctionComponent<DeleteDatabaseConfirmationPanelProps> = ({
|
export const DeleteDatabaseConfirmationPanel: FunctionComponent<DeleteDatabaseConfirmationPanelProps> = ({
|
||||||
explorer,
|
explorer,
|
||||||
selectedDatabase,
|
|
||||||
}: DeleteDatabaseConfirmationPanelProps): JSX.Element => {
|
}: DeleteDatabaseConfirmationPanelProps): JSX.Element => {
|
||||||
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
|
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
|
||||||
const isLastNonEmptyDatabase = useDatabases((state) => state.isLastNonEmptyDatabase);
|
const isLastNonEmptyDatabase = useDatabases((state) => state.isLastNonEmptyDatabase);
|
||||||
|
@ -33,6 +32,7 @@ export const DeleteDatabaseConfirmationPanel: FunctionComponent<DeleteDatabaseCo
|
||||||
const [formError, setFormError] = useState<string>("");
|
const [formError, setFormError] = useState<string>("");
|
||||||
const [databaseInput, setDatabaseInput] = useState<string>("");
|
const [databaseInput, setDatabaseInput] = useState<string>("");
|
||||||
const [databaseFeedbackInput, setDatabaseFeedbackInput] = useState<string>("");
|
const [databaseFeedbackInput, setDatabaseFeedbackInput] = useState<string>("");
|
||||||
|
const selectedDatabase: Database = useSelectedNode.getState().findSelectedDatabase();
|
||||||
|
|
||||||
const submit = async (): Promise<void> => {
|
const submit = async (): Promise<void> => {
|
||||||
if (selectedDatabase?.id() && databaseInput !== selectedDatabase.id()) {
|
if (selectedDatabase?.id() && databaseInput !== selectedDatabase.id()) {
|
||||||
|
@ -54,7 +54,7 @@ export const DeleteDatabaseConfirmationPanel: FunctionComponent<DeleteDatabaseCo
|
||||||
closeSidePanel();
|
closeSidePanel();
|
||||||
explorer.refreshAllDatabases();
|
explorer.refreshAllDatabases();
|
||||||
explorer.tabsManager.closeTabsByComparator((tab) => tab.node?.id() === selectedDatabase.id());
|
explorer.tabsManager.closeTabsByComparator((tab) => tab.node?.id() === selectedDatabase.id());
|
||||||
explorer.selectedNode(undefined);
|
useSelectedNode.getState().setSelectedNode(undefined);
|
||||||
selectedDatabase
|
selectedDatabase
|
||||||
.collections()
|
.collections()
|
||||||
.forEach((collection: Collection) =>
|
.forEach((collection: Collection) =>
|
||||||
|
|
|
@ -23,7 +23,6 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
|
||||||
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
||||||
"isNotebookEnabled": [Function],
|
"isNotebookEnabled": [Function],
|
||||||
"isNotebooksEnabledForAccount": [Function],
|
"isNotebooksEnabledForAccount": [Function],
|
||||||
"isResourceTokenCollectionNodeSelected": [Function],
|
|
||||||
"isSchemaEnabled": [Function],
|
"isSchemaEnabled": [Function],
|
||||||
"isShellEnabled": [Function],
|
"isShellEnabled": [Function],
|
||||||
"isSynapseLinkUpdating": [Function],
|
"isSynapseLinkUpdating": [Function],
|
||||||
|
@ -48,8 +47,6 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
"parameters": [Function],
|
"parameters": [Function],
|
||||||
},
|
},
|
||||||
"selectedDatabaseId": [Function],
|
|
||||||
"selectedNode": [Function],
|
|
||||||
"sparkClusterConnectionInfo": [Function],
|
"sparkClusterConnectionInfo": [Function],
|
||||||
"tabsManager": TabsManager {
|
"tabsManager": TabsManager {
|
||||||
"activeTab": [Function],
|
"activeTab": [Function],
|
||||||
|
|
|
@ -1,17 +1,10 @@
|
||||||
import { shallow } from "enzyme";
|
import { shallow } from "enzyme";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Explorer from "../../Explorer";
|
|
||||||
import { LoadQueryPane } from "./LoadQueryPane";
|
import { LoadQueryPane } from "./LoadQueryPane";
|
||||||
|
|
||||||
describe("Load Query Pane", () => {
|
describe("Load Query Pane", () => {
|
||||||
it("should render Default properly", () => {
|
it("should render Default properly", () => {
|
||||||
const fakeExplorer = {} as Explorer;
|
const wrapper = shallow(<LoadQueryPane />);
|
||||||
const props = {
|
|
||||||
explorer: fakeExplorer,
|
|
||||||
closePanel: (): void => undefined,
|
|
||||||
};
|
|
||||||
|
|
||||||
const wrapper = shallow(<LoadQueryPane {...props} />);
|
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,14 +7,10 @@ import { Collection } from "../../../Contracts/ViewModels";
|
||||||
import { useSidePanel } from "../../../hooks/useSidePanel";
|
import { useSidePanel } from "../../../hooks/useSidePanel";
|
||||||
import { userContext } from "../../../UserContext";
|
import { userContext } from "../../../UserContext";
|
||||||
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../../Utils/NotificationConsoleUtils";
|
import { logConsoleError, logConsoleInfo, logConsoleProgress } from "../../../Utils/NotificationConsoleUtils";
|
||||||
import Explorer from "../../Explorer";
|
import { useSelectedNode } from "../../useSelectedNode";
|
||||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||||
|
|
||||||
interface LoadQueryPaneProps {
|
export const LoadQueryPane: FunctionComponent = (): JSX.Element => {
|
||||||
explorer: Explorer;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const LoadQueryPane: FunctionComponent<LoadQueryPaneProps> = ({ explorer }: LoadQueryPaneProps): JSX.Element => {
|
|
||||||
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
|
const closeSidePanel = useSidePanel((state) => state.closeSidePanel);
|
||||||
const [isLoading, { setTrue: setLoadingTrue, setFalse: setLoadingFalse }] = useBoolean(false);
|
const [isLoading, { setTrue: setLoadingTrue, setFalse: setLoadingFalse }] = useBoolean(false);
|
||||||
const [formError, setFormError] = useState<string>("");
|
const [formError, setFormError] = useState<string>("");
|
||||||
|
@ -58,7 +54,7 @@ export const LoadQueryPane: FunctionComponent<LoadQueryPaneProps> = ({ explorer
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadQueryFromFile = async (file: File): Promise<void> => {
|
const loadQueryFromFile = async (file: File): Promise<void> => {
|
||||||
const selectedCollection: Collection = explorer?.findSelectedCollection();
|
const selectedCollection: Collection = useSelectedNode.getState().findSelectedCollection();
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
let fileData: string;
|
let fileData: string;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
|
|
@ -13,7 +13,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
|
||||||
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
"isFixedCollectionWithSharedThroughputSupported": [Function],
|
||||||
"isNotebookEnabled": [Function],
|
"isNotebookEnabled": [Function],
|
||||||
"isNotebooksEnabledForAccount": [Function],
|
"isNotebooksEnabledForAccount": [Function],
|
||||||
"isResourceTokenCollectionNodeSelected": [Function],
|
|
||||||
"isSchemaEnabled": [Function],
|
"isSchemaEnabled": [Function],
|
||||||
"isShellEnabled": [Function],
|
"isShellEnabled": [Function],
|
||||||
"isSynapseLinkUpdating": [Function],
|
"isSynapseLinkUpdating": [Function],
|
||||||
|
@ -38,8 +37,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
"parameters": [Function],
|
"parameters": [Function],
|
||||||
},
|
},
|
||||||
"selectedDatabaseId": [Function],
|
|
||||||
"selectedNode": [Function],
|
|
||||||
"sparkClusterConnectionInfo": [Function],
|
"sparkClusterConnectionInfo": [Function],
|
||||||
"tabsManager": TabsManager {
|
"tabsManager": TabsManager {
|
||||||
"activeTab": [Function],
|
"activeTab": [Function],
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
import { shallow } from "enzyme";
|
import { shallow } from "enzyme";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Explorer from "../../Explorer";
|
|
||||||
import { UploadItemsPane } from "./UploadItemsPane";
|
import { UploadItemsPane } from "./UploadItemsPane";
|
||||||
const props = {
|
|
||||||
explorer: new Explorer(),
|
|
||||||
};
|
|
||||||
describe("Upload Items Pane", () => {
|
describe("Upload Items Pane", () => {
|
||||||
it("should render Default properly", () => {
|
it("should render Default properly", () => {
|
||||||
const wrapper = shallow(<UploadItemsPane {...props} />);
|
const wrapper = shallow(<UploadItemsPane />);
|
||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,15 +3,11 @@ import React, { ChangeEvent, FunctionComponent, useState } from "react";
|
||||||
import { Upload } from "../../../Common/Upload/Upload";
|
import { Upload } from "../../../Common/Upload/Upload";
|
||||||
import { UploadDetailsRecord } from "../../../Contracts/ViewModels";
|
import { UploadDetailsRecord } from "../../../Contracts/ViewModels";
|
||||||
import { logConsoleError } from "../../../Utils/NotificationConsoleUtils";
|
import { logConsoleError } from "../../../Utils/NotificationConsoleUtils";
|
||||||
import Explorer from "../../Explorer";
|
|
||||||
import { getErrorMessage } from "../../Tables/Utilities";
|
import { getErrorMessage } from "../../Tables/Utilities";
|
||||||
|
import { useSelectedNode } from "../../useSelectedNode";
|
||||||
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
|
||||||
|
|
||||||
export interface UploadItemsPaneProps {
|
export const UploadItemsPane: FunctionComponent = () => {
|
||||||
explorer: Explorer;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const UploadItemsPane: FunctionComponent<UploadItemsPaneProps> = ({ explorer }: UploadItemsPaneProps) => {
|
|
||||||
const [files, setFiles] = useState<FileList>();
|
const [files, setFiles] = useState<FileList>();
|
||||||
const [uploadFileData, setUploadFileData] = useState<UploadDetailsRecord[]>([]);
|
const [uploadFileData, setUploadFileData] = useState<UploadDetailsRecord[]>([]);
|
||||||
const [formError, setFormError] = useState<string>("");
|
const [formError, setFormError] = useState<string>("");
|
||||||
|
@ -25,7 +21,7 @@ export const UploadItemsPane: FunctionComponent<UploadItemsPaneProps> = ({ explo
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedCollection = explorer.findSelectedCollection();
|
const selectedCollection = useSelectedNode.getState().findSelectedCollection();
|
||||||
setIsExecuting(true);
|
setIsExecuting(true);
|
||||||
|
|
||||||
selectedCollection
|
selectedCollection
|
||||||
|
|
|
@ -1,26 +1,16 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Delete Database Confirmation Pane submit() Should call delete database 1`] = `
|
exports[`Delete Database Confirmation Pane Should call delete database 1`] = `
|
||||||
<DeleteDatabaseConfirmationPanel
|
<DeleteDatabaseConfirmationPanel
|
||||||
closePanel={[Function]}
|
|
||||||
explorer={
|
explorer={
|
||||||
Object {
|
Object {
|
||||||
"isSelectedDatabaseShared": [Function],
|
|
||||||
"refreshAllDatabases": [Function],
|
"refreshAllDatabases": [Function],
|
||||||
"selectedNode": [Function],
|
|
||||||
"tabsManager": TabsManager {
|
"tabsManager": TabsManager {
|
||||||
"activeTab": [Function],
|
"activeTab": [Function],
|
||||||
"openedTabs": [Function],
|
"openedTabs": [Function],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
openNotificationConsole={[Function]}
|
|
||||||
selectedDatabase={
|
|
||||||
Object {
|
|
||||||
"collections": [Function],
|
|
||||||
"id": [Function],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<RightPaneForm
|
<RightPaneForm
|
||||||
formError=""
|
formError=""
|
||||||
|
|
|
@ -7,7 +7,6 @@ jest.mock("../Explorer");
|
||||||
|
|
||||||
const createExplorer = () => {
|
const createExplorer = () => {
|
||||||
const mock = new Explorer();
|
const mock = new Explorer();
|
||||||
mock.selectedNode = ko.observable();
|
|
||||||
mock.isNotebookEnabled = ko.observable(false);
|
mock.isNotebookEnabled = ko.observable(false);
|
||||||
mock.tabsManager = new TabsManager();
|
mock.tabsManager = new TabsManager();
|
||||||
return mock as jest.Mocked<Explorer>;
|
return mock as jest.Mocked<Explorer>;
|
||||||
|
|
|
@ -23,6 +23,7 @@ import { DataSamplesUtil } from "../DataSamples/DataSamplesUtil";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import * as MostRecentActivity from "../MostRecentActivity/MostRecentActivity";
|
import * as MostRecentActivity from "../MostRecentActivity/MostRecentActivity";
|
||||||
import { useDatabases } from "../useDatabases";
|
import { useDatabases } from "../useDatabases";
|
||||||
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
|
|
||||||
export interface SplashScreenItem {
|
export interface SplashScreenItem {
|
||||||
iconSrc: string;
|
iconSrc: string;
|
||||||
|
@ -60,7 +61,7 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
this.subscriptions.push(
|
this.subscriptions.push(
|
||||||
this.container.selectedNode.subscribe(() => this.setState({})),
|
{ dispose: useSelectedNode.subscribe(() => this.setState({})) },
|
||||||
this.container.isNotebookEnabled.subscribe(() => this.setState({}))
|
this.container.isNotebookEnabled.subscribe(() => this.setState({}))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -228,12 +229,12 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.container.isDatabaseNodeOrNoneSelected()) {
|
if (!useSelectedNode.getState().isDatabaseNodeOrNoneSelected()) {
|
||||||
if (userContext.apiType === "SQL" || userContext.apiType === "Gremlin") {
|
if (userContext.apiType === "SQL" || userContext.apiType === "Gremlin") {
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: NewQueryIcon,
|
iconSrc: NewQueryIcon,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = this.container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||||
selectedCollection && selectedCollection.onNewQueryClick(selectedCollection, null);
|
selectedCollection && selectedCollection.onNewQueryClick(selectedCollection, null);
|
||||||
},
|
},
|
||||||
title: "New SQL Query",
|
title: "New SQL Query",
|
||||||
|
@ -243,7 +244,7 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||||
items.push({
|
items.push({
|
||||||
iconSrc: NewQueryIcon,
|
iconSrc: NewQueryIcon,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = this.container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||||
selectedCollection && selectedCollection.onNewMongoQueryClick(selectedCollection, null);
|
selectedCollection && selectedCollection.onNewMongoQueryClick(selectedCollection, null);
|
||||||
},
|
},
|
||||||
title: "New Query",
|
title: "New Query",
|
||||||
|
@ -266,20 +267,14 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||||
title: "New Stored Procedure",
|
title: "New Stored Procedure",
|
||||||
description: null,
|
description: null,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = this.container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||||
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection, null);
|
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection, null);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scale & Settings */
|
/* Scale & Settings */
|
||||||
let isShared = false;
|
const isShared = useSelectedNode.getState().findSelectedDatabase()?.isDatabaseShared();
|
||||||
if (this.container.isDatabaseNodeSelected()) {
|
|
||||||
isShared = this.container.findSelectedDatabase().isDatabaseShared();
|
|
||||||
} else if (this.container.isNodeKindSelected("Collection")) {
|
|
||||||
const database: ViewModels.Database = this.container.findSelectedCollection().getDatabase();
|
|
||||||
isShared = database && database.isDatabaseShared();
|
|
||||||
}
|
|
||||||
|
|
||||||
const label = isShared ? "Settings" : "Scale & Settings";
|
const label = isShared ? "Settings" : "Scale & Settings";
|
||||||
items.push({
|
items.push({
|
||||||
|
@ -287,7 +282,7 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||||
title: label,
|
title: label,
|
||||||
description: null,
|
description: null,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = this.container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||||
selectedCollection && selectedCollection.onSettingsClick();
|
selectedCollection && selectedCollection.onSettingsClick();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -28,6 +28,7 @@ import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandBu
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import { AccessibleVerticalList } from "../Tree/AccessibleVerticalList";
|
import { AccessibleVerticalList } from "../Tree/AccessibleVerticalList";
|
||||||
import DocumentId from "../Tree/DocumentId";
|
import DocumentId from "../Tree/DocumentId";
|
||||||
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
import template from "./DocumentsTab.html";
|
import template from "./DocumentsTab.html";
|
||||||
import TabsBase from "./TabsBase";
|
import TabsBase from "./TabsBase";
|
||||||
|
|
||||||
|
@ -911,13 +912,13 @@ export default class DocumentsTab extends TabsBase {
|
||||||
iconSrc: UploadIcon,
|
iconSrc: UploadIcon,
|
||||||
iconAlt: label,
|
iconAlt: label,
|
||||||
onCommandClick: () => {
|
onCommandClick: () => {
|
||||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
|
||||||
selectedCollection && container.openUploadItemsPanePane();
|
selectedCollection && container.openUploadItemsPanePane();
|
||||||
},
|
},
|
||||||
commandButtonLabel: label,
|
commandButtonLabel: label,
|
||||||
ariaLabel: label,
|
ariaLabel: label,
|
||||||
hasPopup: true,
|
hasPopup: true,
|
||||||
disabled: container.isDatabaseNodeOrNoneSelected(),
|
disabled: useSelectedNode.getState().isDatabaseNodeOrNoneSelected(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { EditorReact } from "../../Controls/Editor/EditorReact";
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
import { useCommandBar } from "../../Menus/CommandBar/CommandBarComponentAdapter";
|
import { useCommandBar } from "../../Menus/CommandBar/CommandBarComponentAdapter";
|
||||||
import StoredProcedure from "../../Tree/StoredProcedure";
|
import StoredProcedure from "../../Tree/StoredProcedure";
|
||||||
|
import { useSelectedNode } from "../../useSelectedNode";
|
||||||
import ScriptTabBase from "../ScriptTabBase";
|
import ScriptTabBase from "../ScriptTabBase";
|
||||||
|
|
||||||
export interface IStorProcTabComponentAccessor {
|
export interface IStorProcTabComponentAccessor {
|
||||||
|
@ -298,12 +299,13 @@ export default class StoredProcedureTabComponent extends React.Component<
|
||||||
}
|
}
|
||||||
|
|
||||||
const database: ViewModels.Database = this.props.collectionBase.getDatabase();
|
const database: ViewModels.Database = this.props.collectionBase.getDatabase();
|
||||||
|
const setSelectedNode = useSelectedNode.getState().setSelectedNode;
|
||||||
if (!database.isDatabaseExpanded()) {
|
if (!database.isDatabaseExpanded()) {
|
||||||
this.props.collectionBase.container.selectedNode(database);
|
setSelectedNode(database);
|
||||||
} else if (!this.props.collectionBase.isCollectionExpanded() || !this.collection.isStoredProceduresExpanded()) {
|
} else if (!this.props.collectionBase.isCollectionExpanded() || !this.collection.isStoredProceduresExpanded()) {
|
||||||
this.props.collectionBase.container.selectedNode(this.props.collectionBase);
|
setSelectedNode(this.props.collectionBase);
|
||||||
} else {
|
} else {
|
||||||
this.props.collectionBase.container.selectedNode(this.node);
|
setSelectedNode(this.node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
|
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import { useCommandBar } from "../Menus/CommandBar/CommandBarComponentAdapter";
|
import { useCommandBar } from "../Menus/CommandBar/CommandBarComponentAdapter";
|
||||||
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
import { WaitsForTemplateViewModel } from "../WaitsForTemplateViewModel";
|
import { WaitsForTemplateViewModel } from "../WaitsForTemplateViewModel";
|
||||||
import { TabsManager } from "./TabsManager";
|
import { TabsManager } from "./TabsManager";
|
||||||
// TODO: Use specific actions for logging telemetry data
|
// TODO: Use specific actions for logging telemetry data
|
||||||
|
@ -74,12 +75,13 @@ export default class TabsBase extends WaitsForTemplateViewModel {
|
||||||
|
|
||||||
protected updateSelectedNode(): void {
|
protected updateSelectedNode(): void {
|
||||||
const relatedDatabase = (this.collection && this.collection.getDatabase()) || this.database;
|
const relatedDatabase = (this.collection && this.collection.getDatabase()) || this.database;
|
||||||
|
const setSelectedNode = useSelectedNode.getState().setSelectedNode;
|
||||||
if (relatedDatabase && !relatedDatabase.isDatabaseExpanded()) {
|
if (relatedDatabase && !relatedDatabase.isDatabaseExpanded()) {
|
||||||
this.getContainer().selectedNode(relatedDatabase);
|
setSelectedNode(relatedDatabase);
|
||||||
} else if (this.collection && !this.collection.isCollectionExpanded()) {
|
} else if (this.collection && !this.collection.isCollectionExpanded()) {
|
||||||
this.getContainer().selectedNode(this.collection);
|
setSelectedNode(this.collection);
|
||||||
} else {
|
} else {
|
||||||
this.getContainer().selectedNode(this.node);
|
setSelectedNode(this.node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,10 +31,6 @@ describe("Collection", () => {
|
||||||
function generateMockCollectionWithDataModel(data: DataModels.Collection): Collection {
|
function generateMockCollectionWithDataModel(data: DataModels.Collection): Collection {
|
||||||
const mockContainer = {} as Explorer;
|
const mockContainer = {} as Explorer;
|
||||||
|
|
||||||
mockContainer.isDatabaseNodeOrNoneSelected = () => {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
return generateCollection(mockContainer, "abc", data, {} as DataModels.Offer);
|
return generateCollection(mockContainer, "abc", data, {} as DataModels.Offer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ import { NewQueryTab } from "../Tabs/QueryTab/QueryTab";
|
||||||
import QueryTablesTab from "../Tabs/QueryTablesTab";
|
import QueryTablesTab from "../Tabs/QueryTablesTab";
|
||||||
import { CollectionSettingsTabV2 } from "../Tabs/SettingsTabV2";
|
import { CollectionSettingsTabV2 } from "../Tabs/SettingsTabV2";
|
||||||
import { useDatabases } from "../useDatabases";
|
import { useDatabases } from "../useDatabases";
|
||||||
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
import ConflictId from "./ConflictId";
|
import ConflictId from "./ConflictId";
|
||||||
import DocumentId from "./DocumentId";
|
import DocumentId from "./DocumentId";
|
||||||
import StoredProcedure from "./StoredProcedure";
|
import StoredProcedure from "./StoredProcedure";
|
||||||
|
@ -223,7 +224,7 @@ export default class Collection implements ViewModels.Collection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public expandCollapseCollection() {
|
public expandCollapseCollection() {
|
||||||
this.container.selectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
||||||
description: "Collection node",
|
description: "Collection node",
|
||||||
|
|
||||||
|
@ -276,7 +277,7 @@ export default class Collection implements ViewModels.Collection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public onDocumentDBDocumentsClick() {
|
public onDocumentDBDocumentsClick() {
|
||||||
this.container.selectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
this.selectedSubnodeKind(ViewModels.CollectionTabKind.Documents);
|
this.selectedSubnodeKind(ViewModels.CollectionTabKind.Documents);
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
||||||
description: "Documents node",
|
description: "Documents node",
|
||||||
|
@ -321,7 +322,7 @@ export default class Collection implements ViewModels.Collection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public onConflictsClick() {
|
public onConflictsClick() {
|
||||||
this.container.selectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
this.selectedSubnodeKind(ViewModels.CollectionTabKind.Conflicts);
|
this.selectedSubnodeKind(ViewModels.CollectionTabKind.Conflicts);
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
||||||
description: "Conflicts node",
|
description: "Conflicts node",
|
||||||
|
@ -366,7 +367,7 @@ export default class Collection implements ViewModels.Collection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public onTableEntitiesClick() {
|
public onTableEntitiesClick() {
|
||||||
this.container.selectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
this.selectedSubnodeKind(ViewModels.CollectionTabKind.QueryTables);
|
this.selectedSubnodeKind(ViewModels.CollectionTabKind.QueryTables);
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
||||||
description: "Entities node",
|
description: "Entities node",
|
||||||
|
@ -419,7 +420,7 @@ export default class Collection implements ViewModels.Collection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public onGraphDocumentsClick() {
|
public onGraphDocumentsClick() {
|
||||||
this.container.selectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
this.selectedSubnodeKind(ViewModels.CollectionTabKind.Graph);
|
this.selectedSubnodeKind(ViewModels.CollectionTabKind.Graph);
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
||||||
description: "Documents node",
|
description: "Documents node",
|
||||||
|
@ -470,7 +471,7 @@ export default class Collection implements ViewModels.Collection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public onMongoDBDocumentsClick = () => {
|
public onMongoDBDocumentsClick = () => {
|
||||||
this.container.selectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
this.selectedSubnodeKind(ViewModels.CollectionTabKind.Documents);
|
this.selectedSubnodeKind(ViewModels.CollectionTabKind.Documents);
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
||||||
description: "Documents node",
|
description: "Documents node",
|
||||||
|
@ -514,7 +515,7 @@ export default class Collection implements ViewModels.Collection {
|
||||||
};
|
};
|
||||||
|
|
||||||
public onSchemaAnalyzerClick = async () => {
|
public onSchemaAnalyzerClick = async () => {
|
||||||
this.container.selectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
this.selectedSubnodeKind(ViewModels.CollectionTabKind.SchemaAnalyzer);
|
this.selectedSubnodeKind(ViewModels.CollectionTabKind.SchemaAnalyzer);
|
||||||
const SchemaAnalyzerTab = await (await import("../Tabs/SchemaAnalyzerTab")).default;
|
const SchemaAnalyzerTab = await (await import("../Tabs/SchemaAnalyzerTab")).default;
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
||||||
|
@ -557,7 +558,7 @@ export default class Collection implements ViewModels.Collection {
|
||||||
};
|
};
|
||||||
|
|
||||||
public onSettingsClick = async (): Promise<void> => {
|
public onSettingsClick = async (): Promise<void> => {
|
||||||
this.container.selectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
this.selectedSubnodeKind(ViewModels.CollectionTabKind.Settings);
|
this.selectedSubnodeKind(ViewModels.CollectionTabKind.Settings);
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
||||||
description: "Settings node",
|
description: "Settings node",
|
||||||
|
@ -744,21 +745,21 @@ export default class Collection implements ViewModels.Collection {
|
||||||
|
|
||||||
public createStoredProcedureNode(data: StoredProcedureDefinition & Resource): StoredProcedure {
|
public createStoredProcedureNode(data: StoredProcedureDefinition & Resource): StoredProcedure {
|
||||||
const node = new StoredProcedure(this.container, this, data);
|
const node = new StoredProcedure(this.container, this, data);
|
||||||
this.container.selectedNode(node);
|
useSelectedNode.getState().setSelectedNode(node);
|
||||||
this.children.push(node);
|
this.children.push(node);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public createUserDefinedFunctionNode(data: UserDefinedFunctionDefinition & Resource): UserDefinedFunction {
|
public createUserDefinedFunctionNode(data: UserDefinedFunctionDefinition & Resource): UserDefinedFunction {
|
||||||
const node = new UserDefinedFunction(this.container, this, data);
|
const node = new UserDefinedFunction(this.container, this, data);
|
||||||
this.container.selectedNode(node);
|
useSelectedNode.getState().setSelectedNode(node);
|
||||||
this.children.push(node);
|
this.children.push(node);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public createTriggerNode(data: TriggerDefinition & Resource): Trigger {
|
public createTriggerNode(data: TriggerDefinition & Resource): Trigger {
|
||||||
const node = new Trigger(this.container, this, data);
|
const node = new Trigger(this.container, this, data);
|
||||||
this.container.selectedNode(node);
|
useSelectedNode.getState().setSelectedNode(node);
|
||||||
this.children.push(node);
|
this.children.push(node);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { logConsoleError } from "../../Utils/NotificationConsoleUtils";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import { DatabaseSettingsTabV2 } from "../Tabs/SettingsTabV2";
|
import { DatabaseSettingsTabV2 } from "../Tabs/SettingsTabV2";
|
||||||
import { useDatabases } from "../useDatabases";
|
import { useDatabases } from "../useDatabases";
|
||||||
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
import Collection from "./Collection";
|
import Collection from "./Collection";
|
||||||
|
|
||||||
export default class Database implements ViewModels.Database {
|
export default class Database implements ViewModels.Database {
|
||||||
|
@ -53,7 +54,7 @@ export default class Database implements ViewModels.Database {
|
||||||
}
|
}
|
||||||
|
|
||||||
public onSettingsClick = () => {
|
public onSettingsClick = () => {
|
||||||
this.container.selectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
this.selectedSubnodeKind(ViewModels.CollectionTabKind.DatabaseSettings);
|
this.selectedSubnodeKind(ViewModels.CollectionTabKind.DatabaseSettings);
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
||||||
description: "Settings node",
|
description: "Settings node",
|
||||||
|
@ -121,25 +122,6 @@ export default class Database implements ViewModels.Database {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public isDatabaseNodeSelected(): boolean {
|
|
||||||
return (
|
|
||||||
!this.isDatabaseExpanded() &&
|
|
||||||
this.container.selectedNode &&
|
|
||||||
this.container.selectedNode() &&
|
|
||||||
this.container.selectedNode().nodeKind === "Database" &&
|
|
||||||
this.container.selectedNode().id() === this.id()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public selectDatabase() {
|
|
||||||
this.container.selectedNode(this);
|
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
|
||||||
description: "Database node",
|
|
||||||
|
|
||||||
dataExplorerArea: Constants.Areas.ResourceTree,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public async expandDatabase() {
|
public async expandDatabase() {
|
||||||
if (this.isDatabaseExpanded()) {
|
if (this.isDatabaseExpanded()) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import DocumentsTab from "../Tabs/DocumentsTab";
|
||||||
import { NewQueryTab } from "../Tabs/QueryTab/QueryTab";
|
import { NewQueryTab } from "../Tabs/QueryTab/QueryTab";
|
||||||
import TabsBase from "../Tabs/TabsBase";
|
import TabsBase from "../Tabs/TabsBase";
|
||||||
import { useDatabases } from "../useDatabases";
|
import { useDatabases } from "../useDatabases";
|
||||||
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
import DocumentId from "./DocumentId";
|
import DocumentId from "./DocumentId";
|
||||||
|
|
||||||
export default class ResourceTokenCollection implements ViewModels.CollectionBase {
|
export default class ResourceTokenCollection implements ViewModels.CollectionBase {
|
||||||
|
@ -104,7 +105,7 @@ export default class ResourceTokenCollection implements ViewModels.CollectionBas
|
||||||
}
|
}
|
||||||
|
|
||||||
public onDocumentDBDocumentsClick() {
|
public onDocumentDBDocumentsClick() {
|
||||||
this.container.selectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
this.selectedSubnodeKind(ViewModels.CollectionTabKind.Documents);
|
this.selectedSubnodeKind(ViewModels.CollectionTabKind.Documents);
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
||||||
description: "Documents node",
|
description: "Documents node",
|
||||||
|
|
|
@ -1,114 +1,101 @@
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
import Explorer from "../Explorer";
|
|
||||||
import TabsBase from "../Tabs/TabsBase";
|
import TabsBase from "../Tabs/TabsBase";
|
||||||
import { ResourceTreeAdapter } from "./ResourceTreeAdapter";
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
|
|
||||||
describe("ResourceTreeAdapter", () => {
|
describe("useSelectedNode.getState()", () => {
|
||||||
const mockContainer = (): Explorer =>
|
const mockTab = {
|
||||||
(({
|
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||||
selectedNode: ko.observable<ViewModels.TreeNode>({
|
} as TabsBase;
|
||||||
nodeKind: "nodeKind",
|
|
||||||
rid: "rid",
|
|
||||||
id: ko.observable<string>("id"),
|
|
||||||
}),
|
|
||||||
tabsManager: {
|
|
||||||
activeTab: ko.observable<TabsBase>({
|
|
||||||
tabKind: ViewModels.CollectionTabKind.Documents,
|
|
||||||
} as TabsBase),
|
|
||||||
},
|
|
||||||
isNotebookEnabled: ko.observable<boolean>(true),
|
|
||||||
databases: ko.observable<ViewModels.Database[]>([]),
|
|
||||||
} as unknown) as Explorer);
|
|
||||||
|
|
||||||
// TODO isDataNodeSelected needs a better design and refactor, but for now, we protect some of the code paths
|
// TODO isDataNodeSelected needs a better design and refactor, but for now, we protect some of the code paths
|
||||||
describe("isDataNodeSelected", () => {
|
describe("isDataNodeSelected", () => {
|
||||||
|
afterEach(() => useSelectedNode.getState().setSelectedNode(undefined));
|
||||||
it("it should not select if no selected node", () => {
|
it("it should not select if no selected node", () => {
|
||||||
const explorer = mockContainer();
|
const isDataNodeSelected = useSelectedNode.getState().isDataNodeSelected(mockTab, "foo", "bar", undefined);
|
||||||
explorer.selectedNode(undefined);
|
|
||||||
const resourceTreeAdapter = new ResourceTreeAdapter(explorer);
|
|
||||||
const isDataNodeSelected = resourceTreeAdapter.isDataNodeSelected("foo", "bar", undefined);
|
|
||||||
expect(isDataNodeSelected).toBeFalsy();
|
expect(isDataNodeSelected).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("it should not select incorrect subnodekinds", () => {
|
it("it should not select incorrect subnodekinds", () => {
|
||||||
const resourceTreeAdapter = new ResourceTreeAdapter(mockContainer());
|
useSelectedNode.getState().setSelectedNode({
|
||||||
const isDataNodeSelected = resourceTreeAdapter.isDataNodeSelected("foo", "bar", undefined);
|
nodeKind: "nodeKind",
|
||||||
|
rid: "rid",
|
||||||
|
id: ko.observable<string>("id"),
|
||||||
|
});
|
||||||
|
const isDataNodeSelected = useSelectedNode.getState().isDataNodeSelected(mockTab, "foo", "bar", undefined);
|
||||||
expect(isDataNodeSelected).toBeFalsy();
|
expect(isDataNodeSelected).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("it should not select if no active tab", () => {
|
it("it should not select if no active tab", () => {
|
||||||
const explorer = mockContainer();
|
useSelectedNode.getState().setSelectedNode({
|
||||||
explorer.tabsManager.activeTab(undefined);
|
nodeKind: "nodeKind",
|
||||||
const resourceTreeAdapter = new ResourceTreeAdapter(explorer);
|
rid: "rid",
|
||||||
const isDataNodeSelected = resourceTreeAdapter.isDataNodeSelected("foo", "bar", undefined);
|
id: ko.observable<string>("id"),
|
||||||
|
});
|
||||||
|
const isDataNodeSelected = useSelectedNode.getState().isDataNodeSelected(undefined, "foo", "bar", undefined);
|
||||||
expect(isDataNodeSelected).toBeFalsy();
|
expect(isDataNodeSelected).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should select if correct database node regardless of subnodekinds", () => {
|
it("should select if correct database node regardless of subnodekinds", () => {
|
||||||
const subNodeKind = ViewModels.CollectionTabKind.Documents;
|
const subNodeKind = ViewModels.CollectionTabKind.Documents;
|
||||||
const explorer = mockContainer();
|
useSelectedNode.getState().setSelectedNode({
|
||||||
explorer.selectedNode(({
|
|
||||||
nodeKind: "Database",
|
nodeKind: "Database",
|
||||||
rid: "dbrid",
|
rid: "dbrid",
|
||||||
id: ko.observable<string>("dbid"),
|
id: ko.observable<string>("dbid"),
|
||||||
selectedSubnodeKind: ko.observable<ViewModels.CollectionTabKind>(subNodeKind),
|
selectedSubnodeKind: ko.observable<ViewModels.CollectionTabKind>(subNodeKind),
|
||||||
} as unknown) as ViewModels.TreeNode);
|
} as ViewModels.TreeNode);
|
||||||
const resourceTreeAdapter = new ResourceTreeAdapter(explorer);
|
const isDataNodeSelected = useSelectedNode
|
||||||
const isDataNodeSelected = resourceTreeAdapter.isDataNodeSelected("dbid", undefined, [
|
.getState()
|
||||||
ViewModels.CollectionTabKind.Documents,
|
.isDataNodeSelected(mockTab, "dbid", undefined, [ViewModels.CollectionTabKind.Documents]);
|
||||||
]);
|
|
||||||
expect(isDataNodeSelected).toBeTruthy();
|
expect(isDataNodeSelected).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should select correct collection node (documents or graph node)", () => {
|
it("should select correct collection node (documents or graph node)", () => {
|
||||||
let subNodeKind = ViewModels.CollectionTabKind.Documents;
|
let subNodeKind = ViewModels.CollectionTabKind.Documents;
|
||||||
const explorer = mockContainer();
|
let activeTab = {
|
||||||
explorer.tabsManager.activeTab({
|
|
||||||
tabKind: subNodeKind,
|
tabKind: subNodeKind,
|
||||||
} as TabsBase);
|
} as TabsBase;
|
||||||
explorer.selectedNode(({
|
useSelectedNode.getState().setSelectedNode({
|
||||||
nodeKind: "Collection",
|
nodeKind: "Collection",
|
||||||
rid: "collrid",
|
rid: "collrid",
|
||||||
databaseId: "dbid",
|
databaseId: "dbid",
|
||||||
id: ko.observable<string>("collid"),
|
id: ko.observable<string>("collid"),
|
||||||
selectedSubnodeKind: ko.observable<ViewModels.CollectionTabKind>(subNodeKind),
|
selectedSubnodeKind: ko.observable<ViewModels.CollectionTabKind>(subNodeKind),
|
||||||
} as unknown) as ViewModels.TreeNode);
|
} as ViewModels.TreeNode);
|
||||||
const resourceTreeAdapter = new ResourceTreeAdapter(explorer);
|
let isDataNodeSelected = useSelectedNode
|
||||||
let isDataNodeSelected = resourceTreeAdapter.isDataNodeSelected("dbid", "collid", [subNodeKind]);
|
.getState()
|
||||||
|
.isDataNodeSelected(activeTab, "dbid", "collid", [subNodeKind]);
|
||||||
expect(isDataNodeSelected).toBeTruthy();
|
expect(isDataNodeSelected).toBeTruthy();
|
||||||
|
|
||||||
subNodeKind = ViewModels.CollectionTabKind.Graph;
|
subNodeKind = ViewModels.CollectionTabKind.Graph;
|
||||||
explorer.tabsManager.activeTab({
|
activeTab = {
|
||||||
tabKind: subNodeKind,
|
tabKind: subNodeKind,
|
||||||
} as TabsBase);
|
} as TabsBase;
|
||||||
explorer.selectedNode(({
|
useSelectedNode.getState().setSelectedNode({
|
||||||
nodeKind: "Collection",
|
nodeKind: "Collection",
|
||||||
rid: "collrid",
|
rid: "collrid",
|
||||||
databaseId: "dbid",
|
databaseId: "dbid",
|
||||||
id: ko.observable<string>("collid"),
|
id: ko.observable<string>("collid"),
|
||||||
selectedSubnodeKind: ko.observable<ViewModels.CollectionTabKind>(subNodeKind),
|
selectedSubnodeKind: ko.observable<ViewModels.CollectionTabKind>(subNodeKind),
|
||||||
} as unknown) as ViewModels.TreeNode);
|
} as ViewModels.TreeNode);
|
||||||
isDataNodeSelected = resourceTreeAdapter.isDataNodeSelected("dbid", "collid", [subNodeKind]);
|
isDataNodeSelected = useSelectedNode.getState().isDataNodeSelected(activeTab, "dbid", "collid", [subNodeKind]);
|
||||||
expect(isDataNodeSelected).toBeTruthy();
|
expect(isDataNodeSelected).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not select incorrect collection node (e.g. Settings)", () => {
|
it("should not select incorrect collection node (e.g. Settings)", () => {
|
||||||
const explorer = mockContainer();
|
useSelectedNode.getState().setSelectedNode({
|
||||||
explorer.selectedNode(({
|
|
||||||
nodeKind: "Collection",
|
nodeKind: "Collection",
|
||||||
rid: "collrid",
|
rid: "collrid",
|
||||||
databaseId: "dbid",
|
databaseId: "dbid",
|
||||||
id: ko.observable<string>("collid"),
|
id: ko.observable<string>("collid"),
|
||||||
selectedSubnodeKind: ko.observable<ViewModels.CollectionTabKind>(ViewModels.CollectionTabKind.Documents),
|
selectedSubnodeKind: ko.observable<ViewModels.CollectionTabKind>(ViewModels.CollectionTabKind.Documents),
|
||||||
} as unknown) as ViewModels.TreeNode);
|
} as ViewModels.TreeNode);
|
||||||
explorer.tabsManager.activeTab({
|
const activeTab = {
|
||||||
tabKind: ViewModels.CollectionTabKind.Documents,
|
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||||
} as TabsBase);
|
} as TabsBase;
|
||||||
const resourceTreeAdapter = new ResourceTreeAdapter(explorer);
|
const isDataNodeSelected = useSelectedNode
|
||||||
const isDataNodeSelected = resourceTreeAdapter.isDataNodeSelected("dbid", "collid", [
|
.getState()
|
||||||
ViewModels.CollectionTabKind.Settings,
|
.isDataNodeSelected(activeTab, "dbid", "collid", [ViewModels.CollectionTabKind.Settings]);
|
||||||
]);
|
|
||||||
expect(isDataNodeSelected).toBeFalsy();
|
expect(isDataNodeSelected).toBeFalsy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { shallow } from "enzyme";
|
import { shallow } from "enzyme";
|
||||||
import * as ko from "knockout";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
|
@ -208,13 +207,6 @@ const schema: DataModels.ISchema = {
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const createMockContainer = (): Explorer => {
|
|
||||||
const mockContainer = new Explorer();
|
|
||||||
mockContainer.selectedNode = ko.observable<ViewModels.TreeNode>();
|
|
||||||
|
|
||||||
return mockContainer;
|
|
||||||
};
|
|
||||||
|
|
||||||
const createMockCollection = (): ViewModels.Collection => {
|
const createMockCollection = (): ViewModels.Collection => {
|
||||||
const mockCollection = {} as DataModels.Collection;
|
const mockCollection = {} as DataModels.Collection;
|
||||||
mockCollection._rid = "fakeRid";
|
mockCollection._rid = "fakeRid";
|
||||||
|
@ -223,17 +215,13 @@ const createMockCollection = (): ViewModels.Collection => {
|
||||||
mockCollection.analyticalStorageTtl = 0;
|
mockCollection.analyticalStorageTtl = 0;
|
||||||
mockCollection.schema = schema;
|
mockCollection.schema = schema;
|
||||||
|
|
||||||
const mockCollectionVM: ViewModels.Collection = new Collection(
|
const mockCollectionVM: ViewModels.Collection = new Collection(new Explorer(), "fakeDatabaseId", mockCollection);
|
||||||
createMockContainer(),
|
|
||||||
"fakeDatabaseId",
|
|
||||||
mockCollection
|
|
||||||
);
|
|
||||||
|
|
||||||
return mockCollectionVM;
|
return mockCollectionVM;
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("Resource tree for schema", () => {
|
describe("Resource tree for schema", () => {
|
||||||
const mockContainer: Explorer = createMockContainer();
|
const mockContainer = new Explorer();
|
||||||
const resourceTree = new ResourceTreeAdapter(mockContainer);
|
const resourceTree = new ResourceTreeAdapter(mockContainer);
|
||||||
|
|
||||||
it("should render", () => {
|
it("should render", () => {
|
||||||
|
|
|
@ -33,6 +33,7 @@ import { NotebookContentItem, NotebookContentItemType } from "../Notebook/Notebo
|
||||||
import { NotebookUtil } from "../Notebook/NotebookUtil";
|
import { NotebookUtil } from "../Notebook/NotebookUtil";
|
||||||
import TabsBase from "../Tabs/TabsBase";
|
import TabsBase from "../Tabs/TabsBase";
|
||||||
import { useDatabases } from "../useDatabases";
|
import { useDatabases } from "../useDatabases";
|
||||||
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
import StoredProcedure from "./StoredProcedure";
|
import StoredProcedure from "./StoredProcedure";
|
||||||
import Trigger from "./Trigger";
|
import Trigger from "./Trigger";
|
||||||
import UserDefinedFunction from "./UserDefinedFunction";
|
import UserDefinedFunction from "./UserDefinedFunction";
|
||||||
|
@ -54,7 +55,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
public constructor(private container: Explorer) {
|
public constructor(private container: Explorer) {
|
||||||
this.parameters = ko.observable(Date.now());
|
this.parameters = ko.observable(Date.now());
|
||||||
|
|
||||||
this.container.selectedNode.subscribe((newValue: any) => this.triggerRender());
|
useSelectedNode.subscribe(() => this.triggerRender());
|
||||||
this.container.tabsManager.activeTab.subscribe((newValue: TabsBase) => this.triggerRender());
|
this.container.tabsManager.activeTab.subscribe((newValue: TabsBase) => this.triggerRender());
|
||||||
this.container.isNotebookEnabled.subscribe((newValue) => this.triggerRender());
|
this.container.isNotebookEnabled.subscribe((newValue) => this.triggerRender());
|
||||||
|
|
||||||
|
@ -183,7 +184,8 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
isExpanded: false,
|
isExpanded: false,
|
||||||
className: "databaseHeader",
|
className: "databaseHeader",
|
||||||
children: [],
|
children: [],
|
||||||
isSelected: () => this.isDataNodeSelected(database.id()),
|
isSelected: () =>
|
||||||
|
useSelectedNode.getState().isDataNodeSelected(this.container.tabsManager.activeTab(), database.id()),
|
||||||
contextMenu: ResourceTreeContextMenuButtonFactory.createDatabaseContextMenu(this.container, database.id()),
|
contextMenu: ResourceTreeContextMenuButtonFactory.createDatabaseContextMenu(this.container, database.id()),
|
||||||
onClick: async (isExpanded) => {
|
onClick: async (isExpanded) => {
|
||||||
// Rewritten version of expandCollapseDatabase():
|
// Rewritten version of expandCollapseDatabase():
|
||||||
|
@ -196,18 +198,22 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
await database.expandDatabase();
|
await database.expandDatabase();
|
||||||
}
|
}
|
||||||
databaseNode.isLoading = false;
|
databaseNode.isLoading = false;
|
||||||
database.selectDatabase();
|
useSelectedNode.getState().setSelectedNode(database);
|
||||||
useCommandBar.getState().setContextButtons([]);
|
useCommandBar.getState().setContextButtons([]);
|
||||||
this.container.tabsManager.refreshActiveTab((tab: TabsBase) => tab.collection?.databaseId === database.id());
|
this.container.tabsManager.refreshActiveTab((tab: TabsBase) => tab.collection?.databaseId === database.id());
|
||||||
},
|
},
|
||||||
onContextMenuOpen: () => this.container.selectedNode(database),
|
onContextMenuOpen: () => useSelectedNode.getState().setSelectedNode(database),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (database.isDatabaseShared()) {
|
if (database.isDatabaseShared()) {
|
||||||
databaseNode.children.push({
|
databaseNode.children.push({
|
||||||
label: "Scale",
|
label: "Scale",
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
this.isDataNodeSelected(database.id(), undefined, [ViewModels.CollectionTabKind.DatabaseSettings]),
|
useSelectedNode
|
||||||
|
.getState()
|
||||||
|
.isDataNodeSelected(this.container.tabsManager.activeTab(), database.id(), undefined, [
|
||||||
|
ViewModels.CollectionTabKind.DatabaseSettings,
|
||||||
|
]),
|
||||||
onClick: database.onSettingsClick.bind(database),
|
onClick: database.onSettingsClick.bind(database),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -253,10 +259,12 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
mostRecentActivity.collectionWasOpened(userContext.databaseAccount?.id, collection);
|
mostRecentActivity.collectionWasOpened(userContext.databaseAccount?.id, collection);
|
||||||
},
|
},
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
this.isDataNodeSelected(collection.databaseId, collection.id(), [
|
useSelectedNode
|
||||||
ViewModels.CollectionTabKind.Documents,
|
.getState()
|
||||||
ViewModels.CollectionTabKind.Graph,
|
.isDataNodeSelected(this.container.tabsManager.activeTab(), collection.databaseId, collection.id(), [
|
||||||
]),
|
ViewModels.CollectionTabKind.Documents,
|
||||||
|
ViewModels.CollectionTabKind.Graph,
|
||||||
|
]),
|
||||||
contextMenu: ResourceTreeContextMenuButtonFactory.createCollectionContextMenuButton(this.container, collection),
|
contextMenu: ResourceTreeContextMenuButtonFactory.createCollectionContextMenuButton(this.container, collection),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -265,9 +273,11 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
label: "Schema (Preview)",
|
label: "Schema (Preview)",
|
||||||
onClick: collection.onSchemaAnalyzerClick.bind(collection),
|
onClick: collection.onSchemaAnalyzerClick.bind(collection),
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
this.isDataNodeSelected(collection.databaseId, collection.id(), [
|
useSelectedNode
|
||||||
ViewModels.CollectionTabKind.SchemaAnalyzer,
|
.getState()
|
||||||
]),
|
.isDataNodeSelected(this.container.tabsManager.activeTab(), collection.databaseId, collection.id(), [
|
||||||
|
ViewModels.CollectionTabKind.SchemaAnalyzer,
|
||||||
|
]),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,7 +286,11 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
label: database.isDatabaseShared() || isServerlessAccount() ? "Settings" : "Scale & Settings",
|
label: database.isDatabaseShared() || isServerlessAccount() ? "Settings" : "Scale & Settings",
|
||||||
onClick: collection.onSettingsClick.bind(collection),
|
onClick: collection.onSettingsClick.bind(collection),
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
this.isDataNodeSelected(collection.databaseId, collection.id(), [ViewModels.CollectionTabKind.Settings]),
|
useSelectedNode
|
||||||
|
.getState()
|
||||||
|
.isDataNodeSelected(this.container.tabsManager.activeTab(), collection.databaseId, collection.id(), [
|
||||||
|
ViewModels.CollectionTabKind.Settings,
|
||||||
|
]),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +316,11 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
label: "Conflicts",
|
label: "Conflicts",
|
||||||
onClick: collection.onConflictsClick.bind(collection),
|
onClick: collection.onConflictsClick.bind(collection),
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
this.isDataNodeSelected(collection.databaseId, collection.id(), [ViewModels.CollectionTabKind.Conflicts]),
|
useSelectedNode
|
||||||
|
.getState()
|
||||||
|
.isDataNodeSelected(this.container.tabsManager.activeTab(), collection.databaseId, collection.id(), [
|
||||||
|
ViewModels.CollectionTabKind.Conflicts,
|
||||||
|
]),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,7 +333,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
contextMenu: ResourceTreeContextMenuButtonFactory.createCollectionContextMenuButton(this.container, collection),
|
contextMenu: ResourceTreeContextMenuButtonFactory.createCollectionContextMenuButton(this.container, collection),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
// Rewritten version of expandCollapseCollection
|
// Rewritten version of expandCollapseCollection
|
||||||
this.container.selectedNode(collection);
|
useSelectedNode.getState().setSelectedNode(collection);
|
||||||
useCommandBar.getState().setContextButtons([]);
|
useCommandBar.getState().setContextButtons([]);
|
||||||
this.container.tabsManager.refreshActiveTab(
|
this.container.tabsManager.refreshActiveTab(
|
||||||
(tab: TabsBase) =>
|
(tab: TabsBase) =>
|
||||||
|
@ -329,8 +347,11 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
collection.loadTriggers();
|
collection.loadTriggers();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isSelected: () => this.isDataNodeSelected(collection.databaseId, collection.id()),
|
isSelected: () =>
|
||||||
onContextMenuOpen: () => this.container.selectedNode(collection),
|
useSelectedNode
|
||||||
|
.getState()
|
||||||
|
.isDataNodeSelected(this.container.tabsManager.activeTab(), collection.databaseId, collection.id()),
|
||||||
|
onContextMenuOpen: () => useSelectedNode.getState().setSelectedNode(collection),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,9 +362,11 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
label: sp.id(),
|
label: sp.id(),
|
||||||
onClick: sp.open.bind(sp),
|
onClick: sp.open.bind(sp),
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
this.isDataNodeSelected(collection.databaseId, collection.id(), [
|
useSelectedNode
|
||||||
ViewModels.CollectionTabKind.StoredProcedures,
|
.getState()
|
||||||
]),
|
.isDataNodeSelected(this.container.tabsManager.activeTab(), collection.databaseId, collection.id(), [
|
||||||
|
ViewModels.CollectionTabKind.StoredProcedures,
|
||||||
|
]),
|
||||||
contextMenu: ResourceTreeContextMenuButtonFactory.createStoreProcedureContextMenuItems(this.container, sp),
|
contextMenu: ResourceTreeContextMenuButtonFactory.createStoreProcedureContextMenuItems(this.container, sp),
|
||||||
})),
|
})),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
|
@ -363,9 +386,11 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
label: udf.id(),
|
label: udf.id(),
|
||||||
onClick: udf.open.bind(udf),
|
onClick: udf.open.bind(udf),
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
this.isDataNodeSelected(collection.databaseId, collection.id(), [
|
useSelectedNode
|
||||||
ViewModels.CollectionTabKind.UserDefinedFunctions,
|
.getState()
|
||||||
]),
|
.isDataNodeSelected(this.container.tabsManager.activeTab(), collection.databaseId, collection.id(), [
|
||||||
|
ViewModels.CollectionTabKind.UserDefinedFunctions,
|
||||||
|
]),
|
||||||
contextMenu: ResourceTreeContextMenuButtonFactory.createUserDefinedFunctionContextMenuItems(
|
contextMenu: ResourceTreeContextMenuButtonFactory.createUserDefinedFunctionContextMenuItems(
|
||||||
this.container,
|
this.container,
|
||||||
udf
|
udf
|
||||||
|
@ -388,7 +413,11 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
label: trigger.id(),
|
label: trigger.id(),
|
||||||
onClick: trigger.open.bind(trigger),
|
onClick: trigger.open.bind(trigger),
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
this.isDataNodeSelected(collection.databaseId, collection.id(), [ViewModels.CollectionTabKind.Triggers]),
|
useSelectedNode
|
||||||
|
.getState()
|
||||||
|
.isDataNodeSelected(this.container.tabsManager.activeTab(), collection.databaseId, collection.id(), [
|
||||||
|
ViewModels.CollectionTabKind.Triggers,
|
||||||
|
]),
|
||||||
contextMenu: ResourceTreeContextMenuButtonFactory.createTriggerContextMenuItems(this.container, trigger),
|
contextMenu: ResourceTreeContextMenuButtonFactory.createTriggerContextMenuItems(this.container, trigger),
|
||||||
})),
|
})),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
|
@ -818,44 +847,4 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
public triggerRender() {
|
public triggerRender() {
|
||||||
window.requestAnimationFrame(() => this.parameters(Date.now()));
|
window.requestAnimationFrame(() => this.parameters(Date.now()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* public for testing purposes
|
|
||||||
* @param databaseId
|
|
||||||
* @param collectionId
|
|
||||||
* @param subnodeKinds
|
|
||||||
*/
|
|
||||||
public isDataNodeSelected(
|
|
||||||
databaseId: string,
|
|
||||||
collectionId?: string,
|
|
||||||
subnodeKinds?: ViewModels.CollectionTabKind[]
|
|
||||||
): boolean {
|
|
||||||
if (!this.container.selectedNode || !this.container.selectedNode()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const selectedNode = this.container.selectedNode();
|
|
||||||
const isNodeSelected = collectionId
|
|
||||||
? (selectedNode as ViewModels.Collection).databaseId === databaseId && selectedNode.id() === collectionId
|
|
||||||
: selectedNode.id() === databaseId;
|
|
||||||
|
|
||||||
if (!isNodeSelected) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subnodeKinds === undefined || !Array.isArray(subnodeKinds)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const activeTab = this.container.tabsManager.activeTab();
|
|
||||||
const selectedSubnodeKind = collectionId
|
|
||||||
? (selectedNode as ViewModels.Collection).selectedSubnodeKind()
|
|
||||||
: (selectedNode as ViewModels.Database).selectedSubnodeKind();
|
|
||||||
|
|
||||||
return (
|
|
||||||
activeTab &&
|
|
||||||
subnodeKinds.includes(activeTab.tabKind) &&
|
|
||||||
selectedSubnodeKind !== undefined &&
|
|
||||||
subnodeKinds.includes(selectedSubnodeKind)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import { ResourceTreeAdapterForResourceToken } from "./ResourceTreeAdapterForRes
|
||||||
const createMockContainer = (): Explorer => {
|
const createMockContainer = (): Explorer => {
|
||||||
let mockContainer = {} as Explorer;
|
let mockContainer = {} as Explorer;
|
||||||
mockContainer.resourceTokenCollection = createMockCollection(mockContainer);
|
mockContainer.resourceTokenCollection = createMockCollection(mockContainer);
|
||||||
mockContainer.selectedNode = ko.observable<ViewModels.TreeNode>();
|
|
||||||
|
|
||||||
return mockContainer;
|
return mockContainer;
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@ import Explorer from "../Explorer";
|
||||||
import { useCommandBar } from "../Menus/CommandBar/CommandBarComponentAdapter";
|
import { useCommandBar } from "../Menus/CommandBar/CommandBarComponentAdapter";
|
||||||
import { mostRecentActivity } from "../MostRecentActivity/MostRecentActivity";
|
import { mostRecentActivity } from "../MostRecentActivity/MostRecentActivity";
|
||||||
import { NotebookContentItem } from "../Notebook/NotebookContentItem";
|
import { NotebookContentItem } from "../Notebook/NotebookContentItem";
|
||||||
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
|
|
||||||
export class ResourceTreeAdapterForResourceToken implements ReactAdapter {
|
export class ResourceTreeAdapterForResourceToken implements ReactAdapter {
|
||||||
public parameters: ko.Observable<number>;
|
public parameters: ko.Observable<number>;
|
||||||
|
@ -18,7 +19,7 @@ export class ResourceTreeAdapterForResourceToken implements ReactAdapter {
|
||||||
this.parameters = ko.observable(Date.now());
|
this.parameters = ko.observable(Date.now());
|
||||||
|
|
||||||
this.container.resourceTokenCollection.subscribe(() => this.triggerRender());
|
this.container.resourceTokenCollection.subscribe(() => this.triggerRender());
|
||||||
this.container.selectedNode.subscribe((newValue: any) => this.triggerRender());
|
useSelectedNode.subscribe(() => this.triggerRender());
|
||||||
this.container.tabsManager && this.container.tabsManager.activeTab.subscribe(() => this.triggerRender());
|
this.container.tabsManager && this.container.tabsManager.activeTab.subscribe(() => this.triggerRender());
|
||||||
|
|
||||||
this.triggerRender();
|
this.triggerRender();
|
||||||
|
@ -48,7 +49,11 @@ export class ResourceTreeAdapterForResourceToken implements ReactAdapter {
|
||||||
mostRecentActivity.collectionWasOpened(userContext.databaseAccount?.id, collection);
|
mostRecentActivity.collectionWasOpened(userContext.databaseAccount?.id, collection);
|
||||||
},
|
},
|
||||||
isSelected: () =>
|
isSelected: () =>
|
||||||
this.isDataNodeSelected(collection.databaseId, collection.id(), ViewModels.CollectionTabKind.Documents),
|
useSelectedNode
|
||||||
|
.getState()
|
||||||
|
.isDataNodeSelected(this.container.tabsManager.activeTab(), collection.databaseId, collection.id(), [
|
||||||
|
ViewModels.CollectionTabKind.Documents,
|
||||||
|
]),
|
||||||
});
|
});
|
||||||
|
|
||||||
const collectionNode: TreeNode = {
|
const collectionNode: TreeNode = {
|
||||||
|
@ -59,13 +64,16 @@ export class ResourceTreeAdapterForResourceToken implements ReactAdapter {
|
||||||
className: "collectionHeader",
|
className: "collectionHeader",
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
// Rewritten version of expandCollapseCollection
|
// Rewritten version of expandCollapseCollection
|
||||||
this.container.selectedNode(collection);
|
useSelectedNode.getState().setSelectedNode(collection);
|
||||||
useCommandBar.getState().setContextButtons([]);
|
useCommandBar.getState().setContextButtons([]);
|
||||||
this.container.tabsManager.refreshActiveTab(
|
this.container.tabsManager.refreshActiveTab(
|
||||||
(tab) => tab.collection?.id() === collection.id() && tab.collection.databaseId === collection.databaseId
|
(tab) => tab.collection?.id() === collection.id() && tab.collection.databaseId === collection.databaseId
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
isSelected: () => this.isDataNodeSelected(collection.databaseId, collection.id()),
|
isSelected: () =>
|
||||||
|
useSelectedNode
|
||||||
|
.getState()
|
||||||
|
.isDataNodeSelected(this.container.tabsManager.activeTab(), collection.databaseId, collection.id()),
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -75,35 +83,6 @@ export class ResourceTreeAdapterForResourceToken implements ReactAdapter {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public isDataNodeSelected(
|
|
||||||
databaseId: string,
|
|
||||||
collectionId?: string,
|
|
||||||
subnodeKind?: ViewModels.CollectionTabKind
|
|
||||||
): boolean {
|
|
||||||
if (!this.container.selectedNode || !this.container.selectedNode()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const selectedNode = this.container.selectedNode();
|
|
||||||
const isNodeSelected = collectionId
|
|
||||||
? (selectedNode as ViewModels.Collection).databaseId === databaseId && selectedNode.id() === collectionId
|
|
||||||
: selectedNode.id() === databaseId;
|
|
||||||
|
|
||||||
if (!isNodeSelected) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!subnodeKind) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const activeTab = this.container.tabsManager.activeTab();
|
|
||||||
const selectedSubnodeKind = collectionId
|
|
||||||
? (selectedNode as ViewModels.Collection).selectedSubnodeKind()
|
|
||||||
: (selectedNode as ViewModels.Database).selectedSubnodeKind();
|
|
||||||
|
|
||||||
return activeTab && activeTab.tabKind === subnodeKind && selectedSubnodeKind === subnodeKind;
|
|
||||||
}
|
|
||||||
|
|
||||||
public triggerRender() {
|
public triggerRender() {
|
||||||
window.requestAnimationFrame(() => this.parameters(Date.now()));
|
window.requestAnimationFrame(() => this.parameters(Date.now()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import Explorer from "../Explorer";
|
||||||
import { getErrorMessage } from "../Tables/Utilities";
|
import { getErrorMessage } from "../Tables/Utilities";
|
||||||
import { NewStoredProcedureTab } from "../Tabs/StoredProcedureTab/StoredProcedureTab";
|
import { NewStoredProcedureTab } from "../Tabs/StoredProcedureTab/StoredProcedureTab";
|
||||||
import TabsBase from "../Tabs/TabsBase";
|
import TabsBase from "../Tabs/TabsBase";
|
||||||
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
|
|
||||||
const sampleStoredProcedureBody: string = `// SAMPLE STORED PROCEDURE
|
const sampleStoredProcedureBody: string = `// SAMPLE STORED PROCEDURE
|
||||||
function sample(prefix) {
|
function sample(prefix) {
|
||||||
|
@ -87,7 +88,7 @@ export default class StoredProcedure {
|
||||||
}
|
}
|
||||||
|
|
||||||
public select() {
|
public select() {
|
||||||
this.container.selectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
||||||
description: "Stored procedure node",
|
description: "Stored procedure node",
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstan
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import TriggerTab from "../Tabs/TriggerTab";
|
import TriggerTab from "../Tabs/TriggerTab";
|
||||||
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
|
|
||||||
export default class Trigger {
|
export default class Trigger {
|
||||||
public nodeKind: string;
|
public nodeKind: string;
|
||||||
|
@ -32,7 +33,7 @@ export default class Trigger {
|
||||||
}
|
}
|
||||||
|
|
||||||
public select() {
|
public select() {
|
||||||
this.container.selectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
||||||
description: "Trigger node",
|
description: "Trigger node",
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstan
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import UserDefinedFunctionTab from "../Tabs/UserDefinedFunctionTab";
|
import UserDefinedFunctionTab from "../Tabs/UserDefinedFunctionTab";
|
||||||
|
import { useSelectedNode } from "../useSelectedNode";
|
||||||
|
|
||||||
export default class UserDefinedFunction {
|
export default class UserDefinedFunction {
|
||||||
public nodeKind: string;
|
public nodeKind: string;
|
||||||
|
@ -82,7 +83,7 @@ export default class UserDefinedFunction {
|
||||||
};
|
};
|
||||||
|
|
||||||
public select() {
|
public select() {
|
||||||
this.container.selectedNode(this);
|
useSelectedNode.getState().setSelectedNode(this);
|
||||||
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
|
||||||
description: "UDF item node",
|
description: "UDF item node",
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
import _ from "underscore";
|
||||||
|
import create, { UseStore } from "zustand";
|
||||||
|
import * as ViewModels from "../Contracts/ViewModels";
|
||||||
|
import TabsBase from "./Tabs/TabsBase";
|
||||||
|
import { useDatabases } from "./useDatabases";
|
||||||
|
|
||||||
|
export interface SelectedNodeState {
|
||||||
|
selectedNode: ViewModels.TreeNode;
|
||||||
|
setSelectedNode: (node: ViewModels.TreeNode) => void;
|
||||||
|
isDatabaseNodeOrNoneSelected: () => boolean;
|
||||||
|
findSelectedDatabase: () => ViewModels.Database;
|
||||||
|
findSelectedCollection: () => ViewModels.Collection;
|
||||||
|
isDataNodeSelected: (
|
||||||
|
activeTab: TabsBase,
|
||||||
|
databaseId: string,
|
||||||
|
collectionId?: string,
|
||||||
|
subnodeKinds?: ViewModels.CollectionTabKind[]
|
||||||
|
) => boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSelectedNode: UseStore<SelectedNodeState> = create((set, get) => ({
|
||||||
|
selectedNode: undefined,
|
||||||
|
setSelectedNode: (node: ViewModels.TreeNode) => set({ selectedNode: node }),
|
||||||
|
isDatabaseNodeOrNoneSelected: (): boolean => {
|
||||||
|
const selectedNode = get().selectedNode;
|
||||||
|
return !selectedNode || selectedNode.nodeKind === "Database";
|
||||||
|
},
|
||||||
|
findSelectedDatabase: (): ViewModels.Database => {
|
||||||
|
const selectedNode = get().selectedNode;
|
||||||
|
if (!selectedNode) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (selectedNode.nodeKind === "Database") {
|
||||||
|
return _.find(
|
||||||
|
useDatabases.getState().databases,
|
||||||
|
(database: ViewModels.Database) => database.id() === selectedNode.id()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedNode.nodeKind === "Collection") {
|
||||||
|
return selectedNode.database;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectedNode.collection?.database;
|
||||||
|
},
|
||||||
|
findSelectedCollection: (): ViewModels.Collection => {
|
||||||
|
const selectedNode = get().selectedNode;
|
||||||
|
return (selectedNode.nodeKind === "Collection" ? selectedNode : selectedNode.collection) as ViewModels.Collection;
|
||||||
|
},
|
||||||
|
isDataNodeSelected: (
|
||||||
|
activeTab: TabsBase,
|
||||||
|
databaseId: string,
|
||||||
|
collectionId?: string,
|
||||||
|
subnodeKinds?: ViewModels.CollectionTabKind[]
|
||||||
|
): boolean => {
|
||||||
|
const selectedNode = get().selectedNode;
|
||||||
|
if (!selectedNode) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isNodeSelected = collectionId
|
||||||
|
? (selectedNode as ViewModels.Collection).databaseId === databaseId && selectedNode.id() === collectionId
|
||||||
|
: selectedNode.id() === databaseId;
|
||||||
|
|
||||||
|
if (!isNodeSelected) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subnodeKinds === undefined || !Array.isArray(subnodeKinds)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectedSubnodeKind = collectionId
|
||||||
|
? (selectedNode as ViewModels.Collection).selectedSubnodeKind()
|
||||||
|
: (selectedNode as ViewModels.Database).selectedSubnodeKind();
|
||||||
|
|
||||||
|
return (
|
||||||
|
activeTab &&
|
||||||
|
subnodeKinds.includes(activeTab.tabKind) &&
|
||||||
|
selectedSubnodeKind !== undefined &&
|
||||||
|
subnodeKinds.includes(selectedSubnodeKind)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}));
|
Loading…
Reference in New Issue