ngx-dynamic-entity-builder 1.3.0 → 1.5.0

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 (35) hide show
  1. package/README.md +2 -1
  2. package/fesm2022/ngx-dynamic-entity-builder.mjs +521 -105
  3. package/fesm2022/ngx-dynamic-entity-builder.mjs.map +1 -1
  4. package/package.json +7 -7
  5. package/types/ngx-dynamic-entity-builder.d.ts +582 -0
  6. package/esm2022/lib/builder-store.service.mjs +0 -1057
  7. package/esm2022/lib/clone.mjs +0 -14
  8. package/esm2022/lib/components/entity-builder-canvas.component.mjs +0 -84
  9. package/esm2022/lib/components/entity-builder-tree-node.component.mjs +0 -192
  10. package/esm2022/lib/components/entity-reference-config.component.mjs +0 -405
  11. package/esm2022/lib/components/field-inspector.component.mjs +0 -139
  12. package/esm2022/lib/components/field-palette.component.mjs +0 -57
  13. package/esm2022/lib/components/field-rules-list.component.mjs +0 -224
  14. package/esm2022/lib/components/referenced-field-config.component.mjs +0 -235
  15. package/esm2022/lib/components/rule-form.component.mjs +0 -201
  16. package/esm2022/lib/components/tab-manager.component.mjs +0 -354
  17. package/esm2022/lib/entity-builder.component.mjs +0 -159
  18. package/esm2022/lib/field-catalog.mjs +0 -6
  19. package/esm2022/ngx-dynamic-entity-builder.mjs +0 -5
  20. package/esm2022/public-api.mjs +0 -16
  21. package/index.d.ts +0 -5
  22. package/lib/builder-store.service.d.ts +0 -206
  23. package/lib/clone.d.ts +0 -9
  24. package/lib/components/entity-builder-canvas.component.d.ts +0 -9
  25. package/lib/components/entity-builder-tree-node.component.d.ts +0 -17
  26. package/lib/components/entity-reference-config.component.d.ts +0 -29
  27. package/lib/components/field-inspector.component.d.ts +0 -33
  28. package/lib/components/field-palette.component.d.ts +0 -13
  29. package/lib/components/field-rules-list.component.d.ts +0 -19
  30. package/lib/components/referenced-field-config.component.d.ts +0 -24
  31. package/lib/components/rule-form.component.d.ts +0 -16
  32. package/lib/components/tab-manager.component.d.ts +0 -28
  33. package/lib/entity-builder.component.d.ts +0 -45
  34. package/lib/field-catalog.d.ts +0 -5
  35. package/public-api.d.ts +0 -12
package/package.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "ngx-dynamic-entity-builder",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Angular standalone visual builder for authoring dynamic-entity EntityConfig (fields, tabs, validators, RBAC).",
5
+ "//typings": "Local workspace resolution only: ng-packagr 21 writes types/ngx-dynamic-entity-builder.d.ts into dist/package.json. Do NOT add a 'main' field here — ng-packagr does not generate one, so it would be copied verbatim and resolve wrongly in the published package.",
6
+ "typings": "types/ngx-dynamic-entity-builder.d.ts",
5
7
  "peerDependencies": {
6
8
  "@angular/cdk": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0",
7
9
  "@angular/common": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0",
8
10
  "@angular/core": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0",
9
11
  "@angular/forms": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0",
10
12
  "@angular/material": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0",
11
- "@dynamic-entity/core": "^1.3.0",
12
- "ngx-dynamic-entity": "^1.3.0",
13
+ "@dynamic-entity/core": "^1.5.0",
14
+ "ngx-dynamic-entity": "^1.5.0",
13
15
  "rxjs": "^7.0.0"
14
16
  },
15
17
  "keywords": [
@@ -33,18 +35,16 @@
33
35
  },
34
36
  "author": "Nizamudeen",
35
37
  "module": "fesm2022/ngx-dynamic-entity-builder.mjs",
36
- "typings": "index.d.ts",
37
38
  "exports": {
38
39
  "./package.json": {
39
40
  "default": "./package.json"
40
41
  },
41
42
  ".": {
42
- "types": "./index.d.ts",
43
- "esm2022": "./esm2022/ngx-dynamic-entity-builder.mjs",
44
- "esm": "./esm2022/ngx-dynamic-entity-builder.mjs",
43
+ "types": "./types/ngx-dynamic-entity-builder.d.ts",
45
44
  "default": "./fesm2022/ngx-dynamic-entity-builder.mjs"
46
45
  }
47
46
  },
47
+ "type": "module",
48
48
  "dependencies": {
49
49
  "tslib": "^2.3.0"
50
50
  }
