Skip to content

Commit e9ea123

Browse files
authored
feat(diff-tool) - make some improvements (#941)
* feat(diff-tool) - make some improvements * fix format * fix recursive fields * remove dead code * fix fieldProps * fix basicInformationVersions
1 parent 72cc1dc commit e9ea123

5 files changed

Lines changed: 275 additions & 264 deletions

File tree

src/components/JsonSchemaComparison/SchemaFormComparison.tsx

Lines changed: 82 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,11 @@ interface SchemaFormComparisonProps {
2424
const FieldWrapper = ({
2525
children,
2626
diffType,
27-
orderChanged,
2827
changes,
2928
}: {
3029
children: React.ReactNode;
3130
diffType: 'added' | 'removed' | 'modified' | 'unchanged';
3231
fieldName: string;
33-
orderChanged?: { oldIndex: number; newIndex: number };
3432
changes?: {
3533
label?: { old: string; new: string };
3634
required?: { old: boolean; new: boolean };
@@ -54,9 +52,9 @@ const FieldWrapper = ({
5452
nestedFields?: unknown[];
5553
};
5654
}) => {
57-
const styles = getDiffStyles(diffType, !!orderChanged);
55+
const styles = getDiffStyles(diffType);
5856

59-
if (diffType === 'unchanged' && !orderChanged) {
57+
if (diffType === 'unchanged') {
6058
return <div>{children}</div>;
6159
}
6260

@@ -78,14 +76,7 @@ const FieldWrapper = ({
7876
),
7977
};
8078

81-
const reorderedBadge = orderChanged && diffType === 'unchanged' && (
82-
<span className='text-xs font-semibold text-blue-700 bg-blue-100 px-2 py-1 rounded'>
83-
MOVED
84-
</span>
85-
);
86-
87-
const badge =
88-
reorderedBadge || (diffType !== 'unchanged' && badges[diffType]);
79+
const badge = badges[diffType];
8980

9081
const renderChanges = () => {
9182
if (!changes || diffType !== 'modified') return null;
@@ -221,12 +212,7 @@ const FieldWrapper = ({
221212

222213
return (
223214
<div className={`p-3 mb-2 rounded ${styles} relative`}>
224-
<div className='absolute top-2 right-2'>
225-
{badge}
226-
{orderChanged && diffType !== 'unchanged' && (
227-
<span className='ml-2 text-xs text-gray-600'>(position changed)</span>
228-
)}
229-
</div>
215+
<div className='absolute top-2 right-2'>{badge}</div>
230216
{children}
231217
{renderChanges()}
232218
</div>
@@ -248,7 +234,6 @@ const FormPanel = ({
248234
string,
249235
{
250236
diffType: 'added' | 'removed' | 'modified' | 'unchanged';
251-
orderChanged?: { oldIndex: number; newIndex: number };
252237
changes?: unknown;
253238
}
254239
>;
@@ -260,26 +245,83 @@ const FormPanel = ({
260245
});
261246

262247
const fieldsWithWrappers = useMemo(() => {
263-
return fields.map((field) => {
264-
const diff = diffMap.get(field.name);
265-
const diffType = diff?.diffType || 'unchanged';
266-
const orderChanged = diff?.orderChanged;
267-
const changes = diff?.changes;
268-
269-
return {
270-
...field,
271-
WrapperComponent: ({ children }: { children: React.ReactNode }) => (
272-
<FieldWrapper
273-
diffType={diffType}
274-
fieldName={field.name}
275-
orderChanged={orderChanged}
276-
changes={changes as never}
277-
>
278-
{children}
279-
</FieldWrapper>
280-
),
281-
};
282-
});
248+
// Recursive function to apply wrappers to fields and their nested fields
249+
const applyWrappers = (
250+
fields: JSFField[],
251+
diffMap: Map<
252+
string,
253+
{
254+
diffType: 'added' | 'removed' | 'modified' | 'unchanged';
255+
changes?: unknown;
256+
}
257+
>,
258+
): JSFField[] => {
259+
return fields.map((field) => {
260+
const diff = diffMap.get(field.name);
261+
const diffType = diff?.diffType || 'unchanged';
262+
const changes = diff?.changes;
263+
264+
// If this field has nested fields (e.g., fieldset), recursively apply wrappers
265+
const nestedFields = (field as never as { fields?: JSFField[] }).fields;
266+
let processedField = field;
267+
268+
if (nestedFields && Array.isArray(nestedFields)) {
269+
// Build a nested diff map from the changes.nestedFields
270+
const nestedDiffMap = new Map<
271+
string,
272+
{
273+
diffType: 'added' | 'removed' | 'modified' | 'unchanged';
274+
changes?: unknown;
275+
}
276+
>();
277+
278+
if (
279+
changes &&
280+
typeof changes === 'object' &&
281+
'nestedFields' in changes &&
282+
Array.isArray(changes.nestedFields)
283+
) {
284+
(
285+
changes.nestedFields as Array<{
286+
fieldName: string;
287+
diffType: 'added' | 'removed' | 'modified' | 'unchanged';
288+
changes?: unknown;
289+
}>
290+
).forEach((nestedDiff) => {
291+
nestedDiffMap.set(nestedDiff.fieldName, {
292+
diffType: nestedDiff.diffType,
293+
changes: nestedDiff.changes,
294+
});
295+
});
296+
}
297+
298+
// Recursively apply wrappers to nested fields
299+
const wrappedNestedFields = applyWrappers(
300+
nestedFields,
301+
nestedDiffMap,
302+
);
303+
processedField = {
304+
...field,
305+
fields: wrappedNestedFields,
306+
} as JSFField;
307+
}
308+
309+
return {
310+
...processedField,
311+
WrapperComponent: ({ children }: { children: React.ReactNode }) => (
312+
<FieldWrapper
313+
diffType={diffType}
314+
fieldName={field.name}
315+
changes={changes as never}
316+
>
317+
{children}
318+
</FieldWrapper>
319+
),
320+
};
321+
});
322+
};
323+
324+
return applyWrappers(fields, diffMap);
283325
}, [fields, diffMap]);
284326

285327
return (
@@ -369,8 +411,7 @@ export const SchemaFormComparison = ({
369411
const hasNoDifferences =
370412
diff.added.length === 0 &&
371413
diff.removed.length === 0 &&
372-
diff.modified.length === 0 &&
373-
diff.reordered.length === 0;
414+
diff.modified.length === 0;
374415

375416
return (
376417
<div className='space-y-6'>
@@ -409,15 +450,6 @@ export const SchemaFormComparison = ({
409450
</span>
410451
</div>
411452
)}
412-
{diff.reordered.length > 0 && (
413-
<div className='flex items-center gap-2'>
414-
<span className='w-4 h-4 bg-blue-500 rounded'></span>
415-
<span className='text-sm'>
416-
{diff.reordered.length} field
417-
{diff.reordered.length > 1 ? 's' : ''} reordered
418-
</span>
419-
</div>
420-
)}
421453
</div>
422454
)}
423455
</CardContent>

src/components/JsonSchemaComparison/formDiffDetector.ts

Lines changed: 16 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ export type DiffType = 'added' | 'removed' | 'modified' | 'unchanged';
66
export interface FieldDiff {
77
fieldName: string;
88
diffType: DiffType;
9-
orderChanged?: { oldIndex: number; newIndex: number };
109
changes?: {
1110
label?: { old: string; new: string };
1211
required?: { old: boolean; new: boolean };
@@ -36,7 +35,6 @@ export interface FormDiff {
3635
removed: string[];
3736
modified: string[];
3837
unchanged: string[];
39-
reordered: string[];
4038
fieldDiffs: Map<string, FieldDiff>;
4139
}
4240

@@ -125,24 +123,14 @@ const compareNestedFields = (
125123
const hasChanges =
126124
nestedDiff.added.length > 0 ||
127125
nestedDiff.removed.length > 0 ||
128-
nestedDiff.modified.length > 0 ||
129-
nestedDiff.reordered.length > 0;
126+
nestedDiff.modified.length > 0;
130127

131128
if (!hasChanges) return undefined;
132129

133130
return Array.from(nestedDiff.fieldDiffs.values());
134131
};
135132

136-
const isFieldModified = (
137-
field1: JSFField,
138-
field2: JSFField,
139-
index1: number,
140-
index2: number,
141-
): boolean => {
142-
if (index1 !== index2) {
143-
return true;
144-
}
145-
133+
const isFieldModified = (field1: JSFField, field2: JSFField): boolean => {
146134
// Only compare user-facing schema properties, not internal/computed ones
147135
// Ignore: schema (Yup), computedAttributes, scopedJsonSchema, errorMessage, meta, description
148136
// Note: nested fields are checked via compareNestedFields to avoid deep equal with problematic properties
@@ -178,8 +166,7 @@ const isFieldModified = (
178166
return (
179167
nestedDiff.added.length > 0 ||
180168
nestedDiff.removed.length > 0 ||
181-
nestedDiff.modified.length > 0 ||
182-
nestedDiff.reordered.length > 0
169+
nestedDiff.modified.length > 0
183170
);
184171
})();
185172

@@ -280,18 +267,13 @@ export const compareFormFields = (
280267
const validFields1 = fields1.filter(validateField);
281268
const validFields2 = fields2.filter(validateField);
282269

283-
const fieldMap1 = new Map(
284-
validFields1.map((f, i) => [f.name, { field: f, index: i }]),
285-
);
286-
const fieldMap2 = new Map(
287-
validFields2.map((f, i) => [f.name, { field: f, index: i }]),
288-
);
270+
const fieldMap1 = new Map(validFields1.map((f) => [f.name, { field: f }]));
271+
const fieldMap2 = new Map(validFields2.map((f) => [f.name, { field: f }]));
289272

290273
const added: string[] = [];
291274
const removed: string[] = [];
292275
const modified: string[] = [];
293276
const unchanged: string[] = [];
294-
const reordered: string[] = [];
295277
const fieldDiffs = new Map<string, FieldDiff>();
296278

297279
fieldMap2.forEach((_, name) => {
@@ -304,39 +286,23 @@ export const compareFormFields = (
304286
}
305287
});
306288

307-
fieldMap1.forEach(({ field: field1, index: index1 }, name) => {
289+
fieldMap1.forEach(({ field: field1 }, name) => {
308290
if (!fieldMap2.has(name)) {
309291
removed.push(name);
310292
fieldDiffs.set(name, {
311293
fieldName: name,
312294
diffType: 'removed',
313295
});
314296
} else {
315-
const { field: field2, index: index2 } = fieldMap2.get(name)!;
316-
317-
if (isFieldModified(field1, field2, index1, index2)) {
318-
const onlyPositionChanged =
319-
index1 !== index2 && !isFieldModified(field1, field2, index1, index1);
320-
321-
if (onlyPositionChanged) {
322-
reordered.push(name);
323-
fieldDiffs.set(name, {
324-
fieldName: name,
325-
diffType: 'unchanged',
326-
orderChanged: { oldIndex: index1, newIndex: index2 },
327-
});
328-
} else {
329-
modified.push(name);
330-
fieldDiffs.set(name, {
331-
fieldName: name,
332-
diffType: 'modified',
333-
orderChanged:
334-
index1 !== index2
335-
? { oldIndex: index1, newIndex: index2 }
336-
: undefined,
337-
changes: getFieldChanges(field1, field2),
338-
});
339-
}
297+
const { field: field2 } = fieldMap2.get(name)!;
298+
299+
if (isFieldModified(field1, field2)) {
300+
modified.push(name);
301+
fieldDiffs.set(name, {
302+
fieldName: name,
303+
diffType: 'modified',
304+
changes: getFieldChanges(field1, field2),
305+
});
340306
} else {
341307
unchanged.push(name);
342308
fieldDiffs.set(name, {
@@ -352,19 +318,11 @@ export const compareFormFields = (
352318
removed,
353319
modified,
354320
unchanged,
355-
reordered,
356321
fieldDiffs,
357322
};
358323
};
359324

360-
export const getDiffStyles = (
361-
diffType: DiffType,
362-
hasOrderChange?: boolean,
363-
): string => {
364-
if (hasOrderChange && diffType === 'unchanged') {
365-
return 'bg-blue-50 border-l-4 border-blue-500';
366-
}
367-
325+
export const getDiffStyles = (diffType: DiffType): string => {
368326
switch (diffType) {
369327
case 'added':
370328
return 'bg-green-50 border-l-4 border-green-500';
Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,15 @@
1-
we have different snapshots from contract details
2-
3-
like @priv/json_schemas/contract_details/snapshots/PRT/1.json
4-
5-
I need for every country to have all the versions for example latest is this file @priv/json_schemas/contract_details/PRT.json
6-
7-
I want the output like this
8-
9-
COUNTRY_CONTRACT_VERSIONS: Record<string, VersionOption[]> = {
10-
DEU: [
1+
Generate a TypeScript constant called COUNTRY_CONTRACT_VERSIONS that maps country codes to their available contract detail versions.
2+
For each country in apps/tiger/priv/json_schemas/contract_details/ (excluding base.json):
3+
1. Count the number of snapshot files in snapshots/{COUNTRY}/ (these are historical versions)
4+
2. Add 1 for the current version in the root directory ({COUNTRY}.json)
5+
3. Create an array of version objects from 1 to the total count
6+
Output format:
7+
```typescript
8+
const COUNTRY_CONTRACT_VERSIONS: Record<string, VersionOption[]> = {
9+
COUNTRY_CODE: [
1110
{ value: 1, label: 'v1' },
1211
{ value: 2, label: 'v2' },
13-
{ value: 'latest', label: 'Latest' },
12+
// ... up to the total version count
1413
],
15-
USA: [
16-
{ value: 1, label: 'v1' },
17-
{ value: 'latest', label: 'Latest' },
18-
],
19-
// ... other countries
14+
// ... all countries sorted alphabetically
2015
};

0 commit comments

Comments
 (0)