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.
|
|
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.
|
|
14
|
-
"ngx-dynamic-entity": "^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
|
|
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
|
|
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
|
-
*
|
|
96
|
-
*
|
|
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
|
|
134
|
-
* the top level
|
|
135
|
-
* duplicated, moved or reordered
|
|
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
|
-
*
|
|
195
|
-
*
|
|
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
|
|
200
|
-
*
|
|
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
|
|
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
|
-
*
|
|
782
|
-
*
|
|
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
|
-
|
|
1096
|
-
|
|
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 };
|