mirror of
https://github.com/chartdb/chartdb.git
synced 2025-11-16 11:51:34 +00:00
create diagram dialog refactor
This commit is contained in:
committed by
Guy Ben-Aharon
parent
e8f54c621a
commit
dbe4b335e1
@@ -1,20 +1,7 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Button } from '@/components/button/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/dialog/dialog';
|
||||
import { Dialog, DialogContent } from '@/components/dialog/dialog';
|
||||
import { DialogProps } from '@radix-ui/react-dialog';
|
||||
import { ToggleGroup, ToggleGroupItem } from '@/components/toggle/toggle-group';
|
||||
import { DatabaseType } from '@/lib/domain/database-type';
|
||||
import { databaseLogoMap, databaseSecondaryLogoMap } from '@/lib/databases';
|
||||
import { CodeSnippet } from '@/components/code-snippet/code-snippet';
|
||||
import { Textarea } from '@/components/textarea/textarea';
|
||||
import { useStorage } from '@/hooks/use-storage';
|
||||
import { Diagram, loadFromDatabaseMetadata } from '@/lib/domain/diagram';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
@@ -27,25 +14,10 @@ import {
|
||||
import { generateId } from '@/lib/utils';
|
||||
import { useChartDB } from '@/hooks/use-chartdb';
|
||||
import { useDialog } from '@/hooks/use-dialog';
|
||||
import { importMetadataScripts } from '@/lib/data/import-metadata/scripts/scripts';
|
||||
import { Link } from '@/components/link/link';
|
||||
import { LayoutGrid } from 'lucide-react';
|
||||
import {
|
||||
DatabaseEdition,
|
||||
databaseEditionToImageMap,
|
||||
databaseEditionToLabelMap,
|
||||
databaseTypeToEditionMap,
|
||||
} from '@/lib/domain/database-edition';
|
||||
import {
|
||||
Avatar,
|
||||
AvatarFallback,
|
||||
AvatarImage,
|
||||
} from '@/components/avatar/avatar';
|
||||
|
||||
enum CreateDiagramDialogStep {
|
||||
SELECT_DATABASE = 'SELECT_DATABASE',
|
||||
IMPORT_DATABASE = 'IMPORT_DATABASE',
|
||||
}
|
||||
import { DatabaseEdition } from '@/lib/domain/database-edition';
|
||||
import { CreateDiagramDialogSelectDatabase } from './create-diagram-dialog-select-database';
|
||||
import { CreateDiagramDialogStep } from './create-diagram-dialog-step';
|
||||
import { CreateDiagramDialogImportDatabase } from './create-diagram-dialog-import-database';
|
||||
|
||||
const errorScriptOutputMessage =
|
||||
'Invalid JSON. Please correct it or contact us at chartdb.io@gmail.com for help.';
|
||||
@@ -112,11 +84,6 @@ export const CreateDiagramDialog: React.FC<CreateDiagramDialogProps> = ({
|
||||
|
||||
const hasExistingDiagram = (diagramId ?? '').trim().length !== 0;
|
||||
|
||||
const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
const inputValue = e.target.value;
|
||||
setScriptResult(inputValue);
|
||||
};
|
||||
|
||||
const createNewDiagram = useCallback(async () => {
|
||||
let diagram: Diagram = {
|
||||
id: generateId(),
|
||||
@@ -161,319 +128,6 @@ export const CreateDiagramDialog: React.FC<CreateDiagramDialogProps> = ({
|
||||
errorMessage,
|
||||
]);
|
||||
|
||||
const renderDatabaseOption = useCallback((type: DatabaseType) => {
|
||||
const logo = databaseLogoMap[type];
|
||||
return (
|
||||
<ToggleGroupItem
|
||||
value={type}
|
||||
aria-label="Toggle bold"
|
||||
className="flex size-20 md:size-32"
|
||||
>
|
||||
<img src={logo} alt="PostgreSQL" />
|
||||
</ToggleGroupItem>
|
||||
);
|
||||
}, []);
|
||||
|
||||
const renderExamplesOption = useCallback(
|
||||
() => (
|
||||
<div
|
||||
className="flex size-20 cursor-pointer flex-col items-center rounded-md border py-3 text-center md:size-32"
|
||||
onClick={() => window.open('/examples')}
|
||||
>
|
||||
<div className="flex flex-1 items-center">
|
||||
<Link href="/examples" className="text-sm text-primary">
|
||||
<LayoutGrid size={34} />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex flex-col-reverse">
|
||||
<Link
|
||||
href="/examples"
|
||||
className="hidden text-sm text-primary md:flex"
|
||||
>
|
||||
Check Examples
|
||||
</Link>
|
||||
<Link
|
||||
href="/examples"
|
||||
className="flex text-xs text-primary md:hidden"
|
||||
>
|
||||
Examples
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
const renderHeader = useCallback(() => {
|
||||
switch (step) {
|
||||
case CreateDiagramDialogStep.SELECT_DATABASE:
|
||||
return (
|
||||
<DialogHeader>
|
||||
<DialogTitle>What is your Database?</DialogTitle>
|
||||
<DialogDescription>
|
||||
Each database has its own unique features and
|
||||
capabilities.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
);
|
||||
case CreateDiagramDialogStep.IMPORT_DATABASE:
|
||||
return (
|
||||
<DialogHeader>
|
||||
<DialogTitle>Import your Database</DialogTitle>
|
||||
</DialogHeader>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}, [step]);
|
||||
|
||||
const renderContent = useCallback(() => {
|
||||
switch (step) {
|
||||
case CreateDiagramDialogStep.SELECT_DATABASE:
|
||||
return (
|
||||
<div className="flex flex-1 items-center justify-center">
|
||||
<ToggleGroup
|
||||
value={databaseType}
|
||||
onValueChange={(value: DatabaseType) => {
|
||||
if (!value) {
|
||||
setDatabaseType(DatabaseType.GENERIC);
|
||||
} else {
|
||||
setDatabaseType(value);
|
||||
setStep(
|
||||
CreateDiagramDialogStep.IMPORT_DATABASE
|
||||
);
|
||||
}
|
||||
}}
|
||||
type="single"
|
||||
className="grid grid-flow-row grid-cols-3 gap-6"
|
||||
>
|
||||
{renderDatabaseOption(DatabaseType.MYSQL)}
|
||||
{renderDatabaseOption(DatabaseType.POSTGRESQL)}
|
||||
{renderDatabaseOption(DatabaseType.MARIADB)}
|
||||
{renderDatabaseOption(DatabaseType.SQLITE)}
|
||||
{renderDatabaseOption(DatabaseType.SQL_SERVER)}
|
||||
{renderExamplesOption()}
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
);
|
||||
case CreateDiagramDialogStep.IMPORT_DATABASE:
|
||||
return (
|
||||
<div className="flex w-full flex-1 flex-col gap-6">
|
||||
{databaseTypeToEditionMap[databaseType].length > 0 ? (
|
||||
<div className="flex flex-col gap-1 md:flex-row">
|
||||
<p className="text-sm leading-6 text-muted-foreground">
|
||||
Database edition:
|
||||
</p>
|
||||
<ToggleGroup
|
||||
type="single"
|
||||
className="ml-1 gap-2"
|
||||
value={
|
||||
!databaseEdition
|
||||
? 'regular'
|
||||
: databaseEdition
|
||||
}
|
||||
onValueChange={(value) => {
|
||||
setDatabaseEdition(
|
||||
value === 'regular'
|
||||
? undefined
|
||||
: (value as DatabaseEdition)
|
||||
);
|
||||
}}
|
||||
>
|
||||
<ToggleGroupItem
|
||||
value="regular"
|
||||
variant="outline"
|
||||
className="h-6 gap-1 p-0 px-2 shadow-none"
|
||||
>
|
||||
<Avatar className="size-4">
|
||||
<AvatarImage
|
||||
src={
|
||||
databaseSecondaryLogoMap[
|
||||
databaseType
|
||||
]
|
||||
}
|
||||
alt="Regular"
|
||||
/>
|
||||
<AvatarFallback>
|
||||
Regular
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
Regular
|
||||
</ToggleGroupItem>
|
||||
{databaseTypeToEditionMap[databaseType].map(
|
||||
(edition) => (
|
||||
<ToggleGroupItem
|
||||
value={edition}
|
||||
key={edition}
|
||||
variant="outline"
|
||||
className="h-6 gap-1 p-0 px-2 shadow-none"
|
||||
>
|
||||
<Avatar className="size-4">
|
||||
<AvatarImage
|
||||
src={
|
||||
databaseEditionToImageMap[
|
||||
edition
|
||||
]
|
||||
}
|
||||
alt={
|
||||
databaseEditionToLabelMap[
|
||||
edition
|
||||
]
|
||||
}
|
||||
/>
|
||||
<AvatarFallback>
|
||||
{
|
||||
databaseEditionToLabelMap[
|
||||
edition
|
||||
]
|
||||
}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
{
|
||||
databaseEditionToLabelMap[
|
||||
edition
|
||||
]
|
||||
}
|
||||
</ToggleGroupItem>
|
||||
)
|
||||
)}
|
||||
</ToggleGroup>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
1. Run this script in your database:
|
||||
</p>
|
||||
<CodeSnippet
|
||||
className="max-h-40 w-full"
|
||||
code={importMetadataScripts[databaseType]({
|
||||
databaseEdition,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex h-48 flex-col gap-1">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
2. Paste the script result here:
|
||||
</p>
|
||||
<Textarea
|
||||
className="w-full flex-1 rounded-md bg-muted p-2 text-sm"
|
||||
placeholder="Script result here..."
|
||||
value={scriptResult}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
{errorMessage && (
|
||||
<p className="mt-2 text-sm text-red-700">
|
||||
{errorMessage}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}, [
|
||||
errorMessage,
|
||||
databaseEdition,
|
||||
step,
|
||||
databaseType,
|
||||
scriptResult,
|
||||
renderDatabaseOption,
|
||||
setDatabaseType,
|
||||
renderExamplesOption,
|
||||
]);
|
||||
|
||||
const renderFooter = useCallback(() => {
|
||||
switch (step) {
|
||||
case CreateDiagramDialogStep.SELECT_DATABASE:
|
||||
return (
|
||||
<DialogFooter className="mt-4 flex !justify-between gap-2">
|
||||
{hasExistingDiagram ? (
|
||||
<DialogClose asChild>
|
||||
<Button type="button" variant="secondary">
|
||||
Cancel
|
||||
</Button>
|
||||
</DialogClose>
|
||||
) : (
|
||||
<div></div>
|
||||
)}
|
||||
<div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end sm:space-x-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={createNewDiagram}
|
||||
>
|
||||
Empty diagram
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="default"
|
||||
disabled={databaseType === DatabaseType.GENERIC}
|
||||
onClick={() =>
|
||||
setStep(
|
||||
CreateDiagramDialogStep.IMPORT_DATABASE
|
||||
)
|
||||
}
|
||||
>
|
||||
Continue
|
||||
</Button>
|
||||
</div>
|
||||
</DialogFooter>
|
||||
);
|
||||
case CreateDiagramDialogStep.IMPORT_DATABASE:
|
||||
return (
|
||||
<DialogFooter className="mt-4 flex !justify-between gap-2">
|
||||
<div className="flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={() =>
|
||||
setStep(
|
||||
CreateDiagramDialogStep.SELECT_DATABASE
|
||||
)
|
||||
}
|
||||
>
|
||||
Back
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end sm:space-x-2">
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={createNewDiagram}
|
||||
>
|
||||
Empty diagram
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="default"
|
||||
disabled={
|
||||
scriptResult.trim().length === 0 ||
|
||||
errorMessage.length > 0
|
||||
}
|
||||
onClick={createNewDiagram}
|
||||
>
|
||||
Import
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</div>
|
||||
</DialogFooter>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}, [
|
||||
step,
|
||||
databaseType,
|
||||
scriptResult,
|
||||
createNewDiagram,
|
||||
hasExistingDiagram,
|
||||
errorMessage,
|
||||
]);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
{...dialog}
|
||||
@@ -491,9 +145,26 @@ export const CreateDiagramDialog: React.FC<CreateDiagramDialogProps> = ({
|
||||
className="flex w-[90vw] flex-col overflow-y-auto xl:min-w-[45vw]"
|
||||
showClose={hasExistingDiagram}
|
||||
>
|
||||
{renderHeader()}
|
||||
{renderContent()}
|
||||
{renderFooter()}
|
||||
{step === CreateDiagramDialogStep.SELECT_DATABASE ? (
|
||||
<CreateDiagramDialogSelectDatabase
|
||||
createNewDiagram={createNewDiagram}
|
||||
databaseType={databaseType}
|
||||
hasExistingDiagram={hasExistingDiagram}
|
||||
setDatabaseType={setDatabaseType}
|
||||
setStep={setStep}
|
||||
/>
|
||||
) : (
|
||||
<CreateDiagramDialogImportDatabase
|
||||
createNewDiagram={createNewDiagram}
|
||||
databaseEdition={databaseEdition}
|
||||
databaseType={databaseType}
|
||||
errorMessage={errorMessage}
|
||||
scriptResult={scriptResult}
|
||||
setDatabaseEdition={setDatabaseEdition}
|
||||
setStep={setStep}
|
||||
setScriptResult={setScriptResult}
|
||||
/>
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user