clear diagram data

This commit is contained in:
Guy Ben-Aharon
2024-08-23 03:17:52 +03:00
parent c4948b0853
commit c43e8d7f30
9 changed files with 498 additions and 219 deletions

29
package-lock.json generated
View File

@@ -10,6 +10,7 @@
"dependencies": {
"@ai-sdk/openai": "^0.0.51",
"@radix-ui/react-accordion": "^1.2.0",
"@radix-ui/react-alert-dialog": "^1.1.1",
"@radix-ui/react-checkbox": "^1.1.1",
"@radix-ui/react-collapsible": "^1.1.0",
"@radix-ui/react-dialog": "^1.1.1",
@@ -1402,6 +1403,34 @@
}
}
},
"node_modules/@radix-ui/react-alert-dialog": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.1.tgz",
"integrity": "sha512-wmCoJwj7byuVuiLKqDLlX7ClSUU0vd9sdCeM+2Ls+uf13+cpSJoMgwysHq1SGVVkJj5Xn0XWi1NoRCdkMpr6Mw==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.0",
"@radix-ui/react-compose-refs": "1.1.0",
"@radix-ui/react-context": "1.1.0",
"@radix-ui/react-dialog": "1.1.1",
"@radix-ui/react-primitive": "2.0.0",
"@radix-ui/react-slot": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-arrow": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz",

View File

@@ -13,6 +13,7 @@
"dependencies": {
"@ai-sdk/openai": "^0.0.51",
"@radix-ui/react-accordion": "^1.2.0",
"@radix-ui/react-alert-dialog": "^1.1.1",
"@radix-ui/react-checkbox": "^1.1.1",
"@radix-ui/react-collapsible": "^1.1.0",
"@radix-ui/react-dialog": "^1.1.1",

View File

@@ -0,0 +1,139 @@
import * as React from 'react';
import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog';
import { cn } from '@/lib/utils';
import { buttonVariants } from '../button/button-variants';
const AlertDialog = AlertDialogPrimitive.Root;
const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
const AlertDialogPortal = AlertDialogPrimitive.Portal;
const AlertDialogOverlay = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Overlay
className={cn(
'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
className
)}
{...props}
ref={ref}
/>
));
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
const AlertDialogContent = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
>(({ className, ...props }, ref) => (
<AlertDialogPortal>
<AlertDialogOverlay />
<AlertDialogPrimitive.Content
ref={ref}
className={cn(
'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
className
)}
{...props}
/>
</AlertDialogPortal>
));
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
const AlertDialogHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
'flex flex-col space-y-2 text-center sm:text-left',
className
)}
{...props}
/>
);
AlertDialogHeader.displayName = 'AlertDialogHeader';
const AlertDialogFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
className
)}
{...props}
/>
);
AlertDialogFooter.displayName = 'AlertDialogFooter';
const AlertDialogTitle = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Title
ref={ref}
className={cn('text-lg font-semibold', className)}
{...props}
/>
));
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
const AlertDialogDescription = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Description
ref={ref}
className={cn('text-sm text-muted-foreground', className)}
{...props}
/>
));
AlertDialogDescription.displayName =
AlertDialogPrimitive.Description.displayName;
const AlertDialogAction = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Action>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Action
ref={ref}
className={cn(buttonVariants(), className)}
{...props}
/>
));
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
const AlertDialogCancel = React.forwardRef<
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
>(({ className, ...props }, ref) => (
<AlertDialogPrimitive.Cancel
ref={ref}
className={cn(
buttonVariants({ variant: 'outline' }),
'mt-2 sm:mt-0',
className
)}
{...props}
/>
));
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
export {
AlertDialog,
AlertDialogPortal,
AlertDialogOverlay,
AlertDialogTrigger,
AlertDialogContent,
AlertDialogHeader,
AlertDialogFooter,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogAction,
AlertDialogCancel,
};

View File

