ngx-dynamic-entity-builder 2.0.2 → 2.1.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngx-dynamic-entity-builder",
3
- "version": "2.0.2",
3
+ "version": "2.1.1",
4
4
  "description": "Angular standalone visual builder for authoring dynamic-entity EntityConfig (fields, tabs, validators, RBAC).",
5
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
6
  "typings": "types/ngx-dynamic-entity-builder.d.ts",
@@ -10,8 +10,8 @@
10
10
  "@angular/core": "^17.2.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0",
11
11
  "@angular/forms": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0",
12
12
  "@angular/material": "^17.0.0 || ^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0",
13
- "@dynamic-entity/core": "^2.0.2",
14
- "ngx-dynamic-entity": "^2.0.2",
13
+ "@dynamic-entity/core": "^2.1.1",
14
+ "ngx-dynamic-entity": "^2.1.1",
15
15
  "rxjs": "^7.0.0"
16
16
  },
17
17
  "keywords": [
@@ -5,6 +5,7 @@ export { AutoPatchConfig, AutoPatchMapping, DropdownOption, EntityFormConfig, En
5
5
  import * as ngx_dynamic_entity from 'ngx-dynamic-entity';
6
6
  import { UiTextOverridesFor, UiTextParams } from 'ngx-dynamic-entity';
7
7
  export { SYSTEM_DEFAULT_CAN_EDIT } from 'ngx-dynamic-entity';
8
+ import * as ngx_dynamic_entity_builder from 'ngx-dynamic-entity-builder';
8
9
  import { CdkDragDrop } from '@angular/cdk/drag-drop';
9
10
 
10
11
  interface BuilderProblem {
@@ -43,45 +44,18 @@ declare class BuilderStore {
43
44
  /**
44
45
  * Roles of the person using the builder — distinct from `availableRoles`, which is the
45
46
  * vocabulary a schema may reference. Needed so the SYSTEM_DEFAULT_CAN_EDIT predicate can
46
- * be asked a real question; it was previously called with a hardcoded empty array, which
47
- * made any role-checking predicate answer false for everyone.
47
+ * be asked a real question rather than answering for an empty role list.
48
48
  */
49
49
  private readonly _userRoles;
50
50
  private readonly history;
51
- private readonly cursor;
52
- private readonly historyLength;
53
- private lastEditAt;
54
- /** Consecutive edits closer together than this fold into one undo step. */
55
- private static readonly COALESCE_MS;
56
51
  readonly canUndo: _angular_core.Signal<boolean>;
57
52
  readonly canRedo: _angular_core.Signal<boolean>;
58
- /**
59
- * Fold the current state into history.
60
- *
61
- * Called explicitly by the write paths rather than from an `effect`. An effect would have
62
- * been fewer call sites, but it requires an injection context: `BuilderStore` had no
63
- * constructor, so `new BuilderStore()` was legal, and adding one broke every caller that
64
- * did it with NG0203. Explicit calls also make the timing deterministic — a test can
65
- * assert straight after an edit instead of flushing effects first.
66
- *
67
- * Calling it twice for one operation is harmless: the second call sees the same signal
68
- * references already at the cursor and returns.
69
- *
70
- * `setFieldLabel` is bound to a keystroke, so recording every emission would make undo
71
- * walk back one character at a time. Two consecutive edits merge when they land inside
72
- * `COALESCE_MS` *and* the structure is unchanged — a rename coalesces, while adding,
73
- * removing or moving anything always earns its own step however fast it is clicked.
74
- */
75
53
  private record;
76
- /** How many undo steps are kept. */
77
- private static readonly MAX_HISTORY;
78
- /** Counts that distinguish a structural edit from a value edit. */
79
- private shapeOf;
80
54
  /** Start history again from the state just loaded. Nothing before it is undoable. */
81
55
  private resetHistory;
82
56
  undo(): void;
83
57
  redo(): void;
84
- private applyHistory;
58
+ private restore;
85
59
  readonly config: _angular_core.Signal<EntityFormConfig>;
86
60
  readonly selectedFieldId: _angular_core.Signal<string>;
87
61
  readonly activeLanguage: _angular_core.Signal<string>;
@@ -92,11 +66,8 @@ declare class BuilderStore {
92
66
  /**
93
67
  * Every field the config declares, sub-tabs included.
94
68
  *
95
- * This used to stop at top-level tabs, which quietly broke three things at once: nine of
96
- * `insuranceClaims`'s twenty-eight fields never appeared on the canvas, the entity-reference
97
- * picker could not offer a nested field as a source, and the drift check looked a nested
98
- * field up here, got nothing, and returned without checking. The store's structural
99
- * operations already walked the whole tree — only this view did not.
69
+ * The canvas, the entity-reference source picker and the drift check all read this, so it
70
+ * has to reach nested tabs just as the store's structural operations do.
100
71
  *
101
72
  * It deliberately does not descend into a field's own `children`: `group` and `array`
102
73
  * children are rendered by the row that owns them, not as rows of their own.
@@ -130,10 +101,9 @@ declare class BuilderStore {
130
101
  /**
131
102
  * Every tab in the tree, flattened.
132
103
  *
133
- * The structural operations below used to iterate `draft.tabs` directly, which is only
134
- * the top level. A field on a sub-tab could be selected and edited but never removed,
135
- * duplicated, moved or reordered — the builder could author nested configs it was then
136
- * unable to restructure, which is the worst possible state for an authoring tool.
104
+ * The structural operations below go through this rather than `draft.tabs`, which is only
105
+ * the top level — otherwise a field on a sub-tab could be edited but never removed,
106
+ * duplicated, moved or reordered.
137
107
  */
138
108
  private flattenTabs;
139
109
  /**
@@ -191,14 +161,11 @@ declare class BuilderStore {
191
161
  *
192
162
  * Ids are the wiring between fields — rules, cascades, patches and `showWhen` all address
193
163
  * fields by id — so a rename that only touches `field.id` silently breaks that wiring.
194
- * That was survivable while renaming was a rare manual act; label-derived ids make it
195
- * routine, so the references move with it.
196
- */
197
- /**
164
+ * Label-derived ids make renaming routine, so the references move with it.
165
+ *
198
166
  * `key` addresses the field to rename; `oldId` is the bare id every *reference* to it
199
- * carries. They were one parameter, which worked only while an id was unique across the
200
- * config: resolving needs the path, while `showWhen`, `parentField`, `autoPatch` targets
201
- * and rules are all keyed by bare id and never match a path.
167
+ * carries. They are separate because resolving needs the path, while `showWhen`,
168
+ * `parentField`, `autoPatch` targets and rules are all keyed by bare id.
202
169
  */
203
170
  private applyRename;
204
171
  removeField(key: string): void;
@@ -246,6 +213,7 @@ declare class BuilderStore {
246
213
  setFieldHint(id: string, language: string, value: string): void;
247
214
  toggleFlagValidator(id: string, validator: FlagValidator, on: boolean): void;
248
215
  setParamValidator(id: string, validator: ParamValidator, value: number | null): void;
216
+ setPatternValidator(id: string, pattern: string | null): void;
249
217
  getParamValidator(field: NestedFieldConfig, validator: ParamValidator): number | null;
250
218
  hasFlagValidator(field: NestedFieldConfig, validator: FlagValidator): boolean;
251
219
  /**
@@ -267,7 +235,7 @@ declare class BuilderStore {
267
235
  setFieldDataSource(fieldId: string, source: 'none' | 'manual' | 'lookup'): void;
268
236
  /** Set the named list a choice field reads its options from. */
269
237
  setListName(fieldId: string, listName: string): void;
270
- /** Link a field to a field defined in another entity configuration (Phase 8). */
238
+ /** Link a field to a field defined in another entity configuration */
271
239
  linkReferencedField(fieldId: string, sourceEntityKey: string, sourceField: NestedFieldConfig): void;
272
240
  /** Unlink a referenced field back to an independent field. */
273
241
  unlinkReferencedField(fieldId: string): void;
@@ -492,6 +460,7 @@ declare const DEFAULT_BUILDER_TEXT: {
492
460
  sectionAutomation: string;
493
461
  sectionRules: string;
494
462
  sectionReference: string;
463
+ sectionDependencies: string;
495
464
  width: string;
496
465
  widthQuarter: string;
497
466
  widthThird: string;
@@ -609,6 +578,30 @@ declare const DEFAULT_BUILDER_TEXT: {
609
578
  driftHeading: string;
610
579
  driftBody: string;
611
580
  syncWithSource: string;
581
+ pattern: string;
582
+ patternHint: string;
583
+ testPattern: string;
584
+ testPatternPlaceholder: string;
585
+ patternMatch: string;
586
+ patternNoMatch: string;
587
+ patternInvalid: string;
588
+ patternEmptyPrompt: string;
589
+ quickPresets: string;
590
+ dependsOn: string;
591
+ affects: string;
592
+ noDependencies: string;
593
+ ruleGraph: string;
594
+ ruleGraphTitle: string;
595
+ ruleGraphSubtitle: string;
596
+ filterDependencies: string;
597
+ noDependenciesFound: string;
598
+ jumpToField: string;
599
+ closeDialog: string;
600
+ dependencyTypeRule: string;
601
+ dependencyTypeShowWhen: string;
602
+ dependencyTypeCascade: string;
603
+ dependencyTypePatch: string;
604
+ totalDependencies: string;
612
605
  };
613
606
  /** The keys above, as a union — checked in templates, completed in a host's overrides. */
614
607
  type BuilderTextKey = keyof typeof DEFAULT_BUILDER_TEXT;
@@ -722,6 +715,10 @@ declare class EntityBuilderComponent implements OnChanges {
722
715
  toggleRightSidebar(): void;
723
716
  toggleFields(): void;
724
717
  togglePreview(): void;
718
+ readonly ruleGraphOpen: _angular_core.WritableSignal<boolean>;
719
+ openRuleGraph(): void;
720
+ closeRuleGraph(): void;
721
+ onSelectFieldFromGraph(key: string): void;
725
722
  protected collapseLeft(): void;
726
723
  protected expandLeft(): void;
727
724
  protected collapseRight(): void;
@@ -778,11 +775,8 @@ interface PaletteSection {
778
775
  /**
779
776
  * FieldPaletteComponent — the list of buildable field types.
780
777
  *
781
- * Two things changed the day this stopped being a flat grid of twenty-two buttons. The labels
782
- * were clipped mid-word — "Boolean Toggl", "Entity Referen", "File Attachmen" — because the
783
- * grid forced two equal columns and the button refused to wrap, so a third of the palette
784
- * could not be read. And with no order to them, finding "Month & Year" meant scanning the
785
- * whole list: the grouping and the filter are what make a palette this size navigable.
778
+ * Grouped and filterable, because a flat list of twenty-two types is not navigable, and
779
+ * tiles wrap their labels so names like "Entity Reference" are never clipped.
786
780
  */
787
781
  declare class FieldPaletteComponent {
788
782
  /** Builder chrome, overridable via BUILDER_TEXT. */
@@ -833,6 +827,32 @@ declare function fieldPathOptions(config: EntityFormConfig | null | undefined, l
833
827
  */
834
828
  declare function withExistingOptions(options: readonly FieldPathOption[], current: readonly (string | undefined)[]): FieldPathOption[];
835
829
 
830
+ type DependencyType = 'rule' | 'showWhen' | 'cascade' | 'patchOnTrue' | 'autoPatch';
831
+ interface RuleDependencyEdge {
832
+ id: string;
833
+ sourceKey: string;
834
+ sourceLabel: string;
835
+ targetKey: string;
836
+ targetLabel: string;
837
+ type: DependencyType;
838
+ actionSummary: string;
839
+ description: string;
840
+ sourceValid: boolean;
841
+ targetValid: boolean;
842
+ }
843
+ interface RuleDependencyGraphData {
844
+ edges: RuleDependencyEdge[];
845
+ totalRules: number;
846
+ totalShowWhen: number;
847
+ totalCascades: number;
848
+ totalPatches: number;
849
+ }
850
+ /**
851
+ * Computes all dependency edges (rules, showWhen, cascades, patchOnTrue, autoPatch)
852
+ * across an EntityFormConfig and its rules.
853
+ */
854
+ declare function computeRuleDependencies(config: EntityFormConfig | null | undefined, rules?: readonly FormRule[], language?: string): RuleDependencyGraphData;
855
+
836
856
  /**
837
857
  * FieldInspectorComponent — edits every property of the currently selected field.
838
858
  */
@@ -923,9 +943,7 @@ declare class FieldInspectorComponent {
923
943
  }[];
924
944
  /**
925
945
  * Seeds a new condition with the first field not already watched.
926
- *
927
- * It used to seed the literal string `field`, which is not a field id at all — so a new
928
- * condition started out referencing nothing and silently hid the field until it was edited.
946
+ * A seed that names no real field would silently hide this one until edited.
929
947
  */
930
948
  protected addShowWhen(field: NestedFieldConfig): void;
931
949
  protected renameShowWhen(field: NestedFieldConfig, oldKey: string, newKey: string): void;
@@ -937,6 +955,21 @@ declare class FieldInspectorComponent {
937
955
  */
938
956
  private parseShowWhen;
939
957
  private stringifyShowWhen;
958
+ protected readonly testSample: _angular_core.WritableSignal<string>;
959
+ protected readonly regexEvaluation: _angular_core.Signal<{
960
+ status: "empty" | "idle" | "match" | "no-match" | "invalid";
961
+ error?: string;
962
+ }>;
963
+ protected readonly patternPresets: {
964
+ label: string;
965
+ pattern: string;
966
+ }[];
967
+ protected supportsPattern(type: string): boolean;
968
+ protected applyPreset(field: NestedFieldConfig, pattern: string): void;
969
+ protected readonly allDependencies: _angular_core.Signal<ngx_dynamic_entity_builder.RuleDependencyGraphData>;
970
+ protected readonly incomingDependencies: _angular_core.Signal<RuleDependencyEdge[]>;
971
+ protected readonly outgoingDependencies: _angular_core.Signal<RuleDependencyEdge[]>;
972
+ protected selectField(key: string): void;
940
973
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<FieldInspectorComponent, never>;
941
974
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<FieldInspectorComponent, "ngx-field-inspector", never, {}, {}, never, never, true, never>;
942
975
  }
@@ -1092,5 +1125,21 @@ declare class EntityBuilderTreeNodeComponent {
1092
1125
  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>;
1093
1126
  }
1094
1127
 
1095
- export { BUILDER_TEXT, BuilderStore, BuilderTextService, DEFAULT_BUILDER_TEXT, EntityBuilderCanvasComponent, EntityBuilderComponent, EntityBuilderTreeNodeComponent, EntityReferenceConfigComponent, FieldInspectorComponent, FieldPaletteComponent, FieldRulesListComponent, RuleFormComponent, TabManagerComponent, fieldPathOptions, withExistingOptions };
1096
- export type { BuilderFieldGroup, BuilderProblem, BuilderTextKey, BuilderTextOverrides, FieldPathOption };
1128
+ declare class RuleDependencyGraphComponent {
1129
+ protected readonly ui: BuilderTextService;
1130
+ protected readonly store: BuilderStore;
1131
+ readonly dismiss: EventEmitter<void>;
1132
+ readonly selectField: EventEmitter<string>;
1133
+ protected readonly filterQuery: _angular_core.WritableSignal<string>;
1134
+ protected readonly selectedType: _angular_core.WritableSignal<DependencyType | "all">;
1135
+ protected readonly graphData: _angular_core.Signal<ngx_dynamic_entity_builder.RuleDependencyGraphData>;
1136
+ protected readonly filteredEdges: _angular_core.Signal<RuleDependencyEdge[]>;
1137
+ protected typeName(type: DependencyType): string;
1138
+ protected onNodeClick(key: string): void;
1139
+ protected onBackdropClick(event: MouseEvent): void;
1140
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<RuleDependencyGraphComponent, never>;
1141
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<RuleDependencyGraphComponent, "ngx-rule-dependency-graph", never, {}, { "dismiss": "dismiss"; "selectField": "selectField"; }, never, never, true, never>;
1142
+ }
1143
+
1144
+ export { BUILDER_TEXT, BuilderStore, BuilderTextService, DEFAULT_BUILDER_TEXT, EntityBuilderCanvasComponent, EntityBuilderComponent, EntityBuilderTreeNodeComponent, EntityReferenceConfigComponent, FieldInspectorComponent, FieldPaletteComponent, FieldRulesListComponent, RuleDependencyGraphComponent, RuleFormComponent, TabManagerComponent, computeRuleDependencies, fieldPathOptions, withExistingOptions };
1145
+ export type { BuilderFieldGroup, BuilderProblem, BuilderTextKey, BuilderTextOverrides, DependencyType, FieldPathOption, RuleDependencyEdge, RuleDependencyGraphData };