@@ -0,0 +1,582 @@
1
+ import * as _angular_core from '@angular/core';
2
+ import { OnChanges, EventEmitter, SimpleChanges } from '@angular/core';
3
+ import { NestedTabConfig, NestedFieldConfig, EntityFormConfig, FormRule, EntityPermissions, RichFieldType, FlagValidator, ParamValidator, DropdownOption, EntityReferenceConfig, AutoPatchMapping, PatchOnTrueMapping, CommonModuleEntry, FieldTypeMeta, RuleOperator } from '@dynamic-entity/core';
4
+ export { AutoPatchConfig, AutoPatchMapping, DropdownOption, EntityFormConfig, EntityPermissions, EntityReferenceConfig, FIELD_TYPE_CATALOG, FieldTypeMeta, FlagValidator, FormRule, NestedFieldConfig, NestedTabConfig, ParamValidator, PatchOnTrueMapping, RichFieldType, RuleAction, RuleCondition, RuleOperator, createFieldConfig, getFieldTypeMeta, humanizeId } from '@dynamic-entity/core';
5
+ import * as ngx_dynamic_entity from 'ngx-dynamic-entity';
6
+ export { SYSTEM_DEFAULT_CAN_EDIT } from 'ngx-dynamic-entity';
7
+ import { CdkDragDrop } from '@angular/cdk/drag-drop';
8
+
9
+ interface BuilderProblem {
10
+ level: 'error' | 'warning';
11
+ message: string;
12
+ fieldId?: string;
13
+ }
14
+ /** One tab's own fields, for a canvas that has to reorder within the right tab. */
15
+ interface BuilderFieldGroup {
16
+ tabId: string;
17
+ label: NestedTabConfig['label'];
18
+ fields: NestedFieldConfig[];
19
+ }
20
+ declare class BuilderStore {
21
+ private readonly _config;
22
+ private readonly _selectedFieldId;
23
+ private readonly _activeLanguage;
24
+ /** Rules live beside the config: they are persisted per form, not inside `EntityFormConfig`. */
25
+ private readonly _rules;
26
+ /**
27
+ * Field ids the author owns — set by an explicit rename, or by loading a saved config
28
+ * whose ids are already live data keys. Ids outside this set are still derived from the
29
+ * field's label. Builder-session state, deliberately not part of the exported config.
30
+ */
31
+ private readonly manualIds;
32
+ /**
33
+ * Fields whose `refererField` the config declared, rather than the builder stamping it.
34
+ *
35
+ * A declared path is a deliberate binding override and must survive a structural edit. A
36
+ * stamped one is just the field's address, so it has to be rewritten when the field moves.
37
+ * Without the distinction, restamping would destroy the override and not restamping would
38
+ * leave a moved field pointing at where it used to be.
39
+ */
40
+ private readonly authoredRefs;
41
+ private readonly _isDirty;
42
+ /**
43
+ * Roles of the person using the builder — distinct from `availableRoles`, which is the
44
+ * vocabulary a schema may reference. Needed so the SYSTEM_DEFAULT_CAN_EDIT predicate can
45
+ * be asked a real question; it was previously called with a hardcoded empty array, which
46
+ * made any role-checking predicate answer false for everyone.
47
+ */
48
+ private readonly _userRoles;
49
+ readonly config: _angular_core.Signal<EntityFormConfig>;
50
+ readonly selectedFieldId: _angular_core.Signal<string>;
51
+ readonly activeLanguage: _angular_core.Signal<string>;
52
+ readonly rules: _angular_core.Signal<FormRule[]>;
53
+ readonly isDirty: _angular_core.Signal<boolean>;
54
+ readonly userRoles: _angular_core.Signal<string[]>;
55
+ readonly tabs: _angular_core.Signal<NestedTabConfig[]>;
56
+ /**
57
+ * Every field the config declares, sub-tabs included.
58
+ *
59
+ * This used to stop at top-level tabs, which quietly broke three things at once: nine of
60
+ * `insuranceClaims`'s twenty-eight fields never appeared on the canvas, the entity-reference
61
+ * picker could not offer a nested field as a source, and the drift check looked a nested
62
+ * field up here, got nothing, and returned without checking. The store's structural
63
+ * operations already walked the whole tree — only this view did not.
64
+ *
65
+ * It deliberately does not descend into a field's own `children`: `group` and `array`
66
+ * children are rendered by the row that owns them, not as rows of their own.
67
+ */
68
+ readonly fields: _angular_core.Signal<NestedFieldConfig[]>;
69
+ /**
70
+ * The same fields, kept in their owning tab.
71
+ *
72
+ * Drag-and-drop reorders by index, so the canvas needs to know which tab an index belongs
73
+ * to — `reorderField` has always taken a `tabId` for exactly this, and the canvas simply
74
+ * never passed one. Without the grouping a drag on any config with more than one tab
75
+ * reordered `tabs[0]` regardless of what was actually dragged.
76
+ */
77
+ readonly fieldGroups: _angular_core.Signal<BuilderFieldGroup[]>;
78
+ readonly selectedField: _angular_core.Signal<NestedFieldConfig>;
79
+ readonly problems: _angular_core.Signal<BuilderProblem[]>;
80
+ readonly errors: _angular_core.Signal<BuilderProblem[]>;
81
+ readonly isValid: _angular_core.Signal<boolean>;
82
+ load(config: EntityFormConfig): void;
83
+ reset(entity?: string): void;
84
+ resetDirty(): void;
85
+ private emptyConfig;
86
+ setEntityName(entity: string): void;
87
+ setDefaultLanguage(language: string): void;
88
+ setMaskData(mask: boolean): void;
89
+ setPermission(action: keyof EntityPermissions, roles: string[]): void;
90
+ setActiveLanguage(language: string): void;
91
+ /** Roles of the person using the builder, for SYSTEM_DEFAULT_CAN_EDIT. */
92
+ setUserRoles(roles: string[]): void;
93
+ private getAllFields;
94
+ /**
95
+ * Every tab in the tree, flattened.
96
+ *
97
+ * The structural operations below used to iterate `draft.tabs` directly, which is only
98
+ * the top level. A field on a sub-tab could be selected and edited but never removed,
99
+ * duplicated, moved or reordered — the builder could author nested configs it was then
100
+ * unable to restructure, which is the worst possible state for an authoring tool.
101
+ */
102
+ private flattenTabs;
103
+ /**
104
+ * Every field id in the config, including `group`/`array` children.
105
+ *
106
+ * Id uniqueness is a whole-config invariant, not a per-tab one: rules, `showWhen`
107
+ * conditions and `autoPatch` mappings all address fields by bare id, so two fields
108
+ * sharing an id anywhere in the tree interfere with each other. Uniqueness checks must
109
+ * therefore see deeper than `fields()`, which stops at a tab's own fields.
110
+ */
111
+ private allFieldIds;
112
+ private findFieldInTabs;
113
+ addField(type: RichFieldType, targetTabId?: string): string;
114
+ updateField(id: string, patch: Partial<NestedFieldConfig>): void;
115
+ /**
116
+ * Rename a field explicitly, pinning the id so it is no longer derived from the label.
117
+ *
118
+ * Not reachable from the inspector — the id input is read-only by design. This exists for
119
+ * programmatic callers that must match an id to an existing data key.
120
+ */
121
+ renameField(oldId: string, newId: string): void;
122
+ /** Whether this field's id is pinned (loaded from storage or explicitly renamed). */
123
+ hasManualId(id: string): boolean;
124
+ /**
125
+ * Move a field to a new id and repoint every id-based reference in the config at it.
126
+ *
127
+ * Ids are the wiring between fields — rules, cascades, patches and `showWhen` all address
128
+ * fields by id — so a rename that only touches `field.id` silently breaks that wiring.
129
+ * That was survivable while renaming was a rare manual act; label-derived ids make it
130
+ * routine, so the references move with it.
131
+ */
132
+ private applyRename;
133
+ removeField(id: string): void;
134
+ duplicateField(id: string): string | null;
135
+ moveField(id: string, direction: -1 | 1): void;
136
+ /**
137
+ * Moves a field to another tab, keeping its id.
138
+ *
139
+ * The builder could add, remove, duplicate and reorder a field but never relocate one, so
140
+ * a field authored on the wrong tab had to be deleted and rebuilt — losing its validators,
141
+ * options and any rule that pointed at it.
142
+ *
143
+ * The field's `refererField` changes, because it is an address and the field now has a new one.
144
+ * `mutate` restamps it and repoints the rules that named it, so a move does not silently
145
+ * strand them.
146
+ */
147
+ moveFieldToTab(id: string, targetTabId: string): boolean;
148
+ /** Safe reorder for drag & drop within active tab or flat list */
149
+ reorderField(fromIndex: number, toIndex: number, tabId?: string): void;
150
+ selectField(id: string | null): void;
151
+ /**
152
+ * Set a field's label, and derive the field's id from it: type "Employee Count", get
153
+ * `employeeCount`. The inspector renders the id read-only, so this is the only way a
154
+ * new field's id is set.
155
+ *
156
+ * Two things stop derivation: a config loaded from storage (its ids are live data keys
157
+ * that records are already stored under — see `load`), and an explicit `renameField`
158
+ * call, which remains available to programmatic callers.
159
+ *
160
+ * Only the config's default language drives the id; translating a label must not rename
161
+ * anything.
162
+ */
163
+ setFieldLabel(id: string, language: string, value: string): void;
164
+ /** `derived`, or `derived_2`, `derived_3`… if another field already holds it. */
165
+ private availableId;
166
+ setFieldPlaceholder(id: string, language: string, value: string): void;
167
+ toggleFlagValidator(id: string, validator: FlagValidator, on: boolean): void;
168
+ setParamValidator(id: string, validator: ParamValidator, value: number | null): void;
169
+ getParamValidator(field: NestedFieldConfig, validator: ParamValidator): number | null;
170
+ hasFlagValidator(field: NestedFieldConfig, validator: FlagValidator): boolean;
171
+ /**
172
+ * Where a choice field's options come from.
173
+ *
174
+ * `entity` is absent on purpose: in this model an entity reference is a field *type*
175
+ * (`entity-ref`), not a data source a dropdown can switch to, so offering it here would mean
176
+ * mutating the field's type — and rebuilding its control — from a source picker. The
177
+ * exclusion that matters within a choice field is inline `options` vs `listName`.
178
+ */
179
+ fieldDataSource(field: NestedFieldConfig | undefined): 'none' | 'manual' | 'lookup';
180
+ /**
181
+ * Switch a choice field's data source, clearing the one it is leaving.
182
+ *
183
+ * The reference makes these mutually exclusive (doc §4.4) and it has to stay that way here:
184
+ * `optionsFor` resolves inline options first, so a field left holding both would silently
185
+ * ignore its list.
186
+ */
187
+ setFieldDataSource(fieldId: string, source: 'none' | 'manual' | 'lookup'): void;
188
+ /** Set the named list a choice field reads its options from. */
189
+ setListName(fieldId: string, listName: string): void;
190
+ /** Link a field to a field defined in another entity configuration (Phase 8). */
191
+ linkReferencedField(fieldId: string, sourceEntityKey: string, sourceField: NestedFieldConfig): void;
192
+ /** Unlink a referenced field back to an independent field. */
193
+ unlinkReferencedField(fieldId: string): void;
194
+ /** Sync a drifted referenced field with the updated source field definition. */
195
+ syncReferencedField(fieldId: string, currentSourceField: NestedFieldConfig): void;
196
+ /** Scan all referenced fields in the config and update their hasDrift state against current source configs. */
197
+ checkDrift(sourceConfigs: Record<string, EntityFormConfig>): void;
198
+ addOption(fieldId: string): void;
199
+ /** Merge language keys into an option. `setOptionLabel` is the usual single-language path. */
200
+ updateOption(fieldId: string, index: number, patch: DropdownOption): void;
201
+ /**
202
+ * Set an option's text for one language.
203
+ *
204
+ * An option is a language-keyed object and the displayed text **is** the stored value,
205
+ * so this is the only way to edit one — there is no separate value to set.
206
+ */
207
+ setOptionLabel(fieldId: string, index: number, language: string, value: string): void;
208
+ removeOption(fieldId: string, index: number): void;
209
+ /** Merge a patch into a field's `entityReference` block, keeping it enabled. */
210
+ updateEntityReference(fieldId: string, patch: Partial<EntityReferenceConfig>): void;
211
+ addAutoPatchMapping(fieldId: string): void;
212
+ setAutoPatchTargetTab(fieldId: string, targetTab: string): void;
213
+ updateAutoPatchMapping(fieldId: string, index: number, patch: Partial<AutoPatchMapping>): void;
214
+ /** Removing the last mapping drops `autoPatch` entirely — no empty config in the export. */
215
+ removeAutoPatchMapping(fieldId: string, index: number): void;
216
+ addPatchOnTrueMapping(fieldId: string): void;
217
+ updatePatchOnTrueMapping(fieldId: string, index: number, patch: Partial<PatchOnTrueMapping>): void;
218
+ removePatchOnTrueMapping(fieldId: string, index: number): void;
219
+ /** Replace a field's `showWhen` map; an empty map removes the condition. */
220
+ setShowWhen(fieldId: string, showWhen: Record<string, unknown> | undefined): void;
221
+ /** Rules for the field currently selected in the inspector. */
222
+ /**
223
+ * Rules attached to the selected field, whichever way they name it.
224
+ *
225
+ * New rules are authored with the field's path — `[work.address]` — because a bare id
226
+ * cannot distinguish two fields that share one. Rules written before paths existed name it
227
+ * by id, and those must keep showing up here or editing an older config would look like it
228
+ * had lost its rules.
229
+ */
230
+ readonly rulesForSelectedField: _angular_core.Signal<FormRule[]>;
231
+ loadRules(rules: FormRule[]): void;
232
+ addRule(rule: FormRule): string;
233
+ updateRule(id: string, patch: Partial<FormRule>): void;
234
+ removeRule(id: string): void;
235
+ toggleRule(id: string, enabled: boolean): void;
236
+ /** Move a rule in priority order. Priorities are renumbered 1..n so they stay contiguous. */
237
+ moveRule(id: string, direction: -1 | 1): void;
238
+ exportRules(): FormRule[];
239
+ addTab(): string;
240
+ /** Every tab id in the tree, at any depth. Tab ids must be globally unique — they are paths. */
241
+ private allTabIds;
242
+ addSubTab(parentId: string): string;
243
+ setPrimaryTab(tabId: string): void;
244
+ updateTab(id: string, patch: Partial<NestedTabConfig>): void;
245
+ setTabLabel(id: string, language: string, value: string): void;
246
+ removeTab(id: string): void;
247
+ moveTab(id: string, direction: -1 | 1): void;
248
+ exportConfig(): EntityFormConfig;
249
+ /**
250
+ * The single choke point for a structural edit, and therefore the one place refs are kept
251
+ * true.
252
+ *
253
+ * `refererField` is a field's address, so it changes whenever the structure around it does —
254
+ * moving a field to another tab, or into a group, gives it a new one. Rules address fields
255
+ * by ref, so a move that only restamped the field would leave every rule pointing at an
256
+ * address nothing occupies. Both happen here, together, or the config is inconsistent
257
+ * between them.
258
+ */
259
+ private mutate;
260
+ /**
261
+ * Rewrites the address of every field the builder owns, leaving declared overrides alone.
262
+ *
263
+ * `assignFieldRefs` only fills in a missing path, which is right when a config arrives and
264
+ * wrong after a move: the field already has a path, and it is now the wrong one.
265
+ */
266
+ private restampFieldPaths;
267
+ /** Field id → the refs it currently has. A duplicated id has more than one. */
268
+ private refsById;
269
+ /**
270
+ * Rewrites rules that pointed at a ref a move has just changed.
271
+ *
272
+ * A field is matched by its id: if exactly one ref for that id disappeared and exactly one
273
+ * appeared, that is the move and the rules follow it. Anything less clear-cut — two fields
274
+ * sharing an id where one moved — is left alone rather than guessed at, because rewriting
275
+ * the wrong rule is worse than leaving one to be repointed by hand.
276
+ */
277
+ private repointRulesForMovedFields;
278
+ /**
279
+ * Replace one field, copying only the objects on the path to it.
280
+ *
281
+ * `mutate` deep-clones the entire config, which is right for a structural edit but wrong
282
+ * for the two setters bound to keystroke events: typing a label allocated a full copy of
283
+ * the config per character. Here every tab and field outside the target's chain is reused
284
+ * by reference, so the cost is proportional to nesting depth rather than config size —
285
+ * while the parts that did change are still fresh objects, so change detection and the
286
+ * signal both see a new identity.
287
+ *
288
+ * Returns without touching anything when the field is not found.
289
+ */
290
+ private mutateField;
291
+ private uniqueId;
292
+ private validate;
293
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<BuilderStore, never>;
294
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<BuilderStore>;
295
+ }
296
+
297
+ /**
298
+ * EntityBuilderComponent — the top-level visual builder for an EntityFormConfig.
299
+ */
300
+ declare class EntityBuilderComponent implements OnChanges {
301
+ protected readonly store: BuilderStore;
302
+ /**
303
+ * Optional: only apps that registered a CONFIG_SOURCE have one. Used to drop the cached
304
+ * copy of a config the moment it is edited — see `doSave`.
305
+ */
306
+ private readonly configSource;
307
+ /** Existing config to edit. When omitted, the builder starts blank. */
308
+ config?: EntityFormConfig;
309
+ /** Languages available for label/placeholder editing. First entry is the default. */
310
+ languages: string[];
311
+ /** Optional role list — enables multi-select role pickers for RBAC instead of free text. */
312
+ availableRoles: string[];
313
+ /**
314
+ * Roles of the person using the builder. Distinct from `availableRoles`, which is the
315
+ * vocabulary a schema may reference. Passed to the `SYSTEM_DEFAULT_CAN_EDIT` predicate so
316
+ * it can decide whether this user may edit system-default tabs.
317
+ */
318
+ userRoles: string[];
319
+ /** Optional common-module definitions for module tabs; defaults to the built-in list from core. */
320
+ commonModules: readonly CommonModuleEntry[];
321
+ /** Emitted on every change to the working config. */
322
+ configChange: EventEmitter<EntityFormConfig>;
323
+ /** Emitted when the user clicks Save. Carries a clean, deep-cloned config. */
324
+ save: EventEmitter<EntityFormConfig>;
325
+ protected readonly rbacActions: (keyof EntityPermissions)[];
326
+ constructor();
327
+ ngOnChanges(changes: SimpleChanges): void;
328
+ protected doSave(): void;
329
+ protected get json(): string;
330
+ protected copyJson(): void;
331
+ protected rolesFor(action: keyof EntityPermissions): readonly string[];
332
+ protected setRoles(action: keyof EntityPermissions, roles: string[]): void;
333
+ /** Parse a comma-separated role string into a trimmed, de-duplicated array. */
334
+ protected setRolesFromText(action: keyof EntityPermissions, text: string): void;
335
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EntityBuilderComponent, never>;
336
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EntityBuilderComponent, "ngx-entity-builder", never, { "config": { "alias": "config"; "required": false; }; "languages": { "alias": "languages"; "required": false; }; "availableRoles": { "alias": "availableRoles"; "required": false; }; "userRoles": { "alias": "userRoles"; "required": false; }; "commonModules": { "alias": "commonModules"; "required": false; }; }, { "configChange": "configChange"; "save": "save"; }, never, ["[ngxBuilderPreview]"], true, never>;
337
+ }
338
+
339
+ /**
340
+ * FieldPaletteComponent — the list of buildable field types (Angular Material).
341
+ */
342
+ declare class FieldPaletteComponent {
343
+ readonly catalog: readonly FieldTypeMeta[];
344
+ pick: EventEmitter<RichFieldType>;
345
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FieldPaletteComponent, never>;
346
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FieldPaletteComponent, "ngx-field-palette", never, {}, { "pick": "pick"; }, never, never, true, never>;
347
+ }
348
+
349
+ /** One choosable field: the reference stored, the label shown, and the path behind it. */
350
+ interface FieldPathOption {
351
+ value: string;
352
+ label: string;
353
+ path: string;
354
+ }
355
+ /**
356
+ * Every field in the config, offered by path.
357
+ *
358
+ * Four places in the builder name a field — `showWhen` keys, `patchOnTrue` mappings,
359
+ * `autoPatch` targets and rule triggers/targets — and each was a free-text box. Typing an id
360
+ * is the one way left to author an ambiguous reference: ids are unique per scope, so
361
+ * `address` names nothing in particular once two tabs have one. Choosing from this list
362
+ * always yields a path.
363
+ *
364
+ * `collectFieldScopes` rather than the tab-level view, so a field nested inside a `group` is
365
+ * offered too, and every entry carries the scope `refOf` needs.
366
+ */
367
+ declare function fieldPathOptions(config: EntityFormConfig | null | undefined, language: string): FieldPathOption[];
368
+ /**
369
+ * The options plus whatever is already selected.
370
+ *
371
+ * A reference written before paths existed is a bare id, and one written against a field
372
+ * since deleted is a path nothing answers to. Neither appears in the list, and a `mat-select`
373
+ * silently drops a value it has no option for — so opening such a config and saving it would
374
+ * quietly erase the reference. They are kept, and shown as they are.
375
+ */
376
+ declare function withExistingOptions(options: readonly FieldPathOption[], current: readonly (string | undefined)[]): FieldPathOption[];
377
+
378
+ /**
379
+ * FieldInspectorComponent — edits every property of the currently selected field.
380
+ */
381
+ declare class FieldInspectorComponent {
382
+ protected readonly store: BuilderStore;
383
+ protected readonly field: _angular_core.Signal<NestedFieldConfig>;
384
+ protected readonly meta: _angular_core.Signal<FieldTypeMeta>;
385
+ protected lang(): string;
386
+ protected toNum(value: unknown): number | null;
387
+ protected labelValue(field: NestedFieldConfig): string;
388
+ protected placeholderValue(field: NestedFieldConfig): string;
389
+ protected optionLabel(option: DropdownOption): string;
390
+ /**
391
+ * Every tab a field can live on, sub-tabs included.
392
+ *
393
+ * `moveFieldToTab` existed on the store with nothing calling it, so a field authored on the
394
+ * wrong tab had to be deleted and rebuilt — losing its validators, options and every rule
395
+ * aimed at it.
396
+ */
397
+ protected readonly tabOptions: _angular_core.Signal<{
398
+ id: string;
399
+ label: string;
400
+ }[]>;
401
+ /**
402
+ * The tab the selected field currently sits on.
403
+ *
404
+ * Looked up by identity rather than parsed out of the path: the scope of
405
+ * `incident.incidentDetails.incidentTime` is two segments and the field belongs to the
406
+ * *last* of them, while a field inside a group has the group id in that position and
407
+ * belongs to no tab of that name at all.
408
+ */
409
+ protected currentTabId(field: NestedFieldConfig): string;
410
+ protected moveToTab(field: NestedFieldConfig, tabId: string): void;
411
+ /**
412
+ * Fields offered wherever this inspector names one — the `showWhen` key and both ends of a
413
+ * `patchOnTrue` mapping. All three were free text, which is the one way left to write a
414
+ * reference that names two fields at once.
415
+ */
416
+ protected readonly fieldOptions: _angular_core.Signal<FieldPathOption[]>;
417
+ /** Options plus whatever is already selected, so an unknown reference is never dropped. */
418
+ protected optionsWith(...current: (string | undefined)[]): FieldPathOption[];
419
+ protected showWhenEntries(field: NestedFieldConfig): {
420
+ key: string;
421
+ display: string;
422
+ }[];
423
+ /**
424
+ * Seeds a new condition with the first field not already watched.
425
+ *
426
+ * It used to seed the literal string `field`, which is not a field id at all — so a new
427
+ * condition started out referencing nothing and silently hid the field until it was edited.
428
+ */
429
+ protected addShowWhen(field: NestedFieldConfig): void;
430
+ protected renameShowWhen(field: NestedFieldConfig, oldKey: string, newKey: string): void;
431
+ protected setShowWhenValue(field: NestedFieldConfig, key: string, raw: string): void;
432
+ protected removeShowWhen(field: NestedFieldConfig, key: string): void;
433
+ /**
434
+ * `showWhen` compares with `!==`, so the authored type has to survive the round trip:
435
+ * "true"/"false" become booleans and numeric text becomes a number.
436
+ */
437
+ private parseShowWhen;
438
+ private stringifyShowWhen;
439
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FieldInspectorComponent, never>;
440
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FieldInspectorComponent, "ngx-field-inspector", never, {}, {}, never, never, true, never>;
441
+ }
442
+
443
+ /**
444
+ * TabManagerComponent — add / rename / reorder / remove tabs & sub-tabs with systemDefault protection.
445
+ */
446
+ declare class TabManagerComponent {
447
+ protected readonly store: BuilderStore;
448
+ private readonly canEditSystemDefaultsFn;
449
+ protected lang(): string;
450
+ protected tabLabel(tab: {
451
+ label?: any;
452
+ }): string;
453
+ protected canEditTab(tab: NestedTabConfig): boolean;
454
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<TabManagerComponent, never>;
455
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TabManagerComponent, "ngx-tab-manager", never, {}, {}, never, never, true, never>;
456
+ }
457
+
458
+ /**
459
+ * RuleFormComponent — dialog/panel form for creating or editing a FormRule.
460
+ */
461
+ declare class RuleFormComponent {
462
+ private readonly store;
463
+ rule: FormRule;
464
+ save: EventEmitter<FormRule>;
465
+ cancel: EventEmitter<void>;
466
+ readonly operators: RuleOperator[];
467
+ protected readonly fieldOptions: _angular_core.Signal<FieldPathOption[]>;
468
+ /**
469
+ * Methods, not `computed`. Both read `rule`, which is a plain `@Input` object mutated in
470
+ * place rather than a signal — a computed would cache the first evaluation and never see a
471
+ * different rule being edited.
472
+ */
473
+ protected triggerOptions(): FieldPathOption[];
474
+ protected targetOptions(): FieldPathOption[];
475
+ private cachedTargets;
476
+ /**
477
+ * Field targets only — a rule may also target a tab, which this picker does not manage.
478
+ *
479
+ * The array identity is held stable while the contents are unchanged. This is bound through
480
+ * `[ngModel]` on a multi-select, and a fresh array on each call made `ngModel` see a new
481
+ * value on every change-detection pass: it wrote, which scheduled another pass, which built
482
+ * another array. Opening the rule editor locked the browser outright.
483
+ */
484
+ protected targetValues(): string[];
485
+ /**
486
+ * Replaces the field targets, leaving any tab target untouched.
487
+ *
488
+ * Rebuilding `targets` wholesale from this picker would drop tab targets, which it never
489
+ * offered and so cannot know about.
490
+ */
491
+ protected setTargets(ids: string[]): void;
492
+ addCondition(): void;
493
+ removeCondition(index: number): void;
494
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<RuleFormComponent, never>;
495
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<RuleFormComponent, "ngx-rule-form", never, { "rule": { "alias": "rule"; "required": false; }; }, { "save": "save"; "cancel": "cancel"; }, never, never, true, never>;
496
+ }
497
+
498
+ /**
499
+ * FieldRulesListComponent — the rules attached to the selected field: view, reorder,
500
+ * enable/disable, edit, delete. `RuleFormComponent` authors one rule; this owns the set.
501
+ */
502
+ declare class FieldRulesListComponent {
503
+ protected readonly store: BuilderStore;
504
+ /** The rule currently open in the editor — a new draft or a copy of an existing rule. */
505
+ protected readonly editing: _angular_core.WritableSignal<FormRule>;
506
+ protected startCreate(): void;
507
+ protected startEdit(rule: FormRule): void;
508
+ protected commit(rule: FormRule): void;
509
+ /** One-line human summary: `status EQUAL "archived" → hide`. */
510
+ protected summarize(rule: FormRule): string;
511
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<FieldRulesListComponent, never>;
512
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<FieldRulesListComponent, "ngx-field-rules-list", never, {}, {}, never, never, true, never>;
513
+ }
514
+
515
+ /**
516
+ * EntityReferenceConfigComponent — authors the `entityReference` block of an entity-ref field:
517
+ * registry key, display fields, static filters, and the parent→child cascade.
518
+ *
519
+ * Also authors `autoPatch`, since the mappings only make sense against the record the
520
+ * selected reference returns.
521
+ */
522
+ declare class EntityReferenceConfigComponent {
523
+ protected readonly store: BuilderStore;
524
+ protected readonly field: _angular_core.Signal<NestedFieldConfig>;
525
+ /** Sibling fields that can drive a cascade — anything but this field itself. */
526
+ protected readonly parentCandidates: _angular_core.Signal<NestedFieldConfig[]>;
527
+ private readonly fieldOptions;
528
+ /**
529
+ * Cascade parents, offered by path.
530
+ *
531
+ * The picker existed but its values were bare ids, which name a field only while no second
532
+ * scope reuses the id — so the one control that was already a list could still produce an
533
+ * ambiguous reference.
534
+ */
535
+ protected parentOptions(): FieldPathOption[];
536
+ /** Options plus whatever is already selected, so an unknown reference is never dropped. */
537
+ protected optionsWith(...current: (string | undefined)[]): FieldPathOption[];
538
+ private readonly filtersParseError;
539
+ protected readonly filtersError: _angular_core.Signal<string>;
540
+ protected ref(field: NestedFieldConfig): ngx_dynamic_entity.EntityReferenceConfig;
541
+ protected patchRef(field: NestedFieldConfig, patch: Record<string, unknown>): void;
542
+ protected fieldLabel(field: NestedFieldConfig): string;
543
+ protected tabLabel(tabId: string): string;
544
+ protected displayFieldsText(field: NestedFieldConfig): string;
545
+ protected setDisplayFields(field: NestedFieldConfig, value: string): void;
546
+ protected filtersText(field: NestedFieldConfig): string;
547
+ /** Invalid JSON is reported inline and left unapplied rather than silently dropped. */
548
+ protected setFilters(field: NestedFieldConfig, value: string): void;
549
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EntityReferenceConfigComponent, never>;
550
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EntityReferenceConfigComponent, "ngx-entity-reference-config", never, {}, {}, never, never, true, never>;
551
+ }
552
+
553
+ declare class EntityBuilderCanvasComponent {
554
+ protected readonly store: BuilderStore;
555
+ /**
556
+ * Headings only earn their space once the fields are actually split across tabs. A
557
+ * single-tab config — the common case, and every existing spec — renders exactly as before.
558
+ */
559
+ protected showTabHeadings(): boolean;
560
+ protected groupLabel(group: BuilderFieldGroup): string;
561
+ protected onDrop(tabId: string, event: CdkDragDrop<unknown>): void;
562
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EntityBuilderCanvasComponent, never>;
563
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EntityBuilderCanvasComponent, "ngx-entity-builder-canvas", never, {}, {}, never, never, true, never>;
564
+ }
565
+
566
+ declare class EntityBuilderTreeNodeComponent {
567
+ protected readonly store: BuilderStore;
568
+ field: NestedFieldConfig;
569
+ index: number;
570
+ totalCount: number;
571
+ protected fieldTypeLabel(type: string): string;
572
+ protected fieldTypeIcon(type: string): string;
573
+ protected fieldLabel(field: {
574
+ id: string;
575
+ label?: any;
576
+ }): string;
577
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<EntityBuilderTreeNodeComponent, never>;
578
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<EntityBuilderTreeNodeComponent, "ngx-entity-builder-tree-node", never, { "field": { "alias": "field"; "required": true; }; "index": { "alias": "index"; "required": true; }; "totalCount": { "alias": "totalCount"; "required": true; }; }, {}, never, never, true, never>;
579
+ }
580
+
581
+ export { BuilderStore, EntityBuilderCanvasComponent, EntityBuilderComponent, EntityBuilderTreeNodeComponent, EntityReferenceConfigComponent, FieldInspectorComponent, FieldPaletteComponent, FieldRulesListComponent, RuleFormComponent, TabManagerComponent, fieldPathOptions, withExistingOptions };
582
+ export type { BuilderFieldGroup, BuilderProblem, FieldPathOption };