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": { "dependencies": {
"@ai-sdk/openai": "^0.0.51", "@ai-sdk/openai": "^0.0.51",
"@radix-ui/react-accordion": "^1.2.0", "@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-checkbox": "^1.1.1",
"@radix-ui/react-collapsible": "^1.1.0", "@radix-ui/react-collapsible": "^1.1.0",
"@radix-ui/react-dialog": "^1.1.1", "@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": { "node_modules/@radix-ui/react-arrow": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz",

View File

@@ -13,6 +13,7 @@
"dependencies": { "dependencies": {
"@ai-sdk/openai": "^0.0.51", "@ai-sdk/openai": "^0.0.51",
"@radix-ui/react-accordion": "^1.2.0", "@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-checkbox": "^1.1.1",
"@radix-ui/react-collapsible": "^1.1.0", "@radix-ui/react-collapsible": "^1.1.0",
"@radix-ui/react-dialog": "^1.1.1", "@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>; ) => Promise<void>;
loadDiagram: (diagramId: string) => Promise<Diagram | undefined>; loadDiagram: (diagramId: string) => Promise<Diagram | undefined>;
updateDiagramUpdatedAt: () => Promise<void>; updateDiagramUpdatedAt: () => Promise<void>;
clearDiagramData: () => Promise<void>;
// Database type operations // Database type operations
updateDatabaseType: (databaseType: DatabaseType) => Promise<void>; updateDatabaseType: (databaseType: DatabaseType) => Promise<void>;
@@ -138,6 +139,7 @@ export const chartDBContext = createContext<ChartDBContext>({
updateDiagramName: emptyFn, updateDiagramName: emptyFn,
updateDiagramUpdatedAt: emptyFn, updateDiagramUpdatedAt: emptyFn,
loadDiagram: emptyFn, loadDiagram: emptyFn,
clearDiagramData: emptyFn,
// Database type operations // Database type operations
updateDatabaseType: emptyFn, updateDatabaseType: emptyFn,

View File

@@ -15,7 +15,8 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
children, children,
}) => { }) => {
const db = useStorage(); const db = useStorage();
const { addUndoAction, resetRedoStack } = useRedoUndoStack(); const { addUndoAction, resetRedoStack, resetUndoStack } =
useRedoUndoStack();
const [diagramId, setDiagramId] = useState(''); const [diagramId, setDiagramId] = useState('');
const [diagramName, setDiagramName] = useState(''); const [diagramName, setDiagramName] = useState('');
const [diagramCreatedAt, setDiagramCreatedAt] = useState<Date>(new Date()); 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'] = const updateDiagramUpdatedAt: ChartDBContext['updateDiagramUpdatedAt'] =
useCallback(async () => { useCallback(async () => {
const updatedAt = new Date(); const updatedAt = new Date();
@@ -928,6 +946,7 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
updateDiagramName, updateDiagramName,
loadDiagram, loadDiagram,
updateDatabaseType, updateDatabaseType,
clearDiagramData,
updateDiagramUpdatedAt, updateDiagramUpdatedAt,
createTable, createTable,
addTable, addTable,

View File

@@ -41,6 +41,7 @@ export interface StorageContext {
}) => Promise<void>; }) => Promise<void>;
deleteTable: (params: { diagramId: string; id: string }) => Promise<void>; deleteTable: (params: { diagramId: string; id: string }) => Promise<void>;
listTables: (diagramId: string) => Promise<DBTable[]>; listTables: (diagramId: string) => Promise<DBTable[]>;
deleteDiagramTables: (diagramId: string) => Promise<void>;
// Relationships operations // Relationships operations
addRelationship: (params: { addRelationship: (params: {
@@ -60,6 +61,7 @@ export interface StorageContext {
id: string; id: string;
}) => Promise<void>; }) => Promise<void>;
listRelationships: (diagramId: string) => Promise<DBRelationship[]>; listRelationships: (diagramId: string) => Promise<DBRelationship[]>;
deleteDiagramRelationships: (diagramId: string) => Promise<void>;
} }
export const storageContext = createContext<StorageContext>({ export const storageContext = createContext<StorageContext>({
@@ -77,10 +79,12 @@ export const storageContext = createContext<StorageContext>({
updateTable: emptyFn, updateTable: emptyFn,
deleteTable: emptyFn, deleteTable: emptyFn,
listTables: emptyFn, listTables: emptyFn,
deleteDiagramTables: emptyFn,
addRelationship: emptyFn, addRelationship: emptyFn,
getRelationship: emptyFn, getRelationship: emptyFn,
updateRelationship: emptyFn, updateRelationship: emptyFn,
deleteRelationship: emptyFn, deleteRelationship: emptyFn,
listRelationships: 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 }); 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 ({ const updateTable: StorageContext['updateTable'] = async ({
id, id,
attributes, 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 ({ const getRelationship: StorageContext['getRelationship'] = async ({
id, id,
diagramId, diagramId,
@@ -302,6 +316,8 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
updateRelationship, updateRelationship,
deleteRelationship, deleteRelationship,
listRelationships, listRelationships,
deleteDiagramTables,
deleteDiagramRelationships,
}} }}
> >
{children} {children}

View File

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

View File

@@ -32,16 +32,28 @@ import {
databaseTypeToLabelMap, databaseTypeToLabelMap,
} from '@/lib/databases'; } from '@/lib/databases';
import { DatabaseType } from '@/lib/domain/database-type'; 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 interface TopNavbarProps {}
export const TopNavbar: React.FC<TopNavbarProps> = () => { export const TopNavbar: React.FC<TopNavbarProps> = () => {
const { diagramName, updateDiagramName, currentDiagram } = useChartDB(); const { diagramName, updateDiagramName, currentDiagram, clearDiagramData } =
useChartDB();
const { const {
openCreateDiagramDialog, openCreateDiagramDialog,
openOpenDiagramDialog, openOpenDiagramDialog,
openExportSQLDialog, openExportSQLDialog,
} = useDialog(); } = useDialog();
const [showClearAlert, setShowClearAlert] = useState(false);
const [editMode, setEditMode] = useState(false); const [editMode, setEditMode] = useState(false);
const { exportImage } = useExportImage(); const { exportImage } = useExportImage();
const [editedDiagramName, setEditedDiagramName] = const [editedDiagramName, setEditedDiagramName] =
@@ -79,6 +91,11 @@ export const TopNavbar: React.FC<TopNavbarProps> = () => {
setEditMode(true); setEditMode(true);
}; };
const clearDiagramDataHandler = useCallback(async () => {
setShowClearAlert(false);
await clearDiagramData();
}, [clearDiagramData]);
const exportPNG = useCallback(() => { const exportPNG = useCallback(() => {
exportImage('png'); exportImage('png');
}, [exportImage]); }, [exportImage]);
@@ -103,228 +120,279 @@ export const TopNavbar: React.FC<TopNavbarProps> = () => {
}, []); }, []);
return ( 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"> <nav className="flex flex-row items-center justify-between px-4 h-12 border-b">
<div className="flex font-primary items-center"> <div className="flex flex-1 justify-start gap-x-3">
<a <div className="flex font-primary items-center">
href="https://chartdb.io" <a
target="_blank" href="https://chartdb.io"
className="cursor-pointer" target="_blank"
rel="noreferrer" className="cursor-pointer"
> rel="noreferrer"
<img >
src={ChartDBLogo} <img
alt="chartDB" src={ChartDBLogo}
className="h-4 max-w-fit" alt="chartDB"
/> className="h-4 max-w-fit"
</a> />
</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>
<div> <div className="flex flex-row flex-1 justify-center items-center group gap-2">
<Menubar className="border-none shadow-none"> <Tooltip>
<MenubarMenu> <TooltipTrigger>
<MenubarTrigger>File</MenubarTrigger> <img
<MenubarContent> src={
<MenubarItem onClick={createNewDiagram}> databaseSecondaryLogoMap[
New currentDiagram.databaseType
<MenubarShortcut>T</MenubarShortcut> ]
</MenubarItem> }
<MenubarItem onClick={openDiagram}> className="h-5 max-w-fit"
Open alt="database"
</MenubarItem> />
<MenubarSeparator /> </TooltipTrigger>
<MenubarSub> <TooltipContent>
<MenubarSubTrigger> {
Export SQL databaseTypeToLabelMap[
</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[
currentDiagram.databaseType currentDiagram.databaseType
] ]
} }
className="h-5 max-w-fit" </TooltipContent>
alt="database" </Tooltip>
/> <div className="flex">
</TooltipTrigger> <Label>Diagrams/</Label>
<TooltipContent> </div>
{databaseTypeToLabelMap[currentDiagram.databaseType]} <div className="flex flex-row items-center gap-1">
</TooltipContent> {editMode ? (
</Tooltip> <>
<div className="flex"> <Input
<Label>Diagrams/</Label> 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>
<div className="flex flex-row items-center gap-1"> <div className="hidden flex-1 justify-end sm:flex">
{editMode ? ( <Tooltip>
<> <TooltipTrigger>
<Input <Badge variant="secondary" className="flex gap-1">
ref={inputRef} <Save className="h-4" />
autoFocus Last saved
type="text" <TimeAgo datetime={currentDiagram.updatedAt} />
placeholder={diagramName} </Badge>
value={editedDiagramName} </TooltipTrigger>
onClick={(e) => e.stopPropagation()} <TooltipContent>
onChange={(e) => {currentDiagram.updatedAt.toLocaleString()}
setEditedDiagramName(e.target.value) </TooltipContent>
} </Tooltip>
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> </nav>
<div className="hidden flex-1 justify-end sm:flex"> <AlertDialog open={showClearAlert}>
<Tooltip> <AlertDialogContent>
<TooltipTrigger> <AlertDialogHeader>
<Badge variant="secondary" className="flex gap-1"> <AlertDialogTitle>
<Save className="h-4" /> Are you absolutely sure?
Last saved </AlertDialogTitle>
<TimeAgo datetime={currentDiagram.updatedAt} /> <AlertDialogDescription>
</Badge> This action cannot be undone. This will permanently
</TooltipTrigger> delete all the data in the diagram.
<TooltipContent> </AlertDialogDescription>
{currentDiagram.updatedAt.toLocaleString()} </AlertDialogHeader>
</TooltipContent> <AlertDialogFooter>
</Tooltip> <AlertDialogCancel
</div> onClick={() => setShowClearAlert(false)}
</nav> >
Cancel
</AlertDialogCancel>
<AlertDialogAction onClick={clearDiagramDataHandler}>
Clear
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
); );
}; };