fix(share): fix export to handle broken indexes & relationships (#416)

This commit is contained in:
Guy Ben-Aharon
2024-11-18 13:22:10 +02:00
committed by GitHub
parent b4cdcbbbd7
commit 4be3592cf4
16 changed files with 189 additions and 38 deletions

View File

@@ -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>

View File

@@ -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: {

View File

@@ -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: {

View File

@@ -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: {

View File

@@ -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: {

View File

@@ -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: {

View File

@@ -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: {

View File

@@ -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: {

View File

@@ -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

View File

@@ -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: {

View File

@@ -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: {

View File

@@ -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: 'Импорт кода диаграммы',

View File

@@ -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: {

View File

@@ -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: {

View File

@@ -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: {

View File

@@ -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,