Skip to content

Commit da7b980

Browse files
committed
ConFiguration Migration Modal
1 parent 610c282 commit da7b980

File tree

1 file changed

+91
-15
lines changed

1 file changed

+91
-15
lines changed

src/ui/src/components/configuration-layout/ConfigurationLayout.jsx

Lines changed: 91 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,21 @@ const ConfigurationLayout = () => {
5454
const [exportFileName, setExportFileName] = useState('configuration');
5555
const [importError, setImportError] = useState(null);
5656
const [extractionSchema, setExtractionSchema] = useState(null);
57+
const [showMigrationModal, setShowMigrationModal] = useState(false);
58+
const [pendingImportConfig, setPendingImportConfig] = useState(null);
5759

5860
const editorRef = useRef(null);
5961

62+
// Helper function to detect legacy format
63+
const isLegacyFormat = (config) => {
64+
if (!config || !config.classes || !Array.isArray(config.classes)) return false;
65+
if (config.classes.length === 0) return false;
66+
67+
// Check if first class has legacy attributes format (array instead of object with properties)
68+
const firstClass = config.classes[0];
69+
return firstClass.attributes && Array.isArray(firstClass.attributes);
70+
};
71+
6072
// Initialize form values from merged config
6173
useEffect(() => {
6274
if (mergedConfig) {
@@ -897,24 +909,25 @@ const ConfigurationLayout = () => {
897909
reader.onload = (e) => {
898910
try {
899911
setImportError(null);
900-
let importedConfig;
901912
const content = e.target.result;
902913

903-
if (file.name.endsWith('.yaml') || file.name.endsWith('.yml')) {
904-
importedConfig = yaml.load(content);
905-
} else {
906-
importedConfig = JSON.parse(content);
907-
}
914+
const importedConfig = file.name.endsWith('.yaml') || file.name.endsWith('.yml') ? yaml.load(content) : JSON.parse(content);
908915

909916
if (importedConfig && typeof importedConfig === 'object') {
910-
// If the imported config has classes, use them (should be JSON Schema format)
911-
if (importedConfig.classes) {
912-
setExtractionSchema(importedConfig.classes);
917+
// Check if config is in legacy format
918+
if (isLegacyFormat(importedConfig)) {
919+
// Show migration modal and store config for later
920+
setPendingImportConfig(importedConfig);
921+
setShowMigrationModal(true);
922+
} else {
923+
// Modern format - load directly into form
924+
if (importedConfig.classes) {
925+
setExtractionSchema(importedConfig.classes);
926+
}
927+
handleFormChange(importedConfig);
928+
setSaveSuccess(false);
929+
setSaveError(null);
913930
}
914-
915-
handleFormChange(importedConfig);
916-
setSaveSuccess(false);
917-
setSaveError(null);
918931
} else {
919932
setImportError('Invalid configuration file format');
920933
}
@@ -924,8 +937,36 @@ const ConfigurationLayout = () => {
924937
};
925938
reader.readAsText(file);
926939
// Clear the input value to allow re-importing the same file
927-
const input = event.target;
928-
input.value = '';
940+
event.target.value = '';
941+
};
942+
943+
const handleMigrationConfirm = async () => {
944+
if (!pendingImportConfig) return;
945+
946+
setIsSaving(true);
947+
try {
948+
// Send to backend for migration, then reload to get migrated version
949+
const success = await updateConfiguration(pendingImportConfig);
950+
951+
if (success) {
952+
await fetchConfiguration();
953+
setShowMigrationModal(false);
954+
setPendingImportConfig(null);
955+
} else {
956+
setImportError('Failed to import configuration');
957+
setShowMigrationModal(false);
958+
}
959+
} catch (err) {
960+
setImportError(`Import failed: ${err.message}`);
961+
setShowMigrationModal(false);
962+
} finally {
963+
setIsSaving(false);
964+
}
965+
};
966+
967+
const handleMigrationCancel = () => {
968+
setShowMigrationModal(false);
969+
setPendingImportConfig(null);
929970
};
930971

931972
if (loading) {
@@ -1058,6 +1099,41 @@ const ConfigurationLayout = () => {
10581099
</SpaceBetween>
10591100
</Modal>
10601101

1102+
<Modal
1103+
visible={showMigrationModal}
1104+
onDismiss={handleMigrationCancel}
1105+
header="Configuration Migration Required"
1106+
footer={
1107+
<Box float="right">
1108+
<SpaceBetween direction="horizontal" size="xs">
1109+
<Button variant="link" onClick={handleMigrationCancel}>
1110+
Cancel
1111+
</Button>
1112+
<Button variant="primary" onClick={handleMigrationConfirm} loading={isSaving}>
1113+
Save and Migrate
1114+
</Button>
1115+
</SpaceBetween>
1116+
</Box>
1117+
}
1118+
>
1119+
<SpaceBetween direction="vertical" size="m">
1120+
<Box variant="span">
1121+
The configuration file you are importing uses a legacy format that needs to be migrated to the current JSON Schema format.
1122+
</Box>
1123+
<Alert type="info" header="What will happen">
1124+
<ul>
1125+
<li>The configuration will be automatically converted to the new format</li>
1126+
<li>All your settings and document classes will be preserved</li>
1127+
<li>The migrated configuration will be saved to the database</li>
1128+
<li>You can review the changes after migration</li>
1129+
</ul>
1130+
</Alert>
1131+
<Box variant="span">
1132+
Click &quot;Save and Migrate&quot; to proceed with the migration, or &quot;Cancel&quot; to abort the import.
1133+
</Box>
1134+
</SpaceBetween>
1135+
</Modal>
1136+
10611137
<Container
10621138
header={
10631139
<Header

0 commit comments

Comments
 (0)