mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-21 01:41:31 +00:00
Initial Move from Azure DevOps to GitHub
This commit is contained in:
14
src/Explorer/Menus/CommandBar/CommandBarComponent.less
Normal file
14
src/Explorer/Menus/CommandBar/CommandBarComponent.less
Normal file
@@ -0,0 +1,14 @@
|
||||
@import "../../../../less/Common/Constants";
|
||||
|
||||
.dividerContainer {
|
||||
padding: @SmallSpace 0px @SmallSpace 0px;
|
||||
.flex-display();
|
||||
span {
|
||||
border-left: @ButtonBorderWidth solid @BaseMediumHigh;
|
||||
margin: 0 10px 0 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.commandBarContainer {
|
||||
border-bottom: 1px solid @BaseMedium;
|
||||
}
|
||||
103
src/Explorer/Menus/CommandBar/CommandBarComponentAdapter.tsx
Normal file
103
src/Explorer/Menus/CommandBar/CommandBarComponentAdapter.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* This adapter is responsible to render the React component
|
||||
* If the component signals a change through the callback passed in the properties, it must render the React component when appropriate
|
||||
* and update any knockout observables passed from the parent.
|
||||
*/
|
||||
import * as ko from "knockout";
|
||||
import * as React from "react";
|
||||
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import { CommandBarComponentButtonFactory } from "./CommandBarComponentButtonFactory";
|
||||
import { CommandBar, ICommandBarItemProps } from "office-ui-fabric-react/lib/CommandBar";
|
||||
import { StyleConstants } from "../../../Common/Constants";
|
||||
import { CommandBarUtil } from "./CommandBarUtil";
|
||||
|
||||
export class CommandBarComponentAdapter implements ReactAdapter {
|
||||
public parameters: ko.Observable<number>;
|
||||
public container: ViewModels.Explorer;
|
||||
private tabsButtons: ViewModels.NavbarButtonConfig[];
|
||||
|
||||
constructor(container: ViewModels.Explorer) {
|
||||
this.container = container;
|
||||
this.tabsButtons = [];
|
||||
|
||||
// These are the parameters watched by the react binding that will trigger a renderComponent() if one of the ko mutates
|
||||
const toWatch = [
|
||||
container.isPreferredApiTable,
|
||||
container.isPreferredApiMongoDB,
|
||||
container.isPreferredApiDocumentDB,
|
||||
container.isPreferredApiCassandra,
|
||||
container.isPreferredApiGraph,
|
||||
container.deleteCollectionText,
|
||||
container.deleteDatabaseText,
|
||||
container.addCollectionText,
|
||||
container.addDatabaseText,
|
||||
container.isDatabaseNodeOrNoneSelected,
|
||||
container.isDatabaseNodeSelected,
|
||||
container.isNoneSelected,
|
||||
container.isResourceTokenCollectionNodeSelected,
|
||||
container.isHostedDataExplorerEnabled,
|
||||
container.isSynapseLinkUpdating,
|
||||
container.databaseAccount,
|
||||
container.isNotebookTabActive
|
||||
];
|
||||
|
||||
ko.computed(() => ko.toJSON(toWatch)).subscribe(() => this.triggerRender());
|
||||
this.parameters = ko.observable(Date.now());
|
||||
}
|
||||
|
||||
public onUpdateTabsButtons(buttons: ViewModels.NavbarButtonConfig[]): void {
|
||||
this.tabsButtons = buttons;
|
||||
this.triggerRender();
|
||||
}
|
||||
|
||||
public renderComponent(): JSX.Element {
|
||||
const backgroundColor = StyleConstants.BaseLight;
|
||||
|
||||
const staticButtons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(this.container);
|
||||
const contextButtons = (this.tabsButtons || []).concat(
|
||||
CommandBarComponentButtonFactory.createContextCommandBarButtons(this.container)
|
||||
);
|
||||
const controlButtons = CommandBarComponentButtonFactory.createControlCommandBarButtons(this.container);
|
||||
|
||||
const uiFabricStaticButtons = CommandBarUtil.convertButton(staticButtons, backgroundColor);
|
||||
if (this.tabsButtons && this.tabsButtons.length > 0) {
|
||||
uiFabricStaticButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
|
||||
}
|
||||
|
||||
const uiFabricTabsButtons: ICommandBarItemProps[] = CommandBarUtil.convertButton(contextButtons, backgroundColor);
|
||||
|
||||
if (uiFabricTabsButtons.length > 0) {
|
||||
uiFabricStaticButtons.push(CommandBarUtil.createDivider("commandBarDivider"));
|
||||
}
|
||||
|
||||
const uiFabricControlButtons = CommandBarUtil.convertButton(controlButtons, backgroundColor);
|
||||
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
|
||||
|
||||
if (this.container && this.container.isNotebookTabActive()) {
|
||||
uiFabricControlButtons.unshift(
|
||||
CommandBarUtil.createMemoryTracker("memoryTracker", this.container.memoryUsageInfo)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="commandBarContainer">
|
||||
<CommandBar
|
||||
ariaLabel="Use left and right arrow keys to navigate between commands"
|
||||
items={uiFabricStaticButtons.concat(uiFabricTabsButtons)}
|
||||
farItems={uiFabricControlButtons}
|
||||
styles={{
|
||||
root: { backgroundColor: backgroundColor }
|
||||
}}
|
||||
overflowButtonProps={{ ariaLabel: "More commands" }}
|
||||
/>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
private triggerRender() {
|
||||
window.requestAnimationFrame(() => this.parameters(Date.now()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
import * as ko from "knockout";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import { CommandBarComponentButtonFactory } from "./CommandBarComponentButtonFactory";
|
||||
import { ExplorerStub } from "../../OpenActionsStubs";
|
||||
import { GitHubOAuthService } from "../../../GitHub/GitHubOAuthService";
|
||||
|
||||
describe("CommandBarComponentButtonFactory tests", () => {
|
||||
let mockExplorer: ViewModels.Explorer;
|
||||
|
||||
describe("Enable notebook button", () => {
|
||||
const enableNotebookBtnLabel = "Enable Notebooks (Preview)";
|
||||
|
||||
beforeAll(() => {
|
||||
mockExplorer = new ExplorerStub();
|
||||
mockExplorer.addCollectionText = ko.observable("mockText");
|
||||
mockExplorer.isAuthWithResourceToken = ko.observable(false);
|
||||
mockExplorer.isPreferredApiTable = ko.computed(() => true);
|
||||
mockExplorer.isPreferredApiMongoDB = ko.computed<boolean>(() => false);
|
||||
mockExplorer.isPreferredApiCassandra = ko.computed<boolean>(() => false);
|
||||
mockExplorer.isSparkEnabled = ko.observable(true);
|
||||
mockExplorer.isGalleryEnabled = ko.computed<boolean>(() => false);
|
||||
mockExplorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
|
||||
});
|
||||
|
||||
it("Notebooks is already enabled - button should be hidden", () => {
|
||||
mockExplorer.isNotebookEnabled = ko.observable(true);
|
||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
||||
mockExplorer.isRunningOnNationalCloud = ko.observable(false);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const enableNotebookBtn = buttons.find(button => button.commandButtonLabel === enableNotebookBtnLabel);
|
||||
expect(enableNotebookBtn).toBeUndefined();
|
||||
});
|
||||
|
||||
it("Account is running on one of the national clouds - button should be hidden", () => {
|
||||
mockExplorer.isNotebookEnabled = ko.observable(false);
|
||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
|
||||
mockExplorer.isRunningOnNationalCloud = ko.observable(true);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const enableNotebookBtn = buttons.find(button => button.commandButtonLabel === enableNotebookBtnLabel);
|
||||
expect(enableNotebookBtn).toBeUndefined();
|
||||
});
|
||||
|
||||
it("Notebooks is not enabled but is available - button should be shown and enabled", () => {
|
||||
mockExplorer.isNotebookEnabled = ko.observable(false);
|
||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
||||
mockExplorer.isRunningOnNationalCloud = ko.observable(false);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const enableNotebookBtn = buttons.find(button => button.commandButtonLabel === enableNotebookBtnLabel);
|
||||
expect(enableNotebookBtn).toBeDefined();
|
||||
expect(enableNotebookBtn.disabled).toBe(false);
|
||||
expect(enableNotebookBtn.tooltipText).toBe("");
|
||||
});
|
||||
|
||||
it("Notebooks is not enabled and is unavailable - button should be shown and disabled", () => {
|
||||
mockExplorer.isNotebookEnabled = ko.observable(false);
|
||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
|
||||
mockExplorer.isRunningOnNationalCloud = ko.observable(false);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const enableNotebookBtn = buttons.find(button => button.commandButtonLabel === enableNotebookBtnLabel);
|
||||
expect(enableNotebookBtn).toBeDefined();
|
||||
expect(enableNotebookBtn.disabled).toBe(true);
|
||||
expect(enableNotebookBtn.tooltipText).toBe(
|
||||
"Notebooks are not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks."
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Open Mongo Shell button", () => {
|
||||
const openMongoShellBtnLabel = "Open Mongo Shell";
|
||||
|
||||
beforeAll(() => {
|
||||
mockExplorer = new ExplorerStub();
|
||||
mockExplorer.addCollectionText = ko.observable("mockText");
|
||||
mockExplorer.isAuthWithResourceToken = ko.observable(false);
|
||||
mockExplorer.isPreferredApiTable = ko.computed(() => true);
|
||||
mockExplorer.isPreferredApiCassandra = ko.computed<boolean>(() => false);
|
||||
mockExplorer.isSparkEnabled = ko.observable(true);
|
||||
mockExplorer.isGalleryEnabled = ko.computed<boolean>(() => false);
|
||||
mockExplorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mockExplorer.isPreferredApiMongoDB = ko.computed<boolean>(() => true);
|
||||
mockExplorer.isNotebookEnabled = ko.observable(false);
|
||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
|
||||
mockExplorer.isRunningOnNationalCloud = ko.observable(false);
|
||||
});
|
||||
|
||||
it("Mongo Api not available - button should be hidden", () => {
|
||||
mockExplorer.isPreferredApiMongoDB = ko.computed<boolean>(() => false);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const openMongoShellBtn = buttons.find(button => button.commandButtonLabel === openMongoShellBtnLabel);
|
||||
expect(openMongoShellBtn).toBeUndefined();
|
||||
});
|
||||
|
||||
it("Running on a national cloud - button should be hidden", () => {
|
||||
mockExplorer.isRunningOnNationalCloud = ko.observable(true);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const openMongoShellBtn = buttons.find(button => button.commandButtonLabel === openMongoShellBtnLabel);
|
||||
expect(openMongoShellBtn).toBeUndefined();
|
||||
});
|
||||
|
||||
it("Notebooks is not enabled and is unavailable - button should be shown and disabled", () => {
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const openMongoShellBtn = buttons.find(button => button.commandButtonLabel === openMongoShellBtnLabel);
|
||||
expect(openMongoShellBtn).toBeDefined();
|
||||
expect(openMongoShellBtn.disabled).toBe(true);
|
||||
expect(openMongoShellBtn.tooltipText).toBe(
|
||||
"This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks."
|
||||
);
|
||||
});
|
||||
|
||||
it("Notebooks is not enabled and is available - button should be shown and enabled", () => {
|
||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const openMongoShellBtn = buttons.find(button => button.commandButtonLabel === openMongoShellBtnLabel);
|
||||
expect(openMongoShellBtn).toBeDefined();
|
||||
expect(openMongoShellBtn.disabled).toBe(false);
|
||||
expect(openMongoShellBtn.tooltipText).toBe("");
|
||||
});
|
||||
|
||||
it("Notebooks is enabled and is unavailable - button should be shown and enabled", () => {
|
||||
mockExplorer.isNotebookEnabled = ko.observable(true);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const openMongoShellBtn = buttons.find(button => button.commandButtonLabel === openMongoShellBtnLabel);
|
||||
expect(openMongoShellBtn).toBeDefined();
|
||||
expect(openMongoShellBtn.disabled).toBe(false);
|
||||
expect(openMongoShellBtn.tooltipText).toBe("");
|
||||
});
|
||||
|
||||
it("Notebooks is enabled and is available - button should be shown and enabled", () => {
|
||||
mockExplorer.isNotebookEnabled = ko.observable(true);
|
||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const openMongoShellBtn = buttons.find(button => button.commandButtonLabel === openMongoShellBtnLabel);
|
||||
expect(openMongoShellBtn).toBeDefined();
|
||||
expect(openMongoShellBtn.disabled).toBe(false);
|
||||
expect(openMongoShellBtn.tooltipText).toBe("");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Open Cassandra Shell button", () => {
|
||||
const openCassandraShellBtnLabel = "Open Cassandra Shell";
|
||||
|
||||
beforeAll(() => {
|
||||
mockExplorer = new ExplorerStub();
|
||||
mockExplorer.addCollectionText = ko.observable("mockText");
|
||||
mockExplorer.isAuthWithResourceToken = ko.observable(false);
|
||||
mockExplorer.isPreferredApiTable = ko.computed(() => true);
|
||||
mockExplorer.isPreferredApiMongoDB = ko.computed<boolean>(() => false);
|
||||
mockExplorer.isSparkEnabled = ko.observable(true);
|
||||
mockExplorer.isGalleryEnabled = ko.computed<boolean>(() => false);
|
||||
mockExplorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mockExplorer.isPreferredApiCassandra = ko.computed<boolean>(() => true);
|
||||
mockExplorer.isNotebookEnabled = ko.observable(false);
|
||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
|
||||
mockExplorer.isRunningOnNationalCloud = ko.observable(false);
|
||||
});
|
||||
|
||||
it("Cassandra Api not available - button should be hidden", () => {
|
||||
mockExplorer.isPreferredApiCassandra = ko.computed<boolean>(() => false);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const openCassandraShellBtn = buttons.find(button => button.commandButtonLabel === openCassandraShellBtnLabel);
|
||||
expect(openCassandraShellBtn).toBeUndefined();
|
||||
});
|
||||
|
||||
it("Running on a national cloud - button should be hidden", () => {
|
||||
mockExplorer.isRunningOnNationalCloud = ko.observable(true);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const openCassandraShellBtn = buttons.find(button => button.commandButtonLabel === openCassandraShellBtnLabel);
|
||||
expect(openCassandraShellBtn).toBeUndefined();
|
||||
});
|
||||
|
||||
it("Notebooks is not enabled and is unavailable - button should be shown and disabled", () => {
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const openCassandraShellBtn = buttons.find(button => button.commandButtonLabel === openCassandraShellBtnLabel);
|
||||
expect(openCassandraShellBtn).toBeDefined();
|
||||
expect(openCassandraShellBtn.disabled).toBe(true);
|
||||
expect(openCassandraShellBtn.tooltipText).toBe(
|
||||
"This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks."
|
||||
);
|
||||
});
|
||||
|
||||
it("Notebooks is not enabled and is available - button should be shown and enabled", () => {
|
||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const openCassandraShellBtn = buttons.find(button => button.commandButtonLabel === openCassandraShellBtnLabel);
|
||||
expect(openCassandraShellBtn).toBeDefined();
|
||||
expect(openCassandraShellBtn.disabled).toBe(false);
|
||||
expect(openCassandraShellBtn.tooltipText).toBe("");
|
||||
});
|
||||
|
||||
it("Notebooks is enabled and is unavailable - button should be shown and enabled", () => {
|
||||
mockExplorer.isNotebookEnabled = ko.observable(true);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const openCassandraShellBtn = buttons.find(button => button.commandButtonLabel === openCassandraShellBtnLabel);
|
||||
expect(openCassandraShellBtn).toBeDefined();
|
||||
expect(openCassandraShellBtn.disabled).toBe(false);
|
||||
expect(openCassandraShellBtn.tooltipText).toBe("");
|
||||
});
|
||||
|
||||
it("Notebooks is enabled and is available - button should be shown and enabled", () => {
|
||||
mockExplorer.isNotebookEnabled = ko.observable(true);
|
||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(true);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const openCassandraShellBtn = buttons.find(button => button.commandButtonLabel === openCassandraShellBtnLabel);
|
||||
expect(openCassandraShellBtn).toBeDefined();
|
||||
expect(openCassandraShellBtn.disabled).toBe(false);
|
||||
expect(openCassandraShellBtn.tooltipText).toBe("");
|
||||
});
|
||||
});
|
||||
|
||||
describe("GitHub buttons", () => {
|
||||
const connectToGitHubBtnLabel = "Connect to GitHub";
|
||||
const manageGitHubSettingsBtnLabel = "Manage GitHub settings";
|
||||
|
||||
beforeAll(() => {
|
||||
mockExplorer = new ExplorerStub();
|
||||
mockExplorer.addCollectionText = ko.observable("mockText");
|
||||
mockExplorer.isAuthWithResourceToken = ko.observable(false);
|
||||
mockExplorer.isPreferredApiTable = ko.computed(() => true);
|
||||
mockExplorer.isPreferredApiMongoDB = ko.computed<boolean>(() => false);
|
||||
mockExplorer.isPreferredApiCassandra = ko.computed<boolean>(() => false);
|
||||
mockExplorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
mockExplorer.isSparkEnabled = ko.observable(true);
|
||||
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
|
||||
mockExplorer.isNotebooksEnabledForAccount = ko.observable(false);
|
||||
mockExplorer.isRunningOnNationalCloud = ko.observable(false);
|
||||
mockExplorer.isGalleryEnabled = ko.computed<boolean>(() => false);
|
||||
mockExplorer.gitHubOAuthService = new GitHubOAuthService(undefined);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
mockExplorer.isNotebookEnabled = ko.observable(false);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it("Notebooks is enabled and GitHubOAuthService is not logged in - connect to github button should be visible", () => {
|
||||
mockExplorer.isNotebookEnabled = ko.observable(true);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const connectToGitHubBtn = buttons.find(button => button.commandButtonLabel === connectToGitHubBtnLabel);
|
||||
expect(connectToGitHubBtn).toBeDefined();
|
||||
});
|
||||
|
||||
it("Notebooks is enabled and GitHubOAuthService is logged in - manage github settings button should be visible", () => {
|
||||
mockExplorer.isNotebookEnabled = ko.observable(true);
|
||||
mockExplorer.gitHubOAuthService.isLoggedIn = jest.fn().mockReturnValue(true);
|
||||
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
const manageGitHubSettingsBtn = buttons.find(
|
||||
button => button.commandButtonLabel === manageGitHubSettingsBtnLabel
|
||||
);
|
||||
expect(manageGitHubSettingsBtn).toBeDefined();
|
||||
});
|
||||
|
||||
it("Notebooks is not enabled - connect to github and manage github settings buttons should be hidden", () => {
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
|
||||
const connectToGitHubBtn = buttons.find(button => button.commandButtonLabel === connectToGitHubBtnLabel);
|
||||
expect(connectToGitHubBtn).toBeUndefined();
|
||||
|
||||
const manageGitHubSettingsBtn = buttons.find(
|
||||
button => button.commandButtonLabel === manageGitHubSettingsBtnLabel
|
||||
);
|
||||
expect(manageGitHubSettingsBtn).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Resource token", () => {
|
||||
beforeAll(() => {
|
||||
mockExplorer = new ExplorerStub();
|
||||
mockExplorer.addCollectionText = ko.observable("mockText");
|
||||
mockExplorer.isAuthWithResourceToken = ko.observable(true);
|
||||
mockExplorer.isPreferredApiDocumentDB = ko.computed(() => true);
|
||||
mockExplorer.isDatabaseNodeOrNoneSelected = () => true;
|
||||
mockExplorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
mockExplorer.isResourceTokenCollectionNodeSelected = ko.computed(() => true);
|
||||
});
|
||||
|
||||
it("should only show New SQL Query and Open Query buttons", () => {
|
||||
const buttons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(mockExplorer);
|
||||
expect(buttons.length).toBe(2);
|
||||
expect(buttons[0].commandButtonLabel).toBe("New SQL Query");
|
||||
expect(buttons[0].disabled).toBe(false);
|
||||
expect(buttons[1].commandButtonLabel).toBe("Open Query");
|
||||
expect(buttons[1].disabled).toBe(false);
|
||||
expect(buttons[1].children).toBeDefined();
|
||||
expect(buttons[1].children.length).toBe(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,727 @@
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import { PlatformType } from "../../../PlatformType";
|
||||
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||
import { Areas } from "../../../Common/Constants";
|
||||
import TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||
|
||||
import ApacheSparkIcon from "../../../../images/notebook/Apache-spark.svg";
|
||||
import AddDatabaseIcon from "../../../../images/AddDatabase.svg";
|
||||
import AddCollectionIcon from "../../../../images/AddCollection.svg";
|
||||
import AddSqlQueryIcon from "../../../../images/AddSqlQuery_16x16.svg";
|
||||
import BrowseQueriesIcon from "../../../../images/BrowseQuery.svg";
|
||||
import * as Constants from "../../../Common/Constants";
|
||||
import DeleteIcon from "../../../../images/delete.svg";
|
||||
import EditIcon from "../../../../images/edit.svg";
|
||||
import OpenInTabIcon from "../../../../images/open-in-tab.svg";
|
||||
import OpenQueryFromDiskIcon from "../../../../images/OpenQueryFromDisk.svg";
|
||||
import CosmosTerminalIcon from "../../../../images/Cosmos-Terminal.svg";
|
||||
import HostedTerminalIcon from "../../../../images/Hosted-Terminal.svg";
|
||||
import AddStoredProcedureIcon from "../../../../images/AddStoredProcedure.svg";
|
||||
import SettingsIcon from "../../../../images/settings_15x15.svg";
|
||||
import AddUdfIcon from "../../../../images/AddUdf.svg";
|
||||
import AddTriggerIcon from "../../../../images/AddTrigger.svg";
|
||||
import ScaleIcon from "../../../../images/Scale_15x15.svg";
|
||||
import FeedbackIcon from "../../../../images/Feedback-Command.svg";
|
||||
import EnableNotebooksIcon from "../../../../images/notebook/Notebook-enable.svg";
|
||||
import NewNotebookIcon from "../../../../images/notebook/Notebook-new.svg";
|
||||
import ResetWorkspaceIcon from "../../../../images/notebook/Notebook-reset-workspace.svg";
|
||||
import LibraryManageIcon from "../../../../images/notebook/Spark-library-manage.svg";
|
||||
import GalleryIcon from "../../../../images/GalleryIcon.svg";
|
||||
import GitHubIcon from "../../../../images/github.svg";
|
||||
import SynapseIcon from "../../../../images/synapse-link.svg";
|
||||
import { config, Platform } from "../../../Config";
|
||||
|
||||
export class CommandBarComponentButtonFactory {
|
||||
private static counter: number = 0;
|
||||
|
||||
public static createStaticCommandBarButtons(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig[] {
|
||||
if (container.isAuthWithResourceToken()) {
|
||||
return CommandBarComponentButtonFactory.createStaticCommandBarButtonsForResourceToken(container);
|
||||
}
|
||||
|
||||
const newCollectionBtn = CommandBarComponentButtonFactory.createNewCollectionGroup(container);
|
||||
const buttons: ViewModels.NavbarButtonConfig[] = [newCollectionBtn];
|
||||
|
||||
const addSynapseLink = CommandBarComponentButtonFactory.createOpenSynapseLinkDialogButton(container);
|
||||
if (addSynapseLink) {
|
||||
buttons.push(CommandBarComponentButtonFactory.createDivider());
|
||||
buttons.push(addSynapseLink);
|
||||
}
|
||||
|
||||
if (!container.isPreferredApiTable()) {
|
||||
newCollectionBtn.children = [CommandBarComponentButtonFactory.createNewCollectionGroup(container)];
|
||||
const newDatabaseBtn = CommandBarComponentButtonFactory.createNewDatabase(container);
|
||||
newCollectionBtn.children.push(newDatabaseBtn);
|
||||
}
|
||||
|
||||
buttons.push(CommandBarComponentButtonFactory.createDivider());
|
||||
|
||||
if (container.isNotebookEnabled()) {
|
||||
const newNotebookButton = CommandBarComponentButtonFactory.createNewNotebookButton(container);
|
||||
newNotebookButton.children = [
|
||||
CommandBarComponentButtonFactory.createNewNotebookButton(container),
|
||||
CommandBarComponentButtonFactory.createuploadNotebookButton(container)
|
||||
];
|
||||
buttons.push(newNotebookButton);
|
||||
|
||||
if (container.gitHubOAuthService) {
|
||||
buttons.push(CommandBarComponentButtonFactory.createManageGitHubAccountButton(container));
|
||||
}
|
||||
}
|
||||
|
||||
if (!container.isRunningOnNationalCloud()) {
|
||||
if (!container.isNotebookEnabled()) {
|
||||
buttons.push(CommandBarComponentButtonFactory.createEnableNotebooksButton(container));
|
||||
}
|
||||
|
||||
if (container.isPreferredApiMongoDB()) {
|
||||
buttons.push(CommandBarComponentButtonFactory.createOpenMongoTerminalButton(container));
|
||||
}
|
||||
|
||||
if (container.isPreferredApiCassandra()) {
|
||||
buttons.push(CommandBarComponentButtonFactory.createOpenCassandraTerminalButton(container));
|
||||
}
|
||||
}
|
||||
|
||||
if (container.isNotebookEnabled()) {
|
||||
buttons.push(CommandBarComponentButtonFactory.createOpenTerminalButton(container));
|
||||
|
||||
buttons.push(CommandBarComponentButtonFactory.createNotebookWorkspaceResetButton(container));
|
||||
|
||||
if (container.isGalleryEnabled()) {
|
||||
buttons.push(CommandBarComponentButtonFactory.createGalleryButton(container));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Should be replaced with the create arcadia spark pool button
|
||||
// if (!container.isSparkEnabled() && container.isSparkEnabledForAccount()) {
|
||||
// const createSparkClusterButton = CommandBarComponentButtonFactory.createSparkClusterButton(container);
|
||||
// buttons.push(createSparkClusterButton);
|
||||
// }
|
||||
|
||||
// TODO: Should be replaced with the edit/manage/delete arcadia spark pool button
|
||||
// if (container.isSparkEnabled()) {
|
||||
// const manageSparkClusterButton = CommandBarComponentButtonFactory.createMonitorClusterButton(container);
|
||||
// manageSparkClusterButton.children = [
|
||||
// CommandBarComponentButtonFactory.createMonitorClusterButton(container),
|
||||
// CommandBarComponentButtonFactory.createEditClusterButton(container),
|
||||
// CommandBarComponentButtonFactory.createDeleteClusterButton(container),
|
||||
// CommandBarComponentButtonFactory.createLibraryManageButton(container),
|
||||
// CommandBarComponentButtonFactory.createClusterLibraryButton(container)
|
||||
// ];
|
||||
// buttons.push(manageSparkClusterButton);
|
||||
// }
|
||||
|
||||
if (!container.isDatabaseNodeOrNoneSelected()) {
|
||||
if (container.isNotebookEnabled()) {
|
||||
buttons.push(CommandBarComponentButtonFactory.createDivider());
|
||||
}
|
||||
|
||||
const isSqlQuerySupported = container.isPreferredApiDocumentDB() || container.isPreferredApiGraph();
|
||||
if (isSqlQuerySupported) {
|
||||
const newSqlQueryBtn = CommandBarComponentButtonFactory.createNewSQLQueryButton(container);
|
||||
buttons.push(newSqlQueryBtn);
|
||||
}
|
||||
|
||||
const isSupportedOpenQueryApi =
|
||||
container.isPreferredApiDocumentDB() || container.isPreferredApiMongoDB() || container.isPreferredApiGraph();
|
||||
const isSupportedOpenQueryFromDiskApi = container.isPreferredApiDocumentDB() || container.isPreferredApiGraph();
|
||||
if (isSupportedOpenQueryApi && container.selectedNode() && container.findSelectedCollection()) {
|
||||
const openQueryBtn = CommandBarComponentButtonFactory.createOpenQueryButton(container);
|
||||
openQueryBtn.children = [
|
||||
CommandBarComponentButtonFactory.createOpenQueryButton(container),
|
||||
CommandBarComponentButtonFactory.createOpenQueryFromDiskButton(container)
|
||||
];
|
||||
buttons.push(openQueryBtn);
|
||||
} else if (isSupportedOpenQueryFromDiskApi && container.selectedNode() && container.findSelectedCollection()) {
|
||||
buttons.push(CommandBarComponentButtonFactory.createOpenQueryFromDiskButton(container));
|
||||
}
|
||||
|
||||
if (CommandBarComponentButtonFactory.areScriptsSupported(container)) {
|
||||
const label = "New Stored Procedure";
|
||||
const newStoredProcedureBtn: ViewModels.NavbarButtonConfig = {
|
||||
iconSrc: AddStoredProcedureIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
||||
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection, null);
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled: container.isDatabaseNodeOrNoneSelected()
|
||||
};
|
||||
|
||||
newStoredProcedureBtn.children = CommandBarComponentButtonFactory.createScriptCommandButtons(container);
|
||||
buttons.push(newStoredProcedureBtn);
|
||||
}
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
public static createContextCommandBarButtons(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig[] {
|
||||
const buttons: ViewModels.NavbarButtonConfig[] = [];
|
||||
|
||||
if (!container.isDatabaseNodeOrNoneSelected() && container.isPreferredApiMongoDB()) {
|
||||
const label = "New Shell";
|
||||
const newMongoShellBtn: ViewModels.NavbarButtonConfig = {
|
||||
iconSrc: HostedTerminalIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
||||
selectedCollection && (<any>selectedCollection).onNewMongoShellClick();
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled: container.isDatabaseNodeOrNoneSelected() && container.isPreferredApiMongoDB()
|
||||
};
|
||||
buttons.push(newMongoShellBtn);
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
public static createControlCommandBarButtons(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig[] {
|
||||
const buttons: ViewModels.NavbarButtonConfig[] = [];
|
||||
if (window.dataExplorerPlatform === PlatformType.Hosted) {
|
||||
return buttons;
|
||||
}
|
||||
|
||||
if (!container.isPreferredApiCassandra()) {
|
||||
const label = "Settings";
|
||||
const settingsPaneButton: ViewModels.NavbarButtonConfig = {
|
||||
iconSrc: SettingsIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.settingsPane.open(),
|
||||
commandButtonLabel: null,
|
||||
ariaLabel: label,
|
||||
tooltipText: label,
|
||||
hasPopup: true,
|
||||
disabled: false
|
||||
};
|
||||
buttons.push(settingsPaneButton);
|
||||
}
|
||||
|
||||
if (container.isHostedDataExplorerEnabled()) {
|
||||
const label = "Open Full Screen";
|
||||
const fullScreenButton: ViewModels.NavbarButtonConfig = {
|
||||
iconSrc: OpenInTabIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.generateSharedAccessData(),
|
||||
commandButtonLabel: null,
|
||||
ariaLabel: label,
|
||||
tooltipText: label,
|
||||
hasPopup: false,
|
||||
disabled: !container.isHostedDataExplorerEnabled(),
|
||||
className: "OpenFullScreen"
|
||||
};
|
||||
buttons.push(fullScreenButton);
|
||||
}
|
||||
|
||||
if (!container.hasOwnProperty("isEmulator") || !container.isEmulator) {
|
||||
const label = "Feedback";
|
||||
const feedbackButtonOptions: ViewModels.NavbarButtonConfig = {
|
||||
iconSrc: FeedbackIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.provideFeedbackEmail(),
|
||||
commandButtonLabel: null,
|
||||
ariaLabel: label,
|
||||
tooltipText: label,
|
||||
hasPopup: false,
|
||||
disabled: false
|
||||
};
|
||||
buttons.push(feedbackButtonOptions);
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
public static createDivider(): ViewModels.NavbarButtonConfig {
|
||||
const label = `divider${CommandBarComponentButtonFactory.counter++}`;
|
||||
return {
|
||||
isDivider: true,
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
iconSrc: null,
|
||||
iconAlt: null,
|
||||
onCommandClick: null,
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static areScriptsSupported(container: ViewModels.Explorer): boolean {
|
||||
return container.isPreferredApiDocumentDB() || container.isPreferredApiGraph();
|
||||
}
|
||||
|
||||
private static createNewCollectionGroup(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = container.addCollectionText();
|
||||
return {
|
||||
iconSrc: AddCollectionIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.onNewCollectionClicked(),
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
id: "createNewContainerCommandButton"
|
||||
};
|
||||
}
|
||||
|
||||
private static createOpenSynapseLinkDialogButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
if (config.platform === Platform.Emulator) {
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
container.databaseAccount &&
|
||||
container.databaseAccount() &&
|
||||
container.databaseAccount().properties &&
|
||||
container.databaseAccount().properties.enableAnalyticalStorage
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const capabilities =
|
||||
(container.databaseAccount &&
|
||||
container.databaseAccount() &&
|
||||
container.databaseAccount().properties &&
|
||||
container.databaseAccount().properties.capabilities) ||
|
||||
[];
|
||||
if (capabilities.some(capability => capability.name === Constants.CapabilityNames.EnableStorageAnalytics)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const label = "Enable Azure Synapse Link (Preview)";
|
||||
return {
|
||||
iconSrc: SynapseIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.openEnableSynapseLinkDialog(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: container.isSynapseLinkUpdating(),
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static createNewDatabase(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = container.addDatabaseText();
|
||||
return {
|
||||
iconSrc: AddDatabaseIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
container.addDatabasePane.open();
|
||||
document.getElementById("linkAddDatabase").focus();
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true
|
||||
};
|
||||
}
|
||||
|
||||
private static createNewSQLQueryButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
if (container.isPreferredApiDocumentDB() || container.isPreferredApiGraph()) {
|
||||
const label = "New SQL Query";
|
||||
return {
|
||||
iconSrc: AddSqlQueryIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
||||
selectedCollection && selectedCollection.onNewQueryClick(selectedCollection, null);
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled: container.isDatabaseNodeOrNoneSelected()
|
||||
};
|
||||
} else if (container.isPreferredApiMongoDB()) {
|
||||
const label = "New Query";
|
||||
return {
|
||||
iconSrc: AddSqlQueryIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
||||
selectedCollection && (<any>selectedCollection).onNewMongoQueryClick(selectedCollection, null);
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled: container.isDatabaseNodeOrNoneSelected()
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static createScriptCommandButtons(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig[] {
|
||||
const buttons: ViewModels.NavbarButtonConfig[] = [];
|
||||
|
||||
const shouldEnableScriptsCommands: boolean =
|
||||
!container.isDatabaseNodeOrNoneSelected() && CommandBarComponentButtonFactory.areScriptsSupported(container);
|
||||
|
||||
if (shouldEnableScriptsCommands) {
|
||||
const label = "New Stored Procedure";
|
||||
const newStoredProcedureBtn: ViewModels.NavbarButtonConfig = {
|
||||
iconSrc: AddStoredProcedureIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
||||
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection, null);
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled: container.isDatabaseNodeOrNoneSelected()
|
||||
};
|
||||
buttons.push(newStoredProcedureBtn);
|
||||
}
|
||||
|
||||
if (shouldEnableScriptsCommands) {
|
||||
const label = "New UDF";
|
||||
const newUserDefinedFunctionBtn: ViewModels.NavbarButtonConfig = {
|
||||
iconSrc: AddUdfIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
||||
selectedCollection && selectedCollection.onNewUserDefinedFunctionClick(selectedCollection, null);
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled: container.isDatabaseNodeOrNoneSelected()
|
||||
};
|
||||
buttons.push(newUserDefinedFunctionBtn);
|
||||
}
|
||||
|
||||
if (shouldEnableScriptsCommands) {
|
||||
const label = "New Trigger";
|
||||
const newTriggerBtn: ViewModels.NavbarButtonConfig = {
|
||||
iconSrc: AddTriggerIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
||||
selectedCollection && selectedCollection.onNewTriggerClick(selectedCollection, null);
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled: container.isDatabaseNodeOrNoneSelected()
|
||||
};
|
||||
buttons.push(newTriggerBtn);
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
private static createScaleAndSettingsButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
let isShared = false;
|
||||
if (container.isDatabaseNodeSelected()) {
|
||||
isShared = container.findSelectedDatabase().isDatabaseShared();
|
||||
} else if (container.isNodeKindSelected("Collection")) {
|
||||
const database: ViewModels.Database = container.findSelectedCollection().getDatabase();
|
||||
isShared = database && database.isDatabaseShared();
|
||||
}
|
||||
|
||||
const label = isShared ? "Settings" : "Scale & Settings";
|
||||
|
||||
return {
|
||||
iconSrc: ScaleIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
const selectedCollection: ViewModels.Collection = container.findSelectedCollection();
|
||||
selectedCollection && (<any>selectedCollection).onSettingsClick();
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled: container.isDatabaseNodeOrNoneSelected()
|
||||
};
|
||||
}
|
||||
|
||||
private static createNewNotebookButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "New Notebook";
|
||||
return {
|
||||
iconSrc: NewNotebookIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.onNewNotebookClicked(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static createuploadNotebookButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Upload to Notebook Server";
|
||||
return {
|
||||
iconSrc: NewNotebookIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.onUploadToNotebookServerClicked(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static createOpenQueryButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Open Query";
|
||||
return {
|
||||
iconSrc: BrowseQueriesIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.browseQueriesPane.open(),
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled: false
|
||||
};
|
||||
}
|
||||
|
||||
private static createOpenQueryFromDiskButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Open Query From Disk";
|
||||
return {
|
||||
iconSrc: OpenQueryFromDiskIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.loadQueryPane.open(),
|
||||
commandButtonLabel: label,
|
||||
ariaLabel: label,
|
||||
hasPopup: true,
|
||||
disabled: false
|
||||
};
|
||||
}
|
||||
|
||||
private static createEnableNotebooksButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
if (config.platform === Platform.Emulator) {
|
||||
return null;
|
||||
}
|
||||
const label = "Enable Notebooks (Preview)";
|
||||
const tooltip =
|
||||
"Notebooks are not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks.";
|
||||
const description =
|
||||
"Looks like you have not yet created a notebooks workspace for this account. To proceed and start using notebooks, we'll need to create a default notebooks workspace in this account.";
|
||||
return {
|
||||
iconSrc: EnableNotebooksIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.setupNotebooksPane.openWithTitleAndDescription(label, description),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: !container.isNotebooksEnabledForAccount(),
|
||||
ariaLabel: label,
|
||||
tooltipText: container.isNotebooksEnabledForAccount() ? "" : tooltip
|
||||
};
|
||||
}
|
||||
|
||||
private static createSparkClusterButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Enable Spark";
|
||||
return {
|
||||
iconSrc: ApacheSparkIcon,
|
||||
iconAlt: "Enable spark icon",
|
||||
onCommandClick: () => container.setupSparkClusterPane.open(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static createEditClusterButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Edit Cluster";
|
||||
return {
|
||||
iconSrc: EditIcon,
|
||||
iconAlt: "Edit cluster icon",
|
||||
onCommandClick: () => container.manageSparkClusterPane.open(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static createDeleteClusterButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Delete Cluster";
|
||||
return {
|
||||
iconSrc: DeleteIcon,
|
||||
iconAlt: "Delete cluster icon",
|
||||
onCommandClick: () => container.deleteCluster(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static createMonitorClusterButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Monitor Cluster";
|
||||
return {
|
||||
iconSrc: ApacheSparkIcon,
|
||||
iconAlt: "Monitor cluster icon",
|
||||
onCommandClick: () => container.openSparkMasterTab(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static createOpenTerminalButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Open Terminal";
|
||||
return {
|
||||
iconSrc: CosmosTerminalIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.openNotebookTerminal(ViewModels.TerminalKind.Default),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static createGalleryButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "View Gallery";
|
||||
return {
|
||||
iconSrc: GalleryIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.openGallery(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static createOpenMongoTerminalButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Open Mongo Shell";
|
||||
const tooltip =
|
||||
"This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks.";
|
||||
const title = "Set up workspace";
|
||||
const description =
|
||||
"Looks like you have not created a workspace for this account. To proceed and start using features including mongo shell and notebook, we will need to create a default workspace in this account.";
|
||||
const disableButton = !container.isNotebooksEnabledForAccount() && !container.isNotebookEnabled();
|
||||
return {
|
||||
iconSrc: HostedTerminalIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
if (container.isNotebookEnabled()) {
|
||||
container.openNotebookTerminal(ViewModels.TerminalKind.Mongo);
|
||||
} else {
|
||||
container.setupNotebooksPane.openWithTitleAndDescription(title, description);
|
||||
}
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: disableButton,
|
||||
ariaLabel: label,
|
||||
tooltipText: !disableButton ? "" : tooltip
|
||||
};
|
||||
}
|
||||
|
||||
private static createOpenCassandraTerminalButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Open Cassandra Shell";
|
||||
const tooltip =
|
||||
"This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks.";
|
||||
const title = "Set up workspace";
|
||||
const description =
|
||||
"Looks like you have not created a workspace for this account. To proceed and start using features including cassandra shell and notebook, we will need to create a default workspace in this account.";
|
||||
const disableButton = !container.isNotebooksEnabledForAccount() && !container.isNotebookEnabled();
|
||||
return {
|
||||
iconSrc: HostedTerminalIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
if (container.isNotebookEnabled()) {
|
||||
container.openNotebookTerminal(ViewModels.TerminalKind.Cassandra);
|
||||
} else {
|
||||
container.setupNotebooksPane.openWithTitleAndDescription(title, description);
|
||||
}
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: disableButton,
|
||||
ariaLabel: label,
|
||||
tooltipText: !disableButton ? "" : tooltip
|
||||
};
|
||||
}
|
||||
|
||||
private static createNotebookWorkspaceResetButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Reset Workspace";
|
||||
return {
|
||||
iconSrc: ResetWorkspaceIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.resetNotebookWorkspace(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static createManageGitHubAccountButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
let connectedToGitHub: boolean = container.gitHubOAuthService.isLoggedIn();
|
||||
const label = connectedToGitHub ? "Manage GitHub settings" : "Connect to GitHub";
|
||||
return {
|
||||
iconSrc: GitHubIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => {
|
||||
if (!connectedToGitHub) {
|
||||
TelemetryProcessor.trace(Action.NotebooksGitHubConnect, ActionModifiers.Mark, {
|
||||
databaseAccountName: container.databaseAccount() && container.databaseAccount().name,
|
||||
defaultExperience: container.defaultExperience && container.defaultExperience(),
|
||||
dataExplorerArea: Areas.Notebook
|
||||
});
|
||||
}
|
||||
container.gitHubReposPane.open();
|
||||
},
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static createLibraryManageButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Manage Libraries";
|
||||
return {
|
||||
iconSrc: LibraryManageIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.libraryManagePane.open(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static createClusterLibraryButton(container: ViewModels.Explorer): ViewModels.NavbarButtonConfig {
|
||||
const label = "Manage Cluster Libraries";
|
||||
return {
|
||||
iconSrc: LibraryManageIcon,
|
||||
iconAlt: label,
|
||||
onCommandClick: () => container.clusterLibraryPane.open(),
|
||||
commandButtonLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
ariaLabel: label
|
||||
};
|
||||
}
|
||||
|
||||
private static createStaticCommandBarButtonsForResourceToken(
|
||||
container: ViewModels.Explorer
|
||||
): ViewModels.NavbarButtonConfig[] {
|
||||
const newSqlQueryBtn = CommandBarComponentButtonFactory.createNewSQLQueryButton(container);
|
||||
const openQueryBtn = CommandBarComponentButtonFactory.createOpenQueryButton(container);
|
||||
|
||||
newSqlQueryBtn.disabled = !container.isResourceTokenCollectionNodeSelected();
|
||||
newSqlQueryBtn.onCommandClick = () => {
|
||||
const resourceTokenCollection: ViewModels.CollectionBase = container.resourceTokenCollection();
|
||||
resourceTokenCollection && resourceTokenCollection.onNewQueryClick(resourceTokenCollection, undefined);
|
||||
};
|
||||
|
||||
openQueryBtn.disabled = !container.isResourceTokenCollectionNodeSelected();
|
||||
if (!openQueryBtn.disabled) {
|
||||
openQueryBtn.children = [
|
||||
CommandBarComponentButtonFactory.createOpenQueryButton(container),
|
||||
CommandBarComponentButtonFactory.createOpenQueryFromDiskButton(container)
|
||||
];
|
||||
}
|
||||
|
||||
return [newSqlQueryBtn, openQueryBtn];
|
||||
}
|
||||
}
|
||||
82
src/Explorer/Menus/CommandBar/CommandBarUtil.test.tsx
Normal file
82
src/Explorer/Menus/CommandBar/CommandBarUtil.test.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import { CommandBarUtil } from "./CommandBarUtil";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import { ICommandBarItemProps } from "office-ui-fabric-react/lib/CommandBar";
|
||||
|
||||
describe("CommandBarUtil tests", () => {
|
||||
const createButton = (): ViewModels.NavbarButtonConfig => {
|
||||
return {
|
||||
iconSrc: "icon",
|
||||
iconAlt: "label",
|
||||
onCommandClick: (e: React.SyntheticEvent): void => {},
|
||||
commandButtonLabel: "label",
|
||||
ariaLabel: "ariaLabel",
|
||||
hasPopup: true,
|
||||
disabled: true,
|
||||
tooltipText: "tooltipText",
|
||||
children: [],
|
||||
className: "className"
|
||||
};
|
||||
};
|
||||
|
||||
it("should convert simple NavbarButtonConfig button", () => {
|
||||
const btn = createButton();
|
||||
const backgroundColor = "backgroundColor";
|
||||
|
||||
const converteds = CommandBarUtil.convertButton([btn], backgroundColor);
|
||||
expect(converteds.length).toBe(1);
|
||||
const converted = converteds[0];
|
||||
expect(!converted.split);
|
||||
expect(converted.iconProps.imageProps.src).toEqual(btn.iconSrc);
|
||||
expect(converted.iconProps.imageProps.alt).toEqual(btn.iconAlt);
|
||||
expect(converted.onClick).toEqual(btn.onCommandClick);
|
||||
expect(converted.text).toEqual(btn.commandButtonLabel);
|
||||
expect(converted.ariaLabel).toEqual(btn.ariaLabel);
|
||||
expect(converted.disabled).toEqual(btn.disabled);
|
||||
expect(converted.className).toEqual(btn.className);
|
||||
});
|
||||
|
||||
it("should convert NavbarButtonConfig to split button", () => {
|
||||
const btn = createButton();
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const child = createButton();
|
||||
child.commandButtonLabel = `child${i}`;
|
||||
btn.children.push(child);
|
||||
}
|
||||
|
||||
const converteds = CommandBarUtil.convertButton([btn], "backgroundColor");
|
||||
expect(converteds.length).toBe(1);
|
||||
const converted = converteds[0];
|
||||
expect(converted.split);
|
||||
expect(converted.subMenuProps.items.length).toBe(btn.children.length);
|
||||
for (let i = 0; i < converted.subMenuProps.items.length; i++) {
|
||||
expect(converted.subMenuProps.items[i].text).toEqual(btn.children[i].commandButtonLabel);
|
||||
}
|
||||
});
|
||||
|
||||
it("should create buttons with unique keys", () => {
|
||||
const btns: ViewModels.NavbarButtonConfig[] = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
btns.push(createButton());
|
||||
}
|
||||
|
||||
const converteds = CommandBarUtil.convertButton(btns, "backgroundColor");
|
||||
const keys = converteds.map((btn: ICommandBarItemProps) => btn.key);
|
||||
const uniqueKeys = converteds
|
||||
.map((btn: ICommandBarItemProps) => btn.key)
|
||||
.filter((value: string, index: number, self: string[]) => self.indexOf(value) === index);
|
||||
expect(uniqueKeys.length).toBe(btns.length);
|
||||
});
|
||||
|
||||
it("should create icon buttons with tooltips", () => {
|
||||
const btn = createButton();
|
||||
const backgroundColor = "backgroundColor";
|
||||
|
||||
btn.commandButtonLabel = null;
|
||||
let converted = CommandBarUtil.convertButton([btn], backgroundColor)[0];
|
||||
expect(converted.text).toEqual(btn.tooltipText);
|
||||
|
||||
converted = CommandBarUtil.convertButton([btn], backgroundColor)[0];
|
||||
delete btn.commandButtonLabel;
|
||||
expect(converted.text).toEqual(btn.tooltipText);
|
||||
});
|
||||
});
|
||||
183
src/Explorer/Menus/CommandBar/CommandBarUtil.tsx
Normal file
183
src/Explorer/Menus/CommandBar/CommandBarUtil.tsx
Normal file
@@ -0,0 +1,183 @@
|
||||
import * as React from "react";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import { Observable } from "knockout";
|
||||
import { IconType } from "office-ui-fabric-react/lib/Icon";
|
||||
import { IComponentAsProps } from "office-ui-fabric-react/lib/Utilities";
|
||||
import { KeyCodes, StyleConstants } from "../../../Common/Constants";
|
||||
import { ICommandBarItemProps } from "office-ui-fabric-react/lib/CommandBar";
|
||||
import { Dropdown, DropdownMenuItemType, IDropdownStyles, IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
|
||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||
import ChevronDownIcon from "../../../../images/Chevron_down.svg";
|
||||
import { ArcadiaMenuPicker } from "../../Controls/Arcadia/ArcadiaMenuPicker";
|
||||
import { MemoryTrackerComponent } from "./MemoryTrackerComponent";
|
||||
import { MemoryUsageInfo } from "../../../Contracts/DataModels";
|
||||
|
||||
/**
|
||||
* Utilities for CommandBar
|
||||
*/
|
||||
export class CommandBarUtil {
|
||||
/**
|
||||
* Convert our NavbarButtonConfig to UI Fabric buttons
|
||||
* @param btns
|
||||
*/
|
||||
public static convertButton(btns: ViewModels.NavbarButtonConfig[], backgroundColor: string): ICommandBarItemProps[] {
|
||||
const buttonHeightPx = StyleConstants.CommandBarButtonHeight;
|
||||
|
||||
return btns
|
||||
.filter(btn => btn)
|
||||
.map(
|
||||
(btn: ViewModels.NavbarButtonConfig, index: number): ICommandBarItemProps => {
|
||||
if (btn.isDivider) {
|
||||
return CommandBarUtil.createDivider(btn.commandButtonLabel);
|
||||
}
|
||||
|
||||
const isSplit = !!btn.children && btn.children.length > 0;
|
||||
|
||||
const result: ICommandBarItemProps = {
|
||||
iconProps: {
|
||||
iconType: IconType.image,
|
||||
style: {
|
||||
width: StyleConstants.CommandBarIconWidth // 16
|
||||
},
|
||||
imageProps: { src: btn.iconSrc, alt: btn.iconAlt }
|
||||
},
|
||||
onClick: btn.onCommandClick,
|
||||
key: `${btn.commandButtonLabel}${index}`,
|
||||
text: btn.commandButtonLabel || btn.tooltipText,
|
||||
"data-test": btn.commandButtonLabel || btn.tooltipText,
|
||||
title: btn.tooltipText,
|
||||
name: "menuitem",
|
||||
disabled: btn.disabled,
|
||||
ariaLabel: btn.ariaLabel,
|
||||
buttonStyles: {
|
||||
root: {
|
||||
backgroundColor: backgroundColor,
|
||||
height: buttonHeightPx,
|
||||
paddingRight: 0,
|
||||
paddingLeft: 0,
|
||||
minWidth: 24,
|
||||
marginLeft: isSplit ? 0 : 5,
|
||||
marginRight: isSplit ? 0 : 5
|
||||
},
|
||||
rootDisabled: {
|
||||
backgroundColor: backgroundColor,
|
||||
pointerEvents: "auto"
|
||||
},
|
||||
splitButtonMenuButton: {
|
||||
backgroundColor: backgroundColor,
|
||||
selectors: {
|
||||
":hover": { backgroundColor: StyleConstants.AccentLight }
|
||||
},
|
||||
width: 16
|
||||
},
|
||||
label: { fontSize: StyleConstants.mediumFontSize },
|
||||
rootHovered: { backgroundColor: StyleConstants.AccentLight },
|
||||
rootPressed: { backgroundColor: StyleConstants.AccentLight },
|
||||
splitButtonMenuButtonExpanded: {
|
||||
backgroundColor: StyleConstants.AccentExtra,
|
||||
selectors: {
|
||||
":hover": { backgroundColor: StyleConstants.AccentLight }
|
||||
}
|
||||
},
|
||||
splitButtonDivider: {
|
||||
display: "none"
|
||||
},
|
||||
icon: {
|
||||
paddingLeft: 0,
|
||||
paddingRight: 0
|
||||
},
|
||||
splitButtonContainer: {
|
||||
marginLeft: 5,
|
||||
marginRight: 5
|
||||
}
|
||||
},
|
||||
className: btn.className,
|
||||
id: btn.id
|
||||
};
|
||||
|
||||
if (isSplit) {
|
||||
// It's a split button
|
||||
result.split = true;
|
||||
|
||||
result.subMenuProps = {
|
||||
items: CommandBarUtil.convertButton(btn.children, backgroundColor),
|
||||
styles: {
|
||||
list: {
|
||||
// TODO Figure out how to do it the proper way with subComponentStyles.
|
||||
// TODO Remove all this crazy styling once we adopt Ui-Fabric Azure themes
|
||||
selectors: {
|
||||
".ms-ContextualMenu-itemText": { fontSize: StyleConstants.mediumFontSize },
|
||||
".ms-ContextualMenu-link:hover": { backgroundColor: StyleConstants.AccentLight },
|
||||
".ms-ContextualMenu-icon": { width: 16, height: 16 }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
result.menuIconProps = {
|
||||
iconType: IconType.image,
|
||||
style: {
|
||||
width: 12,
|
||||
paddingLeft: 1,
|
||||
paddingTop: 6
|
||||
},
|
||||
imageProps: { src: ChevronDownIcon, alt: btn.iconAlt }
|
||||
};
|
||||
}
|
||||
|
||||
if (btn.isDropdown) {
|
||||
const dropdownStyles: Partial<IDropdownStyles> = {
|
||||
root: { margin: 5 },
|
||||
dropdown: { width: btn.dropdownWidth },
|
||||
title: { fontSize: 12, height: 30, lineHeight: 28 },
|
||||
dropdownItem: { fontSize: 12, lineHeight: 28, minHeight: 30 },
|
||||
dropdownItemSelected: { fontSize: 12, lineHeight: 28, minHeight: 30 }
|
||||
};
|
||||
|
||||
result.commandBarButtonAs = (props: IComponentAsProps<ICommandBarItemProps>) => {
|
||||
return (
|
||||
<Dropdown
|
||||
placeholder={btn.dropdownPlaceholder}
|
||||
defaultSelectedKey={btn.dropdownSelectedKey}
|
||||
onChange={(event: React.FormEvent<HTMLDivElement>, option?: IDropdownOption, index?: number): void =>
|
||||
btn.children[index].onCommandClick(event)
|
||||
}
|
||||
options={btn.children.map((child: CommandButtonComponentProps) => ({
|
||||
key: child.dropdownItemKey,
|
||||
text: child.commandButtonLabel
|
||||
}))}
|
||||
styles={dropdownStyles}
|
||||
/>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
if (btn.isArcadiaPicker && btn.arcadiaProps) {
|
||||
result.commandBarButtonAs = () => <ArcadiaMenuPicker {...btn.arcadiaProps} />;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static createDivider(key: string): ICommandBarItemProps {
|
||||
return {
|
||||
onRender: () => (
|
||||
<div className="dividerContainer">
|
||||
<span />
|
||||
</div>
|
||||
),
|
||||
iconOnly: true,
|
||||
disabled: true,
|
||||
key: key
|
||||
};
|
||||
}
|
||||
|
||||
public static createMemoryTracker(key: string, memoryUsageInfo: Observable<MemoryUsageInfo>): ICommandBarItemProps {
|
||||
return {
|
||||
key,
|
||||
onRender: () => <MemoryTrackerComponent memoryUsageInfo={memoryUsageInfo} />
|
||||
};
|
||||
}
|
||||
}
|
||||
24
src/Explorer/Menus/CommandBar/MemoryTrackerComponent.less
Normal file
24
src/Explorer/Menus/CommandBar/MemoryTrackerComponent.less
Normal file
@@ -0,0 +1,24 @@
|
||||
@import "../../../../less/Common/Constants";
|
||||
|
||||
.memoryTrackerContainer {
|
||||
cursor: default;
|
||||
align-items: center;
|
||||
margin: 0 9px;
|
||||
border: 1px;
|
||||
|
||||
> span {
|
||||
padding-right: 12px;
|
||||
font-size: 13px;
|
||||
font-family: @DataExplorerFont;
|
||||
color: @DefaultFontColor;
|
||||
}
|
||||
|
||||
> .lowMemory {
|
||||
.ms-ProgressIndicator-progressBar {
|
||||
background-color: @SelectionHigh;
|
||||
}
|
||||
.ms-ProgressIndicator-itemDescription {
|
||||
color: @SelectionHigh;
|
||||
}
|
||||
}
|
||||
}
|
||||
50
src/Explorer/Menus/CommandBar/MemoryTrackerComponent.tsx
Normal file
50
src/Explorer/Menus/CommandBar/MemoryTrackerComponent.tsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import * as React from "react";
|
||||
import { Observable, Subscription } from "knockout";
|
||||
import { MemoryUsageInfo } from "../../../Contracts/DataModels";
|
||||
import { ProgressIndicator } from "office-ui-fabric-react/lib/ProgressIndicator";
|
||||
import { Spinner, SpinnerSize } from "office-ui-fabric-react/lib/Spinner";
|
||||
import { Stack } from "office-ui-fabric-react/lib/Stack";
|
||||
|
||||
interface MemoryTrackerProps {
|
||||
memoryUsageInfo: Observable<MemoryUsageInfo>;
|
||||
}
|
||||
|
||||
export class MemoryTrackerComponent extends React.Component<MemoryTrackerProps> {
|
||||
private memoryUsageInfoSubscription: Subscription;
|
||||
|
||||
public componentDidMount(): void {
|
||||
this.memoryUsageInfoSubscription = this.props.memoryUsageInfo.subscribe(() => {
|
||||
this.forceUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
this.memoryUsageInfoSubscription && this.memoryUsageInfoSubscription.dispose();
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
const memoryUsageInfo: MemoryUsageInfo = this.props.memoryUsageInfo();
|
||||
if (!memoryUsageInfo) {
|
||||
return (
|
||||
<Stack className="memoryTrackerContainer" horizontal>
|
||||
<span>Memory</span>
|
||||
<Spinner size={SpinnerSize.medium} />
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
const totalGB = memoryUsageInfo.totalKB / 1048576;
|
||||
const usedGB = totalGB - memoryUsageInfo.freeKB / 1048576;
|
||||
|
||||
return (
|
||||
<Stack className="memoryTrackerContainer" horizontal>
|
||||
<span>Memory</span>
|
||||
<ProgressIndicator
|
||||
className={usedGB / totalGB > 0.8 ? "lowMemory" : ""}
|
||||
description={usedGB.toFixed(1) + " of " + totalGB.toFixed(1) + " GB"}
|
||||
percentComplete={usedGB / totalGB}
|
||||
/>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user