Skip to content

Commit 591e8a1

Browse files
committed
Merge branch 'fix/discovery-config-setup' into 'develop'
Fix/discovery config setup See merge request genaiic-reusable-assets/engagement-artifacts/genaiic-idp-accelerator!394
2 parents 62bfc7c + d388994 commit 591e8a1

File tree

4 files changed

+84
-15
lines changed

4 files changed

+84
-15
lines changed

lib/idp_common_pkg/idp_common/discovery/classes_discovery.py

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,10 @@ def discovery_classes_with_document(self, input_bucket: str, input_prefix: str):
9494
# No need to transform - it's already in the right format
9595
current_class = model_response
9696

97-
custom_item = self.config_manager.get_configuration("Custom")
97+
custom_item_raw = self.config_manager.get_configuration("Custom")
98+
custom_item = cast(Optional[IDPConfig], custom_item_raw)
9899
classes = []
99-
if custom_item and hasattr(custom_item, "classes") and custom_item.classes:
100+
if custom_item and custom_item.classes:
100101
classes = list(custom_item.classes)
101102
# Check for existing class by $id or x-aws-idp-document-type
102103
class_id = current_class.get("$id") or current_class.get(
@@ -115,8 +116,15 @@ def discovery_classes_with_document(self, input_bucket: str, input_prefix: str):
115116
classes.append(current_class)
116117

117118
# Update configuration with new classes
118-
config_data = {"classes": classes}
119-
self.config_manager.save_configuration("Custom", config_data)
119+
# Load existing custom config to preserve all other fields
120+
if not custom_item:
121+
# If no custom config exists, get default as base
122+
default_raw = self.config_manager.get_configuration("Default")
123+
custom_item = cast(Optional[IDPConfig], default_raw) or IDPConfig()
124+
125+
# Update only the classes field, preserving all other config
126+
custom_item.classes = classes
127+
self.config_manager.save_configuration("Custom", custom_item)
120128

121129
return {"status": "SUCCESS"}
122130

@@ -167,9 +175,10 @@ def discovery_classes_with_document_and_ground_truth(
167175
# No need to transform - it's already in the right format
168176
current_class = model_response
169177

170-
custom_item = self.config_manager.get_configuration("Custom")
178+
custom_item_raw = self.config_manager.get_configuration("Custom")
179+
custom_item = cast(Optional[IDPConfig], custom_item_raw)
171180
classes = []
172-
if custom_item and hasattr(custom_item, "classes") and custom_item.classes:
181+
if custom_item and custom_item.classes:
173182
classes = list(custom_item.classes)
174183
# Check for existing class by $id or x-aws-idp-document-type
175184
class_id = current_class.get("$id") or current_class.get(
@@ -188,8 +197,15 @@ def discovery_classes_with_document_and_ground_truth(
188197
classes.append(current_class)
189198

190199
# Update configuration with new classes
191-
config_data = {"classes": classes}
192-
self.config_manager.save_configuration("Custom", config_data)
200+
# Load existing custom config to preserve all other fields
201+
if not custom_item:
202+
# If no custom config exists, get default as base
203+
default_raw = self.config_manager.get_configuration("Default")
204+
custom_item = cast(Optional[IDPConfig], default_raw) or IDPConfig()
205+
206+
# Update only the classes field, preserving all other config
207+
custom_item.classes = classes
208+
self.config_manager.save_configuration("Custom", custom_item)
193209

194210
return {"status": "SUCCESS"}
195211

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -776,14 +776,14 @@ const ConfigurationLayout = () => {
776776
const builtObject = buildObjectFromPaths(differences);
777777
console.log('DEBUG: Built object from paths:', builtObject);
778778

779-
// CRITICAL: Always include the current document schema (classes) if it exists
780-
// This prevents the schema from being lost when saving other configuration changes
781-
if (formValues.classes && Array.isArray(formValues.classes) && formValues.classes.length > 0) {
779+
// CRITICAL: Always include the current document schema (classes) if it exists OR is explicitly empty
780+
// This ensures empty arrays are saved (to wipe all classes) and prevents schema loss
781+
if (formValues.classes && Array.isArray(formValues.classes)) {
782782
builtObject.classes = formValues.classes;
783783
console.log('DEBUG: Including document schema (classes) in save:', formValues.classes);
784784
}
785785

786-
// CRITICAL: If there are no differences AND no schema, don't send update to backend
786+
// CRITICAL: If there are no differences AND no schema changes, don't send update to backend
787787
// This prevents unnecessary API calls and potential data issues
788788
if (Object.keys(builtObject).length === 0) {
789789
console.log('No changes detected, skipping save');
@@ -1245,7 +1245,11 @@ const ConfigurationLayout = () => {
12451245
setExtractionSchema(schemaData);
12461246
if (isDirty) {
12471247
const updatedConfig = { ...formValues };
1248-
if (schemaData && schemaData.length > 0) {
1248+
// CRITICAL: Always set classes, even if empty array (to support wipe all functionality)
1249+
// Handle null (no classes) by setting empty array
1250+
if (schemaData === null) {
1251+
updatedConfig.classes = [];
1252+
} else if (Array.isArray(schemaData)) {
12491253
// Store as 'classes' field with JSON Schema content
12501254
updatedConfig.classes = schemaData;
12511255
}

src/ui/src/components/json-schema-builder/SchemaBuilder.jsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const SchemaBuilder = ({ initialSchema, onChange, onValidate }) => {
4242
exportSchema,
4343
getSelectedClass,
4444
getSelectedAttribute,
45+
clearAllClasses,
4546
} = useSchemaDesigner(initialSchema || []);
4647

4748
const { validateSchema } = useSchemaValidation();
@@ -59,6 +60,7 @@ const SchemaBuilder = ({ initialSchema, onChange, onValidate }) => {
5960
const [editingClass, setEditingClass] = useState(null);
6061
const [showDeleteConfirmModal, setShowDeleteConfirmModal] = useState(false);
6162
const [classToDelete, setClassToDelete] = useState(null);
63+
const [showWipeAllModal, setShowWipeAllModal] = useState(false);
6264
const [aggregatedValidationErrors, setAggregatedValidationErrors] = useState([]);
6365
const lastExportedSchemaRef = useRef(null);
6466
const lastValidationResultRef = useRef(null);
@@ -186,6 +188,15 @@ const SchemaBuilder = ({ initialSchema, onChange, onValidate }) => {
186188
}
187189
};
188190

191+
const handleWipeAll = () => {
192+
setShowWipeAllModal(true);
193+
};
194+
195+
const handleConfirmWipeAll = () => {
196+
clearAllClasses();
197+
setShowWipeAllModal(false);
198+
};
199+
189200
const docTypeCount = classes.filter((c) => c[X_AWS_IDP_DOCUMENT_TYPE]).length;
190201
const sharedCount = classes.filter((c) => !c[X_AWS_IDP_DOCUMENT_TYPE]).length;
191202

@@ -289,6 +300,9 @@ const SchemaBuilder = ({ initialSchema, onChange, onValidate }) => {
289300
>
290301
Export
291302
</Button>
303+
<Button onClick={handleWipeAll} iconName="remove" disabled={classes.length === 0}>
304+
Wipe All
305+
</Button>
292306
</SpaceBetween>
293307
</Box>
294308
}
@@ -775,6 +789,34 @@ const SchemaBuilder = ({ initialSchema, onChange, onValidate }) => {
775789
)}
776790
</SpaceBetween>
777791
</Modal>
792+
793+
<Modal
794+
visible={showWipeAllModal}
795+
onDismiss={() => setShowWipeAllModal(false)}
796+
header="Wipe All Document Classes"
797+
footer={
798+
<Box float="right">
799+
<SpaceBetween direction="horizontal" size="xs">
800+
<Button variant="link" onClick={() => setShowWipeAllModal(false)}>
801+
Cancel
802+
</Button>
803+
<Button variant="primary" onClick={handleConfirmWipeAll}>
804+
Wipe All
805+
</Button>
806+
</SpaceBetween>
807+
</Box>
808+
}
809+
>
810+
<SpaceBetween size="m">
811+
<Alert type="error">
812+
Are you sure you want to delete <strong>all {classes.length} document class(es)</strong>? This action cannot be undone.
813+
</Alert>
814+
<Box variant="p">
815+
All document classes and their attributes will be permanently removed. You will need to recreate them or use the discovery
816+
feature to regenerate your schema.
817+
</Box>
818+
</SpaceBetween>
819+
</Modal>
778820
</SpaceBetween>
779821
</>
780822
);

src/ui/src/hooks/useSchemaDesigner.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -646,10 +646,16 @@ export const useSchemaDesigner = (initialSchema = []) => {
646646

647647
const getSelectedAttribute = useCallback(() => {
648648
const cls = getSelectedClass();
649-
if (!cls || !selectedAttributeId) return null;
650-
return cls.attributes.properties[selectedAttributeId] || null;
649+
return cls?.attributes?.properties?.[selectedAttributeId];
651650
}, [getSelectedClass, selectedAttributeId]);
652651

652+
const clearAllClasses = useCallback(() => {
653+
setClasses([]);
654+
setSelectedClassId(null);
655+
setSelectedAttributeId(null);
656+
setIsDirty(true);
657+
}, []);
658+
653659
return {
654660
classes,
655661
selectedClassId,
@@ -670,5 +676,6 @@ export const useSchemaDesigner = (initialSchema = []) => {
670676
resetDirty,
671677
getSelectedClass,
672678
getSelectedAttribute,
679+
clearAllClasses,
673680
};
674681
};

0 commit comments

Comments
 (0)