@docupace/ihub-config 1.1.26 → 1.1.27

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.
Files changed (37) hide show
  1. package/dist/config-extension.d.ts +15 -2
  2. package/dist/config-extension.d.ts.map +1 -1
  3. package/dist/config-extension.js.map +1 -1
  4. package/dist/config-service.d.ts +6 -2
  5. package/dist/config-service.d.ts.map +1 -1
  6. package/dist/config-service.js +71 -66
  7. package/dist/config-service.js.map +1 -1
  8. package/dist/index.d.ts +2 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/lib/named-array-merge.d.ts +29 -0
  13. package/dist/lib/named-array-merge.d.ts.map +1 -0
  14. package/dist/lib/named-array-merge.js +158 -0
  15. package/dist/lib/named-array-merge.js.map +1 -0
  16. package/dist/mappers/config-mapper.d.ts.map +1 -1
  17. package/dist/mappers/config-mapper.js +1 -0
  18. package/dist/mappers/config-mapper.js.map +1 -1
  19. package/dist/model/graphs/config/fields.graphql +15 -0
  20. package/dist/model/graphs/config/panel.graphql +7 -0
  21. package/dist/model/graphs/config/ui-components.graphql +1 -0
  22. package/dist/providers/index.d.ts +4 -0
  23. package/dist/providers/index.d.ts.map +1 -1
  24. package/dist/providers/index.js +5 -0
  25. package/dist/providers/index.js.map +1 -1
  26. package/dist/providers/screen-layout-patch.d.ts +6 -0
  27. package/dist/providers/screen-layout-patch.d.ts.map +1 -0
  28. package/dist/providers/screen-layout-patch.js +57 -0
  29. package/dist/providers/screen-layout-patch.js.map +1 -0
  30. package/dist/providers/whole-patch.d.ts +6 -0
  31. package/dist/providers/whole-patch.d.ts.map +1 -0
  32. package/dist/providers/whole-patch.js +2 -0
  33. package/dist/providers/whole-patch.js.map +1 -0
  34. package/model/graphs/config/fields.graphql +15 -0
  35. package/model/graphs/config/panel.graphql +7 -0
  36. package/model/graphs/config/ui-components.graphql +1 -0
  37. package/package.json +1 -1
