-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenerateUISchema.ts
More file actions
120 lines (99 loc) · 4.06 KB
/
generateUISchema.ts
File metadata and controls
120 lines (99 loc) · 4.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import {
V2Schema,
JSONFormsUISchema,
JSONFormsLayout
} from '../common/types';
import {
createControl,
createSectionLayout,
getVisibleFields,
groupFieldsBySection
} from './utils';
/**
* Validates V2 schema structure for known issues
*/
const validateV2Schema = (schema: V2Schema): void => {
const invalidFields: string[] = [];
const supportedFieldTypes = ['TEXT', 'NUMERIC', 'DATE_TIME', 'CHOICE_LIST', 'LOCATION', 'COLLECTION', 'ATTACHMENT'];
// Check each field for validity
Object.entries(schema.json.properties).forEach(([fieldName, property]) => {
const uiField = schema.ui.fields[fieldName];
// Skip deprecated fields without UI definitions (they won't be rendered anyway)
if (!uiField && property.deprecated) {
return;
}
if (!uiField) {
invalidFields.push(`${fieldName}: missing UI field definition`);
return;
}
// Check for unsupported field types
if (!supportedFieldTypes.includes(uiField.type)) {
invalidFields.push(`${fieldName}: unsupported field type '${uiField.type}'`);
return;
}
// Check CHOICE_LIST fields for valid structure (not content)
if (uiField.type === 'CHOICE_LIST') {
let hasValidStructure = false;
if (property.type === 'array' && property.items?.anyOf) {
// Check for oneOf arrays in anyOf items for array types (no $ref support)
hasValidStructure = property.items.anyOf.some((anyOfItem: any) =>
anyOfItem.oneOf && Array.isArray(anyOfItem.oneOf) // Empty arrays are valid
);
} else if (property.anyOf) {
// Check direct anyOf structure for string types (no $ref support)
hasValidStructure = property.anyOf.some((anyOfItem: any) =>
anyOfItem.oneOf && Array.isArray(anyOfItem.oneOf) // Empty arrays are valid
);
}
if (!hasValidStructure) {
invalidFields.push(`${fieldName}: CHOICE_LIST field requires embedded oneOf arrays - $ref not supported`);
}
}
});
if (invalidFields.length > 0) {
throw new Error(`Invalid V2 schema structure: ${invalidFields.join(', ')}`);
}
};
/**
* Generates a JSONForms-compatible UI schema from a EarthRanger V2 schema format
*
* React Native Optimization:
* - All layouts are converted to single-column VerticalLayout
* - Multi-column sections are flattened: leftColumn fields first, then rightColumn fields
* - Optimized for mobile form rendering
*
* @param schema - EarthRanger V2 schema with json and ui properties
* @returns JSONForms UI schema with single-column VerticalLayout for React Native
* @throws Error if schema has invalid structure or unsupported field configurations
*/
export const generateUISchema = (schema: V2Schema): JSONFormsUISchema => {
// Validate schema structure first
validateV2Schema(schema);
// Get all visible (non-deprecated) fields
const visibleFields = getVisibleFields(schema);
// Group fields by their parent sections
const fieldsBySection = groupFieldsBySection(visibleFields, schema.ui.sections);
// Create section layouts in the specified order
const sectionLayouts: JSONFormsLayout[] = [];
schema.ui.order.forEach(sectionId => {
const section = schema.ui.sections[sectionId];
const sectionFields = fieldsBySection[sectionId] || [];
// Check if section has any content (fields or headers)
const hasFields = sectionFields.length > 0;
const hasHeaders = [...section.leftColumn, ...section.rightColumn]
.some(item => item.type === 'header' && schema.ui.headers[item.name]);
// Only create layout if section is active and has content
if (section?.isActive && (hasFields || hasHeaders)) {
const sectionControls = sectionFields.map(({ name, property, uiField }) =>
createControl(name, property, uiField)
);
const sectionLayout = createSectionLayout(sectionId, section, sectionControls, schema.ui.headers);
sectionLayouts.push(sectionLayout);
}
});
const uiSchema: JSONFormsUISchema = {
type: 'VerticalLayout',
elements: sectionLayouts
};
return uiSchema;
};