diff --git a/.eslintignore b/.eslintignore
index ae73b21a2..c23885881 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -146,7 +146,7 @@ src/Explorer/Tabs/MongoDocumentsTab.ts
# src/Explorer/Tabs/MongoShellTab.ts
src/Explorer/Tabs/NotebookV2Tab.ts
src/Explorer/Tabs/ScriptTabBase.ts
-src/Explorer/Tabs/StoredProcedureTab.ts
+# src/Explorer/Tabs/StoredProcedureTab.ts
src/Explorer/Tabs/TabComponents.ts
src/Explorer/Tabs/TabsBase.ts
src/Explorer/Tabs/TriggerTab.ts
diff --git a/less/documentDB.less b/less/documentDB.less
index 1c8a7e8bb..271f53992 100644
--- a/less/documentDB.less
+++ b/less/documentDB.less
@@ -724,45 +724,24 @@ execute-sproc-params-pane {
.results-container,
.errors-container {
- padding: @MediumSpace 0px 0px @MediumSpace;
height: 100%;
.flex-display();
.flex-direction();
overflow: hidden;
- .toggles {
- height: @ToggleHeight;
- width: @ToggleWidth;
- margin-left: @MediumSpace;
-
- &:focus {
- .focus();
- }
-
- .tab {
- margin-right: @MediumSpace;
- }
-
- .toggleSwitch {
- .toggleSwitch();
- }
-
- .selectedToggle {
- .selectedToggle();
- }
-
- .unselectedToggle {
- .unselectedToggle();
- }
- }
-
.enterInputParameters {
padding: @LargeSpace @MediumSpace;
}
+
+ div[role="tabpanel"] {
+ height: 100%;
+ padding-bottom: 50px;
+ }
}
.errors-container {
padding-left: (2 * @MediumSpace);
+ padding: @MediumSpace 0px 0px @MediumSpace;
.errors-header {
font-weight: 700;
font-size: @DefaultFontSize;
diff --git a/src/Explorer/Tabs/StoredProcedureTab.html b/src/Explorer/Tabs/StoredProcedureTab.html
deleted file mode 100644
index dc7db1bf7..000000000
--- a/src/Explorer/Tabs/StoredProcedureTab.html
+++ /dev/null
@@ -1,89 +0,0 @@
-
diff --git a/src/Explorer/Tabs/StoredProcedureTab.ts b/src/Explorer/Tabs/StoredProcedureTab.ts
deleted file mode 100644
index 1b3de5502..000000000
--- a/src/Explorer/Tabs/StoredProcedureTab.ts
+++ /dev/null
@@ -1,287 +0,0 @@
-import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
-import * as ko from "knockout";
-import Q from "q";
-import * as _ from "underscore";
-import ExecuteQueryIcon from "../../../images/ExecuteQuery.svg";
-import * as Constants from "../../Common/Constants";
-import { createStoredProcedure } from "../../Common/dataAccess/createStoredProcedure";
-import { updateStoredProcedure } from "../../Common/dataAccess/updateStoredProcedure";
-import editable from "../../Common/EditableUtility";
-import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils";
-import * as ViewModels from "../../Contracts/ViewModels";
-import { useNotificationConsole } from "../../hooks/useNotificationConsole";
-import { Action } from "../../Shared/Telemetry/TelemetryConstants";
-import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
-import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
-import StoredProcedure from "../Tree/StoredProcedure";
-import ScriptTabBase from "./ScriptTabBase";
-import template from "./StoredProcedureTab.html";
-
-enum ToggleState {
- Result = "result",
- Logs = "logs",
-}
-
-export default class StoredProcedureTab extends ScriptTabBase {
- public readonly html = template;
- public collection: ViewModels.Collection;
- public node: StoredProcedure;
- public executeResultsEditorId: string;
- public executeLogsEditorId: string;
- public toggleState: ko.Observable;
- public originalSprocBody: ViewModels.Editable;
- public resultsData: ko.Observable;
- public logsData: ko.Observable;
- public error: ko.Observable;
- public hasResults: ko.Observable;
- public hasErrors: ko.Observable;
-
- constructor(options: ViewModels.ScriptTabOption) {
- super(options);
- super.onActivate.bind(this);
-
- this.executeResultsEditorId = `executestoredprocedureresults${this.tabId}`;
- this.executeLogsEditorId = `executestoredprocedurelogs${this.tabId}`;
- this.toggleState = ko.observable(ToggleState.Result);
- this.originalSprocBody = editable.observable(this.editorContent());
- this.resultsData = ko.observable();
- this.logsData = ko.observable();
- this.error = ko.observable();
- this.hasResults = ko.observable(false);
- this.hasErrors = ko.observable(false);
- this.error.subscribe((error: string) => {
- this.hasErrors(error != null);
- this.hasResults(error == null);
- });
-
- this.ariaLabel("Stored Procedure Body");
- this.buildCommandBarOptions();
- }
-
- public onSaveClick = (): Promise => {
- return this._createStoredProcedure({
- id: this.id(),
- body: this.editorContent(),
- });
- };
-
- public onDiscard = (): Q.Promise => {
- this.setBaselines();
- const original = this.editorContent.getEditableOriginalValue();
- this.originalSprocBody(original);
- this.originalSprocBody.valueHasMutated(); // trigger a re-render of the editor
-
- return Q();
- };
-
- public onUpdateClick = (): Promise => {
- const data = this._getResource();
-
- this.isExecutionError(false);
- this.isExecuting(true);
- const startKey: number = TelemetryProcessor.traceStart(Action.UpdateStoredProcedure, {
- dataExplorerArea: Constants.Areas.Tab,
- tabTitle: this.tabTitle(),
- });
- return updateStoredProcedure(this.collection.databaseId, this.collection.id(), data)
- .then(
- (updatedResource) => {
- this.resource(updatedResource);
- this.tabTitle(updatedResource.id);
- this.node.id(updatedResource.id);
- this.node.body(updatedResource.body as string);
- this.setBaselines();
-
- const editorModel = this.editor() && this.editor().getModel();
- editorModel && editorModel.setValue(updatedResource.body as string);
- this.editorContent.setBaseline(updatedResource.body as string);
- TelemetryProcessor.traceSuccess(
- Action.UpdateStoredProcedure,
- {
- dataExplorerArea: Constants.Areas.Tab,
- tabTitle: this.tabTitle(),
- },
- startKey
- );
- },
- (error: any) => {
- this.isExecutionError(true);
- TelemetryProcessor.traceFailure(
- Action.UpdateStoredProcedure,
- {
- dataExplorerArea: Constants.Areas.Tab,
- tabTitle: this.tabTitle(),
- error: getErrorMessage(error),
- errorStack: getErrorStack(error),
- },
- startKey
- );
- }
- )
- .finally(() => this.isExecuting(false));
- };
-
- public onExecuteSprocsResult(result: any, logsData: any): void {
- const resultData: string = this.renderObjectForEditor(_.omit(result, "scriptLogs").result, null, 4);
- const scriptLogs: string = (result.scriptLogs && decodeURIComponent(result.scriptLogs)) || "";
- const logs: string = this.renderObjectForEditor(scriptLogs, null, 4);
- this.error(null);
- this.resultsData(resultData);
- this.logsData(logs);
- }
-
- public onExecuteSprocsError(error: string): void {
- this.isExecutionError(true);
- console.error(error);
- this.error(error);
- }
-
- public onErrorDetailsClick = (src: any, event: MouseEvent): boolean => {
- useNotificationConsole.getState().expandConsole();
-
- return false;
- };
-
- public onErrorDetailsKeyPress = (src: any, event: KeyboardEvent): boolean => {
- if (event.keyCode === Constants.KeyCodes.Space || event.keyCode === Constants.KeyCodes.Enter) {
- this.onErrorDetailsClick(src, null);
- return false;
- }
-
- return true;
- };
-
- public toggleResult(): void {
- this.toggleState(ToggleState.Result);
- this.resultsData.valueHasMutated(); // needed to refresh the json-editor component
- }
-
- public toggleLogs(): void {
- this.toggleState(ToggleState.Logs);
- this.logsData.valueHasMutated(); // needed to refresh the json-editor component
- }
-
- public onToggleKeyDown = (source: any, event: KeyboardEvent): boolean => {
- if (event.keyCode === Constants.KeyCodes.LeftArrow) {
- this.toggleResult();
- event.stopPropagation();
- return false;
- } else if (event.keyCode === Constants.KeyCodes.RightArrow) {
- this.toggleLogs();
- event.stopPropagation();
- return false;
- }
-
- return true;
- };
-
- public isResultToggled(): boolean {
- return this.toggleState() === ToggleState.Result;
- }
-
- public isLogsToggled(): boolean {
- return this.toggleState() === ToggleState.Logs;
- }
-
- protected updateSelectedNode(): void {
- if (this.collection == null) {
- return;
- }
-
- const database: ViewModels.Database = this.collection.getDatabase();
- if (!database.isDatabaseExpanded()) {
- this.collection.container.selectedNode(database);
- } else if (!this.collection.isCollectionExpanded() || !this.collection.isStoredProceduresExpanded()) {
- this.collection.container.selectedNode(this.collection);
- } else {
- this.collection.container.selectedNode(this.node);
- }
- }
-
- protected buildCommandBarOptions(): void {
- ko.computed(() => ko.toJSON([this.isNew, this.formIsDirty])).subscribe(() => this.updateNavbarWithTabsButtons());
- super.buildCommandBarOptions();
- }
-
- protected getTabsButtons(): CommandButtonComponentProps[] {
- const label = "Execute";
- return super.getTabsButtons().concat({
- iconSrc: ExecuteQueryIcon,
- iconAlt: label,
- onCommandClick: () => {
- this.collection && this.collection.container.openExecuteSprocParamsPanel(this.node);
- },
- commandButtonLabel: label,
- ariaLabel: label,
- hasPopup: false,
- disabled: this.isNew() || this.formIsDirty(),
- });
- }
-
- private _getResource() {
- return {
- id: this.id(),
- body: this.editorContent(),
- };
- }
-
- private _createStoredProcedure(resource: StoredProcedureDefinition): Promise {
- this.isExecutionError(false);
- this.isExecuting(true);
- const startKey: number = TelemetryProcessor.traceStart(Action.CreateStoredProcedure, {
- dataExplorerArea: Constants.Areas.Tab,
- tabTitle: this.tabTitle(),
- });
-
- return createStoredProcedure(this.collection.databaseId, this.collection.id(), resource)
- .then(
- (createdResource) => {
- this.tabTitle(createdResource.id);
- this.isNew(false);
- this.resource(createdResource);
- this.hashLocation(
- `${Constants.HashRoutePrefixes.collectionsWithIds(
- this.collection.databaseId,
- this.collection.id()
- )}/sprocs/${createdResource.id}`
- );
- this.setBaselines();
-
- const editorModel = this.editor() && this.editor().getModel();
- editorModel && editorModel.setValue(createdResource.body as string);
- this.editorContent.setBaseline(createdResource.body as string);
- this.node = this.collection.createStoredProcedureNode(createdResource);
- TelemetryProcessor.traceSuccess(
- Action.CreateStoredProcedure,
- {
- dataExplorerArea: Constants.Areas.Tab,
- tabTitle: this.tabTitle(),
- },
- startKey
- );
- this.editorState(ViewModels.ScriptEditorState.exisitingNoEdits);
- return createdResource;
- },
- (createError) => {
- this.isExecutionError(true);
- TelemetryProcessor.traceFailure(
- Action.CreateStoredProcedure,
- {
- dataExplorerArea: Constants.Areas.Tab,
- tabTitle: this.tabTitle(),
- error: getErrorMessage(createError),
- errorStack: getErrorStack(createError),
- },
- startKey
- );
- return Promise.reject(createError);
- }
- )
- .finally(() => this.isExecuting(false));
- }
-
- public onDelete(): Q.Promise {
- // TODO
- return Q();
- }
-}
diff --git a/src/Explorer/Tabs/StoredProcedureTab/StoredProcedureTab.tsx b/src/Explorer/Tabs/StoredProcedureTab/StoredProcedureTab.tsx
new file mode 100644
index 000000000..3bf332956
--- /dev/null
+++ b/src/Explorer/Tabs/StoredProcedureTab/StoredProcedureTab.tsx
@@ -0,0 +1,70 @@
+import React from "react";
+import { ExecuteSprocResult } from "../../../Common/dataAccess/executeStoredProcedure";
+import * as DataModels from "../../../Contracts/DataModels";
+import * as ViewModels from "../../../Contracts/ViewModels";
+import Explorer from "../../Explorer";
+import StoredProcedure from "../../Tree/StoredProcedure";
+import ScriptTabBase from "../ScriptTabBase";
+import StoredProcedureTabComponent, {
+ IStoredProcTabComponentProps,
+ IStorProcTabComponentAccessor,
+} from "./StoredProcedureTabComponent";
+
+export interface IStoredProcTabProps {
+ container: Explorer;
+ collection: ViewModels.Collection;
+}
+
+export class NewStoredProcedureTab extends ScriptTabBase {
+ public queryText: string;
+ public currentQuery: string;
+ public partitionKey: DataModels.PartitionKey;
+ public iStoredProcTabComponentProps: IStoredProcTabComponentProps;
+ public iStoreProcAccessor: IStorProcTabComponentAccessor;
+ public node: StoredProcedure;
+ public onSaveClick: () => void;
+ public onUpdateClick: () => Promise;
+
+ constructor(options: ViewModels.ScriptTabOption, private props: IStoredProcTabProps) {
+ super(options);
+ this.partitionKey = options.partitionKey;
+
+ this.iStoredProcTabComponentProps = {
+ resource: options.resource,
+ isNew: options.isNew,
+ tabKind: options.tabKind,
+ title: options.title,
+ tabPath: options.tabPath,
+ collectionBase: options.collection,
+ node: options.node,
+ hasLocation: options.hashLocation,
+ scriptTabBaseInstance: this,
+ collection: props.collection,
+ iStorProcTabComponentAccessor: (instance: IStorProcTabComponentAccessor) => {
+ this.iStoreProcAccessor = instance;
+ },
+ container: props.container,
+ };
+ }
+
+ public render(): JSX.Element {
+ return ;
+ }
+
+ public onTabClick(): void {
+ this.manager?.activateTab(this);
+ this.iStoreProcAccessor.onTabClickEvent();
+ }
+
+ public onCloseTabButtonClick(): void {
+ this.manager?.closeTab(this);
+ }
+
+ public onExecuteSprocsResult(result: ExecuteSprocResult): void {
+ this.iStoreProcAccessor.onExecuteSprocsResultEvent(result);
+ }
+
+ public onExecuteSprocsError(error: string): void {
+ this.iStoreProcAccessor.onExecuteSprocsErrorEvent(error);
+ }
+}
diff --git a/src/Explorer/Tabs/StoredProcedureTab/StoredProcedureTabComponent.tsx b/src/Explorer/Tabs/StoredProcedureTab/StoredProcedureTabComponent.tsx
new file mode 100644
index 000000000..6d2b93be5
--- /dev/null
+++ b/src/Explorer/Tabs/StoredProcedureTab/StoredProcedureTabComponent.tsx
@@ -0,0 +1,604 @@
+import { Resource, StoredProcedureDefinition } from "@azure/cosmos";
+import { Pivot, PivotItem } from "@fluentui/react";
+import React from "react";
+import DiscardIcon from "../../../../images/discard.svg";
+import ExecuteQueryIcon from "../../../../images/ExecuteQuery.svg";
+import SaveIcon from "../../../../images/save-cosmos.svg";
+import * as Constants from "../../../Common/Constants";
+import { NormalizedEventKey } from "../../../Common/Constants";
+import { createStoredProcedure } from "../../../Common/dataAccess/createStoredProcedure";
+import { ExecuteSprocResult } from "../../../Common/dataAccess/executeStoredProcedure";
+import { updateStoredProcedure } from "../../../Common/dataAccess/updateStoredProcedure";
+import * as ViewModels from "../../../Contracts/ViewModels";
+import { useNotificationConsole } from "../../../hooks/useNotificationConsole";
+import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
+import { EditorReact } from "../../Controls/Editor/EditorReact";
+import Explorer from "../../Explorer";
+import { useCommandBar } from "../../Menus/CommandBar/CommandBarComponentAdapter";
+import StoredProcedure from "../../Tree/StoredProcedure";
+import ScriptTabBase from "../ScriptTabBase";
+
+export interface IStorProcTabComponentAccessor {
+ onExecuteSprocsResultEvent: (result: ExecuteSprocResult) => void;
+ onExecuteSprocsErrorEvent: (error: string) => void;
+ onTabClickEvent: () => void;
+}
+
+export interface Button {
+ visible: boolean;
+ enabled: boolean;
+ isSelected?: boolean;
+}
+
+interface IStoredProcTabComponentStates {
+ hasResults: boolean;
+ hasErrors: boolean;
+ error: string;
+ resultData: string;
+ logsData: string;
+ originalSprocBody: string;
+ initialEditorContent: string;
+ sProcEditorContent: string;
+ id: string;
+ executeButton: Button;
+ saveButton: Button;
+ updateButton: Button;
+ discardButton: Button;
+}
+
+export interface IStoredProcTabComponentProps {
+ resource: StoredProcedureDefinition;
+ isNew: boolean;
+ tabKind: ViewModels.CollectionTabKind;
+ title: string;
+ tabPath: string;
+ collectionBase: ViewModels.CollectionBase;
+ //eslint-disable-next-line
+ node?: any;
+ hasLocation: string;
+ scriptTabBaseInstance: ScriptTabBase;
+ collection: ViewModels.Collection;
+ iStorProcTabComponentAccessor: (instance: IStorProcTabComponentAccessor) => void;
+ container: Explorer;
+}
+
+export default class StoredProcedureTabComponent extends React.Component<
+ IStoredProcTabComponentProps,
+ IStoredProcTabComponentStates
+> {
+ public node: StoredProcedure;
+ public executeResultsEditorId: string;
+ public executeLogsEditorId: string;
+ public collection: ViewModels.Collection;
+
+ constructor(
+ public storedProcTabCompProps: IStoredProcTabComponentProps,
+ private storedProcTabCompStates: IStoredProcTabComponentStates
+ ) {
+ super(storedProcTabCompProps);
+ this.state = {
+ error: "",
+ hasErrors: false,
+ hasResults: false,
+ resultData: "",
+ logsData: "",
+ originalSprocBody: this.props.resource.body.toString(),
+ initialEditorContent: this.props.resource.body.toString(),
+ sProcEditorContent: this.props.resource.body.toString(),
+ id: this.props.resource.id,
+ executeButton: {
+ enabled: !this.props.scriptTabBaseInstance.isNew(),
+ visible: true,
+ },
+ saveButton: {
+ enabled: (() => {
+ if (!this.props.scriptTabBaseInstance.formIsValid()) {
+ return false;
+ }
+ if (!this.props.scriptTabBaseInstance.formIsDirty()) {
+ return false;
+ }
+ return true;
+ })(),
+ visible: this.props.scriptTabBaseInstance.isNew(),
+ },
+ updateButton: {
+ enabled: (() => {
+ if (!this.props.scriptTabBaseInstance.formIsValid()) {
+ return false;
+ }
+ if (!this.props.scriptTabBaseInstance.formIsDirty()) {
+ return false;
+ }
+ return true;
+ })(),
+ visible: !this.props.scriptTabBaseInstance.isNew(),
+ },
+ discardButton: {
+ enabled: (() => {
+ if (!this.props.scriptTabBaseInstance.formIsValid()) {
+ return false;
+ }
+ if (!this.props.scriptTabBaseInstance.formIsDirty()) {
+ return false;
+ }
+ return true;
+ })(),
+ visible: true,
+ },
+ };
+
+ this.collection = this.props.collection;
+ this.executeResultsEditorId = `executestoredprocedureresults${this.props.scriptTabBaseInstance.tabId}`;
+ this.executeLogsEditorId = `executestoredprocedurelogs${this.props.scriptTabBaseInstance.tabId}`;
+ this.props.scriptTabBaseInstance.ariaLabel("Stored Procedure Body");
+
+ this.props.iStorProcTabComponentAccessor({
+ onExecuteSprocsResultEvent: this.onExecuteSprocsResult.bind(this),
+ onExecuteSprocsErrorEvent: this.onExecuteSprocsError.bind(this),
+ onTabClickEvent: this.onTabClick.bind(this),
+ });
+
+ this.node = this.props.node;
+
+ this.buildCommandBarOptions();
+ }
+
+ public onTabClick(): void {
+ if (this.props.container.tabsManager.openedTabs().length > 0) {
+ useCommandBar.getState().setContextButtons(this.getTabsButtons());
+ }
+ }
+
+ public onSaveClick = (): Promise => {
+ return this._createStoredProcedure({
+ id: this.state.id,
+ body: this.state.sProcEditorContent,
+ });
+ };
+
+ public onDiscard = (): Promise => {
+ const onDiscardPromise = new Promise(() => {
+ this.props.scriptTabBaseInstance.setBaselines();
+ const original = this.props.scriptTabBaseInstance.editorContent.getEditableOriginalValue();
+ if (this.state.updateButton.visible) {
+ this.setState({
+ updateButton: {
+ enabled: false,
+ visible: true,
+ },
+ sProcEditorContent: original,
+ discardButton: {
+ enabled: false,
+ visible: true,
+ },
+ executeButton: {
+ enabled: true,
+ visible: true,
+ },
+ });
+ } else {
+ this.setState({
+ saveButton: {
+ enabled: false,
+ visible: true,
+ },
+ sProcEditorContent: original,
+ discardButton: {
+ enabled: false,
+ visible: true,
+ },
+ executeButton: {
+ enabled: false,
+ visible: true,
+ },
+ id: "",
+ });
+ }
+ });
+
+ setTimeout(() => {
+ useCommandBar.getState().setContextButtons(this.getTabsButtons());
+ }, 100);
+
+ return onDiscardPromise;
+ };
+
+ public onUpdateClick = (): Promise => {
+ const data = this._getResource();
+
+ this.props.scriptTabBaseInstance.isExecutionError(false);
+ this.props.scriptTabBaseInstance.isExecuting(true);
+
+ return updateStoredProcedure(
+ this.props.scriptTabBaseInstance.collection.databaseId,
+ this.props.scriptTabBaseInstance.collection.id(),
+ data
+ )
+ .then(
+ (updatedResource) => {
+ this.props.scriptTabBaseInstance.resource(updatedResource);
+ this.props.scriptTabBaseInstance.tabTitle(updatedResource.id);
+ this.node.id(updatedResource.id);
+ this.node.body(updatedResource.body as string);
+ this.props.scriptTabBaseInstance.setBaselines();
+
+ const editorModel =
+ this.props.scriptTabBaseInstance.editor() && this.props.scriptTabBaseInstance.editor().getModel();
+ editorModel && editorModel.setValue(updatedResource.body as string);
+ this.props.scriptTabBaseInstance.editorContent.setBaseline(updatedResource.body as string);
+ this.setState({
+ discardButton: {
+ enabled: false,
+ visible: true,
+ },
+ updateButton: {
+ enabled: false,
+ visible: true,
+ },
+ executeButton: {
+ enabled: true,
+ visible: true,
+ },
+ });
+ useCommandBar.getState().setContextButtons(this.getTabsButtons());
+ },
+ () => {
+ this.props.scriptTabBaseInstance.isExecutionError(true);
+ }
+ )
+ .finally(() => this.props.scriptTabBaseInstance.isExecuting(false));
+ };
+
+ public onExecuteSprocsResult(result: ExecuteSprocResult): void {
+ const resultData: string = this.props.scriptTabBaseInstance.renderObjectForEditor(result.result, undefined, 4);
+ const scriptLogs: string = (result.scriptLogs && decodeURIComponent(result.scriptLogs)) || "";
+ const logs: string = this.props.scriptTabBaseInstance.renderObjectForEditor(scriptLogs, undefined, 4);
+
+ this.setState({
+ hasResults: false,
+ });
+ setTimeout(() => {
+ this.setState({
+ error: undefined,
+ resultData: resultData,
+ logsData: logs,
+ hasResults: resultData ? true : false,
+ hasErrors: false,
+ });
+ }, 100);
+ }
+
+ public onExecuteSprocsError(error: string): void {
+ this.props.scriptTabBaseInstance.isExecutionError(true);
+ console.error(error);
+ this.setState({
+ error: error,
+ hasErrors: true,
+ hasResults: false,
+ });
+ }
+
+ public onErrorDetailsClick = (): boolean => {
+ useNotificationConsole.getState().expandConsole();
+
+ return false;
+ };
+
+ public onErrorDetailsKeyPress = (event: React.KeyboardEvent): boolean => {
+ if (event.key === NormalizedEventKey.Space || event.key === NormalizedEventKey.Enter) {
+ this.onErrorDetailsClick();
+ return false;
+ }
+
+ return true;
+ };
+
+ protected updateSelectedNode(): void {
+ if (this.props.collectionBase === undefined) {
+ return;
+ }
+
+ const database: ViewModels.Database = this.props.collectionBase.getDatabase();
+ if (!database.isDatabaseExpanded()) {
+ this.props.collectionBase.container.selectedNode(database);
+ } else if (!this.props.collectionBase.isCollectionExpanded() || !this.collection.isStoredProceduresExpanded()) {
+ this.props.collectionBase.container.selectedNode(this.props.collectionBase);
+ } else {
+ this.props.collectionBase.container.selectedNode(this.node);
+ }
+ }
+
+ protected buildCommandBarOptions(): void {
+ useCommandBar.getState().setContextButtons(this.getTabsButtons());
+ }
+
+ protected getTabsButtons(): CommandButtonComponentProps[] {
+ const buttons: CommandButtonComponentProps[] = [];
+ const label = "Save";
+ if (this.state.saveButton.visible) {
+ buttons.push({
+ iconSrc: SaveIcon,
+ iconAlt: label,
+ onCommandClick: this.onSaveClick,
+ commandButtonLabel: label,
+ ariaLabel: label,
+ hasPopup: false,
+ disabled: !this.state.saveButton.enabled,
+ });
+ }
+
+ if (this.state.updateButton.visible) {
+ const label = "Update";
+ buttons.push({
+ iconSrc: SaveIcon,
+ iconAlt: label,
+ onCommandClick: this.onUpdateClick,
+ commandButtonLabel: label,
+ ariaLabel: label,
+ hasPopup: false,
+ disabled: !this.state.updateButton.enabled,
+ });
+ }
+
+ if (this.state.discardButton.visible) {
+ const label = "Discard";
+ buttons.push({
+ iconSrc: DiscardIcon,
+ iconAlt: label,
+ onCommandClick: this.onDiscard,
+ commandButtonLabel: label,
+ ariaLabel: label,
+ hasPopup: false,
+ disabled: !this.state.discardButton.enabled,
+ });
+ }
+
+ if (this.state.executeButton.visible) {
+ const label = "Execute";
+ buttons.push({
+ iconSrc: ExecuteQueryIcon,
+ iconAlt: label,
+ onCommandClick: () => {
+ this.collection.container.openExecuteSprocParamsPanel(this.node);
+ },
+ commandButtonLabel: label,
+ ariaLabel: label,
+ hasPopup: false,
+ disabled: !this.state.executeButton.enabled,
+ });
+ }
+
+ return buttons;
+ }
+
+ private _getResource() {
+ return {
+ id: this.state.id,
+ body: this.state.sProcEditorContent,
+ };
+ }
+
+ private _createStoredProcedure(resource: StoredProcedureDefinition): Promise {
+ this.props.scriptTabBaseInstance.isExecutionError(false);
+ this.props.scriptTabBaseInstance.isExecuting(true);
+
+ return createStoredProcedure(this.props.collectionBase.databaseId, this.props.collectionBase.id(), resource)
+ .then(
+ (createdResource) => {
+ this.props.scriptTabBaseInstance.tabTitle(createdResource.id);
+ this.props.scriptTabBaseInstance.isNew(false);
+ this.props.scriptTabBaseInstance.resource(createdResource);
+ this.props.scriptTabBaseInstance.hashLocation(
+ `${Constants.HashRoutePrefixes.collectionsWithIds(
+ this.props.collectionBase.databaseId,
+ this.props.collectionBase.id()
+ )}/sprocs/${createdResource.id}`
+ );
+ this.props.scriptTabBaseInstance.setBaselines();
+
+ const editorModel =
+ this.props.scriptTabBaseInstance.editor() && this.props.scriptTabBaseInstance.editor().getModel();
+ editorModel && editorModel.setValue(createdResource.body as string);
+ this.props.scriptTabBaseInstance.editorContent.setBaseline(createdResource.body as string);
+ this.node = this.collection.createStoredProcedureNode(createdResource);
+ this.props.container.tabsManager.openedTabs()[
+ this.props.container.tabsManager.openedTabs().length - 1
+ ].node = this.node;
+
+ this.props.scriptTabBaseInstance.editorState(ViewModels.ScriptEditorState.exisitingNoEdits);
+
+ this.setState({
+ executeButton: {
+ enabled: false,
+ visible: true,
+ },
+ });
+ setTimeout(() => {
+ this.setState({
+ executeButton: {
+ enabled: true,
+ visible: true,
+ },
+ updateButton: {
+ enabled: false,
+ visible: true,
+ },
+ saveButton: {
+ enabled: false,
+ visible: false,
+ },
+ discardButton: {
+ enabled: false,
+ visible: true,
+ },
+ sProcEditorContent: this.state.sProcEditorContent,
+ });
+ useCommandBar.getState().setContextButtons(this.getTabsButtons());
+ }, 100);
+
+ return createdResource;
+ },
+ (createError) => {
+ this.props.scriptTabBaseInstance.isExecutionError(true);
+
+ return Promise.reject(createError);
+ }
+ )
+ .finally(() => this.props.scriptTabBaseInstance.isExecuting(false));
+ }
+
+ public onDelete(): Promise {
+ const isDeleted = false;
+ const onDeletePromise = new Promise((resolve) => {
+ resolve(isDeleted);
+ });
+ return onDeletePromise;
+ }
+
+ public handleIdOnChange(event: React.ChangeEvent): void {
+ if (this.state.saveButton.visible) {
+ this.setState({
+ id: event.target.value,
+ saveButton: {
+ enabled: true,
+ visible: this.props.scriptTabBaseInstance.isNew(),
+ },
+ discardButton: {
+ enabled: true,
+ visible: true,
+ },
+ });
+ }
+ setTimeout(() => {
+ useCommandBar.getState().setContextButtons(this.getTabsButtons());
+ }, 1000);
+ }
+
+ public onChangeContent(newConent: string): void {
+ if (this.state.updateButton.visible) {
+ this.setState({
+ updateButton: {
+ enabled: true,
+ visible: true,
+ },
+ discardButton: {
+ enabled: true,
+ visible: true,
+ },
+ executeButton: {
+ enabled: false,
+ visible: true,
+ },
+ sProcEditorContent: newConent,
+ });
+ } else {
+ this.setState({
+ saveButton: {
+ enabled: false,
+ visible: this.props.scriptTabBaseInstance.isNew(),
+ },
+ executeButton: {
+ enabled: false,
+ visible: true,
+ },
+ discardButton: {
+ enabled: true,
+ visible: true,
+ },
+ sProcEditorContent: newConent,
+ });
+ }
+
+ setTimeout(() => {
+ useCommandBar.getState().setContextButtons(this.getTabsButtons());
+ }, 100);
+ }
+
+ render(): JSX.Element {
+ return (
+
+
+
Stored Procedure Id
+
+ ) => this.handleIdOnChange(event)}
+ />
+
+
Stored Procedure Body
+
this.onChangeContent(newContent)}
+ />
+ {this.state.hasResults && (
+
+ )}
+ {this.state.hasErrors && (
+
+ )}
+
+
+ );
+ }
+}
diff --git a/src/Explorer/Tree/StoredProcedure.ts b/src/Explorer/Tree/StoredProcedure.ts
index 9f491287c..2fa9d6eb7 100644
--- a/src/Explorer/Tree/StoredProcedure.ts
+++ b/src/Explorer/Tree/StoredProcedure.ts
@@ -3,13 +3,13 @@ import * as ko from "knockout";
import * as Constants from "../../Common/Constants";
import { deleteStoredProcedure } from "../../Common/dataAccess/deleteStoredProcedure";
import { executeStoredProcedure } from "../../Common/dataAccess/executeStoredProcedure";
-import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
import * as ViewModels from "../../Contracts/ViewModels";
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../UserContext";
import Explorer from "../Explorer";
-import StoredProcedureTab from "../Tabs/StoredProcedureTab";
+import { getErrorMessage } from "../Tables/Utilities";
+import { NewStoredProcedureTab } from "../Tabs/StoredProcedureTab/StoredProcedureTab";
import TabsBase from "../Tabs/TabsBase";
const sampleStoredProcedureBody: string = `// SAMPLE STORED PROCEDURE
@@ -67,16 +67,22 @@ export default class StoredProcedure {
body: sampleStoredProcedureBody,
};
- const storedProcedureTab: StoredProcedureTab = new StoredProcedureTab({
- resource: storedProcedure,
- isNew: true,
- tabKind: ViewModels.CollectionTabKind.StoredProcedures,
- title: `New Stored Procedure ${id}`,
- tabPath: `${source.databaseId}>${source.id()}>New Stored Procedure ${id}`,
- collection: source,
- node: source,
- hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(source.databaseId, source.id())}/sproc`,
- });
+ const storedProcedureTab: NewStoredProcedureTab = new NewStoredProcedureTab(
+ {
+ resource: storedProcedure,
+ isNew: true,
+ tabKind: ViewModels.CollectionTabKind.StoredProcedures,
+ title: `New Stored Procedure ${id}`,
+ tabPath: `${source.databaseId}>${source.id()}>New Stored Procedure ${id}`,
+ collection: source,
+ node: source,
+ hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(source.databaseId, source.id())}/sproc`,
+ },
+ {
+ collection: source,
+ container: source.container,
+ }
+ );
source.container.tabsManager.activateNewTab(storedProcedureTab);
}
@@ -93,11 +99,11 @@ export default class StoredProcedure {
public open = () => {
this.select();
- const storedProcedureTabs: StoredProcedureTab[] = this.container.tabsManager.getTabs(
+ const storedProcedureTabs: NewStoredProcedureTab[] = this.container.tabsManager.getTabs(
ViewModels.CollectionTabKind.StoredProcedures,
(tab: TabsBase) => tab.node && tab.node.rid === this.rid
- ) as StoredProcedureTab[];
- let storedProcedureTab: StoredProcedureTab = storedProcedureTabs && storedProcedureTabs[0];
+ ) as NewStoredProcedureTab[];
+ let storedProcedureTab: NewStoredProcedureTab = storedProcedureTabs && storedProcedureTabs[0];
if (storedProcedureTab) {
this.container.tabsManager.activateTab(storedProcedureTab);
@@ -109,24 +115,29 @@ export default class StoredProcedure {
body: this.body(),
};
- storedProcedureTab = new StoredProcedureTab({
- resource: storedProcedureData,
- isNew: false,
- tabKind: ViewModels.CollectionTabKind.StoredProcedures,
- title: storedProcedureData.id,
- tabPath: `${this.collection.databaseId}>${this.collection.id()}>${storedProcedureData.id}`,
- collection: this.collection,
- node: this,
- hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(
- this.collection.databaseId,
- this.collection.id()
- )}/sprocs/${this.id()}`,
- });
+ storedProcedureTab = new NewStoredProcedureTab(
+ {
+ resource: storedProcedureData,
+ isNew: false,
+ tabKind: ViewModels.CollectionTabKind.StoredProcedures,
+ title: storedProcedureData.id,
+ tabPath: `${this.collection.databaseId}>${this.collection.id()}>${storedProcedureData.id}`,
+ collection: this.collection,
+ node: this,
+ hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(
+ this.collection.databaseId,
+ this.collection.id()
+ )}/sprocs/${this.id()}`,
+ },
+ {
+ collection: this.collection,
+ container: this.container,
+ }
+ );
this.container.tabsManager.activateNewTab(storedProcedureTab);
}
};
-
public delete() {
if (!window.confirm("Are you sure you want to delete the stored procedure?")) {
return;
@@ -142,19 +153,19 @@ export default class StoredProcedure {
}
public execute(params: string[], partitionKeyValue?: string): void {
- const sprocTabs = this.container.tabsManager.getTabs(
+ const sprocTabs: NewStoredProcedureTab[] = this.container.tabsManager.getTabs(
ViewModels.CollectionTabKind.StoredProcedures,
(tab: TabsBase) => tab.node && tab.node.rid === this.rid
- ) as StoredProcedureTab[];
- const sprocTab = sprocTabs && sprocTabs.length > 0 && sprocTabs[0];
+ ) as NewStoredProcedureTab[];
+ const sprocTab: NewStoredProcedureTab = sprocTabs && sprocTabs.length > 0 && sprocTabs[0];
sprocTab.isExecuting(true);
this.container &&
executeStoredProcedure(this.collection, this, partitionKeyValue, params)
.then(
- (result: any) => {
- sprocTab.onExecuteSprocsResult(result, result.scriptLogs);
+ (result) => {
+ sprocTab.onExecuteSprocsResult(result);
},
- (error: any) => {
+ (error) => {
sprocTab.onExecuteSprocsError(getErrorMessage(error));
}
)