import { IconButton, Text, TextField } from "@fluentui/react"; import { Areas } from "Common/Constants"; import DeleteFeedback from "Common/DeleteFeedback"; import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils"; import { deleteCollection } from "Common/dataAccess/deleteCollection"; import { Collection } from "Contracts/ViewModels"; import { Keys, t } from "Localization"; import { DefaultExperienceUtility } from "Shared/DefaultExperienceUtility"; import { Action, ActionModifiers } from "Shared/Telemetry/TelemetryConstants"; import * as TelemetryProcessor from "Shared/Telemetry/TelemetryProcessor"; import { userContext } from "UserContext"; import { getCollectionName } from "Utils/APITypeUtils"; import * as NotificationConsoleUtils from "Utils/NotificationConsoleUtils"; import { useSidePanel } from "hooks/useSidePanel"; import { useTabs } from "hooks/useTabs"; import React, { FunctionComponent, useState } from "react"; import { useDatabases } from "../../useDatabases"; import { useSelectedNode } from "../../useSelectedNode"; import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm"; import { PanelInfoErrorComponent, PanelInfoErrorProps } from "../PanelInfoErrorComponent"; const themedTextFieldStyles = { fieldGroup: { width: 300, backgroundColor: "var(--colorNeutralBackground1)", borderColor: "var(--colorNeutralStroke1)", selectors: { ":hover": { borderColor: "var(--colorNeutralStroke1Hover)" }, }, }, field: { color: "var(--colorNeutralForeground1)", backgroundColor: "var(--colorNeutralBackground1)", }, subComponentStyles: { label: { root: { color: "var(--colorNeutralForeground1)" } }, }, }; export interface DeleteCollectionConfirmationPaneProps { refreshDatabases: () => Promise; } export const DeleteCollectionConfirmationPane: FunctionComponent = ({ refreshDatabases, }: DeleteCollectionConfirmationPaneProps) => { const closeSidePanel = useSidePanel((state) => state.closeSidePanel); const [deleteCollectionFeedback, setDeleteCollectionFeedback] = useState(""); const [inputCollectionName, setInputCollectionName] = useState(""); const [formError, setFormError] = useState(""); const [isExecuting, setIsExecuting] = useState(false); const shouldRecordFeedback = (): boolean => useDatabases.getState().isLastCollection() && !useDatabases.getState().findSelectedDatabase()?.isDatabaseShared(); const collectionName = getCollectionName().toLocaleLowerCase(); const paneTitle = t(Keys.panes.deleteCollection.panelTitle, { collectionName }); const selectedCollection = useSelectedNode.getState().selectedNode ? useSelectedNode.getState().findSelectedCollection() : undefined; const selectedCollectionId = selectedCollection?.id() ?? ""; const onSubmit = async (): Promise => { const collection = useSelectedNode.getState().findSelectedCollection(); if (!collection || inputCollectionName !== collection.id()) { const errorMessage = t(Keys.panes.deleteCollection.inputMismatch, { input: inputCollectionName, selectedId: collection.id(), }); setFormError(errorMessage); NotificationConsoleUtils.logConsoleError( `Error while deleting ${collectionName} ${collection.id()}: ${errorMessage}`, ); return; } const paneInfo = { collectionId: collection.id(), dataExplorerArea: Areas.ContextualPane, paneTitle, }; setFormError(""); setIsExecuting(true); const startKey: number = TelemetryProcessor.traceStart(Action.DeleteCollection, paneInfo); try { await deleteCollection(collection.databaseId, collection.id()); setIsExecuting(false); useSelectedNode.getState().setSelectedNode(collection.database); useTabs .getState() .closeTabsByComparator( (tab) => tab.node?.id() === collection.id() && (tab.node as Collection).databaseId === collection.databaseId, ); refreshDatabases(); TelemetryProcessor.traceSuccess(Action.DeleteCollection, paneInfo, startKey); if (shouldRecordFeedback()) { const deleteFeedback = new DeleteFeedback( userContext.databaseAccount?.id, userContext.databaseAccount?.name, DefaultExperienceUtility.getApiKindFromDefaultExperience(userContext.apiType), deleteCollectionFeedback, ); TelemetryProcessor.trace(Action.DeleteCollection, ActionModifiers.Mark, { message: JSON.stringify(deleteFeedback, Object.getOwnPropertyNames(deleteFeedback)), }); } closeSidePanel(); } catch (error) { const errorMessage = getErrorMessage(error); setFormError(errorMessage); setIsExecuting(false); TelemetryProcessor.traceFailure( Action.DeleteCollection, { ...paneInfo, error: errorMessage, errorStack: getErrorStack(error), }, startKey, ); } }; const props: RightPaneFormProps = { formError: formError, isExecuting, submitButtonText: t(Keys.common.ok), onSubmit, }; const errorProps: PanelInfoErrorProps = { messageType: "warning", showErrorDetails: false, message: t(Keys.panes.deleteCollection.warningMessage), }; const copyableIdLabel = t(Keys.panes.deleteCollection.copyableId, { collectionName: getCollectionName(), }); const confirmContainer = t(Keys.panes.deleteCollection.confirmPrompt, { collectionName: collectionName.toLowerCase(), }); const reasonInfo = t(Keys.panes.deleteCollection.feedbackTitle) + " " + t(Keys.panes.deleteCollection.feedbackReason, { collectionName }); return ( {!formError && }
{copyableIdLabel} ( navigator.clipboard.writeText(selectedCollectionId)} styles={{ root: { height: "100%" } }} /> )} ariaLabel={copyableIdLabel} /> * {confirmContainer} { setInputCollectionName(newInput); }} ariaLabel={confirmContainer} required />
{shouldRecordFeedback() && (
{t(Keys.panes.deleteCollection.feedbackTitle)} {t(Keys.panes.deleteCollection.feedbackReason, { collectionName })} { setDeleteCollectionFeedback(newInput); }} ariaLabel={reasonInfo} />
)}
); };