import ko from "knockout"; import * as React from "react"; import { ReactAdapter } from "../../Bindings/ReactBindingHandler"; import * as Logger from "../../Common/Logger"; import { JunoClient, IPinnedRepo } from "../../Juno/JunoClient"; import * as NotificationConsoleUtils from "../../Utils/NotificationConsoleUtils"; import Explorer from "../Explorer"; import { GenericRightPaneComponent, GenericRightPaneProps } from "./GenericRightPaneComponent"; import { CopyNotebookPaneComponent, CopyNotebookPaneProps } from "./CopyNotebookPaneComponent"; import { IDropdownOption } from "office-ui-fabric-react"; import { GitHubOAuthService } from "../../GitHub/GitHubOAuthService"; import { HttpStatusCodes } from "../../Common/Constants"; import * as GitHubUtils from "../../Utils/GitHubUtils"; import { NotebookContentItemType, NotebookContentItem } from "../Notebook/NotebookContentItem"; import { ResourceTreeAdapter } from "../Tree/ResourceTreeAdapter"; interface Location { type: "MyNotebooks" | "GitHub"; // GitHub owner?: string; repo?: string; branch?: string; } export class CopyNotebookPaneAdapter implements ReactAdapter { private static readonly BranchNameWhiteSpace = " "; parameters: ko.Observable; private isOpened: boolean; private isExecuting: boolean; private formError: string; private formErrorDetail: string; private name: string; private content: string; private pinnedRepos: IPinnedRepo[]; private selectedLocation: Location; constructor( private container: Explorer, private junoClient: JunoClient, private gitHubOAuthService: GitHubOAuthService ) { this.parameters = ko.observable(Date.now()); this.reset(); this.triggerRender(); } public renderComponent(): JSX.Element { if (!this.isOpened) { return undefined; } const genericPaneProps: GenericRightPaneProps = { container: this.container, formError: this.formError, formErrorDetail: this.formErrorDetail, id: "copynotebookpane", isExecuting: this.isExecuting, title: "Copy notebook", submitButtonText: "OK", onClose: () => this.close(), onSubmit: () => this.submit() }; const copyNotebookPaneProps: CopyNotebookPaneProps = { name: this.name, pinnedRepos: this.pinnedRepos, onDropDownChange: this.onDropDownChange }; return ( ); } public triggerRender(): void { window.requestAnimationFrame(() => this.parameters(Date.now())); } public async open(name: string, content: string): Promise { this.name = name; this.content = content; this.isOpened = true; this.triggerRender(); if (this.gitHubOAuthService.isLoggedIn()) { const response = await this.junoClient.getPinnedRepos(this.gitHubOAuthService.getTokenObservable()()?.scope); if (response.status !== HttpStatusCodes.OK && response.status !== HttpStatusCodes.NoContent) { const message = `Received HTTP ${response.status} when fetching pinned repos`; Logger.logError(message, "CopyNotebookPaneAdapter/submit"); NotificationConsoleUtils.logConsoleError(message); } if (response.data?.length > 0) { this.pinnedRepos = response.data; this.triggerRender(); } } } public close(): void { this.reset(); this.triggerRender(); } public async submit(): Promise { let destination: string = this.selectedLocation?.type; let clearMessage: () => void; this.isExecuting = true; this.triggerRender(); try { if (!this.selectedLocation) { throw new Error(`No location selected`); } if (this.selectedLocation.type === "GitHub") { destination = `${destination} - ${GitHubUtils.toRepoFullName( this.selectedLocation.owner, this.selectedLocation.repo )} - ${this.selectedLocation.branch}`; } clearMessage = NotificationConsoleUtils.logConsoleProgress(`Copying ${this.name} to ${destination}`); const notebookContentItem = await this.copyNotebook(this.selectedLocation); if (!notebookContentItem) { throw new Error(`Failed to upload ${this.name}`); } NotificationConsoleUtils.logConsoleInfo(`Successfully copied ${this.name} to ${destination}`); } catch (error) { this.formError = `Failed to copy ${this.name} to ${destination}`; this.formErrorDetail = `${error}`; const message = `${this.formError}: ${this.formErrorDetail}`; Logger.logError(message, "CopyNotebookPaneAdapter/submit"); NotificationConsoleUtils.logConsoleError(message); return; } finally { clearMessage && clearMessage(); this.isExecuting = false; this.triggerRender(); } this.close(); } private copyNotebook = async (location: Location): Promise => { let parent: NotebookContentItem; switch (location.type) { case "MyNotebooks": parent = { name: ResourceTreeAdapter.MyNotebooksTitle, path: this.container.getNotebookBasePath(), type: NotebookContentItemType.Directory }; break; case "GitHub": parent = { name: ResourceTreeAdapter.GitHubReposTitle, path: GitHubUtils.toContentUri( this.selectedLocation.owner, this.selectedLocation.repo, this.selectedLocation.branch, "" ), type: NotebookContentItemType.Directory }; break; default: throw new Error(`Unsupported location type ${location.type}`); } return this.container.uploadFile(this.name, this.content, parent); }; private onDropDownChange = (_: React.FormEvent, option?: IDropdownOption): void => { this.selectedLocation = option?.data; }; private reset = (): void => { this.isOpened = false; this.isExecuting = false; this.formError = undefined; this.formErrorDetail = undefined; this.name = undefined; this.content = undefined; this.pinnedRepos = undefined; this.selectedLocation = undefined; }; }