mirror of
https://github.com/chartdb/chartdb.git
synced 2025-11-03 13:33:25 +00:00
add schema change & table schema view & create new table schema selection
This commit is contained in:
committed by
Guy Ben-Aharon
parent
98f429f9cc
commit
7928705f18
@@ -1,7 +1,9 @@
|
||||
import { createContext } from 'react';
|
||||
import { emptyFn } from '@/lib/utils';
|
||||
import type { DatabaseType } from '@/lib/domain/database-type';
|
||||
import type { BaseAlertDialogProps } from '@/dialogs/base-alert-dialog/base-alert-dialog';
|
||||
import type { TableSchemaDialogProps } from '@/dialogs/table-schema-dialog/table-schema-dialog';
|
||||
import type { ImportDatabaseDialogProps } from '@/dialogs/import-database-dialog/import-database-dialog';
|
||||
import type { ExportSQLDialogProps } from '@/dialogs/export-sql-dialog/export-sql-dialog';
|
||||
|
||||
export interface DialogContext {
|
||||
// Create diagram dialog
|
||||
@@ -13,7 +15,7 @@ export interface DialogContext {
|
||||
closeOpenDiagramDialog: () => void;
|
||||
|
||||
// Export SQL dialog
|
||||
openExportSQLDialog: (params: { targetDatabaseType: DatabaseType }) => void;
|
||||
openExportSQLDialog: (params: Omit<ExportSQLDialogProps, 'dialog'>) => void;
|
||||
closeExportSQLDialog: () => void;
|
||||
|
||||
// Alert dialog
|
||||
@@ -25,8 +27,16 @@ export interface DialogContext {
|
||||
closeCreateRelationshipDialog: () => void;
|
||||
|
||||
// Import database dialog
|
||||
openImportDatabaseDialog: (params: { databaseType: DatabaseType }) => void;
|
||||
openImportDatabaseDialog: (
|
||||
params: Omit<ImportDatabaseDialogProps, 'dialog'>
|
||||
) => void;
|
||||
closeImportDatabaseDialog: () => void;
|
||||
|
||||
// Change table schema dialog
|
||||
openTableSchemaDialog: (
|
||||
params: Omit<TableSchemaDialogProps, 'dialog'>
|
||||
) => void;
|
||||
closeTableSchemaDialog: () => void;
|
||||
}
|
||||
|
||||
export const dialogContext = createContext<DialogContext>({
|
||||
@@ -42,4 +52,6 @@ export const dialogContext = createContext<DialogContext>({
|
||||
openCreateRelationshipDialog: emptyFn,
|
||||
openImportDatabaseDialog: emptyFn,
|
||||
closeImportDatabaseDialog: emptyFn,
|
||||
openTableSchemaDialog: emptyFn,
|
||||
closeTableSchemaDialog: emptyFn,
|
||||
});
|
||||
|
||||
@@ -3,12 +3,17 @@ import type { DialogContext } from './dialog-context';
|
||||
import { dialogContext } from './dialog-context';
|
||||
import { CreateDiagramDialog } from '@/dialogs/create-diagram-dialog/create-diagram-dialog';
|
||||
import { OpenDiagramDialog } from '@/dialogs/open-diagram-dialog/open-diagram-dialog';
|
||||
import type { ExportSQLDialogProps } from '@/dialogs/export-sql-dialog/export-sql-dialog';
|
||||
import { ExportSQLDialog } from '@/dialogs/export-sql-dialog/export-sql-dialog';
|
||||
import { DatabaseType } from '@/lib/domain/database-type';
|
||||
import type { BaseAlertDialogProps } from '@/dialogs/base-alert-dialog/base-alert-dialog';
|
||||
import { BaseAlertDialog } from '@/dialogs/base-alert-dialog/base-alert-dialog';
|
||||
import { CreateRelationshipDialog } from '@/dialogs/create-relationship-dialog/create-relationship-dialog';
|
||||
import type { ImportDatabaseDialogProps } from '@/dialogs/import-database-dialog/import-database-dialog';
|
||||
import { ImportDatabaseDialog } from '@/dialogs/import-database-dialog/import-database-dialog';
|
||||
import type { TableSchemaDialogProps } from '@/dialogs/table-schema-dialog/table-schema-dialog';
|
||||
import { TableSchemaDialog } from '@/dialogs/table-schema-dialog/table-schema-dialog';
|
||||
import { emptyFn } from '@/lib/utils';
|
||||
|
||||
export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
@@ -16,17 +21,21 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
||||
const [openNewDiagramDialog, setOpenNewDiagramDialog] = useState(false);
|
||||
const [openOpenDiagramDialog, setOpenOpenDiagramDialog] = useState(false);
|
||||
const [openExportSQLDialog, setOpenExportSQLDialog] = useState(false);
|
||||
const [openExportSQLDialogParams, setOpenExportSQLDialogParams] = useState<{
|
||||
targetDatabaseType: DatabaseType;
|
||||
}>({ targetDatabaseType: DatabaseType.GENERIC });
|
||||
const [exportSQLDialogParams, setExportSQLDialogParams] = useState<
|
||||
Omit<ExportSQLDialogProps, 'dialog'>
|
||||
>({ targetDatabaseType: DatabaseType.GENERIC });
|
||||
const [openCreateRelationshipDialog, setOpenCreateRelationshipDialog] =
|
||||
useState(false);
|
||||
const [openImportDatabaseDialog, setOpenImportDatabaseDialog] =
|
||||
useState(false);
|
||||
const [openImportDatabaseDialogParams, setOpenImportDatabaseDialogParams] =
|
||||
useState<{ databaseType: DatabaseType }>({
|
||||
const [importDatabaseDialogParams, setImportDatabaseDialogParams] =
|
||||
useState<Omit<ImportDatabaseDialogProps, 'dialog'>>({
|
||||
databaseType: DatabaseType.GENERIC,
|
||||
});
|
||||
const [openTableSchemaDialog, setOpenTableSchemaDialog] = useState(false);
|
||||
const [tableSchemaDialogParams, setTableSchemaDialogParams] = useState<
|
||||
Omit<TableSchemaDialogProps, 'dialog'>
|
||||
>({ schemas: [], onConfirm: emptyFn });
|
||||
const [showAlert, setShowAlert] = useState(false);
|
||||
const [alertParams, setAlertParams] = useState<BaseAlertDialogProps>({
|
||||
title: '',
|
||||
@@ -36,7 +45,7 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
||||
useCallback(
|
||||
({ targetDatabaseType }) => {
|
||||
setOpenExportSQLDialog(true);
|
||||
setOpenExportSQLDialogParams({ targetDatabaseType });
|
||||
setExportSQLDialogParams({ targetDatabaseType });
|
||||
},
|
||||
[setOpenExportSQLDialog]
|
||||
);
|
||||
@@ -45,11 +54,20 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
||||
useCallback(
|
||||
({ databaseType }) => {
|
||||
setOpenImportDatabaseDialog(true);
|
||||
setOpenImportDatabaseDialogParams({ databaseType });
|
||||
setImportDatabaseDialogParams({ databaseType });
|
||||
},
|
||||
[setOpenImportDatabaseDialog]
|
||||
);
|
||||
|
||||
const openTableSchemaDialogHandler: DialogContext['openTableSchemaDialog'] =
|
||||
useCallback(
|
||||
(params) => {
|
||||
setOpenTableSchemaDialog(true);
|
||||
setTableSchemaDialogParams(params);
|
||||
},
|
||||
[setOpenTableSchemaDialog]
|
||||
);
|
||||
|
||||
const showAlertHandler: DialogContext['showAlert'] = useCallback(
|
||||
(params) => {
|
||||
setAlertParams(params);
|
||||
@@ -80,6 +98,8 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
||||
openImportDatabaseDialog: openImportDatabaseDialogHandler,
|
||||
closeImportDatabaseDialog: () =>
|
||||
setOpenImportDatabaseDialog(false),
|
||||
openTableSchemaDialog: openTableSchemaDialogHandler,
|
||||
closeTableSchemaDialog: () => setOpenTableSchemaDialog(false),
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
@@ -87,7 +107,7 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
||||
<OpenDiagramDialog dialog={{ open: openOpenDiagramDialog }} />
|
||||
<ExportSQLDialog
|
||||
dialog={{ open: openExportSQLDialog }}
|
||||
{...openExportSQLDialogParams}
|
||||
{...exportSQLDialogParams}
|
||||
/>
|
||||
<BaseAlertDialog dialog={{ open: showAlert }} {...alertParams} />
|
||||
<CreateRelationshipDialog
|
||||
@@ -95,7 +115,11 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
|
||||
/>
|
||||
<ImportDatabaseDialog
|
||||
dialog={{ open: openImportDatabaseDialog }}
|
||||
{...openImportDatabaseDialogParams}
|
||||
{...importDatabaseDialogParams}
|
||||
/>
|
||||
<TableSchemaDialog
|
||||
dialog={{ open: openTableSchemaDialog }}
|
||||
{...tableSchemaDialogParams}
|
||||
/>
|
||||
</dialogContext.Provider>
|
||||
);
|
||||
|
||||
5
src/dialogs/common/base-dialog-props.ts
Normal file
5
src/dialogs/common/base-dialog-props.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import type { DialogProps } from '@radix-ui/react-dialog';
|
||||
|
||||
export interface BaseDialogProps {
|
||||
dialog: DialogProps;
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Dialog, DialogContent } from '@/components/dialog/dialog';
|
||||
import type { DialogProps } from '@radix-ui/react-dialog';
|
||||
import { DatabaseType } from '@/lib/domain/database-type';
|
||||
import { useStorage } from '@/hooks/use-storage';
|
||||
import type { Diagram } from '@/lib/domain/diagram';
|
||||
@@ -17,10 +16,9 @@ import { SelectDatabase } from './select-database/select-database';
|
||||
import { CreateDiagramDialogStep } from './create-diagram-dialog-step';
|
||||
import { ImportDatabase } from '../common/import-database/import-database';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import type { BaseDialogProps } from '../common/base-dialog-props';
|
||||
|
||||
export interface CreateDiagramDialogProps {
|
||||
dialog: DialogProps;
|
||||
}
|
||||
export interface CreateDiagramDialogProps extends BaseDialogProps {}
|
||||
|
||||
export const CreateDiagramDialog: React.FC<CreateDiagramDialogProps> = ({
|
||||
dialog,
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
DialogTitle,
|
||||
} from '@/components/dialog/dialog';
|
||||
import { useDialog } from '@/hooks/use-dialog';
|
||||
import type { DialogProps } from '@radix-ui/react-dialog';
|
||||
import { FileOutput, FileMinus2, FileType2 } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useChartDB } from '@/hooks/use-chartdb';
|
||||
@@ -17,13 +16,12 @@ import type { SelectBoxOption } from '@/components/select-box/select-box';
|
||||
import { SelectBox } from '@/components/select-box/select-box';
|
||||
import { useLayout } from '@/hooks/use-layout';
|
||||
import { useReactFlow } from '@xyflow/react';
|
||||
import type { BaseDialogProps } from '../common/base-dialog-props';
|
||||
|
||||
const ErrorMessageRelationshipFieldsNotSameType =
|
||||
'Relationships can only be created between fields of the same type';
|
||||
|
||||
export interface CreateRelationshipDialogProps {
|
||||
dialog: DialogProps;
|
||||
}
|
||||
export interface CreateRelationshipDialogProps extends BaseDialogProps {}
|
||||
|
||||
export const CreateRelationshipDialog: React.FC<
|
||||
CreateRelationshipDialogProps
|
||||
|
||||
@@ -19,13 +19,12 @@ import {
|
||||
} from '@/lib/data/export-metadata/export-sql-script';
|
||||
import { databaseTypeToLabelMap } from '@/lib/databases';
|
||||
import { DatabaseType } from '@/lib/domain/database-type';
|
||||
import type { DialogProps } from '@radix-ui/react-dialog';
|
||||
import { Annoyed, Sparkles } from 'lucide-react';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import type { BaseDialogProps } from '../common/base-dialog-props';
|
||||
|
||||
export interface ExportSQLDialogProps {
|
||||
dialog: DialogProps;
|
||||
export interface ExportSQLDialogProps extends BaseDialogProps {
|
||||
targetDatabaseType: DatabaseType;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import { Dialog, DialogContent } from '@/components/dialog/dialog';
|
||||
import { useDialog } from '@/hooks/use-dialog';
|
||||
import type { DatabaseType } from '@/lib/domain/database-type';
|
||||
import type { DialogProps } from '@radix-ui/react-dialog';
|
||||
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { ImportDatabase } from '../common/import-database/import-database';
|
||||
import type { DatabaseEdition } from '@/lib/domain/database-edition';
|
||||
@@ -13,9 +11,9 @@ import { useChartDB } from '@/hooks/use-chartdb';
|
||||
import { useRedoUndoStack } from '@/hooks/use-redo-undo-stack';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { useReactFlow } from '@xyflow/react';
|
||||
import type { BaseDialogProps } from '../common/base-dialog-props';
|
||||
|
||||
export interface ImportDatabaseDialogProps {
|
||||
dialog: DialogProps;
|
||||
export interface ImportDatabaseDialogProps extends BaseDialogProps {
|
||||
databaseType: DatabaseType;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,14 +22,12 @@ import { useConfig } from '@/hooks/use-config';
|
||||
import { useDialog } from '@/hooks/use-dialog';
|
||||
import { useStorage } from '@/hooks/use-storage';
|
||||
import type { Diagram } from '@/lib/domain/diagram';
|
||||
import type { DialogProps } from '@radix-ui/react-dialog';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import type { BaseDialogProps } from '../common/base-dialog-props';
|
||||
|
||||
export interface OpenDiagramDialogProps {
|
||||
dialog: DialogProps;
|
||||
}
|
||||
export interface OpenDiagramDialogProps extends BaseDialogProps {}
|
||||
|
||||
export const OpenDiagramDialog: React.FC<OpenDiagramDialogProps> = ({
|
||||
dialog,
|
||||
|
||||
118
src/dialogs/table-schema-dialog/table-schema-dialog.tsx
Normal file
118
src/dialogs/table-schema-dialog/table-schema-dialog.tsx
Normal file
@@ -0,0 +1,118 @@
|
||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useDialog } from '@/hooks/use-dialog';
|
||||
import {
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/dialog/dialog';
|
||||
import { Button } from '@/components/button/button';
|
||||
import type { DBTable } from '@/lib/domain/db-table';
|
||||
import type { SelectBoxOption } from '@/components/select-box/select-box';
|
||||
import { SelectBox } from '@/components/select-box/select-box';
|
||||
import type { DBSchema } from '@/lib/domain/db-schema';
|
||||
import { schemaNameToSchemaId } from '@/lib/domain/db-schema';
|
||||
import type { BaseDialogProps } from '../common/base-dialog-props';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export interface TableSchemaDialogProps extends BaseDialogProps {
|
||||
table?: DBTable;
|
||||
schemas: DBSchema[];
|
||||
onConfirm: (schema: string) => void;
|
||||
}
|
||||
|
||||
export const TableSchemaDialog: React.FC<TableSchemaDialogProps> = ({
|
||||
dialog,
|
||||
table,
|
||||
schemas,
|
||||
onConfirm,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [selectedSchema, setSelectedSchema] = React.useState<string>(
|
||||
table?.schema
|
||||
? schemaNameToSchemaId(table.schema)
|
||||
: (schemas?.[0]?.id ?? '')
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!dialog.open) return;
|
||||
setSelectedSchema(
|
||||
table?.schema
|
||||
? schemaNameToSchemaId(table.schema)
|
||||
: (schemas?.[0]?.id ?? '')
|
||||
);
|
||||
}, [dialog.open, schemas, table?.schema]);
|
||||
const { closeTableSchemaDialog } = useDialog();
|
||||
|
||||
const handleConfirm = useCallback(() => {
|
||||
onConfirm(selectedSchema);
|
||||
}, [onConfirm, selectedSchema]);
|
||||
|
||||
const schemaOptions: SelectBoxOption[] = useMemo(
|
||||
() =>
|
||||
schemas.map((schema) => ({
|
||||
value: schema.id,
|
||||
label: schema.name,
|
||||
})),
|
||||
[schemas]
|
||||
);
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
{...dialog}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) {
|
||||
closeTableSchemaDialog();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DialogContent className="flex flex-col" showClose>
|
||||
<DialogHeader>
|
||||
<DialogTitle>
|
||||
{table
|
||||
? t('update_table_schema_dialog.title')
|
||||
: t('new_table_schema_dialog.title')}
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
{table
|
||||
? t('update_table_schema_dialog.description', {
|
||||
tableName: table.name,
|
||||
})
|
||||
: t('new_table_schema_dialog.description')}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="grid gap-4 py-1">
|
||||
<div className="grid w-full items-center gap-4">
|
||||
<SelectBox
|
||||
options={schemaOptions}
|
||||
multiple={false}
|
||||
value={selectedSchema}
|
||||
onChange={(value) =>
|
||||
setSelectedSchema(value as string)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<DialogFooter className="flex gap-1 md:justify-between">
|
||||
<DialogClose asChild>
|
||||
<Button variant="secondary">
|
||||
{table
|
||||
? t('update_table_schema_dialog.cancel')
|
||||
: t('new_table_schema_dialog.cancel')}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
<DialogClose asChild>
|
||||
<Button onClick={handleConfirm}>
|
||||
{table
|
||||
? t('update_table_schema_dialog.confirm')
|
||||
: t('new_table_schema_dialog.confirm')}
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
@@ -132,6 +132,7 @@ export const en = {
|
||||
},
|
||||
table_actions: {
|
||||
title: 'Table Actions',
|
||||
change_schema: 'Change Schema',
|
||||
add_field: 'Add Field',
|
||||
add_index: 'Add Index',
|
||||
delete_table: 'Delete Table',
|
||||
@@ -269,6 +270,21 @@ export const en = {
|
||||
},
|
||||
},
|
||||
|
||||
new_table_schema_dialog: {
|
||||
title: 'Select Schema',
|
||||
description:
|
||||
'Multiple schemas are currently displayed. Select one for the new table.',
|
||||
cancel: 'Cancel',
|
||||
confirm: 'Confirm',
|
||||
},
|
||||
|
||||
update_table_schema_dialog: {
|
||||
title: 'Change Schema',
|
||||
description: 'Update table "{{tableName}}" schema',
|
||||
cancel: 'Cancel',
|
||||
confirm: 'Change',
|
||||
},
|
||||
|
||||
relationship_type: {
|
||||
one_to_one: 'One to One',
|
||||
one_to_many: 'One to Many',
|
||||
|
||||
@@ -123,6 +123,7 @@ export const es: LanguageTranslation = {
|
||||
},
|
||||
table_actions: {
|
||||
title: 'Acciones de la Tabla',
|
||||
change_schema: 'Cambiar Esquema',
|
||||
add_field: 'Agregar Campo',
|
||||
add_index: 'Agregar Índice',
|
||||
delete_table: 'Eliminar Tabla',
|
||||
@@ -261,6 +262,21 @@ export const es: LanguageTranslation = {
|
||||
},
|
||||
},
|
||||
|
||||
new_table_schema_dialog: {
|
||||
title: 'Seleccionar Esquema',
|
||||
description:
|
||||
'Actualmente se muestran múltiples esquemas. Selecciona uno para la nueva tabla.',
|
||||
cancel: 'Cancelar',
|
||||
confirm: 'Confirmar',
|
||||
},
|
||||
|
||||
update_table_schema_dialog: {
|
||||
title: 'Cambiar Esquema',
|
||||
description: 'Actualizar esquema de la tabla "{{tableName}}"',
|
||||
cancel: 'Cancelar',
|
||||
confirm: 'Cambiar',
|
||||
},
|
||||
|
||||
multiple_schemas_alert: {
|
||||
title: 'Múltiples Esquemas',
|
||||
description:
|
||||
|
||||
@@ -14,8 +14,8 @@ import { useTranslation } from 'react-i18next';
|
||||
export const CanvasContextMenu: React.FC<React.PropsWithChildren> = ({
|
||||
children,
|
||||
}) => {
|
||||
const { createTable } = useChartDB();
|
||||
const { openCreateRelationshipDialog } = useDialog();
|
||||
const { createTable, filteredSchemas, schemas } = useChartDB();
|
||||
const { openCreateRelationshipDialog, openTableSchemaDialog } = useDialog();
|
||||
const { screenToFlowPosition } = useReactFlow();
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -28,12 +28,37 @@ export const CanvasContextMenu: React.FC<React.PropsWithChildren> = ({
|
||||
y: event.clientY,
|
||||
});
|
||||
|
||||
createTable({
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
});
|
||||
if ((filteredSchemas?.length ?? 0) > 1) {
|
||||
openTableSchemaDialog({
|
||||
onConfirm: (schema) =>
|
||||
createTable({
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
schema,
|
||||
}),
|
||||
schemas: schemas.filter((schema) =>
|
||||
filteredSchemas?.includes(schema.id)
|
||||
),
|
||||
});
|
||||
} else {
|
||||
const schema =
|
||||
filteredSchemas?.length === 1
|
||||
? schemas.find((s) => s.id === filteredSchemas[0])?.name
|
||||
: undefined;
|
||||
createTable({
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
schema,
|
||||
});
|
||||
}
|
||||
},
|
||||
[createTable, screenToFlowPosition]
|
||||
[
|
||||
createTable,
|
||||
screenToFlowPosition,
|
||||
openTableSchemaDialog,
|
||||
schemas,
|
||||
filteredSchemas,
|
||||
]
|
||||
);
|
||||
|
||||
const createRelationshipHandler = useCallback(() => {
|
||||
|
||||
@@ -54,7 +54,7 @@ export const SidePanel: React.FC<SidePanelProps> = () => {
|
||||
|
||||
return (
|
||||
<aside className="flex h-full flex-col overflow-hidden">
|
||||
{schemasOptions.length > 0 && (
|
||||
{schemasOptions.length > 0 ? (
|
||||
<div className="flex items-center justify-center border-b pl-3 pt-0.5">
|
||||
<div className="shrink-0 text-sm font-semibold">
|
||||
{t('side_panel.schema')}
|
||||
@@ -79,7 +79,7 @@ export const SidePanel: React.FC<SidePanelProps> = () => {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
) : null}
|
||||
|
||||
<div className="flex justify-center border-b pt-0.5">
|
||||
<Select
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
FileType2,
|
||||
FileKey2,
|
||||
Check,
|
||||
Group,
|
||||
} from 'lucide-react';
|
||||
import { ListItemHeaderButton } from '@/pages/editor-page/side-panel/list-item-header-button/list-item-header-button';
|
||||
import type { DBTable } from '@/lib/domain/db-table';
|
||||
@@ -26,6 +27,7 @@ import { useReactFlow } from '@xyflow/react';
|
||||
import { useLayout } from '@/hooks/use-layout';
|
||||
import { useBreakpoint } from '@/hooks/use-breakpoint';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useDialog } from '@/hooks/use-dialog';
|
||||
|
||||
export interface TableListItemHeaderProps {
|
||||
table: DBTable;
|
||||
@@ -34,7 +36,15 @@ export interface TableListItemHeaderProps {
|
||||
export const TableListItemHeader: React.FC<TableListItemHeaderProps> = ({
|
||||
table,
|
||||
}) => {
|
||||
const { updateTable, removeTable, createIndex, createField } = useChartDB();
|
||||
const {
|
||||
updateTable,
|
||||
removeTable,
|
||||
createIndex,
|
||||
createField,
|
||||
schemas,
|
||||
filteredSchemas,
|
||||
} = useChartDB();
|
||||
const { openTableSchemaDialog } = useDialog();
|
||||
const { t } = useTranslation();
|
||||
const { fitView, setNodes } = useReactFlow();
|
||||
const { hideSidePanel } = useLayout();
|
||||
@@ -100,6 +110,21 @@ export const TableListItemHeader: React.FC<TableListItemHeaderProps> = ({
|
||||
removeTable(table.id);
|
||||
}, [table.id, removeTable]);
|
||||
|
||||
const updateTableSchema = useCallback(
|
||||
(schema: string) => {
|
||||
updateTable(table.id, { schema });
|
||||
},
|
||||
[table.id, updateTable]
|
||||
);
|
||||
|
||||
const changeSchema = useCallback(() => {
|
||||
openTableSchemaDialog({
|
||||
table,
|
||||
schemas,
|
||||
onConfirm: updateTableSchema,
|
||||
});
|
||||
}, [openTableSchemaDialog, table, schemas, updateTableSchema]);
|
||||
|
||||
const renderDropDownMenu = useCallback(
|
||||
() => (
|
||||
<DropdownMenu>
|
||||
@@ -108,16 +133,35 @@ export const TableListItemHeader: React.FC<TableListItemHeaderProps> = ({
|
||||
<EllipsisVertical />
|
||||
</ListItemHeaderButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-40">
|
||||
<DropdownMenuContent className="w-fit">
|
||||
<DropdownMenuLabel>
|
||||
{t(
|
||||
'side_panel.tables_section.table.table_actions.title'
|
||||
)}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
{schemas.length > 0 ? (
|
||||
<>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
className="flex justify-between gap-4"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
changeSchema();
|
||||
}}
|
||||
>
|
||||
{t(
|
||||
'side_panel.tables_section.table.table_actions.change_schema'
|
||||
)}
|
||||
<Group className="size-3.5" />
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
</>
|
||||
) : null}
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
className="flex justify-between"
|
||||
className="flex justify-between gap-4"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
createField(table.id);
|
||||
@@ -129,7 +173,7 @@ export const TableListItemHeader: React.FC<TableListItemHeaderProps> = ({
|
||||
<FileType2 className="size-3.5" />
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
className="flex justify-between"
|
||||
className="flex justify-between gap-4"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
createIndex(table.id);
|
||||
@@ -156,9 +200,23 @@ export const TableListItemHeader: React.FC<TableListItemHeaderProps> = ({
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
),
|
||||
[table.id, createField, createIndex, deleteTableHandler, t]
|
||||
[
|
||||
table.id,
|
||||
createField,
|
||||
createIndex,
|
||||
deleteTableHandler,
|
||||
t,
|
||||
changeSchema,
|
||||
schemas.length,
|
||||
]
|
||||
);
|
||||
|
||||
let schemaToDisplay;
|
||||
|
||||
if (schemas.length > 1 && !!filteredSchemas && filteredSchemas.length > 1) {
|
||||
schemaToDisplay = table.schema;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="group flex h-11 flex-1 items-center justify-between gap-1 overflow-hidden">
|
||||
<div className="flex min-w-0 flex-1">
|
||||
@@ -174,7 +232,12 @@ export const TableListItemHeader: React.FC<TableListItemHeaderProps> = ({
|
||||
className="h-7 w-full focus-visible:ring-0"
|
||||
/>
|
||||
) : (
|
||||
<div className="truncate">{table.name}</div>
|
||||
<div className="truncate">
|
||||
{table.name}
|
||||
<span className="text-xs text-muted-foreground">
|
||||
{schemaToDisplay ? ` (${schemaToDisplay})` : ''}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-row-reverse">
|
||||
|
||||
@@ -17,11 +17,13 @@ import {
|
||||
TooltipTrigger,
|
||||
} from '@/components/tooltip/tooltip';
|
||||
import { useViewport } from '@xyflow/react';
|
||||
import { useDialog } from '@/hooks/use-dialog';
|
||||
|
||||
export interface TablesSectionProps {}
|
||||
|
||||
export const TablesSection: React.FC<TablesSectionProps> = () => {
|
||||
const { createTable, tables, filteredSchemas } = useChartDB();
|
||||
const { createTable, tables, filteredSchemas, schemas } = useChartDB();
|
||||
const { openTableSchemaDialog } = useDialog();
|
||||
const viewport = useViewport();
|
||||
const { t } = useTranslation();
|
||||
const { closeAllTablesInSidebar, openTableFromSidebar } = useLayout();
|
||||
@@ -38,24 +40,52 @@ export const TablesSection: React.FC<TablesSectionProps> = () => {
|
||||
return tables.filter(filterSchema).filter(filterTableName);
|
||||
}, [tables, filterText, filteredSchemas]);
|
||||
|
||||
const createTableWithLocation = useCallback(
|
||||
async (schema?: string) => {
|
||||
const padding = 80;
|
||||
const centerX =
|
||||
-viewport.x / viewport.zoom + padding / viewport.zoom;
|
||||
const centerY =
|
||||
-viewport.y / viewport.zoom + padding / viewport.zoom;
|
||||
const table = await createTable({
|
||||
x: centerX,
|
||||
y: centerY,
|
||||
schema,
|
||||
});
|
||||
openTableFromSidebar(table.id);
|
||||
},
|
||||
[
|
||||
createTable,
|
||||
openTableFromSidebar,
|
||||
viewport.x,
|
||||
viewport.y,
|
||||
viewport.zoom,
|
||||
]
|
||||
);
|
||||
|
||||
const handleCreateTable = useCallback(async () => {
|
||||
setFilterText('');
|
||||
const padding = 80;
|
||||
const centerX = -viewport.x / viewport.zoom + padding / viewport.zoom;
|
||||
const centerY = -viewport.y / viewport.zoom + padding / viewport.zoom;
|
||||
|
||||
const table = await createTable({
|
||||
x: centerX,
|
||||
y: centerY,
|
||||
});
|
||||
openTableFromSidebar(table.id);
|
||||
if ((filteredSchemas?.length ?? 0) > 1) {
|
||||
openTableSchemaDialog({
|
||||
onConfirm: createTableWithLocation,
|
||||
schemas: schemas.filter((schema) =>
|
||||
filteredSchemas?.includes(schema.id)
|
||||
),
|
||||
});
|
||||
} else {
|
||||
const schema =
|
||||
filteredSchemas?.length === 1
|
||||
? schemas.find((s) => s.id === filteredSchemas[0])?.name
|
||||
: undefined;
|
||||
createTableWithLocation(schema);
|
||||
}
|
||||
}, [
|
||||
createTable,
|
||||
openTableFromSidebar,
|
||||
createTableWithLocation,
|
||||
filteredSchemas,
|
||||
openTableSchemaDialog,
|
||||
schemas,
|
||||
setFilterText,
|
||||
viewport.x,
|
||||
viewport.y,
|
||||
viewport.zoom,
|
||||
]);
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user