@react-typed-forms/schemas 1.0.0-dev.18 → 1.0.0-dev.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.rush/temp/operation/build/state.json +1 -1
- package/lib/controlRender.d.ts +0 -14
- package/lib/hooks.d.ts +2 -1
- package/lib/index.js +135 -56
- package/lib/index.js.map +1 -1
- package/lib/types.d.ts +0 -7
- package/lib/util.d.ts +17 -1
- package/package.json +5 -5
- package/src/controlRender.tsx +3 -113
- package/src/hooks.tsx +22 -6
- package/src/types.ts +0 -8
- package/src/util.ts +200 -1
package/lib/types.d.ts
CHANGED
|
@@ -12,10 +12,6 @@ export interface SchemaField {
|
|
|
12
12
|
searchable?: boolean | null;
|
|
13
13
|
options?: FieldOption[] | null;
|
|
14
14
|
validators?: SchemaValidator[] | null;
|
|
15
|
-
/**
|
|
16
|
-
* @deprecated Use options directly
|
|
17
|
-
*/
|
|
18
|
-
restrictions?: SchemaRestrictions | undefined | null;
|
|
19
15
|
}
|
|
20
16
|
export declare enum FieldType {
|
|
21
17
|
String = "String",
|
|
@@ -35,9 +31,6 @@ export interface EntityRefField extends SchemaField {
|
|
|
35
31
|
entityRefType: string;
|
|
36
32
|
parentField: string;
|
|
37
33
|
}
|
|
38
|
-
export interface SchemaRestrictions {
|
|
39
|
-
options?: FieldOption[] | null;
|
|
40
|
-
}
|
|
41
34
|
export interface FieldOption {
|
|
42
35
|
name: string;
|
|
43
36
|
value: any;
|
package/lib/util.d.ts
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
|
-
import { FieldOption, SchemaField } from "./types";
|
|
1
|
+
import { CompoundField, ControlDefinition, DataControlDefinition, FieldOption, GroupedControlsDefinition, SchemaField } from "./types";
|
|
2
|
+
export declare function applyDefaultValues(v: {
|
|
3
|
+
[k: string]: any;
|
|
4
|
+
} | undefined, fields: SchemaField[]): any;
|
|
5
|
+
export declare function applyDefaultForField(v: any, field: SchemaField, parent: SchemaField[], notElement?: boolean): any;
|
|
6
|
+
export declare function defaultValueForFields(fields: SchemaField[]): any;
|
|
7
|
+
export declare function defaultValueForField(sf: SchemaField): any;
|
|
8
|
+
export declare function elementValueForField(sf: SchemaField): any;
|
|
9
|
+
export declare function findScalarField(fields: SchemaField[], field: string): SchemaField | undefined;
|
|
10
|
+
export declare function findCompoundField(fields: SchemaField[], field: string): CompoundField | undefined;
|
|
11
|
+
export declare function findField(fields: SchemaField[], field: string): SchemaField | undefined;
|
|
12
|
+
export declare function isScalarField(sf: SchemaField): sf is SchemaField;
|
|
13
|
+
export declare function isCompoundField(sf: SchemaField): sf is CompoundField;
|
|
14
|
+
export declare function isDataControl(c: ControlDefinition): c is DataControlDefinition;
|
|
15
|
+
export declare function isGroupControl(c: ControlDefinition): c is GroupedControlsDefinition;
|
|
2
16
|
export declare function fieldHasTag(field: SchemaField, tag: string): boolean;
|
|
3
17
|
export declare function fieldDisplayName(field: SchemaField): string;
|
|
4
18
|
export declare function hasOptions(o: {
|
|
5
19
|
options: FieldOption[] | undefined | null;
|
|
6
20
|
}): boolean;
|
|
21
|
+
export declare function defaultControlForField(sf: SchemaField): DataControlDefinition | GroupedControlsDefinition;
|
|
22
|
+
export declare function addMissingControls(fields: SchemaField[], controls: ControlDefinition[]): ControlDefinition[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-typed-forms/schemas",
|
|
3
|
-
"version": "1.0.0-dev.
|
|
3
|
+
"version": "1.0.0-dev.19",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -25,18 +25,18 @@
|
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@react-typed-forms/core": "^3.0.0-dev.116",
|
|
28
|
-
"
|
|
28
|
+
"clsx": "^1 || ^2",
|
|
29
29
|
"jsonata": "^2.0.3",
|
|
30
|
-
"
|
|
30
|
+
"react": "^18.2.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"typescript": "^5.2.2",
|
|
34
33
|
"@react-typed-forms/transform": "^0.1.0",
|
|
35
34
|
"@types/react": "^18.2.28",
|
|
36
35
|
"microbundle": "^0.15.1",
|
|
37
36
|
"nswag": "^13.18.2",
|
|
37
|
+
"prettier": "^3.0.3",
|
|
38
38
|
"rimraf": "^3.0.2",
|
|
39
|
-
"
|
|
39
|
+
"typescript": "^5.2.2"
|
|
40
40
|
},
|
|
41
41
|
"gitHead": "698e16cd3ab31b7dd0528fc76536f4d3205ce8c6",
|
|
42
42
|
"scripts": {
|
package/src/controlRender.tsx
CHANGED
|
@@ -9,23 +9,15 @@ import {
|
|
|
9
9
|
DisplayControlDefinition,
|
|
10
10
|
EntityExpression,
|
|
11
11
|
FieldOption,
|
|
12
|
-
FieldType,
|
|
13
12
|
GroupedControlsDefinition,
|
|
14
13
|
RenderOptions,
|
|
15
14
|
SchemaField,
|
|
16
15
|
SchemaValidator,
|
|
17
16
|
visitControlDefinition,
|
|
18
17
|
} from "./types";
|
|
19
|
-
import React, {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
Key,
|
|
23
|
-
ReactElement,
|
|
24
|
-
ReactNode,
|
|
25
|
-
useContext,
|
|
26
|
-
} from "react";
|
|
27
|
-
import { Control, newControl } from "@react-typed-forms/core";
|
|
28
|
-
import { fieldDisplayName } from "./util";
|
|
18
|
+
import React, {Context, createContext, Key, ReactElement, ReactNode, useContext,} from "react";
|
|
19
|
+
import {Control, newControl} from "@react-typed-forms/core";
|
|
20
|
+
import {fieldDisplayName, findCompoundField, findField, findScalarField, isDataControl, isGroupControl} from "./util";
|
|
29
21
|
|
|
30
22
|
export interface SchemaHooks {
|
|
31
23
|
useExpression(
|
|
@@ -190,100 +182,10 @@ export interface ActionRendererProps {
|
|
|
190
182
|
onClick: () => void;
|
|
191
183
|
}
|
|
192
184
|
|
|
193
|
-
export function isScalarField(sf: SchemaField): sf is SchemaField {
|
|
194
|
-
return !isCompoundField(sf);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
export function isCompoundField(sf: SchemaField): sf is CompoundField {
|
|
198
|
-
return sf.type === FieldType.Compound;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
185
|
export type AnySchemaFields =
|
|
202
186
|
| SchemaField
|
|
203
187
|
| (Omit<CompoundField, "children"> & { children: AnySchemaFields[] });
|
|
204
188
|
|
|
205
|
-
export function applyDefaultValues(
|
|
206
|
-
v: { [k: string]: any } | undefined,
|
|
207
|
-
fields: SchemaField[],
|
|
208
|
-
): any {
|
|
209
|
-
if (!v) return defaultValueForFields(fields);
|
|
210
|
-
const applyValue = fields.filter(
|
|
211
|
-
(x) => isCompoundField(x) || !(x.field in v),
|
|
212
|
-
);
|
|
213
|
-
if (!applyValue.length) return v;
|
|
214
|
-
const out = { ...v };
|
|
215
|
-
applyValue.forEach((x) => {
|
|
216
|
-
out[x.field] =
|
|
217
|
-
x.field in v
|
|
218
|
-
? applyDefaultForField(v[x.field], x, fields)
|
|
219
|
-
: defaultValueForField(x);
|
|
220
|
-
});
|
|
221
|
-
return out;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export function applyDefaultForField(
|
|
225
|
-
v: any,
|
|
226
|
-
field: SchemaField,
|
|
227
|
-
parent: SchemaField[],
|
|
228
|
-
notElement?: boolean,
|
|
229
|
-
): any {
|
|
230
|
-
if (field.collection && !notElement) {
|
|
231
|
-
return ((v as any[]) ?? []).map((x) =>
|
|
232
|
-
applyDefaultForField(x, field, parent, true),
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
if (isCompoundField(field)) {
|
|
236
|
-
if (!v && !field.required) return v;
|
|
237
|
-
return applyDefaultValues(v, field.treeChildren ? parent : field.children);
|
|
238
|
-
}
|
|
239
|
-
return defaultValueForField(field);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
export function defaultValueForFields(fields: SchemaField[]): any {
|
|
243
|
-
return Object.fromEntries(
|
|
244
|
-
fields.map((x) => [x.field, defaultValueForField(x)]),
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
export function defaultValueForField(sf: SchemaField): any {
|
|
249
|
-
if (isCompoundField(sf)) {
|
|
250
|
-
return sf.required
|
|
251
|
-
? sf.collection
|
|
252
|
-
? []
|
|
253
|
-
: defaultValueForFields(sf.children)
|
|
254
|
-
: undefined;
|
|
255
|
-
}
|
|
256
|
-
if (sf.collection) return [];
|
|
257
|
-
return sf.defaultValue;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
export function elementValueForField(sf: SchemaField): any {
|
|
261
|
-
if (isCompoundField(sf)) {
|
|
262
|
-
return defaultValueForFields(sf.children);
|
|
263
|
-
}
|
|
264
|
-
return sf.defaultValue;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
export function findScalarField(
|
|
268
|
-
fields: SchemaField[],
|
|
269
|
-
field: string,
|
|
270
|
-
): SchemaField | undefined {
|
|
271
|
-
return findField(fields, field);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
export function findCompoundField(
|
|
275
|
-
fields: SchemaField[],
|
|
276
|
-
field: string,
|
|
277
|
-
): CompoundField | undefined {
|
|
278
|
-
return findField(fields, field) as CompoundField | undefined;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
export function findField(
|
|
282
|
-
fields: SchemaField[],
|
|
283
|
-
field: string,
|
|
284
|
-
): SchemaField | undefined {
|
|
285
|
-
return fields.find((x) => x.field === field);
|
|
286
|
-
}
|
|
287
189
|
export function controlTitle(
|
|
288
190
|
title: string | undefined | null,
|
|
289
191
|
field: SchemaField,
|
|
@@ -437,18 +339,6 @@ export function fieldForControl(c: ControlDefinition) {
|
|
|
437
339
|
: undefined;
|
|
438
340
|
}
|
|
439
341
|
|
|
440
|
-
export function isDataControl(
|
|
441
|
-
c: ControlDefinition,
|
|
442
|
-
): c is DataControlDefinition {
|
|
443
|
-
return c.type === ControlDefinitionType.Data;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
export function isGroupControl(
|
|
447
|
-
c: ControlDefinition,
|
|
448
|
-
): c is GroupedControlsDefinition {
|
|
449
|
-
return c.type === ControlDefinitionType.Group;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
342
|
export const AlwaysVisible: Visibility = { value: true, canChange: false };
|
|
453
343
|
|
|
454
344
|
export function createAction(
|
package/src/hooks.tsx
CHANGED
|
@@ -23,15 +23,10 @@ import {
|
|
|
23
23
|
controlForField,
|
|
24
24
|
controlTitle,
|
|
25
25
|
DataRendererProps,
|
|
26
|
-
elementValueForField,
|
|
27
26
|
fieldForControl,
|
|
28
|
-
findCompoundField,
|
|
29
|
-
findField,
|
|
30
27
|
FormEditHooks,
|
|
31
28
|
FormEditState,
|
|
32
29
|
GroupRendererProps,
|
|
33
|
-
isGroupControl,
|
|
34
|
-
isScalarField,
|
|
35
30
|
renderControl,
|
|
36
31
|
SchemaHooks,
|
|
37
32
|
Visibility,
|
|
@@ -49,6 +44,14 @@ import {
|
|
|
49
44
|
useValidator,
|
|
50
45
|
} from "@react-typed-forms/core";
|
|
51
46
|
import jsonata from "jsonata";
|
|
47
|
+
import {
|
|
48
|
+
addMissingControls,
|
|
49
|
+
elementValueForField,
|
|
50
|
+
findCompoundField,
|
|
51
|
+
findField,
|
|
52
|
+
isGroupControl,
|
|
53
|
+
isScalarField,
|
|
54
|
+
} from "./util";
|
|
52
55
|
|
|
53
56
|
export function useDefaultValue(
|
|
54
57
|
definition: DataControlDefinition,
|
|
@@ -140,7 +143,7 @@ export function getDefaultScalarControlProperties(
|
|
|
140
143
|
export function getOptionsForScalarField(
|
|
141
144
|
field: SchemaField,
|
|
142
145
|
): FieldOption[] | undefined | null {
|
|
143
|
-
const opts = field.options
|
|
146
|
+
const opts = field.options;
|
|
144
147
|
if (opts?.length ?? 0 > 0) {
|
|
145
148
|
return opts;
|
|
146
149
|
}
|
|
@@ -423,3 +426,16 @@ function defaultArrayRendererProps(
|
|
|
423
426
|
},
|
|
424
427
|
};
|
|
425
428
|
}
|
|
429
|
+
|
|
430
|
+
export function useControlsWithDefaults(
|
|
431
|
+
definition: GroupedControlsDefinition,
|
|
432
|
+
sf: SchemaField[],
|
|
433
|
+
) {
|
|
434
|
+
return useMemo(
|
|
435
|
+
() =>
|
|
436
|
+
definition.children.length
|
|
437
|
+
? definition
|
|
438
|
+
: { ...definition, children: addMissingControls(sf, []) },
|
|
439
|
+
[sf, definition],
|
|
440
|
+
);
|
|
441
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -12,10 +12,6 @@ export interface SchemaField {
|
|
|
12
12
|
searchable?: boolean | null;
|
|
13
13
|
options?: FieldOption[] | null;
|
|
14
14
|
validators?: SchemaValidator[] | null;
|
|
15
|
-
/**
|
|
16
|
-
* @deprecated Use options directly
|
|
17
|
-
*/
|
|
18
|
-
restrictions?: SchemaRestrictions | undefined | null;
|
|
19
15
|
}
|
|
20
16
|
|
|
21
17
|
export enum FieldType {
|
|
@@ -38,10 +34,6 @@ export interface EntityRefField extends SchemaField {
|
|
|
38
34
|
parentField: string;
|
|
39
35
|
}
|
|
40
36
|
|
|
41
|
-
export interface SchemaRestrictions {
|
|
42
|
-
options?: FieldOption[] | null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
37
|
export interface FieldOption {
|
|
46
38
|
name: string;
|
|
47
39
|
value: any;
|
package/src/util.ts
CHANGED
|
@@ -1,4 +1,119 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
CompoundField,
|
|
3
|
+
ControlDefinition,
|
|
4
|
+
ControlDefinitionType,
|
|
5
|
+
DataControlDefinition,
|
|
6
|
+
DataRenderType,
|
|
7
|
+
FieldOption,
|
|
8
|
+
FieldType,
|
|
9
|
+
GridRenderer,
|
|
10
|
+
GroupedControlsDefinition,
|
|
11
|
+
GroupRenderType,
|
|
12
|
+
SchemaField,
|
|
13
|
+
} from "./types";
|
|
14
|
+
|
|
15
|
+
export function applyDefaultValues(
|
|
16
|
+
v: { [k: string]: any } | undefined,
|
|
17
|
+
fields: SchemaField[],
|
|
18
|
+
): any {
|
|
19
|
+
if (!v) return defaultValueForFields(fields);
|
|
20
|
+
const applyValue = fields.filter(
|
|
21
|
+
(x) => isCompoundField(x) || !(x.field in v),
|
|
22
|
+
);
|
|
23
|
+
if (!applyValue.length) return v;
|
|
24
|
+
const out = { ...v };
|
|
25
|
+
applyValue.forEach((x) => {
|
|
26
|
+
out[x.field] =
|
|
27
|
+
x.field in v
|
|
28
|
+
? applyDefaultForField(v[x.field], x, fields)
|
|
29
|
+
: defaultValueForField(x);
|
|
30
|
+
});
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function applyDefaultForField(
|
|
35
|
+
v: any,
|
|
36
|
+
field: SchemaField,
|
|
37
|
+
parent: SchemaField[],
|
|
38
|
+
notElement?: boolean,
|
|
39
|
+
): any {
|
|
40
|
+
if (field.collection && !notElement) {
|
|
41
|
+
return ((v as any[]) ?? []).map((x) =>
|
|
42
|
+
applyDefaultForField(x, field, parent, true),
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
if (isCompoundField(field)) {
|
|
46
|
+
if (!v && !field.required) return v;
|
|
47
|
+
return applyDefaultValues(v, field.treeChildren ? parent : field.children);
|
|
48
|
+
}
|
|
49
|
+
return defaultValueForField(field);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function defaultValueForFields(fields: SchemaField[]): any {
|
|
53
|
+
return Object.fromEntries(
|
|
54
|
+
fields.map((x) => [x.field, defaultValueForField(x)]),
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function defaultValueForField(sf: SchemaField): any {
|
|
59
|
+
if (isCompoundField(sf)) {
|
|
60
|
+
return sf.required
|
|
61
|
+
? sf.collection
|
|
62
|
+
? []
|
|
63
|
+
: defaultValueForFields(sf.children)
|
|
64
|
+
: undefined;
|
|
65
|
+
}
|
|
66
|
+
if (sf.collection) return [];
|
|
67
|
+
return sf.defaultValue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function elementValueForField(sf: SchemaField): any {
|
|
71
|
+
if (isCompoundField(sf)) {
|
|
72
|
+
return defaultValueForFields(sf.children);
|
|
73
|
+
}
|
|
74
|
+
return sf.defaultValue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function findScalarField(
|
|
78
|
+
fields: SchemaField[],
|
|
79
|
+
field: string,
|
|
80
|
+
): SchemaField | undefined {
|
|
81
|
+
return findField(fields, field);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function findCompoundField(
|
|
85
|
+
fields: SchemaField[],
|
|
86
|
+
field: string,
|
|
87
|
+
): CompoundField | undefined {
|
|
88
|
+
return findField(fields, field) as CompoundField | undefined;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function findField(
|
|
92
|
+
fields: SchemaField[],
|
|
93
|
+
field: string,
|
|
94
|
+
): SchemaField | undefined {
|
|
95
|
+
return fields.find((x) => x.field === field);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function isScalarField(sf: SchemaField): sf is SchemaField {
|
|
99
|
+
return !isCompoundField(sf);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function isCompoundField(sf: SchemaField): sf is CompoundField {
|
|
103
|
+
return sf.type === FieldType.Compound;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function isDataControl(
|
|
107
|
+
c: ControlDefinition,
|
|
108
|
+
): c is DataControlDefinition {
|
|
109
|
+
return c.type === ControlDefinitionType.Data;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function isGroupControl(
|
|
113
|
+
c: ControlDefinition,
|
|
114
|
+
): c is GroupedControlsDefinition {
|
|
115
|
+
return c.type === ControlDefinitionType.Group;
|
|
116
|
+
}
|
|
2
117
|
|
|
3
118
|
export function fieldHasTag(field: SchemaField, tag: string) {
|
|
4
119
|
return Boolean(field.tags?.includes(tag));
|
|
@@ -11,3 +126,87 @@ export function fieldDisplayName(field: SchemaField) {
|
|
|
11
126
|
export function hasOptions(o: { options: FieldOption[] | undefined | null }) {
|
|
12
127
|
return (o.options?.length ?? 0) > 0;
|
|
13
128
|
}
|
|
129
|
+
|
|
130
|
+
export function defaultControlForField(
|
|
131
|
+
sf: SchemaField,
|
|
132
|
+
): DataControlDefinition | GroupedControlsDefinition {
|
|
133
|
+
if (isCompoundField(sf)) {
|
|
134
|
+
return {
|
|
135
|
+
type: ControlDefinitionType.Group,
|
|
136
|
+
title: sf.displayName,
|
|
137
|
+
compoundField: sf.field,
|
|
138
|
+
groupOptions: {
|
|
139
|
+
type: GroupRenderType.Grid,
|
|
140
|
+
hideTitle: false,
|
|
141
|
+
} as GridRenderer,
|
|
142
|
+
children: sf.children.map(defaultControlForField),
|
|
143
|
+
} satisfies GroupedControlsDefinition;
|
|
144
|
+
} else if (isScalarField(sf)) {
|
|
145
|
+
const htmlEditor = sf.tags?.includes("_HtmlEditor");
|
|
146
|
+
return {
|
|
147
|
+
type: ControlDefinitionType.Data,
|
|
148
|
+
title: sf.displayName,
|
|
149
|
+
field: sf.field,
|
|
150
|
+
required: sf.required,
|
|
151
|
+
renderOptions: {
|
|
152
|
+
type: htmlEditor ? DataRenderType.HtmlEditor : DataRenderType.Standard,
|
|
153
|
+
},
|
|
154
|
+
} satisfies DataControlDefinition;
|
|
155
|
+
}
|
|
156
|
+
throw "Unknown schema field";
|
|
157
|
+
}
|
|
158
|
+
function findReferencedControl(
|
|
159
|
+
field: string,
|
|
160
|
+
control: ControlDefinition,
|
|
161
|
+
): ControlDefinition | undefined {
|
|
162
|
+
if (isDataControl(control) && field === control.field) return control;
|
|
163
|
+
if (isGroupControl(control)) {
|
|
164
|
+
if (control.compoundField)
|
|
165
|
+
return field === control.compoundField ? control : undefined;
|
|
166
|
+
return findReferencedControlInArray(field, control.children);
|
|
167
|
+
}
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function findReferencedControlInArray(
|
|
172
|
+
field: string,
|
|
173
|
+
controls: ControlDefinition[],
|
|
174
|
+
): ControlDefinition | undefined {
|
|
175
|
+
for (const c of controls) {
|
|
176
|
+
const ref = findReferencedControl(field, c);
|
|
177
|
+
if (ref) return ref;
|
|
178
|
+
}
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function addMissingControls(
|
|
183
|
+
fields: SchemaField[],
|
|
184
|
+
controls: ControlDefinition[],
|
|
185
|
+
): ControlDefinition[] {
|
|
186
|
+
const changes: {
|
|
187
|
+
field: SchemaField;
|
|
188
|
+
existing: ControlDefinition | undefined;
|
|
189
|
+
}[] = fields.flatMap((x) => {
|
|
190
|
+
if (fieldHasTag(x, "_NoControl")) return [];
|
|
191
|
+
const existing = findReferencedControlInArray(x.field, controls);
|
|
192
|
+
if (!existing || isCompoundField(x)) return { field: x, existing };
|
|
193
|
+
return [];
|
|
194
|
+
});
|
|
195
|
+
const changedCompounds = controls.map((x) => {
|
|
196
|
+
const ex = changes.find((c) => c.existing === x);
|
|
197
|
+
if (!ex) return x;
|
|
198
|
+
const cf = x as GroupedControlsDefinition;
|
|
199
|
+
return {
|
|
200
|
+
...cf,
|
|
201
|
+
children: addMissingControls(
|
|
202
|
+
(ex.field as CompoundField).children,
|
|
203
|
+
cf.children,
|
|
204
|
+
),
|
|
205
|
+
};
|
|
206
|
+
});
|
|
207
|
+
return changedCompounds.concat(
|
|
208
|
+
changes
|
|
209
|
+
.filter((x) => !x.existing)
|
|
210
|
+
.map((x) => defaultControlForField(x.field)),
|
|
211
|
+
);
|
|
212
|
+
}
|