mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-24 19:31:36 +00:00
* Upgrade typescript to 4.9.5 * Fix compile issue and put back files in tsconfig.strict.json * Update test snapshots * Fix jest tests by upgrading jest and other related packages. * Attempt to fix playwright test * Revert "Attempt to fix playwright test" This reverts commit8293f34c9c. * 2nd attempt to fix example test * fix waitFor in playwright * Remove unused describe section * Attempt to fix e2e test * Revert "Attempt to fix e2e test" This reverts commit9745bcd2ef. * Upgrade playwright to latest * Revert "Upgrade playwright to latest" This reverts commite2ea1d0189. * Error test on e2e * Revert "Error test on e2e" This reverts commit124e3764f7. * Try to select dropdown item by xpath selector * Revert "Try to select dropdown item by xpath selector" This reverts commit8eb42a64e2. * Attempt to wait until page is fully loaded * Revert "Attempt to wait until page is fully loaded" This reverts commitbb43fcea6e. * Use playwright selectOption to select dropdown option * Revert "Use playwright selectOption to select dropdown option" This reverts commitdaa8cd0930. * Select dropdown option with playwright api instead of manual click * c7ab4c7ecf7b05f32a85568bce1a667ad8c62703Revert "Select dropdown option with playwright api instead of manual click" This reverts commitc7ab4c7ecf. * Wait for 5s after dropdown click * Revert "Wait for 5s after dropdown click" This reverts commit847e9ad33f. * Try forcing click * Revert "Try forcing click" This reverts commit29b9fa1bda. * Force click on the dropdown and set viewport size bigger. * Force click on the dropdown and set viewport size bigger. * try force clicking option * Skip container test on webkit * Add branded browsers to e2e tests --------- Co-authored-by: Ashley Stanton-Nurse <ashleyst@microsoft.com>
380 lines
10 KiB
TypeScript
380 lines
10 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
import { Link } from "@fluentui/react";
|
|
import { CellId, CellType, ImmutableNotebook } from "@nteract/commutable";
|
|
// Vendor modules
|
|
import { actions, AppState, ContentRef, KernelRef, NotebookContentRecord, selectors } from "@nteract/core";
|
|
import "@nteract/styles/editor-overrides.css";
|
|
import "@nteract/styles/global-variables.css";
|
|
import "codemirror/addon/hint/show-hint.css";
|
|
import "codemirror/lib/codemirror.css";
|
|
import { Notebook } from "Common/Constants";
|
|
import { useDialog } from "Explorer/Controls/Dialog";
|
|
import * as React from "react";
|
|
import { Provider } from "react-redux";
|
|
import "react-table/react-table.css";
|
|
import { AnyAction, Store } from "redux";
|
|
import { NotebookClientV2 } from "../NotebookClientV2";
|
|
import { NotebookContentProviderType, NotebookUtil } from "../NotebookUtil";
|
|
import * as NteractUtil from "../NTeractUtil";
|
|
import * as CdbActions from "./actions";
|
|
import { NotebookComponent } from "./NotebookComponent";
|
|
import "./NotebookComponent.less";
|
|
|
|
export interface NotebookComponentBootstrapperOptions {
|
|
notebookClient: NotebookClientV2;
|
|
contentRef: ContentRef;
|
|
}
|
|
|
|
interface IWrapModel {
|
|
name: string;
|
|
path: string;
|
|
last_modified: Date;
|
|
created: string;
|
|
content: unknown;
|
|
format: string;
|
|
mimetype: unknown;
|
|
size: number;
|
|
writeable: boolean;
|
|
type: string;
|
|
}
|
|
|
|
export class NotebookComponentBootstrapper {
|
|
public contentRef: ContentRef;
|
|
protected renderExtraComponent: () => JSX.Element;
|
|
|
|
private notebookClient: NotebookClientV2;
|
|
|
|
constructor(options: NotebookComponentBootstrapperOptions) {
|
|
this.notebookClient = options.notebookClient;
|
|
this.contentRef = options.contentRef;
|
|
}
|
|
|
|
protected static wrapModelIntoContent(name: string, path: string, content: unknown): IWrapModel {
|
|
return {
|
|
name,
|
|
path,
|
|
last_modified: new Date(),
|
|
created: "",
|
|
content,
|
|
format: "json",
|
|
mimetype: undefined,
|
|
size: 0,
|
|
writeable: false,
|
|
type: "notebook",
|
|
};
|
|
}
|
|
|
|
private renderDefaultNotebookComponent(props: any): JSX.Element {
|
|
return (
|
|
<>
|
|
{this.renderExtraComponent && this.renderExtraComponent()}
|
|
{React.createElement<{ contentRef: ContentRef }>(NotebookComponent, { contentRef: this.contentRef, ...props })}
|
|
</>
|
|
);
|
|
}
|
|
|
|
public getContent(): { name: string; content: string | ImmutableNotebook } {
|
|
const record = this.getStore().getState().core.entities.contents.byRef.get(this.contentRef);
|
|
let content: string | ImmutableNotebook;
|
|
switch (record.model.type) {
|
|
case "notebook":
|
|
content = record.model.notebook;
|
|
break;
|
|
case "file":
|
|
content = record.model.text;
|
|
break;
|
|
default:
|
|
throw new Error(`Unsupported model type ${record.model.type}`);
|
|
}
|
|
|
|
return {
|
|
name: NotebookUtil.getName(record.filepath),
|
|
content,
|
|
};
|
|
}
|
|
|
|
public getNotebookPath(): string {
|
|
return this.getStore().getState().core.entities.contents.byRef.get(this.contentRef)?.filepath;
|
|
}
|
|
|
|
public setContent(name: string, content: unknown): void {
|
|
this.getStore().dispatch(
|
|
actions.fetchContentFulfilled({
|
|
filepath: undefined,
|
|
model: NotebookComponentBootstrapper.wrapModelIntoContent(name, undefined, content),
|
|
kernelRef: undefined,
|
|
contentRef: this.contentRef,
|
|
}),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* We can overload the notebook renderer here
|
|
* @param renderer
|
|
* @props additional props
|
|
*/
|
|
public renderComponent(
|
|
renderer?: any, // TODO FIX THIS React.ComponentClass<{ contentRef: ContentRef; isReadOnly?: boolean }>,
|
|
props?: any,
|
|
): JSX.Element {
|
|
return (
|
|
<Provider store={this.getStore()}>
|
|
{renderer
|
|
? React.createElement<{ contentRef: ContentRef }>(renderer, { contentRef: this.contentRef, ...props })
|
|
: this.renderDefaultNotebookComponent(props)}
|
|
</Provider>
|
|
);
|
|
}
|
|
|
|
/* Notebook operations. See nteract/packages/connected-components/src/notebook-menu/index.tsx */
|
|
public notebookSave(): void {
|
|
if (
|
|
NotebookUtil.getContentProviderType(this.getNotebookPath()) ===
|
|
NotebookContentProviderType.JupyterContentProviderType
|
|
) {
|
|
useDialog.getState().showOkCancelModalDialog(
|
|
Notebook.saveNotebookModalTitle,
|
|
undefined,
|
|
"Save",
|
|
async () => {
|
|
this.getStore().dispatch(
|
|
actions.save({
|
|
contentRef: this.contentRef,
|
|
}),
|
|
);
|
|
},
|
|
"Cancel",
|
|
undefined,
|
|
this.getSaveNotebookSubText(),
|
|
);
|
|
} else {
|
|
this.getStore().dispatch(
|
|
actions.save({
|
|
contentRef: this.contentRef,
|
|
}),
|
|
);
|
|
}
|
|
}
|
|
|
|
public notebookChangeKernel(kernelSpecName: string): void {
|
|
this.getStore().dispatch(
|
|
actions.changeKernelByName({
|
|
contentRef: this.contentRef,
|
|
kernelSpecName,
|
|
oldKernelRef: this.getCurrentKernelRef(),
|
|
}),
|
|
);
|
|
}
|
|
|
|
public notebookRunAndAdvance(): void {
|
|
this.getStore().dispatch(
|
|
CdbActions.executeFocusedCellAndFocusNext({
|
|
contentRef: this.contentRef,
|
|
}),
|
|
);
|
|
}
|
|
|
|
public notebookRunAll(): void {
|
|
this.getStore().dispatch(
|
|
actions.executeAllCells({
|
|
contentRef: this.contentRef,
|
|
}),
|
|
);
|
|
}
|
|
|
|
public notebookInterruptKernel(): void {
|
|
this.getStore().dispatch(
|
|
actions.interruptKernel({
|
|
kernelRef: this.getCurrentKernelRef(),
|
|
}),
|
|
);
|
|
}
|
|
|
|
public notebookKillKernel(): void {
|
|
this.getStore().dispatch(
|
|
actions.killKernel({
|
|
restarting: false,
|
|
kernelRef: this.getCurrentKernelRef(),
|
|
}),
|
|
);
|
|
}
|
|
|
|
public notebookRestartKernel(): void {
|
|
this.getStore().dispatch(
|
|
actions.restartKernel({
|
|
kernelRef: this.getCurrentKernelRef(),
|
|
contentRef: this.contentRef,
|
|
outputHandling: "None",
|
|
}),
|
|
);
|
|
}
|
|
|
|
public notebookClearAllOutputs(): void {
|
|
this.getStore().dispatch(
|
|
actions.clearAllOutputs({
|
|
contentRef: this.contentRef,
|
|
}),
|
|
);
|
|
}
|
|
|
|
public notebookInsertBelow(): void {
|
|
this.getStore().dispatch(
|
|
actions.createCellBelow({
|
|
cellType: "code",
|
|
contentRef: this.contentRef,
|
|
}),
|
|
);
|
|
}
|
|
|
|
public notebookChangeCellType(type: CellType): void {
|
|
const focusedCellId = this.getFocusedCellId();
|
|
if (!focusedCellId) {
|
|
console.error("No focused cell");
|
|
return;
|
|
}
|
|
|
|
this.getStore().dispatch(
|
|
actions.changeCellType({
|
|
id: focusedCellId,
|
|
contentRef: this.contentRef,
|
|
to: type,
|
|
}),
|
|
);
|
|
}
|
|
|
|
public notebokCopy(): void {
|
|
const focusedCellId = this.getFocusedCellId();
|
|
if (!focusedCellId) {
|
|
console.error("No focused cell");
|
|
return;
|
|
}
|
|
|
|
this.getStore().dispatch(
|
|
actions.copyCell({
|
|
id: focusedCellId,
|
|
contentRef: this.contentRef,
|
|
}),
|
|
);
|
|
}
|
|
|
|
public notebookCut(): void {
|
|
const focusedCellId = this.getFocusedCellId();
|
|
if (!focusedCellId) {
|
|
console.error("No focused cell");
|
|
return;
|
|
}
|
|
|
|
this.getStore().dispatch(
|
|
actions.cutCell({
|
|
id: focusedCellId,
|
|
contentRef: this.contentRef,
|
|
}),
|
|
);
|
|
}
|
|
|
|
public notebookPaste(): void {
|
|
this.getStore().dispatch(
|
|
actions.pasteCell({
|
|
contentRef: this.contentRef,
|
|
}),
|
|
);
|
|
}
|
|
|
|
public notebookShutdown(): void {
|
|
const store = this.getStore();
|
|
const kernelRef = this.getCurrentKernelRef();
|
|
|
|
if (kernelRef) {
|
|
store.dispatch(
|
|
actions.killKernel({
|
|
restarting: false,
|
|
kernelRef,
|
|
}),
|
|
);
|
|
}
|
|
|
|
store.dispatch(
|
|
CdbActions.closeNotebook({
|
|
contentRef: this.contentRef,
|
|
}),
|
|
);
|
|
}
|
|
|
|
public isContentDirty(): boolean {
|
|
const content = selectors.content(this.getStore().getState(), { contentRef: this.contentRef });
|
|
if (!content) {
|
|
return false;
|
|
}
|
|
|
|
// TODO Fix this typing here
|
|
return selectors.notebook.isDirty(content.model as never);
|
|
}
|
|
|
|
public isNotebookUntrusted(): boolean {
|
|
return NotebookUtil.isNotebookUntrusted(this.getStore().getState(), this.contentRef);
|
|
}
|
|
|
|
/**
|
|
* For display purposes, only return non-killed kernels
|
|
*/
|
|
public getCurrentKernelName(): string {
|
|
const currentKernel = selectors.kernel(this.getStore().getState(), { kernelRef: this.getCurrentKernelRef() });
|
|
return (currentKernel && currentKernel.status !== "killed" && currentKernel.kernelSpecName) || undefined;
|
|
}
|
|
|
|
// Returns the kernel name to select in the kernels dropdown
|
|
public getSelectedKernelName(): string {
|
|
const currentKernelName = this.getCurrentKernelName();
|
|
if (!currentKernelName) {
|
|
// if there's no live kernel, try to get the kernel name from the notebook metadata
|
|
const content = selectors.content(this.getStore().getState(), { contentRef: this.contentRef });
|
|
const notebook = content && (content as NotebookContentRecord).model.notebook;
|
|
if (!notebook) {
|
|
return undefined;
|
|
}
|
|
|
|
const { kernelSpecName } = NotebookUtil.extractNewKernel("", notebook);
|
|
return kernelSpecName || undefined;
|
|
}
|
|
|
|
return currentKernelName;
|
|
}
|
|
|
|
public getActiveCellTypeStr(): string {
|
|
const content = selectors.content(this.getStore().getState(), { contentRef: this.contentRef });
|
|
return NteractUtil.getCurrentCellType(content as NotebookContentRecord);
|
|
}
|
|
|
|
private getCurrentKernelRef(): KernelRef {
|
|
return selectors.kernelRefByContentRef(this.getStore().getState(), { contentRef: this.contentRef });
|
|
}
|
|
|
|
private getFocusedCellId(): CellId {
|
|
const content = selectors.content(this.getStore().getState(), { contentRef: this.contentRef });
|
|
if (!content) {
|
|
return undefined;
|
|
}
|
|
|
|
return selectors.notebook.cellFocused((content as NotebookContentRecord).model);
|
|
}
|
|
|
|
protected getStore(): Store<AppState, AnyAction> {
|
|
return this.notebookClient.getStore();
|
|
}
|
|
|
|
private getSaveNotebookSubText(): JSX.Element {
|
|
return (
|
|
<>
|
|
<p>{Notebook.saveNotebookModalContent}</p>
|
|
<br />
|
|
<p>
|
|
{Notebook.newNotebookModalContent2}
|
|
<Link href={Notebook.cosmosNotebookHomePageUrl} target="_blank">
|
|
{Notebook.learnMore}
|
|
</Link>
|
|
</p>
|
|
</>
|
|
);
|
|
}
|
|
}
|