mirror of
https://github.com/chartdb/chartdb.git
synced 2026-01-11 06:10:03 -06:00
fix(share): fix export to handle broken indexes & relationships (#416)
This commit is contained in:
@@ -18,6 +18,8 @@ import { useChartDB } from '@/hooks/use-chartdb';
|
||||
import { diagramToJSONOutput } from '@/lib/export-import-utils';
|
||||
import { Spinner } from '@/components/spinner/spinner';
|
||||
import { waitFor } from '@/lib/utils';
|
||||
import { AlertCircle } from 'lucide-react';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/alert/alert';
|
||||
|
||||
export interface ExportDiagramDialogProps extends BaseDialogProps {}
|
||||
|
||||
@@ -28,10 +30,12 @@ export const ExportDiagramDialog: React.FC<ExportDiagramDialogProps> = ({
|
||||
const { diagramName, currentDiagram } = useChartDB();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { closeExportDiagramDialog } = useDialog();
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!dialog.open) return;
|
||||
setIsLoading(false);
|
||||
setError(false);
|
||||
}, [dialog.open]);
|
||||
|
||||
const downloadOutput = useCallback(
|
||||
@@ -47,12 +51,19 @@ export const ExportDiagramDialog: React.FC<ExportDiagramDialogProps> = ({
|
||||
const handleExport = useCallback(async () => {
|
||||
setIsLoading(true);
|
||||
await waitFor(1000);
|
||||
const json = diagramToJSONOutput(currentDiagram);
|
||||
const blob = new Blob([json], { type: 'application/json' });
|
||||
const dataUrl = URL.createObjectURL(blob);
|
||||
downloadOutput(dataUrl);
|
||||
setIsLoading(false);
|
||||
closeExportDiagramDialog();
|
||||
try {
|
||||
const json = diagramToJSONOutput(currentDiagram);
|
||||
const blob = new Blob([json], { type: 'application/json' });
|
||||
const dataUrl = URL.createObjectURL(blob);
|
||||
downloadOutput(dataUrl);
|
||||
setIsLoading(false);
|
||||
closeExportDiagramDialog();
|
||||
} catch (e) {
|
||||
setError(true);
|
||||
setIsLoading(false);
|
||||
|
||||
throw e;
|
||||
}
|
||||
}, [downloadOutput, currentDiagram, closeExportDiagramDialog]);
|
||||
|
||||
const outputTypeOptions: SelectBoxOption[] = useMemo(
|
||||
@@ -90,6 +101,17 @@ export const ExportDiagramDialog: React.FC<ExportDiagramDialogProps> = ({
|
||||
value="json"
|
||||
/>
|
||||
</div>
|
||||
{error ? (
|
||||
<Alert variant="destructive">
|
||||
<AlertCircle className="size-4" />
|
||||
<AlertTitle>
|
||||
{t('export_diagram_dialog.error.title')}
|
||||
</AlertTitle>
|
||||
<AlertDescription>
|
||||
{t('export_diagram_dialog.error.description')}
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
) : null}
|
||||
</div>
|
||||
<DialogFooter className="flex gap-1 md:justify-between">
|
||||
<DialogClose asChild>
|
||||
|
||||
@@ -344,6 +344,11 @@ export const de: LanguageTranslation = {
|
||||
format_json: 'JSON',
|
||||
cancel: 'Cancel',
|
||||
export: 'Export',
|
||||
error: {
|
||||
title: 'Error exporting diagram',
|
||||
description:
|
||||
'Something went wrong. Need help? chartdb.io@gmail.com',
|
||||
},
|
||||
},
|
||||
// TODO: Translate
|
||||
import_diagram_dialog: {
|
||||
|
||||
@@ -340,6 +340,11 @@ export const en = {
|
||||
format_json: 'JSON',
|
||||
cancel: 'Cancel',
|
||||
export: 'Export',
|
||||
error: {
|
||||
title: 'Error exporting diagram',
|
||||
description:
|
||||
'Something went wrong. Need help? chartdb.io@gmail.com',
|
||||
},
|
||||
},
|
||||
|
||||
import_diagram_dialog: {
|
||||
|
||||
@@ -344,6 +344,11 @@ export const es: LanguageTranslation = {
|
||||
format_json: 'JSON',
|
||||
cancel: 'Cancel',
|
||||
export: 'Export',
|
||||
error: {
|
||||
title: 'Error exporting diagram',
|
||||
description:
|
||||
'Something went wrong. Need help? chartdb.io@gmail.com',
|
||||
},
|
||||
},
|
||||
// TODO: Translate
|
||||
import_diagram_dialog: {
|
||||
|
||||
@@ -346,6 +346,11 @@ export const fr: LanguageTranslation = {
|
||||
format_json: 'JSON',
|
||||
cancel: 'Cancel',
|
||||
export: 'Export',
|
||||
error: {
|
||||
title: 'Error exporting diagram',
|
||||
description:
|
||||
'Something went wrong. Need help? chartdb.io@gmail.com',
|
||||
},
|
||||
},
|
||||
// TODO: Translate
|
||||
import_diagram_dialog: {
|
||||
|
||||
@@ -346,6 +346,11 @@ export const hi: LanguageTranslation = {
|
||||
format_json: 'JSON',
|
||||
cancel: 'Cancel',
|
||||
export: 'Export',
|
||||
error: {
|
||||
title: 'Error exporting diagram',
|
||||
description:
|
||||
'Something went wrong. Need help? chartdb.io@gmail.com',
|
||||
},
|
||||
},
|
||||
// TODO: Translate
|
||||
import_diagram_dialog: {
|
||||
|
||||
@@ -348,6 +348,11 @@ export const ja: LanguageTranslation = {
|
||||
format_json: 'JSON',
|
||||
cancel: 'Cancel',
|
||||
export: 'Export',
|
||||
error: {
|
||||
title: 'Error exporting diagram',
|
||||
description:
|
||||
'Something went wrong. Need help? chartdb.io@gmail.com',
|
||||
},
|
||||
},
|
||||
// TODO: Translate
|
||||
import_diagram_dialog: {
|
||||
|
||||
@@ -342,6 +342,11 @@ export const ko_KR: LanguageTranslation = {
|
||||
format_json: 'JSON',
|
||||
cancel: 'Cancel',
|
||||
export: 'Export',
|
||||
error: {
|
||||
title: 'Error exporting diagram',
|
||||
description:
|
||||
'Something went wrong. Need help? chartdb.io@gmail.com',
|
||||
},
|
||||
},
|
||||
// TODO: Translate
|
||||
import_diagram_dialog: {
|
||||
|
||||
@@ -349,6 +349,11 @@ export const mr: LanguageTranslation = {
|
||||
format_json: 'JSON',
|
||||
cancel: 'Cancel',
|
||||
export: 'Export',
|
||||
error: {
|
||||
title: 'Error exporting diagram',
|
||||
description:
|
||||
'Something went wrong. Need help? chartdb.io@gmail.com',
|
||||
},
|
||||
},
|
||||
|
||||
// TO
|
||||
|
||||
@@ -343,6 +343,11 @@ export const ne: LanguageTranslation = {
|
||||
format_json: 'JSON',
|
||||
cancel: 'रद्द गर्नुहोस्',
|
||||
export: 'निर्यात गर्नुहोस्',
|
||||
error: {
|
||||
title: 'Error exporting diagram',
|
||||
description:
|
||||
'Something went wrong. Need help? chartdb.io@gmail.com',
|
||||
},
|
||||
},
|
||||
|
||||
import_diagram_dialog: {
|
||||
|
||||
@@ -343,6 +343,11 @@ export const pt_BR: LanguageTranslation = {
|
||||
format_json: 'JSON',
|
||||
cancel: 'Cancel',
|
||||
export: 'Export',
|
||||
error: {
|
||||
title: 'Error exporting diagram',
|
||||
description:
|
||||
'Something went wrong. Need help? chartdb.io@gmail.com',
|
||||
},
|
||||
},
|
||||
// TODO: Translate
|
||||
import_diagram_dialog: {
|
||||
|
||||
@@ -339,6 +339,12 @@ export const ru: LanguageTranslation = {
|
||||
format_json: 'JSON',
|
||||
cancel: 'Отменить',
|
||||
export: 'Экспортировать',
|
||||
// TODO: Translate
|
||||
error: {
|
||||
title: 'Error exporting diagram',
|
||||
description:
|
||||
'Something went wrong. Need help? chartdb.io@gmail.com',
|
||||
},
|
||||
},
|
||||
import_diagram_dialog: {
|
||||
title: 'Импорт кода диаграммы',
|
||||
|
||||
@@ -343,6 +343,11 @@ export const uk: LanguageTranslation = {
|
||||
format_json: 'JSON',
|
||||
cancel: 'Cancel',
|
||||
export: 'Export',
|
||||
error: {
|
||||
title: 'Error exporting diagram',
|
||||
description:
|
||||
'Something went wrong. Need help? chartdb.io@gmail.com',
|
||||
},
|
||||
},
|
||||
// TODO: Translate
|
||||
import_diagram_dialog: {
|
||||
|
||||
@@ -334,6 +334,12 @@ export const zh_CN: LanguageTranslation = {
|
||||
format_json: 'JSON',
|
||||
cancel: '取消',
|
||||
export: '导出',
|
||||
// TODO: translate
|
||||
error: {
|
||||
title: 'Error exporting diagram',
|
||||
description:
|
||||
'Something went wrong. Need help? chartdb.io@gmail.com',
|
||||
},
|
||||
},
|
||||
|
||||
import_diagram_dialog: {
|
||||
|
||||
@@ -333,6 +333,12 @@ export const zh_TW: LanguageTranslation = {
|
||||
format_json: 'JSON',
|
||||
cancel: '取消',
|
||||
export: '匯出',
|
||||
// TODO: Translate
|
||||
error: {
|
||||
title: 'Error exporting diagram',
|
||||
description:
|
||||
'Something went wrong. Need help? chartdb.io@gmail.com',
|
||||
},
|
||||
},
|
||||
|
||||
import_diagram_dialog: {
|
||||
|
||||
120
src/lib/clone.ts
120
src/lib/clone.ts
@@ -63,28 +63,51 @@ export const cloneTable = (
|
||||
...options.idsMap,
|
||||
]);
|
||||
|
||||
const getNewId = (id: string) => {
|
||||
const getNewId = (id: string): string | null => {
|
||||
const newId = idsMap.get(id);
|
||||
if (!newId) {
|
||||
throw new Error(`Id not found for ${id}`);
|
||||
return null;
|
||||
}
|
||||
return newId;
|
||||
};
|
||||
|
||||
const newTable: DBTable = { ...table, id: getNewId(table.id) };
|
||||
newTable.fields = table.fields.map(
|
||||
(field): DBField => ({
|
||||
...field,
|
||||
id: getNewId(field.id),
|
||||
const tableId = getNewId(table.id);
|
||||
if (!tableId) {
|
||||
throw new Error('Table id not found');
|
||||
}
|
||||
|
||||
const newTable: DBTable = { ...table, id: tableId };
|
||||
newTable.fields = table.fields
|
||||
.map((field): DBField | null => {
|
||||
const id = getNewId(field.id);
|
||||
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...field,
|
||||
id,
|
||||
};
|
||||
})
|
||||
);
|
||||
newTable.indexes = table.indexes.map(
|
||||
(index): DBIndex => ({
|
||||
...index,
|
||||
fieldIds: index.fieldIds.map((id) => getNewId(id)),
|
||||
id: getNewId(index.id),
|
||||
.filter((field): field is DBField => field !== null);
|
||||
newTable.indexes = table.indexes
|
||||
.map((index): DBIndex | null => {
|
||||
const id = getNewId(index.id);
|
||||
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...index,
|
||||
fieldIds: index.fieldIds
|
||||
.map((id) => getNewId(id))
|
||||
.filter((fieldId): fieldId is string => fieldId !== null),
|
||||
id,
|
||||
};
|
||||
})
|
||||
);
|
||||
.filter((index): index is DBIndex => index !== null);
|
||||
|
||||
return newTable;
|
||||
};
|
||||
@@ -102,10 +125,10 @@ export const cloneDiagram = (
|
||||
|
||||
const idsMap = generateIdsMapFromDiagram(diagram, generateId);
|
||||
|
||||
const getNewId = (id: string) => {
|
||||
const getNewId = (id: string): string | null => {
|
||||
const newId = idsMap.get(id);
|
||||
if (!newId) {
|
||||
throw new Error(`Id not found for ${id}`);
|
||||
return null;
|
||||
}
|
||||
return newId;
|
||||
};
|
||||
@@ -116,26 +139,59 @@ export const cloneDiagram = (
|
||||
) ?? [];
|
||||
|
||||
const relationships: DBRelationship[] =
|
||||
diagram.relationships?.map(
|
||||
(relationship): DBRelationship => ({
|
||||
...relationship,
|
||||
id: getNewId(relationship.id),
|
||||
sourceTableId: getNewId(relationship.sourceTableId),
|
||||
targetTableId: getNewId(relationship.targetTableId),
|
||||
sourceFieldId: getNewId(relationship.sourceFieldId),
|
||||
targetFieldId: getNewId(relationship.targetFieldId),
|
||||
diagram.relationships
|
||||
?.map((relationship): DBRelationship | null => {
|
||||
const id = getNewId(relationship.id);
|
||||
const sourceTableId = getNewId(relationship.sourceTableId);
|
||||
const targetTableId = getNewId(relationship.targetTableId);
|
||||
const sourceFieldId = getNewId(relationship.sourceFieldId);
|
||||
const targetFieldId = getNewId(relationship.targetFieldId);
|
||||
|
||||
if (
|
||||
!id ||
|
||||
!sourceTableId ||
|
||||
!targetTableId ||
|
||||
!sourceFieldId ||
|
||||
!targetFieldId
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...relationship,
|
||||
id,
|
||||
sourceTableId,
|
||||
targetTableId,
|
||||
sourceFieldId,
|
||||
targetFieldId,
|
||||
};
|
||||
})
|
||||
) ?? [];
|
||||
.filter(
|
||||
(relationship): relationship is DBRelationship =>
|
||||
relationship !== null
|
||||
) ?? [];
|
||||
|
||||
const dependencies: DBDependency[] =
|
||||
diagram.dependencies?.map(
|
||||
(dependency): DBDependency => ({
|
||||
...dependency,
|
||||
id: getNewId(dependency.id),
|
||||
dependentTableId: getNewId(dependency.dependentTableId),
|
||||
tableId: getNewId(dependency.tableId),
|
||||
diagram.dependencies
|
||||
?.map((dependency): DBDependency | null => {
|
||||
const id = getNewId(dependency.id);
|
||||
const dependentTableId = getNewId(dependency.dependentTableId);
|
||||
const tableId = getNewId(dependency.tableId);
|
||||
|
||||
if (!id || !dependentTableId || !tableId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
...dependency,
|
||||
id,
|
||||
dependentTableId,
|
||||
tableId,
|
||||
};
|
||||
})
|
||||
) ?? [];
|
||||
.filter(
|
||||
(dependency): dependency is DBDependency => dependency !== null
|
||||
) ?? [];
|
||||
|
||||
return {
|
||||
...diagram,
|
||||
|
||||
Reference in New Issue
Block a user