Remove NotebookTab (#35)
This commit is contained in:
parent
23b2d8100f
commit
d32bd8851e
|
@ -202,7 +202,6 @@ src/Explorer/Tabs/GraphTab.ts
|
||||||
src/Explorer/Tabs/MongoDocumentsTab.ts
|
src/Explorer/Tabs/MongoDocumentsTab.ts
|
||||||
src/Explorer/Tabs/MongoQueryTab.ts
|
src/Explorer/Tabs/MongoQueryTab.ts
|
||||||
src/Explorer/Tabs/MongoShellTab.ts
|
src/Explorer/Tabs/MongoShellTab.ts
|
||||||
src/Explorer/Tabs/NotebookTab.ts
|
|
||||||
src/Explorer/Tabs/NotebookV2Tab.ts
|
src/Explorer/Tabs/NotebookV2Tab.ts
|
||||||
src/Explorer/Tabs/QueryTab.test.ts
|
src/Explorer/Tabs/QueryTab.test.ts
|
||||||
src/Explorer/Tabs/QueryTab.ts
|
src/Explorer/Tabs/QueryTab.ts
|
||||||
|
@ -216,7 +215,6 @@ src/Explorer/Tabs/TabComponents.ts
|
||||||
src/Explorer/Tabs/TabsBase.ts
|
src/Explorer/Tabs/TabsBase.ts
|
||||||
src/Explorer/Tabs/TriggerTab.ts
|
src/Explorer/Tabs/TriggerTab.ts
|
||||||
src/Explorer/Tabs/UserDefinedFunctionTab.ts
|
src/Explorer/Tabs/UserDefinedFunctionTab.ts
|
||||||
src/Explorer/Tabs/__mocks__/NotebookTab.ts
|
|
||||||
src/Explorer/Tree/AccessibleVerticalList.ts
|
src/Explorer/Tree/AccessibleVerticalList.ts
|
||||||
src/Explorer/Tree/Collection.test.ts
|
src/Explorer/Tree/Collection.test.ts
|
||||||
src/Explorer/Tree/Collection.ts
|
src/Explorer/Tree/Collection.ts
|
||||||
|
|
|
@ -1176,7 +1176,6 @@ export interface TriggerTab extends ScriptTab {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GraphTab extends Tab {}
|
export interface GraphTab extends Tab {}
|
||||||
export interface NotebookTab extends Tab {}
|
|
||||||
export interface EditorPosition {
|
export interface EditorPosition {
|
||||||
line: number;
|
line: number;
|
||||||
column: number;
|
column: number;
|
||||||
|
@ -1220,7 +1219,7 @@ export enum CollectionTabKind {
|
||||||
MongoShell = 10,
|
MongoShell = 10,
|
||||||
DatabaseSettings = 11,
|
DatabaseSettings = 11,
|
||||||
Conflicts = 12,
|
Conflicts = 12,
|
||||||
Notebook = 13,
|
Notebook = 13 /* Deprecated */,
|
||||||
Terminal = 14,
|
Terminal = 14,
|
||||||
NotebookV2 = 15,
|
NotebookV2 = 15,
|
||||||
SparkMasterTab = 16,
|
SparkMasterTab = 16,
|
||||||
|
|
|
@ -64,10 +64,6 @@ describe("Component Registerer", () => {
|
||||||
expect(ko.components.isRegistered("graph-tab")).toBe(true);
|
expect(ko.components.isRegistered("graph-tab")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should register notebook-tab component", () => {
|
|
||||||
expect(ko.components.isRegistered("notebook-tab")).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should register notebookv2-tab component", () => {
|
it("should register notebookv2-tab component", () => {
|
||||||
expect(ko.components.isRegistered("notebookv2-tab")).toBe(true);
|
expect(ko.components.isRegistered("notebookv2-tab")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
|
@ -42,7 +42,6 @@ ko.components.register("tables-query-tab", new TabComponents.QueryTablesTab());
|
||||||
ko.components.register("graph-tab", new TabComponents.GraphTab());
|
ko.components.register("graph-tab", new TabComponents.GraphTab());
|
||||||
ko.components.register("mongo-shell-tab", new TabComponents.MongoShellTab());
|
ko.components.register("mongo-shell-tab", new TabComponents.MongoShellTab());
|
||||||
ko.components.register("conflicts-tab", new TabComponents.ConflictsTab());
|
ko.components.register("conflicts-tab", new TabComponents.ConflictsTab());
|
||||||
ko.components.register("notebook-tab", new TabComponents.NotebookTab());
|
|
||||||
ko.components.register("notebookv2-tab", new TabComponents.NotebookV2Tab());
|
ko.components.register("notebookv2-tab", new TabComponents.NotebookV2Tab());
|
||||||
ko.components.register("terminal-tab", new TabComponents.TerminalTab());
|
ko.components.register("terminal-tab", new TabComponents.TerminalTab());
|
||||||
ko.components.register("spark-master-tab", new TabComponents.SparkMasterTab());
|
ko.components.register("spark-master-tab", new TabComponents.SparkMasterTab());
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
/**
|
|
||||||
* Message handler to communicate with NotebookApp iframe
|
|
||||||
*/
|
|
||||||
import Q from "q";
|
|
||||||
import * as _ from "underscore";
|
|
||||||
|
|
||||||
import { HashMap } from "../../../Common/HashMap";
|
|
||||||
import { CachedDataPromise } from "../../../Common/MessageHandler";
|
|
||||||
import * as Constants from "../../../Common/Constants";
|
|
||||||
import {
|
|
||||||
MessageTypes,
|
|
||||||
FromNotebookMessage,
|
|
||||||
FromNotebookResponseMessage,
|
|
||||||
FromDataExplorerMessage
|
|
||||||
} from "../../../Terminal/NotebookAppContracts";
|
|
||||||
|
|
||||||
export class NotebookAppMessageHandler {
|
|
||||||
private requestMap: HashMap<CachedDataPromise<any>>;
|
|
||||||
|
|
||||||
constructor(private targetIFrameWindow: Window) {
|
|
||||||
this.requestMap = new HashMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
public handleCachedDataMessage(message: FromNotebookMessage): void {
|
|
||||||
const messageContent = message && (message.message as FromNotebookResponseMessage);
|
|
||||||
if (
|
|
||||||
message == null ||
|
|
||||||
messageContent == null ||
|
|
||||||
messageContent.id == null ||
|
|
||||||
!this.requestMap.has(messageContent.id)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cachedDataPromise = this.requestMap.get(messageContent.id);
|
|
||||||
if (messageContent.error != null) {
|
|
||||||
cachedDataPromise.deferred.reject(messageContent.error);
|
|
||||||
} else {
|
|
||||||
cachedDataPromise.deferred.resolve(messageContent.data);
|
|
||||||
}
|
|
||||||
this.runGarbageCollector();
|
|
||||||
}
|
|
||||||
|
|
||||||
public sendCachedDataMessage<TResponseDataModel>(
|
|
||||||
messageType: MessageTypes,
|
|
||||||
params?: any
|
|
||||||
): Q.Promise<TResponseDataModel> {
|
|
||||||
let cachedDataPromise: CachedDataPromise<TResponseDataModel> = {
|
|
||||||
deferred: Q.defer<TResponseDataModel>(),
|
|
||||||
startTime: new Date(),
|
|
||||||
id: _.uniqueId()
|
|
||||||
};
|
|
||||||
this.requestMap.set(cachedDataPromise.id, cachedDataPromise);
|
|
||||||
this.sendMessage({ type: messageType, params: params, id: cachedDataPromise.id });
|
|
||||||
|
|
||||||
//TODO: Use telemetry to measure optimal time to resolve/reject promises
|
|
||||||
return cachedDataPromise.deferred.promise.timeout(
|
|
||||||
Constants.ClientDefaults.requestTimeoutMs,
|
|
||||||
"Timed out while waiting for response from portal"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sendMessage(data: FromDataExplorerMessage): void {
|
|
||||||
if (!this.targetIFrameWindow) {
|
|
||||||
console.error("targetIFrame not defined. This is not expected");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.targetIFrameWindow.postMessage(data, window.location.href || window.document.referrer);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected runGarbageCollector() {
|
|
||||||
this.requestMap.keys().forEach((key: string) => {
|
|
||||||
const promise: Q.Promise<any> = this.requestMap.get(key).deferred.promise;
|
|
||||||
if (promise.isFulfilled() || promise.isRejected()) {
|
|
||||||
this.requestMap.delete(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -21,7 +21,6 @@ import EnvironmentUtility from "../Common/EnvironmentUtility";
|
||||||
import GraphStylingPane from "./Panes/GraphStylingPane";
|
import GraphStylingPane from "./Panes/GraphStylingPane";
|
||||||
import hasher from "hasher";
|
import hasher from "hasher";
|
||||||
import NewVertexPane from "./Panes/NewVertexPane";
|
import NewVertexPane from "./Panes/NewVertexPane";
|
||||||
import NotebookTab from "./Tabs/NotebookTab";
|
|
||||||
import NotebookV2Tab from "./Tabs/NotebookV2Tab";
|
import NotebookV2Tab from "./Tabs/NotebookV2Tab";
|
||||||
import Q from "q";
|
import Q from "q";
|
||||||
import ResourceTokenCollection from "./Tree/ResourceTokenCollection";
|
import ResourceTokenCollection from "./Tree/ResourceTokenCollection";
|
||||||
|
@ -305,7 +304,7 @@ export default class Explorer implements ViewModels.Explorer {
|
||||||
this.openedTabs &&
|
this.openedTabs &&
|
||||||
this.openedTabs().forEach(tab => {
|
this.openedTabs().forEach(tab => {
|
||||||
if (tab.tabKind === ViewModels.CollectionTabKind.Notebook) {
|
if (tab.tabKind === ViewModels.CollectionTabKind.Notebook) {
|
||||||
(tab as NotebookTab).reconfigureServiceEndpoints();
|
throw new Error("NotebookTab is deprecated. Use NotebookV2Tab");
|
||||||
} else if (tab.tabKind === ViewModels.CollectionTabKind.NotebookV2) {
|
} else if (tab.tabKind === ViewModels.CollectionTabKind.NotebookV2) {
|
||||||
(tab as NotebookV2Tab).reconfigureServiceEndpoints();
|
(tab as NotebookV2Tab).reconfigureServiceEndpoints();
|
||||||
}
|
}
|
||||||
|
@ -2772,7 +2771,7 @@ export default class Explorer implements ViewModels.Explorer {
|
||||||
const openedNotebookTabs = this.openedTabs().filter(
|
const openedNotebookTabs = this.openedTabs().filter(
|
||||||
(tab: ViewModels.Tab) =>
|
(tab: ViewModels.Tab) =>
|
||||||
tab.tabKind === ViewModels.CollectionTabKind.NotebookV2 &&
|
tab.tabKind === ViewModels.CollectionTabKind.NotebookV2 &&
|
||||||
(tab as NotebookTab).notebookPath() === notebookFile.path
|
(tab as NotebookV2Tab).notebookPath() === notebookFile.path
|
||||||
);
|
);
|
||||||
if (openedNotebookTabs.length > 0) {
|
if (openedNotebookTabs.length > 0) {
|
||||||
this.showOkModalDialog("Unable to rename file", "This file is being edited. Please close the tab and try again.");
|
this.showOkModalDialog("Unable to rename file", "This file is being edited. Please close the tab and try again.");
|
||||||
|
@ -2796,12 +2795,12 @@ export default class Explorer implements ViewModels.Explorer {
|
||||||
.filter(
|
.filter(
|
||||||
(tab: ViewModels.Tab) =>
|
(tab: ViewModels.Tab) =>
|
||||||
tab.tabKind === ViewModels.CollectionTabKind.NotebookV2 &&
|
tab.tabKind === ViewModels.CollectionTabKind.NotebookV2 &&
|
||||||
FileSystemUtil.isPathEqual((tab as NotebookTab).notebookPath(), originalPath)
|
FileSystemUtil.isPathEqual((tab as NotebookV2Tab).notebookPath(), originalPath)
|
||||||
)
|
)
|
||||||
.forEach(tab => {
|
.forEach(tab => {
|
||||||
tab.tabTitle(newNotebookFile.name);
|
tab.tabTitle(newNotebookFile.name);
|
||||||
tab.tabPath(newNotebookFile.path);
|
tab.tabPath(newNotebookFile.path);
|
||||||
(tab as NotebookTab).notebookPath(newNotebookFile.path);
|
(tab as NotebookV2Tab).notebookPath(newNotebookFile.path);
|
||||||
});
|
});
|
||||||
|
|
||||||
return newNotebookFile;
|
return newNotebookFile;
|
||||||
|
@ -3039,7 +3038,7 @@ export default class Explorer implements ViewModels.Explorer {
|
||||||
// Don't delete if tab is open to avoid accidental deletion
|
// Don't delete if tab is open to avoid accidental deletion
|
||||||
const openedNotebookTabs = this.openedTabs().filter(
|
const openedNotebookTabs = this.openedTabs().filter(
|
||||||
(tab: ViewModels.Tab) =>
|
(tab: ViewModels.Tab) =>
|
||||||
tab.tabKind === ViewModels.CollectionTabKind.NotebookV2 && (tab as NotebookTab).notebookPath() === item.path
|
tab.tabKind === ViewModels.CollectionTabKind.NotebookV2 && (tab as NotebookV2Tab).notebookPath() === item.path
|
||||||
);
|
);
|
||||||
if (openedNotebookTabs.length > 0) {
|
if (openedNotebookTabs.length > 0) {
|
||||||
this.showOkModalDialog("Unable to delete file", "This file is being edited. Please close the tab and try again.");
|
this.showOkModalDialog("Unable to delete file", "This file is being edited. Please close the tab and try again.");
|
||||||
|
|
|
@ -5,8 +5,6 @@ import Explorer from "../Explorer";
|
||||||
import ko from "knockout";
|
import ko from "knockout";
|
||||||
import { AutopilotTier } from "../../Contracts/DataModels";
|
import { AutopilotTier } from "../../Contracts/DataModels";
|
||||||
|
|
||||||
jest.mock("../Tabs/NotebookTab");
|
|
||||||
|
|
||||||
describe("Add Collection Pane", () => {
|
describe("Add Collection Pane", () => {
|
||||||
describe("isValid()", () => {
|
describe("isValid()", () => {
|
||||||
let explorer: ViewModels.Explorer;
|
let explorer: ViewModels.Explorer;
|
||||||
|
|
|
@ -2,8 +2,6 @@ import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import AddDatabasePane from "./AddDatabasePane";
|
import AddDatabasePane from "./AddDatabasePane";
|
||||||
|
|
||||||
jest.mock("../Tabs/NotebookTab");
|
|
||||||
|
|
||||||
describe("Add Database Pane", () => {
|
describe("Add Database Pane", () => {
|
||||||
describe("getSharedThroughputDefault()", () => {
|
describe("getSharedThroughputDefault()", () => {
|
||||||
let explorer: ViewModels.Explorer;
|
let explorer: ViewModels.Explorer;
|
||||||
|
|
|
@ -2,8 +2,6 @@ import * as Constants from "../../Common/Constants";
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
|
|
||||||
jest.mock("../Tabs/NotebookTab");
|
|
||||||
|
|
||||||
describe("Settings Pane", () => {
|
describe("Settings Pane", () => {
|
||||||
describe("shouldShowQueryPageOptions()", () => {
|
describe("shouldShowQueryPageOptions()", () => {
|
||||||
let explorer: ViewModels.Explorer;
|
let explorer: ViewModels.Explorer;
|
||||||
|
|
|
@ -6,8 +6,6 @@ import { DataAccessUtility } from "../../Platform/Portal/DataAccessUtility";
|
||||||
import Explorer from "../Explorer";
|
import Explorer from "../Explorer";
|
||||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||||
|
|
||||||
jest.mock("./NotebookTab");
|
|
||||||
|
|
||||||
describe("Documents tab", () => {
|
describe("Documents tab", () => {
|
||||||
describe("buildQuery", () => {
|
describe("buildQuery", () => {
|
||||||
it("should generate the right select query for SQL API", () => {
|
it("should generate the right select query for SQL API", () => {
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
<div style="width: 100%; height: 100%; margin-left: 3px;" data-bind="attr: { id: tabId }">
|
|
||||||
<!-- This runs the NotebookApp hosted by DataExplorer -->
|
|
||||||
<iframe
|
|
||||||
style="width:100%; height: 100%; border:none"
|
|
||||||
data-bind="setTemplateReady: true, attr: { id: notebookContainerId, src: notebookAppIFrameSrc }"
|
|
||||||
></iframe>
|
|
||||||
</div>
|
|
|
@ -1,539 +0,0 @@
|
||||||
import * as Q from "q";
|
|
||||||
import * as ko from "knockout";
|
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
|
||||||
import * as DataModels from "../../Contracts/DataModels";
|
|
||||||
import TabsBase from "./TabsBase";
|
|
||||||
|
|
||||||
import NewCellIcon from "../../../images/notebook/Notebook-insert-cell.svg";
|
|
||||||
import CutIcon from "../../../images/notebook/Notebook-cut.svg";
|
|
||||||
import CopyIcon from "../../../images/notebook/Notebook-copy.svg";
|
|
||||||
import PasteIcon from "../../../images/notebook/Notebook-paste.svg";
|
|
||||||
import RunIcon from "../../../images/notebook/Notebook-run.svg";
|
|
||||||
import RunAllIcon from "../../../images/notebook/Notebook-run-all.svg";
|
|
||||||
import RestartIcon from "../../../images/notebook/Notebook-restart.svg";
|
|
||||||
import SaveIcon from "../../../images/save-cosmos.svg";
|
|
||||||
import ClearAllOutputsIcon from "../../../images/notebook/Notebook-clear-all-outputs.svg";
|
|
||||||
import UndoIcon from "../../../images/notebook/Notebook-undo.svg";
|
|
||||||
import RedoIcon from "../../../images/notebook/Notebook-redo.svg";
|
|
||||||
import { CommandBarComponentButtonFactory } from "../Menus/CommandBar/CommandBarComponentButtonFactory";
|
|
||||||
import { NotebookAppMessageHandler } from "../Controls/Notebook/NotebookAppMessageHandler";
|
|
||||||
import * as NotebookAppContracts from "../../Terminal/NotebookAppContracts";
|
|
||||||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
|
||||||
import { isInvalidParentFrameOrigin } from "../../Utils/MessageValidation";
|
|
||||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
|
||||||
import { NotebookTerminalComponent } from "../Controls/Notebook/NotebookTerminalComponent";
|
|
||||||
import { NotebookConfigurationUtils } from "../../Utils/NotebookConfigurationUtils";
|
|
||||||
import { NotebookContentItem } from "../Notebook/NotebookContentItem";
|
|
||||||
|
|
||||||
interface Kernel {
|
|
||||||
name: string;
|
|
||||||
displayName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class NotebookTab extends TabsBase implements ViewModels.Tab {
|
|
||||||
private notebookAppIFrameSrc: ko.Computed<string>;
|
|
||||||
private container: ViewModels.Explorer;
|
|
||||||
public notebookPath: ko.Observable<string>;
|
|
||||||
private messageListener: (ev: MessageEvent) => any;
|
|
||||||
private activeCellTypeStr: string;
|
|
||||||
private notebookContainerId: string;
|
|
||||||
private currentKernelName: string;
|
|
||||||
private availableKernels: Kernel[];
|
|
||||||
private messageHandler: NotebookAppMessageHandler;
|
|
||||||
private notificationProgressId: string;
|
|
||||||
private isSwitchingKernels: ko.Observable<boolean>;
|
|
||||||
|
|
||||||
constructor(options: ViewModels.NotebookTabOptions) {
|
|
||||||
super(options);
|
|
||||||
this.availableKernels = [];
|
|
||||||
this.isSwitchingKernels = ko.observable<boolean>(false);
|
|
||||||
this.messageListener = async (ev: MessageEvent) => {
|
|
||||||
if (isInvalidParentFrameOrigin(ev)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const msg: NotebookAppContracts.FromNotebookMessage = ev.data;
|
|
||||||
|
|
||||||
if (msg.actionType === NotebookAppContracts.ActionTypes.Response) {
|
|
||||||
this.messageHandler.handleCachedDataMessage(msg);
|
|
||||||
} else if (msg.actionType === NotebookAppContracts.ActionTypes.Update) {
|
|
||||||
const updateMessage = msg.message as NotebookAppContracts.FromNotebookUpdateMessage;
|
|
||||||
switch (updateMessage.type) {
|
|
||||||
case NotebookAppContracts.NotebookUpdateTypes.ActiveCellType:
|
|
||||||
this.activeCellTypeStr = updateMessage.arg;
|
|
||||||
this.updateNavbarWithTabsButtons();
|
|
||||||
break;
|
|
||||||
case NotebookAppContracts.NotebookUpdateTypes.KernelChange:
|
|
||||||
this.isSwitchingKernels(false);
|
|
||||||
this.currentKernelName = updateMessage.arg;
|
|
||||||
this.messageHandler
|
|
||||||
.sendCachedDataMessage<NotebookAppContracts.KernelSpecs>(NotebookAppContracts.MessageTypes.KernelList)
|
|
||||||
.then(specs => {
|
|
||||||
this.availableKernels = Object.keys(specs.kernelSpecs)
|
|
||||||
.map((name: string) => ({ name: name, displayName: specs.kernelSpecs[name].displayName }))
|
|
||||||
.sort((a: NotebookAppContracts.KernelOption, b: NotebookAppContracts.KernelOption) => {
|
|
||||||
// Put default at the top, otherwise lexicographically compare
|
|
||||||
if (a.name === specs.defaultName) {
|
|
||||||
return -1;
|
|
||||||
} else if (b.name === specs.defaultName) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return a.displayName.localeCompare(b.displayName);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.updateNavbarWithTabsButtons();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.updateNavbarWithTabsButtons();
|
|
||||||
await this.configureServiceEndpoints(this.currentKernelName);
|
|
||||||
break;
|
|
||||||
case NotebookAppContracts.NotebookUpdateTypes.ClickEvent:
|
|
||||||
this.simulateClick();
|
|
||||||
break;
|
|
||||||
case NotebookAppContracts.NotebookUpdateTypes.SessionStatusChange: {
|
|
||||||
this.handleSessionStateChange(updateMessage.arg as NotebookAppContracts.KernelStatusStates);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
console.error("Unknown command", updateMessage);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
super.onTemplateReady((isTemplateReady: boolean) => {
|
|
||||||
if (isTemplateReady) {
|
|
||||||
window.addEventListener("message", this.messageListener, false);
|
|
||||||
|
|
||||||
const iFrame: HTMLIFrameElement = document.getElementById(this.notebookContainerId) as HTMLIFrameElement;
|
|
||||||
this.messageHandler = new NotebookAppMessageHandler(iFrame.contentWindow);
|
|
||||||
|
|
||||||
this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.Status);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.container = options.container;
|
|
||||||
|
|
||||||
this.notebookAppIFrameSrc = ko.computed<string>(() =>
|
|
||||||
NotebookTerminalComponent.createNotebookAppSrc(
|
|
||||||
this.container.notebookServerInfo(),
|
|
||||||
new Map<string, string>([["notebookpath", options.notebookContentItem.path]])
|
|
||||||
)
|
|
||||||
);
|
|
||||||
this.notebookPath = ko.observable(options.notebookContentItem.path);
|
|
||||||
|
|
||||||
this.notebookContainerId = `notebookContainer-${this.tabId}`;
|
|
||||||
|
|
||||||
this.container.notebookServerInfo.subscribe((newValue: DataModels.NotebookWorkspaceConnectionInfo) => {
|
|
||||||
NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.Info, "New notebook server info received.");
|
|
||||||
});
|
|
||||||
|
|
||||||
this.container &&
|
|
||||||
this.container.arcadiaToken.subscribe(async () => {
|
|
||||||
const currentKernel = this.currentKernelName;
|
|
||||||
if (!currentKernel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await this.configureServiceEndpoints(currentKernel);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public onCloseTabButtonClick(): Q.Promise<any> {
|
|
||||||
const cleanup = () => {
|
|
||||||
this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.Shutdown);
|
|
||||||
window.removeEventListener("message", this.messageListener);
|
|
||||||
this.isActive(false);
|
|
||||||
super.onCloseTabButtonClick();
|
|
||||||
};
|
|
||||||
|
|
||||||
return this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.IsDirty).then((isDirty: boolean) => {
|
|
||||||
if (isDirty) {
|
|
||||||
this.container.showOkCancelModalDialog(
|
|
||||||
"Close without saving?",
|
|
||||||
`File has unsaved changes, close without saving?`,
|
|
||||||
"Close",
|
|
||||||
cleanup,
|
|
||||||
"Cancel",
|
|
||||||
undefined
|
|
||||||
);
|
|
||||||
return Q.resolve(null);
|
|
||||||
} else {
|
|
||||||
cleanup();
|
|
||||||
return Q.resolve(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public onActivate(): Q.Promise<any> {
|
|
||||||
if (this.messageHandler) {
|
|
||||||
this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.Status);
|
|
||||||
}
|
|
||||||
return super.onActivate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async reconfigureServiceEndpoints() {
|
|
||||||
return await this.configureServiceEndpoints(this.currentKernelName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private handleSessionStateChange(state: NotebookAppContracts.KernelStatusStates) {
|
|
||||||
switch (state) {
|
|
||||||
case "reconnecting":
|
|
||||||
this.clearProgressNotification();
|
|
||||||
this.notificationProgressId = NotificationConsoleUtils.logConsoleMessage(
|
|
||||||
ConsoleDataType.InProgress,
|
|
||||||
"Connection with Notebook Server lost. Reconnecting..."
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case "dead":
|
|
||||||
// This happens when the jupyter server detects that the kernel to which the cell was connected is no longer alive.
|
|
||||||
// It can be caused by the jupyter server going down and back up again and informing the client that the kernel to which
|
|
||||||
// it was previously connected to doesn't exist anymore. Send a restart kernel command.
|
|
||||||
if (!this.isSwitchingKernels()) {
|
|
||||||
this.notificationProgressId = NotificationConsoleUtils.logConsoleMessage(
|
|
||||||
ConsoleDataType.InProgress,
|
|
||||||
"Connection with Notebook Server dead. Trying to reconnect..."
|
|
||||||
);
|
|
||||||
this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.RestartKernel);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "connected":
|
|
||||||
this.clearProgressNotification();
|
|
||||||
NotificationConsoleUtils.logConsoleMessage(
|
|
||||||
ConsoleDataType.Info,
|
|
||||||
"Connection with Notebook Server established."
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.clearProgressNotification();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private clearProgressNotification() {
|
|
||||||
if (this.notificationProgressId) {
|
|
||||||
NotificationConsoleUtils.clearInProgressMessageWithId(this.notificationProgressId);
|
|
||||||
this.notificationProgressId = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static isUntitledNotebook(notebookFile: NotebookContentItem): boolean {
|
|
||||||
return notebookFile.name.indexOf("Untitled") === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getContainer(): ViewModels.Explorer {
|
|
||||||
return this.container;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getTabsButtons(): ViewModels.NavbarButtonConfig[] {
|
|
||||||
const saveLabel = "Save";
|
|
||||||
const workspaceLabel = "Workspace";
|
|
||||||
const kernelLabel = "Kernel";
|
|
||||||
const runLabel = "Run";
|
|
||||||
const runActiveCellLabel = "Run Active Cell";
|
|
||||||
const runAllLabel = "Run All";
|
|
||||||
const restartKernelLabel = "Restart Kernel";
|
|
||||||
const clearLabel = "Clear outputs";
|
|
||||||
const newCellLabel = "New Cell";
|
|
||||||
const cellTypeLabel = "Cell Type";
|
|
||||||
const codeLabel = "Code";
|
|
||||||
const markdownLabel = "Markdown";
|
|
||||||
const rawLabel = "Raw";
|
|
||||||
const copyLabel = "Copy";
|
|
||||||
const cutLabel = "Cut";
|
|
||||||
const pasteLabel = "Paste";
|
|
||||||
const undoLabel = "Undo";
|
|
||||||
const redoLabel = "Redo";
|
|
||||||
const cellCodeType = "code";
|
|
||||||
const cellMarkdownType = "markdown";
|
|
||||||
const cellRawType = "raw";
|
|
||||||
let buttons: ViewModels.NavbarButtonConfig[] = [
|
|
||||||
{
|
|
||||||
iconSrc: SaveIcon,
|
|
||||||
iconAlt: saveLabel,
|
|
||||||
onCommandClick: () =>
|
|
||||||
this.sendMessageToNotebook(
|
|
||||||
NotebookAppContracts.MessageTypes.Save
|
|
||||||
).then((result: NotebookAppContracts.ContentItem) =>
|
|
||||||
NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.Info, `File "${result.name}" was saved.`)
|
|
||||||
),
|
|
||||||
commandButtonLabel: saveLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false,
|
|
||||||
ariaLabel: saveLabel
|
|
||||||
},
|
|
||||||
{
|
|
||||||
iconSrc: null,
|
|
||||||
iconAlt: kernelLabel,
|
|
||||||
onCommandClick: () => {},
|
|
||||||
commandButtonLabel: null,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: this.availableKernels.length < 1,
|
|
||||||
isDropdown: true,
|
|
||||||
dropdownPlaceholder: kernelLabel,
|
|
||||||
dropdownSelectedKey: this.currentKernelName,
|
|
||||||
dropdownWidth: 100,
|
|
||||||
children: this.availableKernels.map((kernel: { name: string; displayName: string }) => ({
|
|
||||||
iconSrc: null,
|
|
||||||
iconAlt: kernel.displayName,
|
|
||||||
onCommandClick: () => {
|
|
||||||
this.isSwitchingKernels(true);
|
|
||||||
this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.ChangeKernel, kernel.name);
|
|
||||||
},
|
|
||||||
commandButtonLabel: kernel.displayName,
|
|
||||||
dropdownItemKey: kernel.name,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false,
|
|
||||||
ariaLabel: kernel.displayName
|
|
||||||
})),
|
|
||||||
ariaLabel: kernelLabel
|
|
||||||
},
|
|
||||||
{
|
|
||||||
iconSrc: RunIcon,
|
|
||||||
iconAlt: runLabel,
|
|
||||||
onCommandClick: () => this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.RunAndAdvance),
|
|
||||||
commandButtonLabel: runLabel,
|
|
||||||
ariaLabel: runLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
iconSrc: RunIcon,
|
|
||||||
iconAlt: runActiveCellLabel,
|
|
||||||
onCommandClick: () => this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.RunAndAdvance),
|
|
||||||
commandButtonLabel: runActiveCellLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false,
|
|
||||||
ariaLabel: runActiveCellLabel
|
|
||||||
},
|
|
||||||
{
|
|
||||||
iconSrc: RunAllIcon,
|
|
||||||
iconAlt: runAllLabel,
|
|
||||||
onCommandClick: () => this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.RunAll),
|
|
||||||
commandButtonLabel: runAllLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false,
|
|
||||||
ariaLabel: runAllLabel
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// iconSrc: null,
|
|
||||||
// onCommandClick: () => this.postMessage("switchKernel"),
|
|
||||||
// commandButtonLabel: "Switch Kernel",
|
|
||||||
// hasPopup: false,
|
|
||||||
// disabled: false
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
iconSrc: RestartIcon,
|
|
||||||
iconAlt: restartKernelLabel,
|
|
||||||
onCommandClick: () =>
|
|
||||||
this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.RestartKernel).then(
|
|
||||||
(isSuccessful: boolean) => {
|
|
||||||
// Note: don't handle isSuccessful === false as it gets triggered if user cancels kernel restart modal dialog
|
|
||||||
if (isSuccessful) {
|
|
||||||
NotificationConsoleUtils.logConsoleMessage(
|
|
||||||
ConsoleDataType.Info,
|
|
||||||
"Kernel was successfully restarted"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
),
|
|
||||||
commandButtonLabel: restartKernelLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false,
|
|
||||||
ariaLabel: restartKernelLabel
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
iconSrc: ClearAllOutputsIcon,
|
|
||||||
iconAlt: clearLabel,
|
|
||||||
onCommandClick: () => this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.ClearAllOutputs),
|
|
||||||
commandButtonLabel: clearLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false,
|
|
||||||
ariaLabel: clearLabel
|
|
||||||
},
|
|
||||||
{
|
|
||||||
iconSrc: NewCellIcon,
|
|
||||||
iconAlt: newCellLabel,
|
|
||||||
onCommandClick: () => this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.InsertBelow),
|
|
||||||
commandButtonLabel: newCellLabel,
|
|
||||||
ariaLabel: newCellLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false
|
|
||||||
},
|
|
||||||
CommandBarComponentButtonFactory.createDivider(),
|
|
||||||
{
|
|
||||||
iconSrc: null,
|
|
||||||
iconAlt: null,
|
|
||||||
onCommandClick: () => {},
|
|
||||||
commandButtonLabel: null,
|
|
||||||
ariaLabel: cellTypeLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false,
|
|
||||||
isDropdown: true,
|
|
||||||
dropdownPlaceholder: cellTypeLabel,
|
|
||||||
dropdownSelectedKey: this.activeCellTypeStr,
|
|
||||||
dropdownWidth: 110,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
iconSrc: null,
|
|
||||||
iconAlt: null,
|
|
||||||
onCommandClick: () =>
|
|
||||||
this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.ChangeCellType, cellCodeType),
|
|
||||||
commandButtonLabel: codeLabel,
|
|
||||||
ariaLabel: codeLabel,
|
|
||||||
dropdownItemKey: cellCodeType,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
iconSrc: null,
|
|
||||||
iconAlt: null,
|
|
||||||
onCommandClick: () =>
|
|
||||||
this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.ChangeCellType, cellMarkdownType),
|
|
||||||
commandButtonLabel: markdownLabel,
|
|
||||||
ariaLabel: markdownLabel,
|
|
||||||
dropdownItemKey: cellMarkdownType,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
iconSrc: null,
|
|
||||||
iconAlt: null,
|
|
||||||
onCommandClick: () =>
|
|
||||||
this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.ChangeCellType, cellRawType),
|
|
||||||
commandButtonLabel: rawLabel,
|
|
||||||
ariaLabel: rawLabel,
|
|
||||||
dropdownItemKey: cellRawType,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
iconSrc: CopyIcon,
|
|
||||||
iconAlt: copyLabel,
|
|
||||||
onCommandClick: () => this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.Copy),
|
|
||||||
commandButtonLabel: copyLabel,
|
|
||||||
ariaLabel: copyLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
iconSrc: CopyIcon,
|
|
||||||
iconAlt: copyLabel,
|
|
||||||
onCommandClick: () => this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.Copy),
|
|
||||||
commandButtonLabel: copyLabel,
|
|
||||||
ariaLabel: copyLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
iconSrc: CutIcon,
|
|
||||||
iconAlt: cutLabel,
|
|
||||||
onCommandClick: () => this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.Cut),
|
|
||||||
commandButtonLabel: cutLabel,
|
|
||||||
ariaLabel: cutLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
iconSrc: PasteIcon,
|
|
||||||
iconAlt: pasteLabel,
|
|
||||||
onCommandClick: () => this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.Paste),
|
|
||||||
commandButtonLabel: pasteLabel,
|
|
||||||
ariaLabel: pasteLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
iconSrc: UndoIcon,
|
|
||||||
iconAlt: undoLabel,
|
|
||||||
onCommandClick: () => this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.Undo),
|
|
||||||
commandButtonLabel: undoLabel,
|
|
||||||
ariaLabel: undoLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
iconSrc: UndoIcon,
|
|
||||||
iconAlt: undoLabel,
|
|
||||||
onCommandClick: () => this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.Undo),
|
|
||||||
commandButtonLabel: undoLabel,
|
|
||||||
ariaLabel: undoLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
iconSrc: RedoIcon,
|
|
||||||
iconAlt: redoLabel,
|
|
||||||
onCommandClick: () => this.sendMessageToNotebook(NotebookAppContracts.MessageTypes.Redo),
|
|
||||||
commandButtonLabel: redoLabel,
|
|
||||||
ariaLabel: redoLabel,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
if (this.container.hasStorageAnalyticsAfecFeature()) {
|
|
||||||
const arcadiaWorkspaceDropdown: ViewModels.NavbarButtonConfig = {
|
|
||||||
iconSrc: null,
|
|
||||||
iconAlt: workspaceLabel,
|
|
||||||
ariaLabel: workspaceLabel,
|
|
||||||
onCommandClick: () => {},
|
|
||||||
commandButtonLabel: null,
|
|
||||||
hasPopup: false,
|
|
||||||
disabled: this.container.arcadiaWorkspaces.length < 1,
|
|
||||||
isDropdown: false,
|
|
||||||
isArcadiaPicker: true,
|
|
||||||
arcadiaProps: {
|
|
||||||
selectedSparkPool: null,
|
|
||||||
workspaces: this.container.arcadiaWorkspaces(),
|
|
||||||
onSparkPoolSelect: () => {},
|
|
||||||
onCreateNewWorkspaceClicked: () => {
|
|
||||||
this.container.createWorkspace();
|
|
||||||
},
|
|
||||||
onCreateNewSparkPoolClicked: (workspaceResourceId: string) => {
|
|
||||||
this.container.createSparkPool(workspaceResourceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
buttons.splice(1, 0, arcadiaWorkspaceDropdown);
|
|
||||||
}
|
|
||||||
return buttons;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected buildCommandBarOptions(): void {
|
|
||||||
this.updateNavbarWithTabsButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async configureServiceEndpoints(kernelName: string) {
|
|
||||||
const notebookConnectionInfo = this.container && this.container.notebookServerInfo();
|
|
||||||
const sparkClusterConnectionInfo = this.container && this.container.sparkClusterConnectionInfo();
|
|
||||||
await NotebookConfigurationUtils.configureServiceEndpoints(
|
|
||||||
this.notebookPath(),
|
|
||||||
notebookConnectionInfo,
|
|
||||||
kernelName,
|
|
||||||
sparkClusterConnectionInfo
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private sendMessageToNotebook(type: NotebookAppContracts.MessageTypes, arg?: string): Q.Promise<any> {
|
|
||||||
return this.messageHandler.sendCachedDataMessage(type, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The iframe swallows any click event which breaks the logic to dismiss the menu, so we simulate a click from the message
|
|
||||||
*/
|
|
||||||
private simulateClick() {
|
|
||||||
if (!this.tabId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const event = document.createEvent("Events");
|
|
||||||
event.initEvent("click", true, false);
|
|
||||||
document.getElementById(this.tabId).dispatchEvent(event);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,8 +5,6 @@ import Explorer from "../Explorer";
|
||||||
import { CollectionStub, DatabaseStub } from "../../Explorer/OpenActionsStubs";
|
import { CollectionStub, DatabaseStub } from "../../Explorer/OpenActionsStubs";
|
||||||
import QueryTab from "./QueryTab";
|
import QueryTab from "./QueryTab";
|
||||||
|
|
||||||
jest.mock("./NotebookTab");
|
|
||||||
|
|
||||||
describe("Query Tab", () => {
|
describe("Query Tab", () => {
|
||||||
function getNewQueryTabForContainer(container: ViewModels.Explorer): ViewModels.QueryTab {
|
function getNewQueryTabForContainer(container: ViewModels.Explorer): ViewModels.QueryTab {
|
||||||
const database: ViewModels.Database = new DatabaseStub({
|
const database: ViewModels.Database = new DatabaseStub({
|
||||||
|
|
|
@ -9,8 +9,6 @@ import Explorer from "../Explorer";
|
||||||
import SettingsTab from "../Tabs/SettingsTab";
|
import SettingsTab from "../Tabs/SettingsTab";
|
||||||
import { DataAccessUtility } from "../../Platform/Portal/DataAccessUtility";
|
import { DataAccessUtility } from "../../Platform/Portal/DataAccessUtility";
|
||||||
|
|
||||||
jest.mock("./NotebookTab");
|
|
||||||
|
|
||||||
describe("Settings tab", () => {
|
describe("Settings tab", () => {
|
||||||
const baseCollection: DataModels.Collection = {
|
const baseCollection: DataModels.Collection = {
|
||||||
defaultTtl: 200,
|
defaultTtl: 200,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import DocumentsTabTemplate from "./DocumentsTab.html";
|
import DocumentsTabTemplate from "./DocumentsTab.html";
|
||||||
import ConflictsTabTemplate from "./ConflictsTab.html";
|
import ConflictsTabTemplate from "./ConflictsTab.html";
|
||||||
import GraphTabTemplate from "./GraphTab.html";
|
import GraphTabTemplate from "./GraphTab.html";
|
||||||
import NotebookTabTemplate from "./NotebookTab.html";
|
|
||||||
import SparkMasterTabTemplate from "./SparkMasterTab.html";
|
import SparkMasterTabTemplate from "./SparkMasterTab.html";
|
||||||
import NotebookV2TabTemplate from "./NotebookV2Tab.html";
|
import NotebookV2TabTemplate from "./NotebookV2Tab.html";
|
||||||
import TerminalTabTemplate from "./TerminalTab.html";
|
import TerminalTabTemplate from "./TerminalTab.html";
|
||||||
|
@ -51,15 +50,6 @@ export class GraphTab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NotebookTab {
|
|
||||||
constructor() {
|
|
||||||
return {
|
|
||||||
viewModel: TabComponent,
|
|
||||||
template: NotebookTabTemplate
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SparkMasterTab {
|
export class SparkMasterTab {
|
||||||
constructor() {
|
constructor() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
|
||||||
import TabsBase from "../TabsBase";
|
|
||||||
|
|
||||||
export default class NotebookTab extends TabsBase implements ViewModels.Tab {
|
|
||||||
constructor(options: ViewModels.NotebookTabOptions) {
|
|
||||||
super(options);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,7 +6,6 @@ import { TreeComponent, TreeNode, TreeNodeMenuItem } from "../Controls/TreeCompo
|
||||||
import * as ViewModels from "../../Contracts/ViewModels";
|
import * as ViewModels from "../../Contracts/ViewModels";
|
||||||
import { NotebookContentItem, NotebookContentItemType } from "../Notebook/NotebookContentItem";
|
import { NotebookContentItem, NotebookContentItemType } from "../Notebook/NotebookContentItem";
|
||||||
import { ResourceTreeContextMenuButtonFactory } from "../ContextMenuButtonFactory";
|
import { ResourceTreeContextMenuButtonFactory } from "../ContextMenuButtonFactory";
|
||||||
import NotebookTab from "../Tabs/NotebookTab";
|
|
||||||
import * as MostRecentActivity from "../MostRecentActivity/MostRecentActivity";
|
import * as MostRecentActivity from "../MostRecentActivity/MostRecentActivity";
|
||||||
import { CosmosClient } from "../../Common/CosmosClient";
|
import { CosmosClient } from "../../Common/CosmosClient";
|
||||||
import CosmosDBIcon from "../../../images/Azure-Cosmos-DB.svg";
|
import CosmosDBIcon from "../../../images/Azure-Cosmos-DB.svg";
|
||||||
|
@ -526,7 +525,10 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
return (
|
return (
|
||||||
activeTab &&
|
activeTab &&
|
||||||
activeTab.tabKind === ViewModels.CollectionTabKind.NotebookV2 &&
|
activeTab.tabKind === ViewModels.CollectionTabKind.NotebookV2 &&
|
||||||
(activeTab as NotebookTab).notebookPath() === item.path
|
/* TODO Redesign Tab interface so that resource tree doesn't need to know about NotebookV2Tab.
|
||||||
|
NotebookV2Tab could be dynamically imported, but not worth it to just get this type right.
|
||||||
|
*/
|
||||||
|
(activeTab as any).notebookPath() === item.path
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
contextMenu: createFileContextMenu
|
contextMenu: createFileContextMenu
|
||||||
|
@ -640,7 +642,10 @@ export class ResourceTreeAdapter implements ReactAdapter {
|
||||||
return (
|
return (
|
||||||
activeTab &&
|
activeTab &&
|
||||||
activeTab.tabKind === ViewModels.CollectionTabKind.NotebookV2 &&
|
activeTab.tabKind === ViewModels.CollectionTabKind.NotebookV2 &&
|
||||||
(activeTab as NotebookTab).notebookPath() === item.path
|
/* TODO Redesign Tab interface so that resource tree doesn't need to know about NotebookV2Tab.
|
||||||
|
NotebookV2Tab could be dynamically imported, but not worth it to just get this type right.
|
||||||
|
*/
|
||||||
|
(activeTab as any).notebookPath() === item.path
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
contextMenu:
|
contextMenu:
|
||||||
|
|
|
@ -5,8 +5,6 @@ import * as Constants from "../Common/Constants";
|
||||||
import Explorer from "../Explorer/Explorer";
|
import Explorer from "../Explorer/Explorer";
|
||||||
import { TabRouteHandler } from "./TabRouteHandler";
|
import { TabRouteHandler } from "./TabRouteHandler";
|
||||||
|
|
||||||
jest.mock("../Explorer/Tabs/NotebookTab");
|
|
||||||
|
|
||||||
describe("TabRouteHandler", () => {
|
describe("TabRouteHandler", () => {
|
||||||
let tabRouteHandler: TabRouteHandler;
|
let tabRouteHandler: TabRouteHandler;
|
||||||
|
|
||||||
|
|
|
@ -66,8 +66,6 @@ c.NotebookApp.disable_check_xsrf = True
|
||||||
* There is a "New Cell" button in the CommandBar outside the jupyter iframe which will add a cell inside the notebook.
|
* There is a "New Cell" button in the CommandBar outside the jupyter iframe which will add a cell inside the notebook.
|
||||||
|
|
||||||
# Notes
|
# Notes
|
||||||
* The iframe in the Data Explorer Tab loads jupyter with the server and notebook pathname passed in the query parameters (they're hardcoded right now):
|
|
||||||
cosmosdb-dataexplorer/Product/Portal/DataExplorer/src/Explorer/Tabs/NotebookTab.html
|
|
||||||
* The Emulator is located in: C:\Program Files\Azure Cosmos DB Emulator\Packages\DataExplorer
|
* The Emulator is located in: C:\Program Files\Azure Cosmos DB Emulator\Packages\DataExplorer
|
||||||
* Running "jupyter notebook" serves the jupyter traditional frontend. There is an alternate frontend also developed by jupyter which is modular and customizable called: JupyterLab. We use their "notebook" example in this project slightly modified to pass the server and notebook pathname via iframe url's parameters:
|
* Running "jupyter notebook" serves the jupyter traditional frontend. There is an alternate frontend also developed by jupyter which is modular and customizable called: JupyterLab. We use their "notebook" example in this project slightly modified to pass the server and notebook pathname via iframe url's parameters:
|
||||||
https://github.com/jupyterlab/jupyterlab/tree/master/examples/notebook
|
https://github.com/jupyterlab/jupyterlab/tree/master/examples/notebook
|
||||||
|
|
|
@ -337,10 +337,6 @@
|
||||||
<conflicts-tab params="{data: $data}"></conflicts-tab>
|
<conflicts-tab params="{data: $data}"></conflicts-tab>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
|
|
||||||
<!-- ko if: $data.tabKind === 13 -->
|
|
||||||
<notebook-tab params="{data: $data}"></notebook-tab>
|
|
||||||
<!-- /ko -->
|
|
||||||
|
|
||||||
<!-- ko if: $data.tabKind === 14 -->
|
<!-- ko if: $data.tabKind === 14 -->
|
||||||
<terminal-tab params="{data: $data}"></terminal-tab>
|
<terminal-tab params="{data: $data}"></terminal-tab>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
"./src/Contracts/Versions.ts",
|
"./src/Contracts/Versions.ts",
|
||||||
"./src/Controls/Heatmap/HeatmapDatatypes.ts",
|
"./src/Controls/Heatmap/HeatmapDatatypes.ts",
|
||||||
"./src/Definitions/plotly.js-cartesian-dist.d-min.ts",
|
"./src/Definitions/plotly.js-cartesian-dist.d-min.ts",
|
||||||
"./src/Explorer/Controls/Notebook/NotebookAppMessageHandler.ts",
|
|
||||||
"./src/Explorer/Controls/Toolbar/IToolbarAction.ts",
|
"./src/Explorer/Controls/Toolbar/IToolbarAction.ts",
|
||||||
"./src/Explorer/Controls/Toolbar/IToolbarDisplayable.ts",
|
"./src/Explorer/Controls/Toolbar/IToolbarDisplayable.ts",
|
||||||
"./src/Explorer/Controls/Toolbar/IToolbarDropDown.ts",
|
"./src/Explorer/Controls/Toolbar/IToolbarDropDown.ts",
|
||||||
|
|
Loading…
Reference in New Issue