@@ -0,0 +1,29 @@
1
+ export type NamedObject = Record<string, unknown> & {
2
+ name: string;
3
+ };
4
+ export declare function isNamedObjectArray(value: unknown): value is NamedObject[];
5
+ export declare function mergeMatchedFields<T extends Record<string, unknown>>(base: T, override: T, isSelfContained: (item: NamedObject) => boolean, stampCustom?: boolean): T;
6
+ /**
7
+ * Folds `override` onto `base`, both arrays of named objects: matched-by-name pairs
8
+ * merge (recursively — see `mergeMatchedFields`), an override entry with no base match
9
+ * is kept when `isSelfContained` says it stands on its own and dropped otherwise, and
10
+ * any base entry the override never mentions is appended, unchanged, after the merged
11
+ * entries (in their original relative order). Final order is exactly the order
12
+ * produced above — override order first, then untouched base leftovers.
13
+ *
14
+ * `stampCustom`, when true, additionally marks every entry this call produces with
15
+ * `custom: boolean` — `true` for a self-contained override entry with no base
16
+ * counterpart (an insertion, stamped all the way through its own nested named-object
17
+ * arrays via `deepStampCustom`, since the whole subtree is equally new), `false` for a
18
+ * matched pair or an untouched base entry (present in the base config, whether or not
19
+ * this override touches its own attributes). This is Screen Designer's whole-object-patch
20
+ * equivalent of `Column.inherited`/`TableCriteria.inherited`, computed in one pass here
21
+ * rather than `ConfigService`'s separate `stampInherited` fold — that fold exists to
22
+ * answer "would this survive without *this identity's own scope tier*" across several
23
+ * cascaded layers, a question that doesn't arise for a single whole-object patch with no
24
+ * tiers: the one merge pass already knows, per item, whether a base counterpart exists.
25
+ * `false` (the default) leaves `Table.columns`/`filter.criteria` — the other caller of
26
+ * this function — completely unaffected.
27
+ */
28
+ export declare function mergeNamedObjectArray(base: NamedObject[], override: NamedObject[], isSelfContained: (item: NamedObject) => boolean, stampCustom?: boolean): NamedObject[];
29
+ //# sourceMappingURL=named-array-merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"named-array-merge.d.ts","sourceRoot":"","sources":["../../src/lib/named-array-merge.ts"],"names":[],"mappings":"AA+BA,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,EAAE,CAUzE;AA+DD,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,IAAI,EAAE,CAAC,EACP,QAAQ,EAAE,CAAC,EACX,eAAe,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,EAC/C,WAAW,UAAQ,GAClB,CAAC,CAsBH;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,WAAW,EAAE,EACnB,QAAQ,EAAE,WAAW,EAAE,EACvB,eAAe,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,EAC/C,WAAW,UAAQ,GAClB,WAAW,EAAE,CAuCf"}
@@ -0,0 +1,158 @@
1
+ // Generic merge semantics for a config-path override against the base value it
2
+ // overrides. Originally built only for `Table.columns`/`filter.criteria` (flat arrays),
3
+ // generalized here so a nested tree of named-object arrays (e.g. Screen Designer's
4
+ // tabs → rows → elements) resolves through the exact same algorithm — see
5
+ // `ConfigService`'s `mergeSubPathOverrideValue` (subPath overrides) and
6
+ // `WholePatchMerger` implementations such as `ScreenLayoutPatchMerger` (whole-object
7
+ // patch overrides), the current callers of `mergeMatchedFields`/`mergeNamedObjectArray`
8
+ // respectively.
9
+ //
10
+ // When both the current value and the override value are arrays of objects each
11
+ // carrying a string `name`, override elements are merged onto their base counterpart by
12
+ // name (override wins per-attribute, everything else inherited) instead of the override
13
+ // replacing the array wholesale. This is what makes a saved override non-destructive:
14
+ // - Reordering falls out of the override array's own element order.
15
+ // - "Hiding" an element is an attribute override (e.g. `visible: false`) on an element
16
+ // that's still present, not a deletion.
17
+ // - A base element the override never mentions is appended unchanged, so a base
18
+ // element added later still surfaces for someone with an existing override, instead
19
+ // of being permanently absent from their frozen array.
20
+ // - An override element naming something not found in the base is kept as-is when the
21
+ // caller's `isSelfContained` predicate says it carries enough of its own definition
22
+ // to stand alone (e.g. a hand-authored column, or a brand-new Screen Designer node),
23
+ // or silently dropped when it's a thin reference whose target no longer exists — this
24
+ // never throws; the stale reference just doesn't round-trip into the next save.
25
+ //
26
+ // A matched pair is merged field-by-field, recursing into any nested named-object array
27
+ // or plain-object wrapper found on both sides (see `mergeMatchedFields`) — needed for a
28
+ // nested tree like Screen Designer's `Tab.page.panel.rows`/`PanelRow.elements`, and a
29
+ // no-op for a flat shape like `Column`/`TableCriteria`, which have no such nested field
30
+ // to recurse into.
31
+ export function isNamedObjectArray(value) {
32
+ return (Array.isArray(value) &&
33
+ value.every((item) => item !== null &&
34
+ typeof item === 'object' &&
35
+ typeof item.name === 'string'));
36
+ }
37
+ function isPlainObject(value) {
38
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
39
+ }
40
+ // Recursively stamps `custom` onto `item` and every named-object-array descendant it
41
+ // carries (e.g. a freshly-inserted row's own freshly-inserted elements) — used only for
42
+ // a self-contained override item with no base counterpart at all, where the whole
43
+ // subtree is equally new and none of it can be found by a further name lookup. Plain
44
+ // object wrappers (e.g. `Tab.page`) are walked through but never stamped themselves —
45
+ // only actual named-object-array entries (tabs/rows/elements) carry `custom`.
46
+ function deepStampCustom(item, custom) {
47
+ const stamped = { ...item, custom };
48
+ for (const key of Object.keys(item)) {
49
+ const value = item[key];
50
+ if (isNamedObjectArray(value)) {
51
+ stamped[key] = value.map((child) => deepStampCustom(child, custom));
52
+ }
53
+ else if (isPlainObject(value)) {
54
+ stamped[key] = deepStampCustomInPlainObject(value, custom);
55
+ }
56
+ }
57
+ return stamped;
58
+ }
59
+ function deepStampCustomInPlainObject(obj, custom) {
60
+ const result = { ...obj };
61
+ for (const key of Object.keys(obj)) {
62
+ const value = obj[key];
63
+ if (isNamedObjectArray(value)) {
64
+ result[key] = value.map((child) => deepStampCustom(child, custom));
65
+ }
66
+ else if (isPlainObject(value)) {
67
+ result[key] = deepStampCustomInPlainObject(value, custom);
68
+ }
69
+ }
70
+ return result;
71
+ }
72
+ // Merges a matched base/override pair field-by-field: override wins per-attribute
73
+ // (the base spread first, then the override spread over it), except that a field
74
+ // present as a named-object array or plain object on *both* sides recurses instead of
75
+ // the override's value flatly overwriting the base's whole subtree — otherwise a
76
+ // row's `elements` (or a tab's `page`) would be silently replaced/truncated by
77
+ // whatever the override happens to carry for that field, rather than merged the same
78
+ // name-keyed way as the top level.
79
+ //
80
+ // Exported (not just used internally by mergeNamedObjectArray) so a whole-object patch
81
+ // override — one that doesn't come pre-split by JSONPath the way subPath overrides do —
82
+ // can be folded onto a fully resolved config the same generic way, field by field,
83
+ // instead of a caller having to know which top-level field(s) the patch touches. See
84
+ // `WholePatchMerger` in `providers/whole-patch.ts`.
85
+ //
86
+ // `stampCustom` (off by default, so the existing `Table.columns`/`filter.criteria`
87
+ // sub-path merge is unaffected) tells `mergeNamedObjectArray` to also stamp each
88
+ // named-object-array entry it produces with `custom: boolean` — see that function's own
89
+ // doc comment for what it means and why it's computed here rather than the multi-tier
90
+ // way `ConfigService`'s own `inherited` is (`stampInherited`).
91
+ export function mergeMatchedFields(base, override, isSelfContained, stampCustom = false) {
92
+ const merged = { ...base, ...override };
93
+ for (const key of Object.keys(override)) {
94
+ const baseValue = base[key];
95
+ const overrideValue = override[key];
96
+ if (isNamedObjectArray(baseValue) && isNamedObjectArray(overrideValue)) {
97
+ merged[key] = mergeNamedObjectArray(baseValue, overrideValue, isSelfContained, stampCustom);
98
+ }
99
+ else if (isPlainObject(baseValue) && isPlainObject(overrideValue)) {
100
+ merged[key] = mergeMatchedFields(baseValue, overrideValue, isSelfContained, stampCustom);
101
+ }
102
+ }
103
+ return merged;
104
+ }
105
+ /**
106
+ * Folds `override` onto `base`, both arrays of named objects: matched-by-name pairs
107
+ * merge (recursively — see `mergeMatchedFields`), an override entry with no base match
108
+ * is kept when `isSelfContained` says it stands on its own and dropped otherwise, and
109
+ * any base entry the override never mentions is appended, unchanged, after the merged
110
+ * entries (in their original relative order). Final order is exactly the order
111
+ * produced above — override order first, then untouched base leftovers.
112
+ *
113
+ * `stampCustom`, when true, additionally marks every entry this call produces with
114
+ * `custom: boolean` — `true` for a self-contained override entry with no base
115
+ * counterpart (an insertion, stamped all the way through its own nested named-object
116
+ * arrays via `deepStampCustom`, since the whole subtree is equally new), `false` for a
117
+ * matched pair or an untouched base entry (present in the base config, whether or not
118
+ * this override touches its own attributes). This is Screen Designer's whole-object-patch
119
+ * equivalent of `Column.inherited`/`TableCriteria.inherited`, computed in one pass here
120
+ * rather than `ConfigService`'s separate `stampInherited` fold — that fold exists to
121
+ * answer "would this survive without *this identity's own scope tier*" across several
122
+ * cascaded layers, a question that doesn't arise for a single whole-object patch with no
123
+ * tiers: the one merge pass already knows, per item, whether a base counterpart exists.
124
+ * `false` (the default) leaves `Table.columns`/`filter.criteria` — the other caller of
125
+ * this function — completely unaffected.
126
+ */
127
+ export function mergeNamedObjectArray(base, override, isSelfContained, stampCustom = false) {
128
+ const baseByName = new Map(base.map((item) => [item.name, item]));
129
+ const merged = [];
130
+ const seenNames = new Set();
131
+ for (const overrideItem of override) {
132
+ // Guard against a corrupted/hand-edited override array carrying two elements with
133
+ // the same name — only the first is kept, so the merged result never has
134
+ // duplicate names.
135
+ if (seenNames.has(overrideItem.name)) {
136
+ continue;
137
+ }
138
+ seenNames.add(overrideItem.name);
139
+ const baseItem = baseByName.get(overrideItem.name);
140
+ if (baseItem) {
141
+ const mergedItem = mergeMatchedFields(baseItem, overrideItem, isSelfContained, stampCustom);
142
+ merged.push(stampCustom ? { ...mergedItem, custom: false } : mergedItem);
143
+ }
144
+ else if (isSelfContained(overrideItem)) {
145
+ merged.push(stampCustom ? deepStampCustom(overrideItem, true) : overrideItem);
146
+ }
147
+ // else: a thin reference to a name that no longer resolves — drop it.
148
+ }
149
+ const mergedNames = new Set(merged.map((item) => item.name));
150
+ const untouchedBaseItems = base.filter((item) => !mergedNames.has(item.name));
151
+ return [
152
+ ...merged,
153
+ ...(stampCustom
154
+ ? untouchedBaseItems.map((item) => ({ ...item, custom: false }))
155
+ : untouchedBaseItems),
156
+ ];
157
+ }
158
+ //# sourceMappingURL=named-array-merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"named-array-merge.js","sourceRoot":"","sources":["../../src/lib/named-array-merge.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"config-mapper.d.ts","sourceRoot":"","sources":["../../src/mappers/config-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAGrE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,MAAM,MAAM,iBAAiB,GAAG,KAAK,KAAK,EAAE,KAAK,KAAK,cAAc,CAAC;AAErE,wBAAgB,uBAAuB,CACrC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,iBAAiB,CAiBnB"}
1
+ {"version":3,"file":"config-mapper.d.ts","sourceRoot":"","sources":["../../src/mappers/config-mapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAGrE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,MAAM,MAAM,iBAAiB,GAAG,KAAK,KAAK,EAAE,KAAK,KAAK,cAAc,CAAC;AAErE,wBAAgB,uBAAuB,CACrC,OAAO,CAAC,EAAE,sBAAsB,GAC/B,iBAAiB,CAkBnB"}
@@ -12,6 +12,7 @@ export function createConfigMapperClass(options) {
12
12
  configStores: options?.configStores ?? getConfigStores(),
13
13
  configInjectorResolvers: options?.configInjectorResolvers,
14
14
  providers: options?.providers,
15
+ wholePatchMergers: options?.wholePatchMergers,
15
16
  resolvers: options?.resolvers,
16
17
  configurationOverrideProvider: options?.configurationOverrideProvider,
17
18
  });
