import { ImmutableNotebook, toJS } from "@nteract/commutable"; import React, { FunctionComponent, useEffect, useState } from "react"; import { HttpStatusCodes } from "../../../Common/Constants"; import { getErrorMessage, getErrorStack, handleError } from "../../../Common/ErrorHandlingUtils"; import { JunoClient } from "../../../Juno/JunoClient"; import { Action } from "../../../Shared/Telemetry/TelemetryConstants"; import { traceFailure, traceStart, traceSuccess } from "../../../Shared/Telemetry/TelemetryProcessor"; import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils"; import { CodeOfConductComponent } from "../../Controls/NotebookGallery/CodeOfConductComponent"; import { GalleryTab } from "../../Controls/NotebookGallery/GalleryViewerComponent"; import Explorer from "../../Explorer"; import * as FileSystemUtil from "../../Notebook/FileSystemUtil"; import { GenericRightPaneComponent, GenericRightPaneProps, } from "../GenericRightPaneComponent/GenericRightPaneComponent"; import { PublishNotebookPaneComponent, PublishNotebookPaneProps } from "./PublishNotebookPaneComponent"; export interface PublishNotebookPaneAProps { explorer: Explorer; closePanel: () => void; openNotificationConsole: () => void; junoClient: JunoClient; name: string; author: string; notebookContent: string | ImmutableNotebook; parentDomElement: HTMLElement; } export const PublishNotebookPane: FunctionComponent = ({ explorer: container, junoClient, closePanel, name, author, notebookContent, parentDomElement, }: PublishNotebookPaneAProps): JSX.Element => { const [isCodeOfConductAccepted, setIsCodeOfConductAccepted] = useState(false); const [content, setContent] = useState(""); const [formError, setFormError] = useState(""); const [formErrorDetail, setFormErrorDetail] = useState(""); const [isExecuting, setIsExecuting] = useState(); const [notebookName, setNotebookName] = useState(name); const [notebookDescription, setNotebookDescription] = useState(""); const [notebookTags, setNotebookTags] = useState(""); const [imageSrc, setImageSrc] = useState(); const CodeOfConductAccepted = async () => { try { const response = await junoClient.isCodeOfConductAccepted(); if (response.status !== HttpStatusCodes.OK && response.status !== HttpStatusCodes.NoContent) { throw new Error(`Received HTTP ${response.status} when accepting code of conduct`); } setIsCodeOfConductAccepted(response.data); } catch (error) { handleError( error, "PublishNotebookPaneAdapter/isCodeOfConductAccepted", "Failed to check if code of conduct was accepted" ); } }; const [notebookObject, setNotebookObject] = useState(); useEffect(() => { CodeOfConductAccepted(); let newContent; if (typeof notebookContent === "string") { newContent = notebookContent as string; } else { newContent = JSON.stringify(toJS(notebookContent)); setNotebookObject(notebookContent); } setContent(newContent); }, []); const submit = async (): Promise => { const clearPublishingMessage = NotificationConsoleUtils.logConsoleProgress(`Publishing ${name} to gallery`); setIsExecuting(true); let startKey: number; if (!notebookName || !notebookDescription || !author || !imageSrc) { setFormError(`Failed to publish ${notebookName} to gallery`); setFormErrorDetail("Name, description, author and cover image are required"); createFormError(formError, formErrorDetail, "PublishNotebookPaneAdapter/submit"); setIsExecuting(false); return; } try { startKey = traceStart(Action.NotebooksGalleryPublish, {}); const response = await junoClient.publishNotebook( notebookName, notebookDescription, notebookTags?.split(","), author, imageSrc, content ); const data = response.data; if (data) { let isPublishPending = false; if (data.pendingScanJobIds?.length > 0) { isPublishPending = true; NotificationConsoleUtils.logConsoleInfo( `Content of ${name} is currently being scanned for illegal content. It will not be available in the public gallery until the review is complete (may take a few days).` ); } else { NotificationConsoleUtils.logConsoleInfo(`Published ${notebookName} to gallery`); container.openGallery(GalleryTab.Published); } traceSuccess( Action.NotebooksGalleryPublish, { notebookId: data.id, isPublishPending, }, startKey ); } } catch (error) { traceFailure( Action.NotebooksGalleryPublish, { error: getErrorMessage(error), errorStack: getErrorStack(error), }, startKey ); const errorMessage = getErrorMessage(error); setFormError(`Failed to publish ${FileSystemUtil.stripExtension(notebookName, "ipynb")} to gallery`); setFormErrorDetail(`${errorMessage}`); handleError(errorMessage, "PublishNotebookPaneAdapter/submit", formError); return; } finally { clearPublishingMessage(); setIsExecuting(false); } closePanel(); }; const createFormError = (formError: string, formErrorDetail: string, area: string): void => { setFormError(formError); setFormErrorDetail(formErrorDetail); handleError(formErrorDetail, area, formError); }; const clearFormError = (): void => { setFormError(""); setFormErrorDetail(""); }; const props: GenericRightPaneProps = { formError: formError, formErrorDetail: formErrorDetail, id: "publishnotebookpane", isExecuting: isExecuting, title: "Publish to gallery", submitButtonText: "Publish", onSubmit: () => submit(), onClose: closePanel, expandConsole: () => container.expandConsole(), isSubmitButtonHidden: !isCodeOfConductAccepted, }; const publishNotebookPaneProps: PublishNotebookPaneProps = { notebookDescription, notebookTags, imageSrc, notebookName, notebookAuthor: author, notebookCreatedDate: new Date().toISOString(), notebookObject: notebookObject, notebookParentDomElement: parentDomElement, onError: createFormError, clearFormError: clearFormError, setNotebookName, setNotebookDescription, setNotebookTags, setImageSrc, }; return ( {!isCodeOfConductAccepted ? (
{ setIsCodeOfConductAccepted(isAccepted); }} />
) : ( )}
); };