@@ -23,6 +23,7 @@ export interface ChartDBContext {
) => Promise<void>;
loadDiagram: (diagramId: string) => Promise<Diagram | undefined>;
updateDiagramUpdatedAt: () => Promise<void>;
clearDiagramData: () => Promise<void>;
// Database type operations
updateDatabaseType: (databaseType: DatabaseType) => Promise<void>;
@@ -138,6 +139,7 @@ export const chartDBContext = createContext<ChartDBContext>({
updateDiagramName: emptyFn,
updateDiagramUpdatedAt: emptyFn,
loadDiagram: emptyFn,
clearDiagramData: emptyFn,
// Database type operations
updateDatabaseType: emptyFn,

View File

@@ -15,7 +15,8 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
children,
}) => {
const db = useStorage();
const { addUndoAction, resetRedoStack } = useRedoUndoStack();
const { addUndoAction, resetRedoStack, resetUndoStack } =
useRedoUndoStack();
const [diagramId, setDiagramId] = useState('');
const [diagramName, setDiagramName] = useState('');
const [diagramCreatedAt, setDiagramCreatedAt] = useState<Date>(new Date());
@@ -47,6 +48,23 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
]
);
const clearDiagramData: ChartDBContext['clearDiagramData'] =
useCallback(async () => {
const updatedAt = new Date();
setTables([]);
setRelationships([]);
setDiagramUpdatedAt(updatedAt);
resetRedoStack();
resetUndoStack();
await Promise.all([
db.updateDiagram({ id: diagramId, attributes: { updatedAt } }),
db.deleteDiagramTables(diagramId),
db.deleteDiagramRelationships(diagramId),
]);
}, [db, diagramId, resetRedoStack, resetUndoStack]);
const updateDiagramUpdatedAt: ChartDBContext['updateDiagramUpdatedAt'] =
useCallback(async () => {
const updatedAt = new Date();
@@ -928,6 +946,7 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
updateDiagramName,
loadDiagram,
updateDatabaseType,
clearDiagramData,
updateDiagramUpdatedAt,
createTable,
addTable,

View File

@@ -41,6 +41,7 @@ export interface StorageContext {
}) => Promise<void>;
deleteTable: (params: { diagramId: string; id: string }) => Promise<void>;
listTables: (diagramId: string) => Promise<DBTable[]>;
deleteDiagramTables: (diagramId: string) => Promise<void>;
// Relationships operations
addRelationship: (params: {
@@ -60,6 +61,7 @@ export interface StorageContext {
id: string;
}) => Promise<void>;
listRelationships: (diagramId: string) => Promise<DBRelationship[]>;
deleteDiagramRelationships: (diagramId: string) => Promise<void>;
}
export const storageContext = createContext<StorageContext>({
@@ -77,10 +79,12 @@ export const storageContext = createContext<StorageContext>({
updateTable: emptyFn,
deleteTable: emptyFn,
listTables: emptyFn,
deleteDiagramTables: emptyFn,
addRelationship: emptyFn,
getRelationship: emptyFn,
updateRelationship: emptyFn,
deleteRelationship: emptyFn,
listRelationships: emptyFn,
deleteDiagramRelationships: emptyFn,
});

View File

@@ -188,6 +188,12 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
return await db.db_tables.get({ id, diagramId });
};
const deleteDiagramTables: StorageContext['deleteDiagramTables'] = async (
diagramId: string
) => {
await db.db_tables.where('diagramId').equals(diagramId).delete();
};
const updateTable: StorageContext['updateTable'] = async ({
id,
attributes,
@@ -238,6 +244,14 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
});
};
const deleteDiagramRelationships: StorageContext['deleteDiagramRelationships'] =
async (diagramId: string) => {
await db.db_relationships
.where('diagramId')
.equals(diagramId)
.delete();
};
const getRelationship: StorageContext['getRelationship'] = async ({
id,
diagramId,
@@ -302,6 +316,8 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
updateRelationship,
deleteRelationship,
listRelationships,
deleteDiagramTables,
deleteDiagramRelationships,
}}
>
{children}

View File

@@ -45,6 +45,7 @@ export const ExportSQLDialog: React.FC<ExportSQLDialogProps> = ({
}, [targetDatabaseType, currentDiagram]);
useEffect(() => {
if (!dialog.open) return;
setScript(undefined);
const fetchScript = async () => {
const script = await exportSQLScript();

View File

@@ -32,16 +32,28 @@ import {
databaseTypeToLabelMap,
} from '@/lib/databases';
import { DatabaseType } from '@/lib/domain/database-type';
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from '@/components/alert-dialog/alert-dialog';
export interface TopNavbarProps {}
export const TopNavbar: React.FC<TopNavbarProps> = () => {
const { diagramName, updateDiagramName, currentDiagram } = useChartDB();
const { diagramName, updateDiagramName, currentDiagram, clearDiagramData } =
useChartDB();
const {
openCreateDiagramDialog,
openOpenDiagramDialog,
openExportSQLDialog,
} = useDialog();
const [showClearAlert, setShowClearAlert] = useState(false);
const [editMode, setEditMode] = useState(false);
const { exportImage } = useExportImage();
const [editedDiagramName, setEditedDiagramName] =
@@ -79,6 +91,11 @@ export const TopNavbar: React.FC<TopNavbarProps> = () => {
setEditMode(true);
};
const clearDiagramDataHandler = useCallback(async () => {
setShowClearAlert(false);
await clearDiagramData();
}, [clearDiagramData]);
const exportPNG = useCallback(() => {
exportImage('png');
}, [exportImage]);
@@ -103,228 +120,279 @@ export const TopNavbar: React.FC<TopNavbarProps> = () => {
}, []);
return (
<nav className="flex flex-row items-center justify-between px-4 h-12 border-b">
<div className="flex flex-1 justify-start gap-x-3">
<div className="flex font-primary items-center">
<a
href="https://chartdb.io"
target="_blank"
className="cursor-pointer"
rel="noreferrer"
>
<img
src={ChartDBLogo}
alt="chartDB"
className="h-4 max-w-fit"
/>
</a>
<>
<nav className="flex flex-row items-center justify-between px-4 h-12 border-b">
<div className="flex flex-1 justify-start gap-x-3">
<div className="flex font-primary items-center">
<a
href="https://chartdb.io"
target="_blank"
className="cursor-pointer"
rel="noreferrer"
>
<img
src={ChartDBLogo}
alt="chartDB"
className="h-4 max-w-fit"
/>
</a>
</div>
<div>
<Menubar className="border-none shadow-none">
<MenubarMenu>
<MenubarTrigger>File</MenubarTrigger>
<MenubarContent>
<MenubarItem onClick={createNewDiagram}>
New
<MenubarShortcut>T</MenubarShortcut>
</MenubarItem>
<MenubarItem onClick={openDiagram}>
Open
</MenubarItem>
<MenubarSeparator />
<MenubarSub>
<MenubarSubTrigger>
Export SQL
</MenubarSubTrigger>
<MenubarSubContent>
<MenubarItem
onClick={() =>
openExportSQLDialog({
targetDatabaseType:
DatabaseType.GENERIC,
})
}
>
{
databaseTypeToLabelMap[
'generic'
]
}
</MenubarItem>
<MenubarItem
onClick={() =>
openExportSQLDialog({
targetDatabaseType:
DatabaseType.POSTGRESQL,
})
}
>
{
databaseTypeToLabelMap[
'postgresql'
]
}
</MenubarItem>
<MenubarItem
onClick={() =>
openExportSQLDialog({
targetDatabaseType:
DatabaseType.MYSQL,
})
}
>
{
databaseTypeToLabelMap[
'mysql'
]
}
</MenubarItem>
<MenubarItem
onClick={() =>
openExportSQLDialog({
targetDatabaseType:
DatabaseType.SQL_SERVER,
})
}
>
{
databaseTypeToLabelMap[
'sql_server'
]
}
</MenubarItem>
<MenubarItem
onClick={() =>
openExportSQLDialog({
targetDatabaseType:
DatabaseType.MARIADB,
})
}
>
{
databaseTypeToLabelMap[
'mariadb'
]
}
</MenubarItem>
<MenubarItem
onClick={() =>
openExportSQLDialog({
targetDatabaseType:
DatabaseType.SQLITE,
})
}
>
{
databaseTypeToLabelMap[
'sqlite'
]
}
</MenubarItem>
</MenubarSubContent>
</MenubarSub>
<MenubarSub>
<MenubarSubTrigger>
Export as
</MenubarSubTrigger>
<MenubarSubContent>
<MenubarItem onClick={exportPNG}>
PNG
</MenubarItem>
<MenubarItem onClick={exportJPG}>
JPG
</MenubarItem>
<MenubarItem onClick={exportSVG}>
SVG
</MenubarItem>
</MenubarSubContent>
</MenubarSub>
<MenubarSeparator />
<MenubarItem>Exit</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>Edit</MenubarTrigger>
<MenubarContent>
<MenubarItem>
Undo{' '}
<MenubarShortcut>Z</MenubarShortcut>
</MenubarItem>
<MenubarItem>
Redo{' '}
<MenubarShortcut>Z</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarItem
onClick={() => setShowClearAlert(true)}
>
Clear
</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>Help</MenubarTrigger>
<MenubarContent>
<MenubarItem onClick={openChartDBIO}>
Visit ChartDB
</MenubarItem>
<MenubarItem onClick={openJoinSlack}>
Join us on Slack
</MenubarItem>
</MenubarContent>
</MenubarMenu>
</Menubar>
</div>
</div>
<div>
<Menubar className="border-none shadow-none">
<MenubarMenu>
<MenubarTrigger>File</MenubarTrigger>
<MenubarContent>
<MenubarItem onClick={createNewDiagram}>
New
<MenubarShortcut>T</MenubarShortcut>
</MenubarItem>
<MenubarItem onClick={openDiagram}>
Open
</MenubarItem>
<MenubarSeparator />
<MenubarSub>
<MenubarSubTrigger>
Export SQL
</MenubarSubTrigger>
<MenubarSubContent>
<MenubarItem
onClick={() =>
openExportSQLDialog({
targetDatabaseType:
DatabaseType.GENERIC,
})
}
>
{databaseTypeToLabelMap['generic']}
</MenubarItem>
<MenubarItem
onClick={() =>
openExportSQLDialog({
targetDatabaseType:
DatabaseType.POSTGRESQL,
})
}
>
{
databaseTypeToLabelMap[
'postgresql'
]
}
</MenubarItem>
<MenubarItem
onClick={() =>
openExportSQLDialog({
targetDatabaseType:
DatabaseType.MYSQL,
})
}
>
{databaseTypeToLabelMap['mysql']}
</MenubarItem>
<MenubarItem
onClick={() =>
openExportSQLDialog({
targetDatabaseType:
DatabaseType.SQL_SERVER,
})
}
>
{
databaseTypeToLabelMap[
'sql_server'
]
}
</MenubarItem>
<MenubarItem
onClick={() =>
openExportSQLDialog({
targetDatabaseType:
DatabaseType.MARIADB,
})
}
>
{databaseTypeToLabelMap['mariadb']}
</MenubarItem>
<MenubarItem
onClick={() =>
openExportSQLDialog({
targetDatabaseType:
DatabaseType.SQLITE,
})
}
>
{databaseTypeToLabelMap['sqlite']}
</MenubarItem>
</MenubarSubContent>
</MenubarSub>
<MenubarSub>
<MenubarSubTrigger>
Export as
</MenubarSubTrigger>
<MenubarSubContent>
<MenubarItem onClick={exportPNG}>
PNG
</MenubarItem>
<MenubarItem onClick={exportJPG}>
JPG
</MenubarItem>
<MenubarItem onClick={exportSVG}>
SVG
</MenubarItem>
</MenubarSubContent>
</MenubarSub>
<MenubarSeparator />
<MenubarItem>Exit</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>Edit</MenubarTrigger>
<MenubarContent>
<MenubarItem>
Undo <MenubarShortcut>Z</MenubarShortcut>
</MenubarItem>
<MenubarItem>
Redo <MenubarShortcut>Z</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarItem>Clear</MenubarItem>
</MenubarContent>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger>Help</MenubarTrigger>
<MenubarContent>
<MenubarItem onClick={openChartDBIO}>
Visit ChartDB
</MenubarItem>
<MenubarItem onClick={openJoinSlack}>
Join us on Slack
</MenubarItem>
</MenubarContent>
</MenubarMenu>
</Menubar>
</div>
</div>
<div className="flex flex-row flex-1 justify-center items-center group gap-2">
<Tooltip>
<TooltipTrigger>
<img
src={
databaseSecondaryLogoMap[
<div className="flex flex-row flex-1 justify-center items-center group gap-2">
<Tooltip>
<TooltipTrigger>
<img
src={
databaseSecondaryLogoMap[
currentDiagram.databaseType
]
}
className="h-5 max-w-fit"
alt="database"
/>
</TooltipTrigger>
<TooltipContent>
{
databaseTypeToLabelMap[
currentDiagram.databaseType
]
}
className="h-5 max-w-fit"
alt="database"
/>
</TooltipTrigger>
<TooltipContent>
{databaseTypeToLabelMap[currentDiagram.databaseType]}
</TooltipContent>
</Tooltip>
<div className="flex">
<Label>Diagrams/</Label>
</TooltipContent>
</Tooltip>
<div className="flex">
<Label>Diagrams/</Label>
</div>
<div className="flex flex-row items-center gap-1">
{editMode ? (
<>
<Input
ref={inputRef}
autoFocus
type="text"
placeholder={diagramName}
value={editedDiagramName}
onClick={(e) => e.stopPropagation()}
onChange={(e) =>
setEditedDiagramName(e.target.value)
}
className="h-7 focus-visible:ring-0"
/>
<Button
variant="ghost"
className="hover:bg-primary-foreground p-2 w-7 h-7 text-slate-500 hover:text-slate-700 hidden group-hover:flex"
onClick={editDiagramName}
>
<Check />
</Button>
</>
) : (
<>
<Label>{diagramName}</Label>
<Button
variant="ghost"
className="hover:bg-primary-foreground p-2 w-7 h-7 text-slate-500 hover:text-slate-700 hidden group-hover:flex"
onClick={enterEditMode}
>
<Pencil />
</Button>
</>
)}
</div>
</div>
<div className="flex flex-row items-center gap-1">
{editMode ? (
<>
<Input
ref={inputRef}
autoFocus
type="text"
placeholder={diagramName}
value={editedDiagramName}
onClick={(e) => e.stopPropagation()}
onChange={(e) =>
setEditedDiagramName(e.target.value)
}
className="h-7 focus-visible:ring-0"
/>
<Button
variant="ghost"
className="hover:bg-primary-foreground p-2 w-7 h-7 text-slate-500 hover:text-slate-700 hidden group-hover:flex"
onClick={editDiagramName}
>
<Check />
</Button>
</>
) : (
<>
<Label>{diagramName}</Label>
<Button
variant="ghost"
className="hover:bg-primary-foreground p-2 w-7 h-7 text-slate-500 hover:text-slate-700 hidden group-hover:flex"
onClick={enterEditMode}
>
<Pencil />
</Button>
</>
)}
<div className="hidden flex-1 justify-end sm:flex">
<Tooltip>
<TooltipTrigger>
<Badge variant="secondary" className="flex gap-1">
<Save className="h-4" />
Last saved
<TimeAgo datetime={currentDiagram.updatedAt} />
</Badge>
</TooltipTrigger>
<TooltipContent>
{currentDiagram.updatedAt.toLocaleString()}
</TooltipContent>
</Tooltip>
</div>
</div>
<div className="hidden flex-1 justify-end sm:flex">
<Tooltip>
<TooltipTrigger>
<Badge variant="secondary" className="flex gap-1">
<Save className="h-4" />
Last saved
<TimeAgo datetime={currentDiagram.updatedAt} />
</Badge>
</TooltipTrigger>
<TooltipContent>
{currentDiagram.updatedAt.toLocaleString()}
</TooltipContent>
</Tooltip>
</div>
</nav>
</nav>
<AlertDialog open={showClearAlert}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>
Are you absolutely sure?
</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently
delete all the data in the diagram.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel
onClick={() => setShowClearAlert(false)}
>
Cancel
</AlertDialogCancel>
<AlertDialogAction onClick={clearDiagramDataHandler}>
Clear
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
);
};