@@ -1 +1 @@
1
- {"version":3,"file":"config-mapper.js","sourceRoot":"","sources":["../../src/mappers/config-mapper.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAI7D,MAAM,UAAU,uBAAuB,CACrC,OAAgC;IAEhC,OAAO,MAAM,YAAa,SAAQ,cAAc;QAC9C,YAAY,KAAY;YACtB,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACzB,CAAC;QAED,IAAI;YACF,oBAAoB,CAAC;gBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,YAAY,EAAE,OAAO,EAAE,YAAY,IAAI,eAAe,EAAE;gBACxD,uBAAuB,EAAE,OAAO,EAAE,uBAAuB;gBACzD,SAAS,EAAE,OAAO,EAAE,SAAS;gBAC7B,SAAS,EAAE,OAAO,EAAE,SAAS;gBAC7B,6BAA6B,EAAE,OAAO,EAAE,6BAA6B;aACtE,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"config-mapper.js","sourceRoot":"","sources":["../../src/mappers/config-mapper.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAI7D,MAAM,UAAU,uBAAuB,CACrC,OAAgC;IAEhC,OAAO,MAAM,YAAa,SAAQ,cAAc;QAC9C,YAAY,KAAY;YACtB,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACzB,CAAC;QAED,IAAI;YACF,oBAAoB,CAAC;gBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,YAAY,EAAE,OAAO,EAAE,YAAY,IAAI,eAAe,EAAE;gBACxD,uBAAuB,EAAE,OAAO,EAAE,uBAAuB;gBACzD,SAAS,EAAE,OAAO,EAAE,SAAS;gBAC7B,iBAAiB,EAAE,OAAO,EAAE,iBAAiB;gBAC7C,SAAS,EAAE,OAAO,EAAE,SAAS;gBAC7B,6BAA6B,EAAE,OAAO,EAAE,6BAA6B;aACtE,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -64,12 +64,14 @@ type InputField implements IField & IRowElement & IElement {
64
64
  maxRows: Int
65
65
  minRows: Int
66
66
  # End of text area configuration
67
+ custom: Boolean
67
68
  }
68
69
 
69
70
  type CustomValidator implements IRowElement & IElement {
70
71
  validationRule: String
71
72
  errorMessage: String
72
73
  paths: [String!]!
74
+ custom: Boolean
73
75
  }
74
76
 
75
77
  union Fields = InputField | PhoneField | DateField | DateRangeField | SelectField | ToggleField | BooleanField | TextElement
@@ -93,6 +95,7 @@ type RepeaterField implements IRowElement & IElement {
93
95
  validateUnique: Boolean
94
96
  duplicateMessage: String
95
97
  itemValidation: ItemValidation
98
+ custom: Boolean
96
99
  }
97
100
 
98
101
  type ControlGroup implements IRowElement & IElement {
@@ -101,6 +104,7 @@ type ControlGroup implements IRowElement & IElement {
101
104
  skipId: Boolean
102
105
  controlOptions: ISelectOptions!
103
106
  fields: [Fields!]!
107
+ custom: Boolean
104
108
  }
105
109
 
106
110
  # Renders the currently-linked records of a multi-valued reference attribute
@@ -131,6 +135,7 @@ type ReferenceTable implements IField & IRowElement & IElement {
131
135
  confirmDelete: Boolean
132
136
  maxRows: Int
133
137
  rowMenuItems: [MenuItem!]
138
+ custom: Boolean
134
139
  }
135
140
 
136
141
  type PhoneField implements IField & IRowElement & IElement {
@@ -149,6 +154,7 @@ type PhoneField implements IField & IRowElement & IElement {
149
154
  visibilityCondition: String
150
155
  disabledCondition: String
151
156
  validation: GenericFieldValidation
157
+ custom: Boolean
152
158
  }
153
159
 
154
160
  type DateField implements IField & IRowElement & IElement {
@@ -168,6 +174,7 @@ type DateField implements IField & IRowElement & IElement {
168
174
  minDate: String # e.q. "now" or "2025-03-20"
169
175
  maxDate: String # e.q. "now" or "2025-03-20"
170
176
  validation: GenericFieldValidation
177
+ custom: Boolean
171
178
  }
172
179
 
173
180
  type DateRangeField implements IDateRangeField & IRowElement & IElement {
@@ -187,6 +194,7 @@ type DateRangeField implements IDateRangeField & IRowElement & IElement {
187
194
  visibilityCondition: String
188
195
  disabledCondition: String
189
196
  validation: GenericFieldValidation
197
+ custom: Boolean
190
198
  }
191
199
 
192
200
  type SelectField implements IField & IRowElement & IElement {
@@ -212,6 +220,7 @@ type SelectField implements IField & IRowElement & IElement {
212
220
  helperText: String
213
221
  autoSelectSingleOption: Boolean
214
222
  validation: GenericFieldValidation
223
+ custom: Boolean
215
224
  }
216
225
 
217
226
  type ToggleField implements IField & IRowElement & IElement {
@@ -234,6 +243,7 @@ type ToggleField implements IField & IRowElement & IElement {
234
243
  disabledCondition: String
235
244
  linkedFields: [String!]
236
245
  validation: GenericFieldValidation
246
+ custom: Boolean
237
247
  }
238
248
 
239
249
  type BooleanField implements IField & IRowElement & IElement {
@@ -252,6 +262,7 @@ type BooleanField implements IField & IRowElement & IElement {
252
262
  disabledCondition: String
253
263
  linkedFields: [String!]
254
264
  validation: GenericFieldValidation
265
+ custom: Boolean
255
266
  }
256
267
 
257
268
  type ChipSelectWithInputField implements IField & IRowElement & IElement {
@@ -277,6 +288,7 @@ type ChipSelectWithInputField implements IField & IRowElement & IElement {
277
288
  disabledCondition: String
278
289
  linkedFields: [String!]
279
290
  validation: ChipSelectValidation
291
+ custom: Boolean
280
292
  }
281
293
 
282
294
  type CustomField implements IField & IRowElement & IElement {
@@ -296,6 +308,7 @@ type CustomField implements IField & IRowElement & IElement {
296
308
  visibilityCondition: String
297
309
  disabledCondition: String
298
310
  validation: GenericFieldValidation
311
+ custom: Boolean
299
312
  }
300
313
 
301
314
  type StatusChipField implements IField & IRowElement & IElement {
@@ -305,6 +318,7 @@ type StatusChipField implements IField & IRowElement & IElement {
305
318
  name: String!
306
319
  path: String!
307
320
  validation: GenericFieldValidation
321
+ custom: Boolean
308
322
  }
309
323
 
310
324
  type CheckboxGroupValue {
@@ -325,6 +339,7 @@ type CheckboxGroup implements IRowElement & IElement {
325
339
  values: [CheckboxGroupValue!]!
326
340
  visibilityCondition: String
327
341
  disabledCondition: String
342
+ custom: Boolean
328
343
  }
329
344
 
330
345
  enum FieldValueType {
@@ -27,4 +27,11 @@ type PanelRow implements IPanelRow {
27
27
  title: String
28
28
  titleVariant: String
29
29
  visibilityCondition: String
30
+ """
31
+ Screen Designer: true when this group exists only via the screen layout patch — no
32
+ counterpart in the raw base config — vs. `false`/absent for a real group (whether or
33
+ not the patch also overrides some of its properties). See `Tab.custom` for the full
34
+ reasoning; stamped the same way, one level down the tree.
35
+ """
36
+ custom: Boolean
30
37
  }
@@ -8,4 +8,5 @@ type TextElement implements IRowElement & IElement {
8
8
  valueExpression: String
9
9
  variant: String
10
10
  visibilityCondition: String
11
+ custom: Boolean
11
12
  }
@@ -1,4 +1,8 @@
1
1
  import { ConfigProviders } from './base-config.js';
2
+ import type { WholePatchMergers } from './whole-patch.js';
2
3
  export declare const builtInProviders: ConfigProviders;
4
+ export declare const builtInWholePatchMergers: WholePatchMergers;
3
5
  export type { ConfigProviders } from './base-config.js';
6
+ export type { WholePatchMerger, WholePatchMergers } from './whole-patch.js';
7
+ export { SCREEN_LAYOUT_PATCH_CONTENT_TYPE } from './screen-layout-patch.js';
4
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGnD,eAAO,MAAM,gBAAgB,EAAE,eAE9B,CAAC;AAEF,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAMnD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,eAAO,MAAM,gBAAgB,EAAE,eAE9B,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,iBAEtC,CAAC;AAEF,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACxD,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EAAE,gCAAgC,EAAE,MAAM,0BAA0B,CAAC"}
@@ -1,5 +1,10 @@
1
1
  import { DashboardPageConfigProvider } from './dashboard-page-config.js';
2
+ import { ScreenLayoutPatchMerger, SCREEN_LAYOUT_PATCH_CONTENT_TYPE, } from './screen-layout-patch.js';
2
3
  export const builtInProviders = {
3
4
  DashboardPage: DashboardPageConfigProvider,
4
5
  };
6
+ export const builtInWholePatchMergers = {
7
+ [SCREEN_LAYOUT_PATCH_CONTENT_TYPE]: new ScreenLayoutPatchMerger(),
8
+ };
9
+ export { SCREEN_LAYOUT_PATCH_CONTENT_TYPE } from './screen-layout-patch.js';
5
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAEzE,MAAM,CAAC,MAAM,gBAAgB,GAAoB;IAC/C,aAAa,EAAE,2BAA2B;CAC3C,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EACL,uBAAuB,EACvB,gCAAgC,GACjC,MAAM,0BAA0B,CAAC;AAGlC,MAAM,CAAC,MAAM,gBAAgB,GAAoB;IAC/C,aAAa,EAAE,2BAA2B;CAC3C,CAAC;AAEF,MAAM,CAAC,MAAM,wBAAwB,GAAsB;IACzD,CAAC,gCAAgC,CAAC,EAAE,IAAI,uBAAuB,EAAE;CAClE,CAAC;AAIF,OAAO,EAAE,gCAAgC,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { WholePatchMerger } from './whole-patch.js';
2
+ export declare const SCREEN_LAYOUT_PATCH_CONTENT_TYPE = "application/x-screen-layout-patch+json";
3
+ export declare class ScreenLayoutPatchMerger implements WholePatchMerger {
4
+ merge(processedObj: any, patch: any): any;
5
+ }
6
+ //# sourceMappingURL=screen-layout-patch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen-layout-patch.d.ts","sourceRoot":"","sources":["../../src/providers/screen-layout-patch.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAKzD,eAAO,MAAM,gCAAgC,2CACH,CAAC;AAW3C,qBAAa,uBAAwB,YAAW,gBAAgB;IAC9D,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,GAAG;CA4D1C"}
@@ -0,0 +1,57 @@
1
+ import { mergeMatchedFields, } from '../lib/named-array-merge.js';
2
+ // `Configuration.value` is typed CLOB, but the underlying attribute is JSON — for a
3
+ // JSON-shaped value like a screen layout patch, it can come back already parsed as an
4
+ // object rather than as the JSON string it was saved as.
5
+ export const SCREEN_LAYOUT_PATCH_CONTENT_TYPE = 'application/x-screen-layout-patch+json';
6
+ // A Screen Designer override entry counts as "self-contained" when it carries a
7
+ // `__typename` — every full tab/row/element node the client builds for a brand-new,
8
+ // not-yet-in-the-base-config entry always does (see `AddElementDialog.buildDefaultNode`
9
+ // and the client's new-tab/new-row construction), while a thin `{ name, ...diffs }`
10
+ // reference to an existing base node never does.
11
+ function isSelfContainedScreenLayoutNode(item) {
12
+ return typeof item.__typename === 'string' && item.__typename.length > 0;
13
+ }
14
+ export class ScreenLayoutPatchMerger {
15
+ merge(processedObj, patch) {
16
+ // A screen layout patch is always tabs-shaped (`{ tabs: [...] }`), but the config
17
+ // path it's saved against doesn't have to resolve to a bare `TabbedPage` — a modal
18
+ // config like `modals/select-account-holder` resolves to an `AnyPage` that wraps
19
+ // the real `TabbedPage` via `tabbedPages[0]` (a `$ref`, in that case). Detect that
20
+ // shape and merge onto the nested TabbedPage instead, so the patch lands on
21
+ // `tabbedPages[0].tabs` rather than a same-named `tabs` field bolted onto the
22
+ // AnyPage root (which `mergeMatchedFields` would otherwise do silently, since
23
+ // `tabbedPages` itself doesn't qualify as a named-object array to recurse into —
24
+ // `TabbedPage` has no `name` field).
25
+ if (!processedObj?.tabs && Array.isArray(processedObj?.tabbedPages)) {
26
+ const [tabbedPage, ...restTabbedPages] = processedObj.tabbedPages;
27
+ return {
28
+ ...processedObj,
29
+ tabbedPages: [
30
+ mergeMatchedFields(tabbedPage, patch, isSelfContainedScreenLayoutNode, true),
31
+ ...restTabbedPages,
32
+ ],
33
+ };
34
+ }
35
+ // A `WizardPage` (e.g. `contacts/add-new-contact`) has no `tabs`/`tabbedPages` of
36
+ // its own — its `TabbedPage`(s) live nested one level down, at `steps[].page`. A
37
+ // wizard can carry more than one `TabbedPage` step (add-new-contact has both
38
+ // `enterContactInformation` and `reviewContactInformation`, mutually exclusive by
39
+ // `visibilityCondition` but $ref-ing the identical tabs) — apply the same patch to
40
+ // every step whose `page.tabs` exists, so whichever step is actually visible at
41
+ // runtime reflects the edit, and leave every other step (ComponentPage, etc.)
42
+ // untouched.
43
+ if (!processedObj?.tabbedPages && Array.isArray(processedObj?.steps)) {
44
+ return {
45
+ ...processedObj,
46
+ steps: processedObj.steps.map((step) => step?.page?.tabs
47
+ ? {
48
+ ...step,
49
+ page: mergeMatchedFields(step.page, patch, isSelfContainedScreenLayoutNode, true),
50
+ }
51
+ : step),
52
+ };
53
+ }
54
+ return mergeMatchedFields(processedObj, patch, isSelfContainedScreenLayoutNode, true);
55
+ }
56
+ }
57
+ //# sourceMappingURL=screen-layout-patch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen-layout-patch.js","sourceRoot":"","sources":["../../src/providers/screen-layout-patch.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,GAEnB,MAAM,6BAA6B,CAAC;AAGrC,oFAAoF;AACpF,sFAAsF;AACtF,yDAAyD;AACzD,MAAM,CAAC,MAAM,gCAAgC,GAC3C,wCAAwC,CAAC;AAE3C,gFAAgF;AAChF,oFAAoF;AACpF,wFAAwF;AACxF,oFAAoF;AACpF,iDAAiD;AACjD,SAAS,+BAA+B,CAAC,IAAiB;IACxD,OAAO,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,OAAO,uBAAuB;IAClC,KAAK,CAAC,YAAiB,EAAE,KAAU;QACjC,kFAAkF;QAClF,mFAAmF;QACnF,iFAAiF;QACjF,mFAAmF;QACnF,4EAA4E;QAC5E,8EAA8E;QAC9E,8EAA8E;QAC9E,iFAAiF;QACjF,qCAAqC;QACrC,IAAI,CAAC,YAAY,EAAE,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,EAAE,WAAW,CAAC,EAAE,CAAC;YACpE,MAAM,CAAC,UAAU,EAAE,GAAG,eAAe,CAAC,GAAG,YAAY,CAAC,WAAW,CAAC;YAClE,OAAO;gBACL,GAAG,YAAY;gBACf,WAAW,EAAE;oBACX,kBAAkB,CAChB,UAAU,EACV,KAAK,EACL,+BAA+B,EAC/B,IAAI,CACL;oBACD,GAAG,eAAe;iBACnB;aACF,CAAC;QACJ,CAAC;QAED,kFAAkF;QAClF,iFAAiF;QACjF,6EAA6E;QAC7E,kFAAkF;QAClF,mFAAmF;QACnF,gFAAgF;QAChF,8EAA8E;QAC9E,aAAa;QACb,IAAI,CAAC,YAAY,EAAE,WAAW,IAAI,KAAK,CAAC,OAAO,CAAC,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC;YACrE,OAAO;gBACL,GAAG,YAAY;gBACf,KAAK,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAS,EAAE,EAAE,CAC1C,IAAI,EAAE,IAAI,EAAE,IAAI;oBACd,CAAC,CAAC;wBACE,GAAG,IAAI;wBACP,IAAI,EAAE,kBAAkB,CACtB,IAAI,CAAC,IAAI,EACT,KAAK,EACL,+BAA+B,EAC/B,IAAI,CACL;qBACF;oBACH,CAAC,CAAC,IAAI,CACT;aACF,CAAC;QACJ,CAAC;QAED,OAAO,kBAAkB,CACvB,YAAY,EACZ,KAAK,EACL,+BAA+B,EAC/B,IAAI,CACL,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ export interface WholePatchMerger {
2
+ /** Merges a parsed whole-patch document onto the fully processed config. */
3
+ merge(processedObj: any, patch: any): any;
4
+ }
5
+ export type WholePatchMergers = Record<string, WholePatchMerger>;
6
+ //# sourceMappingURL=whole-patch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whole-patch.d.ts","sourceRoot":"","sources":["../../src/providers/whole-patch.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,GAAG,GAAG,CAAC;CAC3C;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=whole-patch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whole-patch.js","sourceRoot":"","sources":["../../src/providers/whole-patch.ts"],"names":[],"mappings":""}
@@ -64,12 +64,14 @@ type InputField implements IField & IRowElement & IElement {
64
64
  maxRows: Int
65
65
  minRows: Int
66
66
  # End of text area configuration
67
+ custom: Boolean
67
68
  }
68
69
 
69
70
  type CustomValidator implements IRowElement & IElement {
70
71
  validationRule: String
71
72
  errorMessage: String
72
73
  paths: [String!]!
74
+ custom: Boolean
73
75
  }
74
76
 
75
77
  union Fields = InputField | PhoneField | DateField | DateRangeField | SelectField | ToggleField | BooleanField | TextElement
@@ -93,6 +95,7 @@ type RepeaterField implements IRowElement & IElement {
93
95
  validateUnique: Boolean
94
96
  duplicateMessage: String
95
97
  itemValidation: ItemValidation
98
+ custom: Boolean
96
99
  }
97
100
 
98
101
  type ControlGroup implements IRowElement & IElement {
@@ -101,6 +104,7 @@ type ControlGroup implements IRowElement & IElement {
101
104
  skipId: Boolean
102
105
  controlOptions: ISelectOptions!
103
106
  fields: [Fields!]!
107
+ custom: Boolean
104
108
  }
105
109
 
106
110
  # Renders the currently-linked records of a multi-valued reference attribute
@@ -131,6 +135,7 @@ type ReferenceTable implements IField & IRowElement & IElement {
131
135
  confirmDelete: Boolean
132
136
  maxRows: Int
133
137
  rowMenuItems: [MenuItem!]
138
+ custom: Boolean
134
139
  }
135
140
 
136
141
  type PhoneField implements IField & IRowElement & IElement {
@@ -149,6 +154,7 @@ type PhoneField implements IField & IRowElement & IElement {
149
154
  visibilityCondition: String
150
155
  disabledCondition: String
151
156
  validation: GenericFieldValidation
157
+ custom: Boolean
152
158
  }
153
159
 
154
160
  type DateField implements IField & IRowElement & IElement {
@@ -168,6 +174,7 @@ type DateField implements IField & IRowElement & IElement {
168
174
  minDate: String # e.q. "now" or "2025-03-20"
169
175
  maxDate: String # e.q. "now" or "2025-03-20"
170
176
  validation: GenericFieldValidation
177
+ custom: Boolean
171
178
  }
172
179
 
173
180
  type DateRangeField implements IDateRangeField & IRowElement & IElement {
@@ -187,6 +194,7 @@ type DateRangeField implements IDateRangeField & IRowElement & IElement {
187
194
  visibilityCondition: String
188
195
  disabledCondition: String
189
196
  validation: GenericFieldValidation
197
+ custom: Boolean
190
198
  }
191
199
 
192
200
  type SelectField implements IField & IRowElement & IElement {
@@ -212,6 +220,7 @@ type SelectField implements IField & IRowElement & IElement {
212
220
  helperText: String
213
221
  autoSelectSingleOption: Boolean
214
222
  validation: GenericFieldValidation
223
+ custom: Boolean
215
224
  }
216
225
 
217
226
  type ToggleField implements IField & IRowElement & IElement {
@@ -234,6 +243,7 @@ type ToggleField implements IField & IRowElement & IElement {
234
243
  disabledCondition: String
235
244
  linkedFields: [String!]
236
245
  validation: GenericFieldValidation
246
+ custom: Boolean
237
247
  }
238
248
 
239
249
  type BooleanField implements IField & IRowElement & IElement {
@@ -252,6 +262,7 @@ type BooleanField implements IField & IRowElement & IElement {
252
262
  disabledCondition: String
253
263
  linkedFields: [String!]
254
264
  validation: GenericFieldValidation
265
+ custom: Boolean
255
266
  }
256
267
 
257
268
  type ChipSelectWithInputField implements IField & IRowElement & IElement {
@@ -277,6 +288,7 @@ type ChipSelectWithInputField implements IField & IRowElement & IElement {
277
288
  disabledCondition: String
278
289
  linkedFields: [String!]
279
290
  validation: ChipSelectValidation
291
+ custom: Boolean
280
292
  }
281
293
 
282
294
  type CustomField implements IField & IRowElement & IElement {
@@ -296,6 +308,7 @@ type CustomField implements IField & IRowElement & IElement {
296
308
  visibilityCondition: String
297
309
  disabledCondition: String
298
310
  validation: GenericFieldValidation
311
+ custom: Boolean
299
312
  }
300
313
 
301
314
  type StatusChipField implements IField & IRowElement & IElement {
@@ -305,6 +318,7 @@ type StatusChipField implements IField & IRowElement & IElement {
305
318
  name: String!
306
319
  path: String!
307
320
  validation: GenericFieldValidation
321
+ custom: Boolean
308
322
  }
309
323
 
310
324
  type CheckboxGroupValue {
@@ -325,6 +339,7 @@ type CheckboxGroup implements IRowElement & IElement {
325
339
  values: [CheckboxGroupValue!]!
326
340
  visibilityCondition: String
327
341
  disabledCondition: String
342
+ custom: Boolean
328
343
  }
329
344
 
330
345
  enum FieldValueType {
@@ -27,4 +27,11 @@ type PanelRow implements IPanelRow {
27
27
  title: String
28
28
  titleVariant: String
29
29
  visibilityCondition: String
30
+ """
31
+ Screen Designer: true when this group exists only via the screen layout patch — no
32
+ counterpart in the raw base config — vs. `false`/absent for a real group (whether or
33
+ not the patch also overrides some of its properties). See `Tab.custom` for the full
34
+ reasoning; stamped the same way, one level down the tree.
35
+ """
36
+ custom: Boolean
30
37
  }
@@ -8,4 +8,5 @@ type TextElement implements IRowElement & IElement {
8
8
  valueExpression: String
9
9
  variant: String
10
10
  visibilityCondition: String
11
+ custom: Boolean
11
12
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docupace/ihub-config",
3
- "version": "1.1.26",
3
+ "version": "1.1.27",
4
4
  "description": "Reusable config GraphQL extension and standalone server",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",