ngx-dynamic-entity-builder 1.3.0 → 1.4.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.
- package/README.md +2 -1
- package/fesm2022/ngx-dynamic-entity-builder.mjs +409 -92
- package/fesm2022/ngx-dynamic-entity-builder.mjs.map +1 -1
- package/package.json +7 -7
- package/types/ngx-dynamic-entity-builder.d.ts +523 -0
- package/esm2022/lib/builder-store.service.mjs +0 -1057
- package/esm2022/lib/clone.mjs +0 -14
- package/esm2022/lib/components/entity-builder-canvas.component.mjs +0 -84
- package/esm2022/lib/components/entity-builder-tree-node.component.mjs +0 -192
- package/esm2022/lib/components/entity-reference-config.component.mjs +0 -405
- package/esm2022/lib/components/field-inspector.component.mjs +0 -139
- package/esm2022/lib/components/field-palette.component.mjs +0 -57
- package/esm2022/lib/components/field-rules-list.component.mjs +0 -224
- package/esm2022/lib/components/referenced-field-config.component.mjs +0 -235
- package/esm2022/lib/components/rule-form.component.mjs +0 -201
- package/esm2022/lib/components/tab-manager.component.mjs +0 -354
- package/esm2022/lib/entity-builder.component.mjs +0 -159
- package/esm2022/lib/field-catalog.mjs +0 -6
- package/esm2022/ngx-dynamic-entity-builder.mjs +0 -5
- package/esm2022/public-api.mjs +0 -16
- package/index.d.ts +0 -5
- package/lib/builder-store.service.d.ts +0 -206
- package/lib/clone.d.ts +0 -9
- package/lib/components/entity-builder-canvas.component.d.ts +0 -9
- package/lib/components/entity-builder-tree-node.component.d.ts +0 -17
- package/lib/components/entity-reference-config.component.d.ts +0 -29
- package/lib/components/field-inspector.component.d.ts +0 -33
- package/lib/components/field-palette.component.d.ts +0 -13
- package/lib/components/field-rules-list.component.d.ts +0 -19
- package/lib/components/referenced-field-config.component.d.ts +0 -24
- package/lib/components/rule-form.component.d.ts +0 -16
- package/lib/components/tab-manager.component.d.ts +0 -28
- package/lib/entity-builder.component.d.ts +0 -45
- package/lib/field-catalog.d.ts +0 -5
- package/public-api.d.ts +0 -12
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, effect, inject } from '@angular/core';
|
|
2
|
-
import { FormsModule } from '@angular/forms';
|
|
3
|
-
import { MatButtonModule } from '@angular/material/button';
|
|
4
|
-
import { MatCardModule } from '@angular/material/card';
|
|
5
|
-
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
6
|
-
import { MatExpansionModule } from '@angular/material/expansion';
|
|
7
|
-
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
8
|
-
import { MatIconModule } from '@angular/material/icon';
|
|
9
|
-
import { MatInputModule } from '@angular/material/input';
|
|
10
|
-
import { MatSelectModule } from '@angular/material/select';
|
|
11
|
-
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
|
12
|
-
import { MatToolbarModule } from '@angular/material/toolbar';
|
|
13
|
-
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
14
|
-
import { COMMON_MODULES, } from '@dynamic-entity/core';
|
|
15
|
-
import { ConfigSourceService } from 'ngx-dynamic-entity';
|
|
16
|
-
import { BuilderStore } from './builder-store.service';
|
|
17
|
-
import { FieldInspectorComponent } from './components/field-inspector.component';
|
|
18
|
-
import { FieldPaletteComponent } from './components/field-palette.component';
|
|
19
|
-
import { TabManagerComponent } from './components/tab-manager.component';
|
|
20
|
-
import { EntityBuilderCanvasComponent } from './components/entity-builder-canvas.component';
|
|
21
|
-
import * as i0 from "@angular/core";
|
|
22
|
-
import * as i1 from "@angular/forms";
|
|
23
|
-
import * as i2 from "@angular/material/button";
|
|
24
|
-
import * as i3 from "@angular/material/card";
|
|
25
|
-
import * as i4 from "@angular/material/expansion";
|
|
26
|
-
import * as i5 from "@angular/material/form-field";
|
|
27
|
-
import * as i6 from "@angular/material/icon";
|
|
28
|
-
import * as i7 from "@angular/material/input";
|
|
29
|
-
import * as i8 from "@angular/material/select";
|
|
30
|
-
import * as i9 from "@angular/material/core";
|
|
31
|
-
import * as i10 from "@angular/material/slide-toggle";
|
|
32
|
-
import * as i11 from "@angular/material/toolbar";
|
|
33
|
-
import * as i12 from "@angular/material/tooltip";
|
|
34
|
-
/** RBAC actions surfaced in the settings panel. */
|
|
35
|
-
const RBAC_ACTIONS = ['view', 'edit', 'delete'];
|
|
36
|
-
/** Shared stable empty array — never allocate a fresh [] per change-detection (mat-select loops). */
|
|
37
|
-
const EMPTY_ROLES = Object.freeze([]);
|
|
38
|
-
/**
|
|
39
|
-
* EntityBuilderComponent — the top-level visual builder for an EntityFormConfig.
|
|
40
|
-
*/
|
|
41
|
-
export class EntityBuilderComponent {
|
|
42
|
-
store = inject(BuilderStore);
|
|
43
|
-
/**
|
|
44
|
-
* Optional: only apps that registered a CONFIG_SOURCE have one. Used to drop the cached
|
|
45
|
-
* copy of a config the moment it is edited — see `doSave`.
|
|
46
|
-
*/
|
|
47
|
-
configSource = inject(ConfigSourceService, { optional: true });
|
|
48
|
-
/** Existing config to edit. When omitted, the builder starts blank. */
|
|
49
|
-
config;
|
|
50
|
-
/** Languages available for label/placeholder editing. First entry is the default. */
|
|
51
|
-
languages = ['en'];
|
|
52
|
-
/** Optional role list — enables multi-select role pickers for RBAC instead of free text. */
|
|
53
|
-
availableRoles = [];
|
|
54
|
-
/**
|
|
55
|
-
* Roles of the person using the builder. Distinct from `availableRoles`, which is the
|
|
56
|
-
* vocabulary a schema may reference. Passed to the `SYSTEM_DEFAULT_CAN_EDIT` predicate so
|
|
57
|
-
* it can decide whether this user may edit system-default tabs.
|
|
58
|
-
*/
|
|
59
|
-
userRoles = [];
|
|
60
|
-
/** Optional common-module definitions for module tabs; defaults to the built-in list from core. */
|
|
61
|
-
commonModules = COMMON_MODULES;
|
|
62
|
-
/** Emitted on every change to the working config. */
|
|
63
|
-
configChange = new EventEmitter();
|
|
64
|
-
/** Emitted when the user clicks Save. Carries a clean, deep-cloned config. */
|
|
65
|
-
save = new EventEmitter();
|
|
66
|
-
rbacActions = RBAC_ACTIONS;
|
|
67
|
-
constructor() {
|
|
68
|
-
effect(() => this.configChange.emit(this.store.config()), { allowSignalWrites: true });
|
|
69
|
-
}
|
|
70
|
-
ngOnChanges(changes) {
|
|
71
|
-
if (changes['config'] && changes['config'].currentValue !== changes['config'].previousValue) {
|
|
72
|
-
if (this.config)
|
|
73
|
-
this.store.load(this.config);
|
|
74
|
-
else if (changes['config'].isFirstChange())
|
|
75
|
-
this.store.reset();
|
|
76
|
-
}
|
|
77
|
-
if (changes['languages'] && this.languages.length) {
|
|
78
|
-
const active = this.store.activeLanguage();
|
|
79
|
-
if (!this.languages.includes(active))
|
|
80
|
-
this.store.setActiveLanguage(this.languages[0]);
|
|
81
|
-
}
|
|
82
|
-
if (changes['userRoles']) {
|
|
83
|
-
this.store.setUserRoles(this.userRoles);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
// ─── Toolbar actions ──────────────────────────────────────────────────────
|
|
87
|
-
doSave() {
|
|
88
|
-
const config = this.store.exportConfig();
|
|
89
|
-
// Saving is the moment this entity's config changes, so anything holding a cached copy is
|
|
90
|
-
// now stale — most visibly a referenced field elsewhere resolving against the old schema.
|
|
91
|
-
// ConfigSourceService caches per entity and exposed clearCache from the start, but nothing
|
|
92
|
-
// ever called it, so a cache entry lived for the lifetime of the page.
|
|
93
|
-
this.configSource?.clearCache(config.entity);
|
|
94
|
-
this.save.emit(config);
|
|
95
|
-
}
|
|
96
|
-
get json() {
|
|
97
|
-
return JSON.stringify(this.store.exportConfig(), null, 2);
|
|
98
|
-
}
|
|
99
|
-
copyJson() {
|
|
100
|
-
if (typeof navigator !== 'undefined' && navigator.clipboard) {
|
|
101
|
-
void navigator.clipboard.writeText(this.json);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
// ─── RBAC settings ────────────────────────────────────────────────────────
|
|
105
|
-
rolesFor(action) {
|
|
106
|
-
// Return the stored array (stable ref between mutations) or a shared empty — NOT a fresh [],
|
|
107
|
-
// which would make the bound mat-select re-evaluate every CD and loop forever.
|
|
108
|
-
return this.store.config().permissions?.[action] ?? EMPTY_ROLES;
|
|
109
|
-
}
|
|
110
|
-
setRoles(action, roles) {
|
|
111
|
-
this.store.setPermission(action, roles);
|
|
112
|
-
}
|
|
113
|
-
/** Parse a comma-separated role string into a trimmed, de-duplicated array. */
|
|
114
|
-
setRolesFromText(action, text) {
|
|
115
|
-
const roles = Array.from(new Set(text
|
|
116
|
-
.split(',')
|
|
117
|
-
.map(r => r.trim())
|
|
118
|
-
.filter(Boolean)));
|
|
119
|
-
this.store.setPermission(action, roles);
|
|
120
|
-
}
|
|
121
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EntityBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
122
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: EntityBuilderComponent, isStandalone: true, selector: "ngx-entity-builder", inputs: { config: "config", languages: "languages", availableRoles: "availableRoles", userRoles: "userRoles", commonModules: "commonModules" }, outputs: { configChange: "configChange", save: "save" }, providers: [BuilderStore], usesOnChanges: true, ngImport: i0, template: "<mat-toolbar class=\"deb-toolbar\" color=\"primary\">\n <mat-icon>dashboard_customize</mat-icon>\n <span class=\"deb-toolbar__title\">Entity Builder</span>\n <span class=\"deb-spacer\"></span>\n\n @if (store.problems().length) {\n <button\n mat-button\n type=\"button\"\n class=\"deb-problems\"\n [class.deb-problems--error]=\"!store.isValid()\"\n [matTooltip]=\"store.problems().length + ' issue(s) \u2014 hover items in the list'\"\n >\n <mat-icon>{{ store.isValid() ? 'warning' : 'error' }}</mat-icon>\n {{ store.errors().length }} / {{ store.problems().length }}\n </button>\n }\n\n <button mat-button type=\"button\" (click)=\"copyJson()\">\n <mat-icon>content_copy</mat-icon> Copy JSON\n </button>\n <!-- primary, not accent: white on Material's default pink accent is 3.33:1, below AA. -->\n <button mat-flat-button color=\"primary\" type=\"button\" [disabled]=\"!store.isValid()\" (click)=\"doSave()\">\n <mat-icon>save</mat-icon> Save\n </button>\n</mat-toolbar>\n\n<div class=\"deb-body\">\n <!-- \u2500\u2500\u2500 Left: settings, palette, tabs \u2500\u2500\u2500 -->\n <div class=\"deb-col deb-col--left\">\n <mat-card>\n <mat-card-content>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>Entity name</mat-label>\n <input\n matInput\n [ngModel]=\"store.config().entity\"\n (ngModelChange)=\"store.setEntityName($event)\"\n placeholder=\"e.g. clients\"\n />\n </mat-form-field>\n\n <div class=\"deb-row\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-grow\">\n <mat-label>Editing language</mat-label>\n <mat-select\n [ngModel]=\"store.activeLanguage()\"\n (ngModelChange)=\"store.setActiveLanguage($event)\"\n >\n @for (l of languages; track l) {\n <mat-option [value]=\"l\">{{ l }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n </div>\n\n <mat-slide-toggle\n [ngModel]=\"store.config().maskData ?? false\"\n (ngModelChange)=\"store.setMaskData($event)\"\n >Mask this entity (RBAC)</mat-slide-toggle>\n\n <mat-expansion-panel class=\"deb-rbac\">\n <mat-expansion-panel-header>\n <mat-panel-title>Permissions</mat-panel-title>\n </mat-expansion-panel-header>\n @for (action of rbacActions; track action) {\n @if (availableRoles.length) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>{{ action }} roles</mat-label>\n <mat-select multiple [ngModel]=\"rolesFor(action)\" (ngModelChange)=\"setRoles(action, $event)\">\n @for (role of availableRoles; track role) {\n <mat-option [value]=\"role\">{{ role }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n } @else {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>{{ action }} roles (comma-separated)</mat-label>\n <input\n matInput\n [ngModel]=\"rolesFor(action).join(', ')\"\n (ngModelChange)=\"setRolesFromText(action, $event)\"\n />\n </mat-form-field>\n }\n }\n <p class=\"deb-hint\">Empty = no restriction for that action.</p>\n </mat-expansion-panel>\n </mat-card-content>\n </mat-card>\n\n <mat-card>\n <mat-card-header><mat-card-title>Add field</mat-card-title></mat-card-header>\n <mat-card-content>\n <ngx-field-palette (pick)=\"store.addField($event)\"></ngx-field-palette>\n </mat-card-content>\n </mat-card>\n\n <mat-card>\n <mat-card-content>\n <ngx-tab-manager></ngx-tab-manager>\n </mat-card-content>\n </mat-card>\n </div>\n\n <!-- \u2500\u2500\u2500 Center: field canvas \u2500\u2500\u2500 -->\n <div class=\"deb-col deb-col--center\">\n <ngx-entity-builder-canvas />\n </div>\n\n <!-- \u2500\u2500\u2500 Right: inspector \u2500\u2500\u2500 -->\n <div class=\"deb-col deb-col--right\">\n <mat-card>\n <mat-card-header><mat-card-title>Field properties</mat-card-title></mat-card-header>\n <mat-card-content>\n <ngx-field-inspector></ngx-field-inspector>\n </mat-card-content>\n </mat-card>\n </div>\n</div>\n\n<!-- \u2500\u2500\u2500 Footer: JSON + optional live preview \u2500\u2500\u2500 -->\n<div class=\"deb-footer\">\n <mat-expansion-panel>\n <mat-expansion-panel-header>\n <mat-panel-title><mat-icon>data_object</mat-icon> Config JSON</mat-panel-title>\n </mat-expansion-panel-header>\n <pre class=\"deb-json\">{{ json }}</pre>\n </mat-expansion-panel>\n\n <div class=\"deb-preview-slot\">\n <ng-content select=\"[ngxBuilderPreview]\"></ng-content>\n </div>\n</div>\n", styles: [":host{--deb-accent: #6366f1;--deb-accent-hover: #4f46e5;--deb-accent-soft: #eeef2;--deb-border: #e2e8f0;--deb-muted: #64748b;--deb-surface: #ffffff;display:block}.deb-toolbar__title{margin-left:8px;font-family:var(--font-heading, sans-serif);font-size:16px;font-weight:700;color:#fff}.deb-spacer{flex:1 1 auto}.deb-problems--error{color:#ef4444;font-weight:600}.deb-full{width:100%}.deb-grow{flex:1}.deb-row{display:flex;gap:8px;align-items:center}.deb-section-title{font-family:var(--font-heading, sans-serif);font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--deb-muted)}.deb-hint{margin:4px 0 0;font-size:12px;color:var(--deb-muted)}.deb-chip{display:inline-block;padding:3px 10px;border-radius:9999px;background:var(--deb-accent-soft);color:var(--deb-accent-hover);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.03em}.deb-chip--muted{background:#f1f5f9;color:var(--deb-muted)}.deb-body{display:grid;grid-template-columns:320px minmax(0,1fr) 380px;gap:20px;padding:20px;align-items:start}.deb-col{display:flex;flex-direction:column;gap:16px;min-width:0}.deb-col--right{position:sticky;top:20px}@media (max-width: 1100px){.deb-body{grid-template-columns:1fr}.deb-col--right{position:static}}.deb-field-list{display:flex;flex-direction:column;gap:10px}.deb-field-row{display:flex;align-items:center;gap:10px;padding:10px 14px;border:1px solid var(--deb-border);border-radius:10px;background:var(--deb-surface);cursor:pointer;box-shadow:0 1px 3px #00000008;transition:all .18s cubic-bezier(.16,1,.3,1)}.deb-field-row:hover{border-color:#a5b4fc;background:#fcfaff;transform:translateY(-1px);box-shadow:0 4px 12px #6366f114}.deb-field-row--active{border-color:var(--deb-accent);border-left:4px solid var(--deb-accent);background:#f5f3ff;box-shadow:0 4px 16px #6366f12e}.deb-type-badge{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;padding:2px 7px;border-radius:6px;background:#e0e7ff;color:#4338ca}.deb-drag-handle{cursor:grab;color:#94a3b8;transition:color .15s}.deb-drag-handle:hover,.deb-field-type{color:var(--deb-accent)}.deb-field-meta{display:flex;flex-direction:column;min-width:0;flex:1}.deb-field-label{font-family:var(--font-heading, sans-serif);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#0f172a;font-size:14px}.deb-field-id{font-size:11px;color:var(--deb-muted);font-family:ui-monospace,SFMono-Regular,monospace}.deb-req{color:#ef4444;font-weight:700}.deb-empty,.deb-inspector__empty{text-align:center;color:var(--deb-muted);padding:40px 16px}.deb-empty mat-icon{transform:scale(1.8);margin-bottom:16px;color:#cbd5e1}.cdk-drag-preview{box-shadow:0 12px 28px #4f46e538;border-radius:10px;border:1px solid var(--deb-accent);background:#fff}.cdk-drag-placeholder{opacity:.35}.cdk-drag-animating{transition:transform .2s cubic-bezier(0,0,.2,1)}.deb-field-list.cdk-drop-list-dragging .deb-field-row:not(.cdk-drag-placeholder){transition:transform .2s cubic-bezier(0,0,.2,1)}.deb-footer{padding:0 20px 20px;display:flex;flex-direction:column;gap:16px}.deb-json{margin:0;max-height:320px;overflow:auto;font-family:ui-monospace,SFMono-Regular,monospace;font-size:12px;line-height:1.5;padding:14px;background:#0f172a;color:#e2e8f0;border-radius:10px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i2.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatCardModule }, { kind: "component", type: i3.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i3.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i3.MatCardHeader, selector: "mat-card-header" }, { kind: "directive", type: i3.MatCardTitle, selector: "mat-card-title, [mat-card-title], [matCardTitle]" }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "ngmodule", type: MatExpansionModule }, { kind: "component", type: i4.MatExpansionPanel, selector: "mat-expansion-panel", inputs: ["hideToggle", "togglePosition"], outputs: ["afterExpand", "afterCollapse"], exportAs: ["matExpansionPanel"] }, { kind: "component", type: i4.MatExpansionPanelHeader, selector: "mat-expansion-panel-header", inputs: ["expandedHeight", "collapsedHeight", "tabIndex"] }, { kind: "directive", type: i4.MatExpansionPanelTitle, selector: "mat-panel-title" }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i5.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i9.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: i10.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "component", type: i11.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i12.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: FieldPaletteComponent, selector: "ngx-field-palette", outputs: ["pick"] }, { kind: "component", type: TabManagerComponent, selector: "ngx-tab-manager" }, { kind: "component", type: FieldInspectorComponent, selector: "ngx-field-inspector" }, { kind: "component", type: EntityBuilderCanvasComponent, selector: "ngx-entity-builder-canvas" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
123
|
-
}
|
|
124
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EntityBuilderComponent, decorators: [{
|
|
125
|
-
type: Component,
|
|
126
|
-
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ngx-entity-builder', standalone: true, providers: [BuilderStore], imports: [
|
|
127
|
-
FormsModule,
|
|
128
|
-
MatButtonModule,
|
|
129
|
-
MatCardModule,
|
|
130
|
-
MatCheckboxModule,
|
|
131
|
-
MatExpansionModule,
|
|
132
|
-
MatFormFieldModule,
|
|
133
|
-
MatIconModule,
|
|
134
|
-
MatInputModule,
|
|
135
|
-
MatSelectModule,
|
|
136
|
-
MatSlideToggleModule,
|
|
137
|
-
MatToolbarModule,
|
|
138
|
-
MatTooltipModule,
|
|
139
|
-
FieldPaletteComponent,
|
|
140
|
-
TabManagerComponent,
|
|
141
|
-
FieldInspectorComponent,
|
|
142
|
-
EntityBuilderCanvasComponent,
|
|
143
|
-
], template: "<mat-toolbar class=\"deb-toolbar\" color=\"primary\">\n <mat-icon>dashboard_customize</mat-icon>\n <span class=\"deb-toolbar__title\">Entity Builder</span>\n <span class=\"deb-spacer\"></span>\n\n @if (store.problems().length) {\n <button\n mat-button\n type=\"button\"\n class=\"deb-problems\"\n [class.deb-problems--error]=\"!store.isValid()\"\n [matTooltip]=\"store.problems().length + ' issue(s) \u2014 hover items in the list'\"\n >\n <mat-icon>{{ store.isValid() ? 'warning' : 'error' }}</mat-icon>\n {{ store.errors().length }} / {{ store.problems().length }}\n </button>\n }\n\n <button mat-button type=\"button\" (click)=\"copyJson()\">\n <mat-icon>content_copy</mat-icon> Copy JSON\n </button>\n <!-- primary, not accent: white on Material's default pink accent is 3.33:1, below AA. -->\n <button mat-flat-button color=\"primary\" type=\"button\" [disabled]=\"!store.isValid()\" (click)=\"doSave()\">\n <mat-icon>save</mat-icon> Save\n </button>\n</mat-toolbar>\n\n<div class=\"deb-body\">\n <!-- \u2500\u2500\u2500 Left: settings, palette, tabs \u2500\u2500\u2500 -->\n <div class=\"deb-col deb-col--left\">\n <mat-card>\n <mat-card-content>\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>Entity name</mat-label>\n <input\n matInput\n [ngModel]=\"store.config().entity\"\n (ngModelChange)=\"store.setEntityName($event)\"\n placeholder=\"e.g. clients\"\n />\n </mat-form-field>\n\n <div class=\"deb-row\">\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-grow\">\n <mat-label>Editing language</mat-label>\n <mat-select\n [ngModel]=\"store.activeLanguage()\"\n (ngModelChange)=\"store.setActiveLanguage($event)\"\n >\n @for (l of languages; track l) {\n <mat-option [value]=\"l\">{{ l }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n </div>\n\n <mat-slide-toggle\n [ngModel]=\"store.config().maskData ?? false\"\n (ngModelChange)=\"store.setMaskData($event)\"\n >Mask this entity (RBAC)</mat-slide-toggle>\n\n <mat-expansion-panel class=\"deb-rbac\">\n <mat-expansion-panel-header>\n <mat-panel-title>Permissions</mat-panel-title>\n </mat-expansion-panel-header>\n @for (action of rbacActions; track action) {\n @if (availableRoles.length) {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>{{ action }} roles</mat-label>\n <mat-select multiple [ngModel]=\"rolesFor(action)\" (ngModelChange)=\"setRoles(action, $event)\">\n @for (role of availableRoles; track role) {\n <mat-option [value]=\"role\">{{ role }}</mat-option>\n }\n </mat-select>\n </mat-form-field>\n } @else {\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\n <mat-label>{{ action }} roles (comma-separated)</mat-label>\n <input\n matInput\n [ngModel]=\"rolesFor(action).join(', ')\"\n (ngModelChange)=\"setRolesFromText(action, $event)\"\n />\n </mat-form-field>\n }\n }\n <p class=\"deb-hint\">Empty = no restriction for that action.</p>\n </mat-expansion-panel>\n </mat-card-content>\n </mat-card>\n\n <mat-card>\n <mat-card-header><mat-card-title>Add field</mat-card-title></mat-card-header>\n <mat-card-content>\n <ngx-field-palette (pick)=\"store.addField($event)\"></ngx-field-palette>\n </mat-card-content>\n </mat-card>\n\n <mat-card>\n <mat-card-content>\n <ngx-tab-manager></ngx-tab-manager>\n </mat-card-content>\n </mat-card>\n </div>\n\n <!-- \u2500\u2500\u2500 Center: field canvas \u2500\u2500\u2500 -->\n <div class=\"deb-col deb-col--center\">\n <ngx-entity-builder-canvas />\n </div>\n\n <!-- \u2500\u2500\u2500 Right: inspector \u2500\u2500\u2500 -->\n <div class=\"deb-col deb-col--right\">\n <mat-card>\n <mat-card-header><mat-card-title>Field properties</mat-card-title></mat-card-header>\n <mat-card-content>\n <ngx-field-inspector></ngx-field-inspector>\n </mat-card-content>\n </mat-card>\n </div>\n</div>\n\n<!-- \u2500\u2500\u2500 Footer: JSON + optional live preview \u2500\u2500\u2500 -->\n<div class=\"deb-footer\">\n <mat-expansion-panel>\n <mat-expansion-panel-header>\n <mat-panel-title><mat-icon>data_object</mat-icon> Config JSON</mat-panel-title>\n </mat-expansion-panel-header>\n <pre class=\"deb-json\">{{ json }}</pre>\n </mat-expansion-panel>\n\n <div class=\"deb-preview-slot\">\n <ng-content select=\"[ngxBuilderPreview]\"></ng-content>\n </div>\n</div>\n", styles: [":host{--deb-accent: #6366f1;--deb-accent-hover: #4f46e5;--deb-accent-soft: #eeef2;--deb-border: #e2e8f0;--deb-muted: #64748b;--deb-surface: #ffffff;display:block}.deb-toolbar__title{margin-left:8px;font-family:var(--font-heading, sans-serif);font-size:16px;font-weight:700;color:#fff}.deb-spacer{flex:1 1 auto}.deb-problems--error{color:#ef4444;font-weight:600}.deb-full{width:100%}.deb-grow{flex:1}.deb-row{display:flex;gap:8px;align-items:center}.deb-section-title{font-family:var(--font-heading, sans-serif);font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--deb-muted)}.deb-hint{margin:4px 0 0;font-size:12px;color:var(--deb-muted)}.deb-chip{display:inline-block;padding:3px 10px;border-radius:9999px;background:var(--deb-accent-soft);color:var(--deb-accent-hover);font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.03em}.deb-chip--muted{background:#f1f5f9;color:var(--deb-muted)}.deb-body{display:grid;grid-template-columns:320px minmax(0,1fr) 380px;gap:20px;padding:20px;align-items:start}.deb-col{display:flex;flex-direction:column;gap:16px;min-width:0}.deb-col--right{position:sticky;top:20px}@media (max-width: 1100px){.deb-body{grid-template-columns:1fr}.deb-col--right{position:static}}.deb-field-list{display:flex;flex-direction:column;gap:10px}.deb-field-row{display:flex;align-items:center;gap:10px;padding:10px 14px;border:1px solid var(--deb-border);border-radius:10px;background:var(--deb-surface);cursor:pointer;box-shadow:0 1px 3px #00000008;transition:all .18s cubic-bezier(.16,1,.3,1)}.deb-field-row:hover{border-color:#a5b4fc;background:#fcfaff;transform:translateY(-1px);box-shadow:0 4px 12px #6366f114}.deb-field-row--active{border-color:var(--deb-accent);border-left:4px solid var(--deb-accent);background:#f5f3ff;box-shadow:0 4px 16px #6366f12e}.deb-type-badge{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;padding:2px 7px;border-radius:6px;background:#e0e7ff;color:#4338ca}.deb-drag-handle{cursor:grab;color:#94a3b8;transition:color .15s}.deb-drag-handle:hover,.deb-field-type{color:var(--deb-accent)}.deb-field-meta{display:flex;flex-direction:column;min-width:0;flex:1}.deb-field-label{font-family:var(--font-heading, sans-serif);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#0f172a;font-size:14px}.deb-field-id{font-size:11px;color:var(--deb-muted);font-family:ui-monospace,SFMono-Regular,monospace}.deb-req{color:#ef4444;font-weight:700}.deb-empty,.deb-inspector__empty{text-align:center;color:var(--deb-muted);padding:40px 16px}.deb-empty mat-icon{transform:scale(1.8);margin-bottom:16px;color:#cbd5e1}.cdk-drag-preview{box-shadow:0 12px 28px #4f46e538;border-radius:10px;border:1px solid var(--deb-accent);background:#fff}.cdk-drag-placeholder{opacity:.35}.cdk-drag-animating{transition:transform .2s cubic-bezier(0,0,.2,1)}.deb-field-list.cdk-drop-list-dragging .deb-field-row:not(.cdk-drag-placeholder){transition:transform .2s cubic-bezier(0,0,.2,1)}.deb-footer{padding:0 20px 20px;display:flex;flex-direction:column;gap:16px}.deb-json{margin:0;max-height:320px;overflow:auto;font-family:ui-monospace,SFMono-Regular,monospace;font-size:12px;line-height:1.5;padding:14px;background:#0f172a;color:#e2e8f0;border-radius:10px}\n"] }]
|
|
144
|
-
}], ctorParameters: () => [], propDecorators: { config: [{
|
|
145
|
-
type: Input
|
|
146
|
-
}], languages: [{
|
|
147
|
-
type: Input
|
|
148
|
-
}], availableRoles: [{
|
|
149
|
-
type: Input
|
|
150
|
-
}], userRoles: [{
|
|
151
|
-
type: Input
|
|
152
|
-
}], commonModules: [{
|
|
153
|
-
type: Input
|
|
154
|
-
}], configChange: [{
|
|
155
|
-
type: Output
|
|
156
|
-
}], save: [{
|
|
157
|
-
type: Output
|
|
158
|
-
}] } });
|
|
159
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5LWJ1aWxkZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9lbnRpdHktYnVpbGRlci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi9zcmMvbGliL2VudGl0eS1idWlsZGVyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBYSxNQUFNLEVBQWlCLE1BQU0sRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDMUksT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDL0QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDakUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDbEUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDM0QsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDdEUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDN0QsT0FBTyxFQUNMLGNBQWMsR0FJZixNQUFNLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3pELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUNqRixPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxzQ0FBc0MsQ0FBQztBQUM3RSxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUN6RSxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSw4Q0FBOEMsQ0FBQzs7Ozs7Ozs7Ozs7Ozs7QUFFNUYsbURBQW1EO0FBQ25ELE1BQU0sWUFBWSxHQUFnQyxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUM7QUFFN0UscUdBQXFHO0FBQ3JHLE1BQU0sV0FBVyxHQUFzQixNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBRXpEOztHQUVHO0FBMkJILE1BQU0sT0FBTyxzQkFBc0I7SUFDZCxLQUFLLEdBQUcsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQ2hEOzs7T0FHRztJQUNjLFlBQVksR0FBRyxNQUFNLENBQUMsbUJBQW1CLEVBQUUsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUVoRix1RUFBdUU7SUFDOUQsTUFBTSxDQUFvQjtJQUNuQyxxRkFBcUY7SUFDNUUsU0FBUyxHQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdEMsNEZBQTRGO0lBQ25GLGNBQWMsR0FBYSxFQUFFLENBQUM7SUFDdkM7Ozs7T0FJRztJQUNNLFNBQVMsR0FBYSxFQUFFLENBQUM7SUFDbEMsbUdBQW1HO0lBQzFGLGFBQWEsR0FBaUMsY0FBYyxDQUFDO0lBRXRFLHFEQUFxRDtJQUMzQyxZQUFZLEdBQUcsSUFBSSxZQUFZLEVBQW9CLENBQUM7SUFDOUQsOEVBQThFO0lBQ3BFLElBQUksR0FBRyxJQUFJLFlBQVksRUFBb0IsQ0FBQztJQUVuQyxXQUFXLEdBQUcsWUFBWSxDQUFDO0lBRTlDO1FBQ0UsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLGlCQUFpQixFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDekYsQ0FBQztJQUVELFdBQVcsQ0FBQyxPQUFzQjtRQUNoQyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsWUFBWSxLQUFLLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxhQUFhLEVBQUUsQ0FBQztZQUM1RixJQUFJLElBQUksQ0FBQyxNQUFNO2dCQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztpQkFDekMsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUMsYUFBYSxFQUFFO2dCQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDakUsQ0FBQztRQUNELElBQUksT0FBTyxDQUFDLFdBQVcsQ0FBQyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDbEQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUMzQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDO2dCQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3hGLENBQUM7UUFDRCxJQUFJLE9BQU8sQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO1lBQ3pCLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUMxQyxDQUFDO0lBQ0gsQ0FBQztJQUVELDZFQUE2RTtJQUVuRSxNQUFNO1FBQ2QsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUV6QywwRkFBMEY7UUFDMUYsMEZBQTBGO1FBQzFGLDJGQUEyRjtRQUMzRix1RUFBdUU7UUFDdkUsSUFBSSxDQUFDLFlBQVksRUFBRSxVQUFVLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRTdDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3pCLENBQUM7SUFFRCxJQUFjLElBQUk7UUFDaEIsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsWUFBWSxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQzVELENBQUM7SUFFUyxRQUFRO1FBQ2hCLElBQUksT0FBTyxTQUFTLEtBQUssV0FBVyxJQUFJLFNBQVMsQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUM1RCxLQUFLLFNBQVMsQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNoRCxDQUFDO0lBQ0gsQ0FBQztJQUVELDZFQUE2RTtJQUVuRSxRQUFRLENBQUMsTUFBK0I7UUFDaEQsNkZBQTZGO1FBQzdGLCtFQUErRTtRQUMvRSxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksV0FBVyxDQUFDO0lBQ2xFLENBQUM7SUFFUyxRQUFRLENBQUMsTUFBK0IsRUFBRSxLQUFlO1FBQ2pFLElBQUksQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBRUQsK0VBQStFO0lBQ3JFLGdCQUFnQixDQUFDLE1BQStCLEVBQUUsSUFBWTtRQUN0RSxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsSUFBSSxDQUN0QixJQUFJLEdBQUcsQ0FDTCxJQUFJO2FBQ0QsS0FBSyxDQUFDLEdBQUcsQ0FBQzthQUNWLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQzthQUNsQixNQUFNLENBQUMsT0FBTyxDQUFDLENBQ25CLENBQ0YsQ0FBQztRQUNGLElBQUksQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQztJQUMxQyxDQUFDO3dHQS9GVSxzQkFBc0I7NEZBQXRCLHNCQUFzQiwwUUF0QnRCLENBQUMsWUFBWSxDQUFDLCtDQ3ZDM0IsOGlLQXNJQSw4d0dEN0ZJLFdBQVcsOG1CQUNYLGVBQWUsMk5BQ2YsYUFBYSxrWkFDYixpQkFBaUIsOEJBQ2pCLGtCQUFrQix5ZEFDbEIsa0JBQWtCLDBTQUNsQixhQUFhLG1MQUNiLGNBQWMsMFdBQ2QsZUFBZSxtckJBQ2Ysb0JBQW9CLG1XQUNwQixnQkFBZ0IsaUpBQ2hCLGdCQUFnQiw4VEFDaEIscUJBQXFCLGlGQUNyQixtQkFBbUIsNERBQ25CLHVCQUF1QixnRUFDdkIsNEJBQTRCOzs0RkFLbkIsc0JBQXNCO2tCQTFCbEMsU0FBUztzQ0FDUyx1QkFBdUIsQ0FBQyxNQUFNLFlBQ3JDLG9CQUFvQixjQUNsQixJQUFJLGFBQ0wsQ0FBQyxZQUFZLENBQUMsV0FDaEI7d0JBQ1AsV0FBVzt3QkFDWCxlQUFlO3dCQUNmLGFBQWE7d0JBQ2IsaUJBQWlCO3dCQUNqQixrQkFBa0I7d0JBQ2xCLGtCQUFrQjt3QkFDbEIsYUFBYTt3QkFDYixjQUFjO3dCQUNkLGVBQWU7d0JBQ2Ysb0JBQW9CO3dCQUNwQixnQkFBZ0I7d0JBQ2hCLGdCQUFnQjt3QkFDaEIscUJBQXFCO3dCQUNyQixtQkFBbUI7d0JBQ25CLHVCQUF1Qjt3QkFDdkIsNEJBQTRCO3FCQUM3Qjt3REFhUSxNQUFNO3NCQUFkLEtBQUs7Z0JBRUcsU0FBUztzQkFBakIsS0FBSztnQkFFRyxjQUFjO3NCQUF0QixLQUFLO2dCQU1HLFNBQVM7c0JBQWpCLEtBQUs7Z0JBRUcsYUFBYTtzQkFBckIsS0FBSztnQkFHSSxZQUFZO3NCQUFyQixNQUFNO2dCQUVHLElBQUk7c0JBQWIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgSW5wdXQsIE9uQ2hhbmdlcywgT3V0cHV0LCBTaW1wbGVDaGFuZ2VzLCBlZmZlY3QsIGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBNYXRCdXR0b25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9idXR0b24nO1xuaW1wb3J0IHsgTWF0Q2FyZE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2NhcmQnO1xuaW1wb3J0IHsgTWF0Q2hlY2tib3hNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9jaGVja2JveCc7XG5pbXBvcnQgeyBNYXRFeHBhbnNpb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9leHBhbnNpb24nO1xuaW1wb3J0IHsgTWF0Rm9ybUZpZWxkTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvZm9ybS1maWVsZCc7XG5pbXBvcnQgeyBNYXRJY29uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvaWNvbic7XG5pbXBvcnQgeyBNYXRJbnB1dE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2lucHV0JztcbmltcG9ydCB7IE1hdFNlbGVjdE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3NlbGVjdCc7XG5pbXBvcnQgeyBNYXRTbGlkZVRvZ2dsZU1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3NsaWRlLXRvZ2dsZSc7XG5pbXBvcnQgeyBNYXRUb29sYmFyTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvdG9vbGJhcic7XG5pbXBvcnQgeyBNYXRUb29sdGlwTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvdG9vbHRpcCc7XG5pbXBvcnQge1xuICBDT01NT05fTU9EVUxFUyxcbiAgdHlwZSBDb21tb25Nb2R1bGVFbnRyeSxcbiAgdHlwZSBFbnRpdHlGb3JtQ29uZmlnLFxuICB0eXBlIEVudGl0eVBlcm1pc3Npb25zLFxufSBmcm9tICdAZHluYW1pYy1lbnRpdHkvY29yZSc7XG5pbXBvcnQgeyBDb25maWdTb3VyY2VTZXJ2aWNlIH0gZnJvbSAnbmd4LWR5bmFtaWMtZW50aXR5JztcbmltcG9ydCB7IEJ1aWxkZXJTdG9yZSB9IGZyb20gJy4vYnVpbGRlci1zdG9yZS5zZXJ2aWNlJztcbmltcG9ydCB7IEZpZWxkSW5zcGVjdG9yQ29tcG9uZW50IH0gZnJvbSAnLi9jb21wb25lbnRzL2ZpZWxkLWluc3BlY3Rvci5jb21wb25lbnQnO1xuaW1wb3J0IHsgRmllbGRQYWxldHRlQ29tcG9uZW50IH0gZnJvbSAnLi9jb21wb25lbnRzL2ZpZWxkLXBhbGV0dGUuY29tcG9uZW50JztcbmltcG9ydCB7IFRhYk1hbmFnZXJDb21wb25lbnQgfSBmcm9tICcuL2NvbXBvbmVudHMvdGFiLW1hbmFnZXIuY29tcG9uZW50JztcbmltcG9ydCB7IEVudGl0eUJ1aWxkZXJDYW52YXNDb21wb25lbnQgfSBmcm9tICcuL2NvbXBvbmVudHMvZW50aXR5LWJ1aWxkZXItY2FudmFzLmNvbXBvbmVudCc7XG5cbi8qKiBSQkFDIGFjdGlvbnMgc3VyZmFjZWQgaW4gdGhlIHNldHRpbmdzIHBhbmVsLiAqL1xuY29uc3QgUkJBQ19BQ1RJT05TOiAoa2V5b2YgRW50aXR5UGVybWlzc2lvbnMpW10gPSBbJ3ZpZXcnLCAnZWRpdCcsICdkZWxldGUnXTtcblxuLyoqIFNoYXJlZCBzdGFibGUgZW1wdHkgYXJyYXkg4oCUIG5ldmVyIGFsbG9jYXRlIGEgZnJlc2ggW10gcGVyIGNoYW5nZS1kZXRlY3Rpb24gKG1hdC1zZWxlY3QgbG9vcHMpLiAqL1xuY29uc3QgRU1QVFlfUk9MRVM6IHJlYWRvbmx5IHN0cmluZ1tdID0gT2JqZWN0LmZyZWV6ZShbXSk7XG5cbi8qKlxuICogRW50aXR5QnVpbGRlckNvbXBvbmVudCDigJQgdGhlIHRvcC1sZXZlbCB2aXN1YWwgYnVpbGRlciBmb3IgYW4gRW50aXR5Rm9ybUNvbmZpZy5cbiAqL1xuQENvbXBvbmVudCh7XG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBzZWxlY3RvcjogJ25neC1lbnRpdHktYnVpbGRlcicsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIHByb3ZpZGVyczogW0J1aWxkZXJTdG9yZV0sXG4gIGltcG9ydHM6IFtcbiAgICBGb3Jtc01vZHVsZSxcbiAgICBNYXRCdXR0b25Nb2R1bGUsXG4gICAgTWF0Q2FyZE1vZHVsZSxcbiAgICBNYXRDaGVja2JveE1vZHVsZSxcbiAgICBNYXRFeHBhbnNpb25Nb2R1bGUsXG4gICAgTWF0Rm9ybUZpZWxkTW9kdWxlLFxuICAgIE1hdEljb25Nb2R1bGUsXG4gICAgTWF0SW5wdXRNb2R1bGUsXG4gICAgTWF0U2VsZWN0TW9kdWxlLFxuICAgIE1hdFNsaWRlVG9nZ2xlTW9kdWxlLFxuICAgIE1hdFRvb2xiYXJNb2R1bGUsXG4gICAgTWF0VG9vbHRpcE1vZHVsZSxcbiAgICBGaWVsZFBhbGV0dGVDb21wb25lbnQsXG4gICAgVGFiTWFuYWdlckNvbXBvbmVudCxcbiAgICBGaWVsZEluc3BlY3RvckNvbXBvbmVudCxcbiAgICBFbnRpdHlCdWlsZGVyQ2FudmFzQ29tcG9uZW50LFxuICBdLFxuICB0ZW1wbGF0ZVVybDogJy4vZW50aXR5LWJ1aWxkZXIuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybDogJy4vZW50aXR5LWJ1aWxkZXIuY29tcG9uZW50LmNzcycsXG59KVxuZXhwb3J0IGNsYXNzIEVudGl0eUJ1aWxkZXJDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgc3RvcmUgPSBpbmplY3QoQnVpbGRlclN0b3JlKTtcbiAgLyoqXG4gICAqIE9wdGlvbmFsOiBvbmx5IGFwcHMgdGhhdCByZWdpc3RlcmVkIGEgQ09ORklHX1NPVVJDRSBoYXZlIG9uZS4gVXNlZCB0byBkcm9wIHRoZSBjYWNoZWRcbiAgICogY29weSBvZiBhIGNvbmZpZyB0aGUgbW9tZW50IGl0IGlzIGVkaXRlZCDigJQgc2VlIGBkb1NhdmVgLlxuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBjb25maWdTb3VyY2UgPSBpbmplY3QoQ29uZmlnU291cmNlU2VydmljZSwgeyBvcHRpb25hbDogdHJ1ZSB9KTtcblxuICAvKiogRXhpc3RpbmcgY29uZmlnIHRvIGVkaXQuIFdoZW4gb21pdHRlZCwgdGhlIGJ1aWxkZXIgc3RhcnRzIGJsYW5rLiAqL1xuICBASW5wdXQoKSBjb25maWc/OiBFbnRpdHlGb3JtQ29uZmlnO1xuICAvKiogTGFuZ3VhZ2VzIGF2YWlsYWJsZSBmb3IgbGFiZWwvcGxhY2Vob2xkZXIgZWRpdGluZy4gRmlyc3QgZW50cnkgaXMgdGhlIGRlZmF1bHQuICovXG4gIEBJbnB1dCgpIGxhbmd1YWdlczogc3RyaW5nW10gPSBbJ2VuJ107XG4gIC8qKiBPcHRpb25hbCByb2xlIGxpc3Qg4oCUIGVuYWJsZXMgbXVsdGktc2VsZWN0IHJvbGUgcGlja2VycyBmb3IgUkJBQyBpbnN0ZWFkIG9mIGZyZWUgdGV4dC4gKi9cbiAgQElucHV0KCkgYXZhaWxhYmxlUm9sZXM6IHN0cmluZ1tdID0gW107XG4gIC8qKlxuICAgKiBSb2xlcyBvZiB0aGUgcGVyc29uIHVzaW5nIHRoZSBidWlsZGVyLiBEaXN0aW5jdCBmcm9tIGBhdmFpbGFibGVSb2xlc2AsIHdoaWNoIGlzIHRoZVxuICAgKiB2b2NhYnVsYXJ5IGEgc2NoZW1hIG1heSByZWZlcmVuY2UuIFBhc3NlZCB0byB0aGUgYFNZU1RFTV9ERUZBVUxUX0NBTl9FRElUYCBwcmVkaWNhdGUgc29cbiAgICogaXQgY2FuIGRlY2lkZSB3aGV0aGVyIHRoaXMgdXNlciBtYXkgZWRpdCBzeXN0ZW0tZGVmYXVsdCB0YWJzLlxuICAgKi9cbiAgQElucHV0KCkgdXNlclJvbGVzOiBzdHJpbmdbXSA9IFtdO1xuICAvKiogT3B0aW9uYWwgY29tbW9uLW1vZHVsZSBkZWZpbml0aW9ucyBmb3IgbW9kdWxlIHRhYnM7IGRlZmF1bHRzIHRvIHRoZSBidWlsdC1pbiBsaXN0IGZyb20gY29yZS4gKi9cbiAgQElucHV0KCkgY29tbW9uTW9kdWxlczogcmVhZG9ubHkgQ29tbW9uTW9kdWxlRW50cnlbXSA9IENPTU1PTl9NT0RVTEVTO1xuXG4gIC8qKiBFbWl0dGVkIG9uIGV2ZXJ5IGNoYW5nZSB0byB0aGUgd29ya2luZyBjb25maWcuICovXG4gIEBPdXRwdXQoKSBjb25maWdDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPEVudGl0eUZvcm1Db25maWc+KCk7XG4gIC8qKiBFbWl0dGVkIHdoZW4gdGhlIHVzZXIgY2xpY2tzIFNhdmUuIENhcnJpZXMgYSBjbGVhbiwgZGVlcC1jbG9uZWQgY29uZmlnLiAqL1xuICBAT3V0cHV0KCkgc2F2ZSA9IG5ldyBFdmVudEVtaXR0ZXI8RW50aXR5Rm9ybUNvbmZpZz4oKTtcblxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgcmJhY0FjdGlvbnMgPSBSQkFDX0FDVElPTlM7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgZWZmZWN0KCgpID0+IHRoaXMuY29uZmlnQ2hhbmdlLmVtaXQodGhpcy5zdG9yZS5jb25maWcoKSksIHsgYWxsb3dTaWduYWxXcml0ZXM6IHRydWUgfSk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKGNoYW5nZXNbJ2NvbmZpZyddICYmIGNoYW5nZXNbJ2NvbmZpZyddLmN1cnJlbnRWYWx1ZSAhPT0gY2hhbmdlc1snY29uZmlnJ10ucHJldmlvdXNWYWx1ZSkge1xuICAgICAgaWYgKHRoaXMuY29uZmlnKSB0aGlzLnN0b3JlLmxvYWQodGhpcy5jb25maWcpO1xuICAgICAgZWxzZSBpZiAoY2hhbmdlc1snY29uZmlnJ10uaXNGaXJzdENoYW5nZSgpKSB0aGlzLnN0b3JlLnJlc2V0KCk7XG4gICAgfVxuICAgIGlmIChjaGFuZ2VzWydsYW5ndWFnZXMnXSAmJiB0aGlzLmxhbmd1YWdlcy5sZW5ndGgpIHtcbiAgICAgIGNvbnN0IGFjdGl2ZSA9IHRoaXMuc3RvcmUuYWN0aXZlTGFuZ3VhZ2UoKTtcbiAgICAgIGlmICghdGhpcy5sYW5ndWFnZXMuaW5jbHVkZXMoYWN0aXZlKSkgdGhpcy5zdG9yZS5zZXRBY3RpdmVMYW5ndWFnZSh0aGlzLmxhbmd1YWdlc1swXSk7XG4gICAgfVxuICAgIGlmIChjaGFuZ2VzWyd1c2VyUm9sZXMnXSkge1xuICAgICAgdGhpcy5zdG9yZS5zZXRVc2VyUm9sZXModGhpcy51c2VyUm9sZXMpO1xuICAgIH1cbiAgfVxuXG4gIC8vIOKUgOKUgOKUgCBUb29sYmFyIGFjdGlvbnMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHJvdGVjdGVkIGRvU2F2ZSgpOiB2b2lkIHtcbiAgICBjb25zdCBjb25maWcgPSB0aGlzLnN0b3JlLmV4cG9ydENvbmZpZygpO1xuXG4gICAgLy8gU2F2aW5nIGlzIHRoZSBtb21lbnQgdGhpcyBlbnRpdHkncyBjb25maWcgY2hhbmdlcywgc28gYW55dGhpbmcgaG9sZGluZyBhIGNhY2hlZCBjb3B5IGlzXG4gICAgLy8gbm93IHN0YWxlIOKAlCBtb3N0IHZpc2libHkgYSByZWZlcmVuY2VkIGZpZWxkIGVsc2V3aGVyZSByZXNvbHZpbmcgYWdhaW5zdCB0aGUgb2xkIHNjaGVtYS5cbiAgICAvLyBDb25maWdTb3VyY2VTZXJ2aWNlIGNhY2hlcyBwZXIgZW50aXR5IGFuZCBleHBvc2VkIGNsZWFyQ2FjaGUgZnJvbSB0aGUgc3RhcnQsIGJ1dCBub3RoaW5nXG4gICAgLy8gZXZlciBjYWxsZWQgaXQsIHNvIGEgY2FjaGUgZW50cnkgbGl2ZWQgZm9yIHRoZSBsaWZldGltZSBvZiB0aGUgcGFnZS5cbiAgICB0aGlzLmNvbmZpZ1NvdXJjZT8uY2xlYXJDYWNoZShjb25maWcuZW50aXR5KTtcblxuICAgIHRoaXMuc2F2ZS5lbWl0KGNvbmZpZyk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZ2V0IGpzb24oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodGhpcy5zdG9yZS5leHBvcnRDb25maWcoKSwgbnVsbCwgMik7XG4gIH1cblxuICBwcm90ZWN0ZWQgY29weUpzb24oKTogdm9pZCB7XG4gICAgaWYgKHR5cGVvZiBuYXZpZ2F0b3IgIT09ICd1bmRlZmluZWQnICYmIG5hdmlnYXRvci5jbGlwYm9hcmQpIHtcbiAgICAgIHZvaWQgbmF2aWdhdG9yLmNsaXBib2FyZC53cml0ZVRleHQodGhpcy5qc29uKTtcbiAgICB9XG4gIH1cblxuICAvLyDilIDilIDilIAgUkJBQyBzZXR0aW5ncyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICBwcm90ZWN0ZWQgcm9sZXNGb3IoYWN0aW9uOiBrZXlvZiBFbnRpdHlQZXJtaXNzaW9ucyk6IHJlYWRvbmx5IHN0cmluZ1tdIHtcbiAgICAvLyBSZXR1cm4gdGhlIHN0b3JlZCBhcnJheSAoc3RhYmxlIHJlZiBiZXR3ZWVuIG11dGF0aW9ucykgb3IgYSBzaGFyZWQgZW1wdHkg4oCUIE5PVCBhIGZyZXNoIFtdLFxuICAgIC8vIHdoaWNoIHdvdWxkIG1ha2UgdGhlIGJvdW5kIG1hdC1zZWxlY3QgcmUtZXZhbHVhdGUgZXZlcnkgQ0QgYW5kIGxvb3AgZm9yZXZlci5cbiAgICByZXR1cm4gdGhpcy5zdG9yZS5jb25maWcoKS5wZXJtaXNzaW9ucz8uW2FjdGlvbl0gPz8gRU1QVFlfUk9MRVM7XG4gIH1cblxuICBwcm90ZWN0ZWQgc2V0Um9sZXMoYWN0aW9uOiBrZXlvZiBFbnRpdHlQZXJtaXNzaW9ucywgcm9sZXM6IHN0cmluZ1tdKTogdm9pZCB7XG4gICAgdGhpcy5zdG9yZS5zZXRQZXJtaXNzaW9uKGFjdGlvbiwgcm9sZXMpO1xuICB9XG5cbiAgLyoqIFBhcnNlIGEgY29tbWEtc2VwYXJhdGVkIHJvbGUgc3RyaW5nIGludG8gYSB0cmltbWVkLCBkZS1kdXBsaWNhdGVkIGFycmF5LiAqL1xuICBwcm90ZWN0ZWQgc2V0Um9sZXNGcm9tVGV4dChhY3Rpb246IGtleW9mIEVudGl0eVBlcm1pc3Npb25zLCB0ZXh0OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCByb2xlcyA9IEFycmF5LmZyb20oXG4gICAgICBuZXcgU2V0KFxuICAgICAgICB0ZXh0XG4gICAgICAgICAgLnNwbGl0KCcsJylcbiAgICAgICAgICAubWFwKHIgPT4gci50cmltKCkpXG4gICAgICAgICAgLmZpbHRlcihCb29sZWFuKSxcbiAgICAgICksXG4gICAgKTtcbiAgICB0aGlzLnN0b3JlLnNldFBlcm1pc3Npb24oYWN0aW9uLCByb2xlcyk7XG4gIH1cbn1cbiIsIjxtYXQtdG9vbGJhciBjbGFzcz1cImRlYi10b29sYmFyXCIgY29sb3I9XCJwcmltYXJ5XCI+XG4gIDxtYXQtaWNvbj5kYXNoYm9hcmRfY3VzdG9taXplPC9tYXQtaWNvbj5cbiAgPHNwYW4gY2xhc3M9XCJkZWItdG9vbGJhcl9fdGl0bGVcIj5FbnRpdHkgQnVpbGRlcjwvc3Bhbj5cbiAgPHNwYW4gY2xhc3M9XCJkZWItc3BhY2VyXCI+PC9zcGFuPlxuXG4gIEBpZiAoc3RvcmUucHJvYmxlbXMoKS5sZW5ndGgpIHtcbiAgICA8YnV0dG9uXG4gICAgICBtYXQtYnV0dG9uXG4gICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgIGNsYXNzPVwiZGViLXByb2JsZW1zXCJcbiAgICAgIFtjbGFzcy5kZWItcHJvYmxlbXMtLWVycm9yXT1cIiFzdG9yZS5pc1ZhbGlkKClcIlxuICAgICAgW21hdFRvb2x0aXBdPVwic3RvcmUucHJvYmxlbXMoKS5sZW5ndGggKyAnIGlzc3VlKHMpIOKAlCBob3ZlciBpdGVtcyBpbiB0aGUgbGlzdCdcIlxuICAgID5cbiAgICAgIDxtYXQtaWNvbj57eyBzdG9yZS5pc1ZhbGlkKCkgPyAnd2FybmluZycgOiAnZXJyb3InIH19PC9tYXQtaWNvbj5cbiAgICAgIHt7IHN0b3JlLmVycm9ycygpLmxlbmd0aCB9fSAvIHt7IHN0b3JlLnByb2JsZW1zKCkubGVuZ3RoIH19XG4gICAgPC9idXR0b24+XG4gIH1cblxuICA8YnV0dG9uIG1hdC1idXR0b24gdHlwZT1cImJ1dHRvblwiIChjbGljayk9XCJjb3B5SnNvbigpXCI+XG4gICAgPG1hdC1pY29uPmNvbnRlbnRfY29weTwvbWF0LWljb24+IENvcHkgSlNPTlxuICA8L2J1dHRvbj5cbiAgPCEtLSBwcmltYXJ5LCBub3QgYWNjZW50OiB3aGl0ZSBvbiBNYXRlcmlhbCdzIGRlZmF1bHQgcGluayBhY2NlbnQgaXMgMy4zMzoxLCBiZWxvdyBBQS4gLS0+XG4gIDxidXR0b24gbWF0LWZsYXQtYnV0dG9uIGNvbG9yPVwicHJpbWFyeVwiIHR5cGU9XCJidXR0b25cIiBbZGlzYWJsZWRdPVwiIXN0b3JlLmlzVmFsaWQoKVwiIChjbGljayk9XCJkb1NhdmUoKVwiPlxuICAgIDxtYXQtaWNvbj5zYXZlPC9tYXQtaWNvbj4gU2F2ZVxuICA8L2J1dHRvbj5cbjwvbWF0LXRvb2xiYXI+XG5cbjxkaXYgY2xhc3M9XCJkZWItYm9keVwiPlxuICA8IS0tIOKUgOKUgOKUgCBMZWZ0OiBzZXR0aW5ncywgcGFsZXR0ZSwgdGFicyDilIDilIDilIAgLS0+XG4gIDxkaXYgY2xhc3M9XCJkZWItY29sIGRlYi1jb2wtLWxlZnRcIj5cbiAgICA8bWF0LWNhcmQ+XG4gICAgICA8bWF0LWNhcmQtY29udGVudD5cbiAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgc3Vic2NyaXB0U2l6aW5nPVwiZHluYW1pY1wiIGNsYXNzPVwiZGViLWZ1bGxcIj5cbiAgICAgICAgICA8bWF0LWxhYmVsPkVudGl0eSBuYW1lPC9tYXQtbGFiZWw+XG4gICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICBtYXRJbnB1dFxuICAgICAgICAgICAgW25nTW9kZWxdPVwic3RvcmUuY29uZmlnKCkuZW50aXR5XCJcbiAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnNldEVudGl0eU5hbWUoJGV2ZW50KVwiXG4gICAgICAgICAgICBwbGFjZWhvbGRlcj1cImUuZy4gY2xpZW50c1wiXG4gICAgICAgICAgLz5cbiAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiZGViLXJvd1wiPlxuICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIiBjbGFzcz1cImRlYi1ncm93XCI+XG4gICAgICAgICAgICA8bWF0LWxhYmVsPkVkaXRpbmcgbGFuZ3VhZ2U8L21hdC1sYWJlbD5cbiAgICAgICAgICAgIDxtYXQtc2VsZWN0XG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cInN0b3JlLmFjdGl2ZUxhbmd1YWdlKClcIlxuICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS5zZXRBY3RpdmVMYW5ndWFnZSgkZXZlbnQpXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgQGZvciAobCBvZiBsYW5ndWFnZXM7IHRyYWNrIGwpIHtcbiAgICAgICAgICAgICAgICA8bWF0LW9wdGlvbiBbdmFsdWVdPVwibFwiPnt7IGwgfX08L21hdC1vcHRpb24+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDwvbWF0LXNlbGVjdD5cbiAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8bWF0LXNsaWRlLXRvZ2dsZVxuICAgICAgICAgIFtuZ01vZGVsXT1cInN0b3JlLmNvbmZpZygpLm1hc2tEYXRhID8/IGZhbHNlXCJcbiAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS5zZXRNYXNrRGF0YSgkZXZlbnQpXCJcbiAgICAgICAgPk1hc2sgdGhpcyBlbnRpdHkgKFJCQUMpPC9tYXQtc2xpZGUtdG9nZ2xlPlxuXG4gICAgICAgIDxtYXQtZXhwYW5zaW9uLXBhbmVsIGNsYXNzPVwiZGViLXJiYWNcIj5cbiAgICAgICAgICA8bWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XG4gICAgICAgICAgICA8bWF0LXBhbmVsLXRpdGxlPlBlcm1pc3Npb25zPC9tYXQtcGFuZWwtdGl0bGU+XG4gICAgICAgICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsLWhlYWRlcj5cbiAgICAgICAgICBAZm9yIChhY3Rpb24gb2YgcmJhY0FjdGlvbnM7IHRyYWNrIGFjdGlvbikge1xuICAgICAgICAgICAgQGlmIChhdmFpbGFibGVSb2xlcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgc3Vic2NyaXB0U2l6aW5nPVwiZHluYW1pY1wiIGNsYXNzPVwiZGViLWZ1bGxcIj5cbiAgICAgICAgICAgICAgICA8bWF0LWxhYmVsPnt7IGFjdGlvbiB9fSByb2xlczwvbWF0LWxhYmVsPlxuICAgICAgICAgICAgICAgIDxtYXQtc2VsZWN0IG11bHRpcGxlIFtuZ01vZGVsXT1cInJvbGVzRm9yKGFjdGlvbilcIiAobmdNb2RlbENoYW5nZSk9XCJzZXRSb2xlcyhhY3Rpb24sICRldmVudClcIj5cbiAgICAgICAgICAgICAgICAgIEBmb3IgKHJvbGUgb2YgYXZhaWxhYmxlUm9sZXM7IHRyYWNrIHJvbGUpIHtcbiAgICAgICAgICAgICAgICAgICAgPG1hdC1vcHRpb24gW3ZhbHVlXT1cInJvbGVcIj57eyByb2xlIH19PC9tYXQtb3B0aW9uPlxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIDwvbWF0LXNlbGVjdD5cbiAgICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgYXBwZWFyYW5jZT1cIm91dGxpbmVcIiBzdWJzY3JpcHRTaXppbmc9XCJkeW5hbWljXCIgY2xhc3M9XCJkZWItZnVsbFwiPlxuICAgICAgICAgICAgICAgIDxtYXQtbGFiZWw+e3sgYWN0aW9uIH19IHJvbGVzIChjb21tYS1zZXBhcmF0ZWQpPC9tYXQtbGFiZWw+XG4gICAgICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgICAgICBtYXRJbnB1dFxuICAgICAgICAgICAgICAgICAgW25nTW9kZWxdPVwicm9sZXNGb3IoYWN0aW9uKS5qb2luKCcsICcpXCJcbiAgICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInNldFJvbGVzRnJvbVRleHQoYWN0aW9uLCAkZXZlbnQpXCJcbiAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICA8cCBjbGFzcz1cImRlYi1oaW50XCI+RW1wdHkgPSBubyByZXN0cmljdGlvbiBmb3IgdGhhdCBhY3Rpb24uPC9wPlxuICAgICAgICA8L21hdC1leHBhbnNpb24tcGFuZWw+XG4gICAgICA8L21hdC1jYXJkLWNvbnRlbnQ+XG4gICAgPC9tYXQtY2FyZD5cblxuICAgIDxtYXQtY2FyZD5cbiAgICAgIDxtYXQtY2FyZC1oZWFkZXI+PG1hdC1jYXJkLXRpdGxlPkFkZCBmaWVsZDwvbWF0LWNhcmQtdGl0bGU+PC9tYXQtY2FyZC1oZWFkZXI+XG4gICAgICA8bWF0LWNhcmQtY29udGVudD5cbiAgICAgICAgPG5neC1maWVsZC1wYWxldHRlIChwaWNrKT1cInN0b3JlLmFkZEZpZWxkKCRldmVudClcIj48L25neC1maWVsZC1wYWxldHRlPlxuICAgICAgPC9tYXQtY2FyZC1jb250ZW50PlxuICAgIDwvbWF0LWNhcmQ+XG5cbiAgICA8bWF0LWNhcmQ+XG4gICAgICA8bWF0LWNhcmQtY29udGVudD5cbiAgICAgICAgPG5neC10YWItbWFuYWdlcj48L25neC10YWItbWFuYWdlcj5cbiAgICAgIDwvbWF0LWNhcmQtY29udGVudD5cbiAgICA8L21hdC1jYXJkPlxuICA8L2Rpdj5cblxuICA8IS0tIOKUgOKUgOKUgCBDZW50ZXI6IGZpZWxkIGNhbnZhcyDilIDilIDilIAgLS0+XG4gIDxkaXYgY2xhc3M9XCJkZWItY29sIGRlYi1jb2wtLWNlbnRlclwiPlxuICAgIDxuZ3gtZW50aXR5LWJ1aWxkZXItY2FudmFzIC8+XG4gIDwvZGl2PlxuXG4gIDwhLS0g4pSA4pSA4pSAIFJpZ2h0OiBpbnNwZWN0b3Ig4pSA4pSA4pSAIC0tPlxuICA8ZGl2IGNsYXNzPVwiZGViLWNvbCBkZWItY29sLS1yaWdodFwiPlxuICAgIDxtYXQtY2FyZD5cbiAgICAgIDxtYXQtY2FyZC1oZWFkZXI+PG1hdC1jYXJkLXRpdGxlPkZpZWxkIHByb3BlcnRpZXM8L21hdC1jYXJkLXRpdGxlPjwvbWF0LWNhcmQtaGVhZGVyPlxuICAgICAgPG1hdC1jYXJkLWNvbnRlbnQ+XG4gICAgICAgIDxuZ3gtZmllbGQtaW5zcGVjdG9yPjwvbmd4LWZpZWxkLWluc3BlY3Rvcj5cbiAgICAgIDwvbWF0LWNhcmQtY29udGVudD5cbiAgICA8L21hdC1jYXJkPlxuICA8L2Rpdj5cbjwvZGl2PlxuXG48IS0tIOKUgOKUgOKUgCBGb290ZXI6IEpTT04gKyBvcHRpb25hbCBsaXZlIHByZXZpZXcg4pSA4pSA4pSAIC0tPlxuPGRpdiBjbGFzcz1cImRlYi1mb290ZXJcIj5cbiAgPG1hdC1leHBhbnNpb24tcGFuZWw+XG4gICAgPG1hdC1leHBhbnNpb24tcGFuZWwtaGVhZGVyPlxuICAgICAgPG1hdC1wYW5lbC10aXRsZT48bWF0LWljb24+ZGF0YV9vYmplY3Q8L21hdC1pY29uPiZuYnNwO0NvbmZpZyBKU09OPC9tYXQtcGFuZWwtdGl0bGU+XG4gICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsLWhlYWRlcj5cbiAgICA8cHJlIGNsYXNzPVwiZGViLWpzb25cIj57eyBqc29uIH19PC9wcmU+XG4gIDwvbWF0LWV4cGFuc2lvbi1wYW5lbD5cblxuICA8ZGl2IGNsYXNzPVwiZGViLXByZXZpZXctc2xvdFwiPlxuICAgIDxuZy1jb250ZW50IHNlbGVjdD1cIltuZ3hCdWlsZGVyUHJldmlld11cIj48L25nLWNvbnRlbnQ+XG4gIDwvZGl2PlxuPC9kaXY+XG4iXX0=
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* field-catalog.ts — re-exports shared field catalog from @dynamic-entity/core.
|
|
3
|
-
* Single source of truth shared by both visual builder and renderer.
|
|
4
|
-
*/
|
|
5
|
-
export { FIELD_TYPE_CATALOG, getFieldTypeMeta, humanizeId, createFieldConfig, } from '@dynamic-entity/core';
|
|
6
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmllbGQtY2F0YWxvZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvZmllbGQtY2F0YWxvZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0dBR0c7QUFDSCxPQUFPLEVBQ0wsa0JBQWtCLEVBQ2xCLGdCQUFnQixFQUNoQixVQUFVLEVBQ1YsaUJBQWlCLEdBSWxCLE1BQU0sc0JBQXNCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIGZpZWxkLWNhdGFsb2cudHMg4oCUIHJlLWV4cG9ydHMgc2hhcmVkIGZpZWxkIGNhdGFsb2cgZnJvbSBAZHluYW1pYy1lbnRpdHkvY29yZS5cbiAqIFNpbmdsZSBzb3VyY2Ugb2YgdHJ1dGggc2hhcmVkIGJ5IGJvdGggdmlzdWFsIGJ1aWxkZXIgYW5kIHJlbmRlcmVyLlxuICovXG5leHBvcnQge1xuICBGSUVMRF9UWVBFX0NBVEFMT0csXG4gIGdldEZpZWxkVHlwZU1ldGEsXG4gIGh1bWFuaXplSWQsXG4gIGNyZWF0ZUZpZWxkQ29uZmlnLFxuICB0eXBlIEZpZWxkVHlwZU1ldGEsXG4gIHR5cGUgRmxhZ1ZhbGlkYXRvcixcbiAgdHlwZSBQYXJhbVZhbGlkYXRvcixcbn0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuIl19
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generated bundle index. Do not edit.
|
|
3
|
-
*/
|
|
4
|
-
export * from './public-api';
|
|
5
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWR5bmFtaWMtZW50aXR5LWJ1aWxkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbmd4LWR5bmFtaWMtZW50aXR5LWJ1aWxkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLGNBQWMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9wdWJsaWMtYXBpJztcbiJdfQ==
|
package/esm2022/public-api.mjs
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// Main component
|
|
2
|
-
export * from './lib/entity-builder.component';
|
|
3
|
-
// Sub-components (individually importable — reusability rule, mirrors ngx-dynamic-entity)
|
|
4
|
-
export * from './lib/components/field-palette.component';
|
|
5
|
-
export * from './lib/components/field-inspector.component';
|
|
6
|
-
export * from './lib/components/tab-manager.component';
|
|
7
|
-
export * from './lib/components/rule-form.component';
|
|
8
|
-
export * from './lib/components/field-rules-list.component';
|
|
9
|
-
export * from './lib/components/entity-reference-config.component';
|
|
10
|
-
export * from './lib/components/entity-builder-canvas.component';
|
|
11
|
-
export * from './lib/components/entity-builder-tree-node.component';
|
|
12
|
-
// Store (provided per builder instance)
|
|
13
|
-
export * from './lib/builder-store.service';
|
|
14
|
-
// Catalog + helpers
|
|
15
|
-
export * from './lib/field-catalog';
|
|
16
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wdWJsaWMtYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGlCQUFpQjtBQUNqQixjQUFjLGdDQUFnQyxDQUFDO0FBRS9DLDBGQUEwRjtBQUMxRixjQUFjLDBDQUEwQyxDQUFDO0FBQ3pELGNBQWMsNENBQTRDLENBQUM7QUFDM0QsY0FBYyx3Q0FBd0MsQ0FBQztBQUN2RCxjQUFjLHNDQUFzQyxDQUFDO0FBQ3JELGNBQWMsNkNBQTZDLENBQUM7QUFDNUQsY0FBYyxvREFBb0QsQ0FBQztBQUNuRSxjQUFjLGtEQUFrRCxDQUFDO0FBQ2pFLGNBQWMscURBQXFELENBQUM7QUFFcEUsd0NBQXdDO0FBQ3hDLGNBQWMsNkJBQTZCLENBQUM7QUFFNUMsb0JBQW9CO0FBQ3BCLGNBQWMscUJBQXFCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBNYWluIGNvbXBvbmVudFxuZXhwb3J0ICogZnJvbSAnLi9saWIvZW50aXR5LWJ1aWxkZXIuY29tcG9uZW50JztcblxuLy8gU3ViLWNvbXBvbmVudHMgKGluZGl2aWR1YWxseSBpbXBvcnRhYmxlIOKAlCByZXVzYWJpbGl0eSBydWxlLCBtaXJyb3JzIG5neC1keW5hbWljLWVudGl0eSlcbmV4cG9ydCAqIGZyb20gJy4vbGliL2NvbXBvbmVudHMvZmllbGQtcGFsZXR0ZS5jb21wb25lbnQnO1xuZXhwb3J0ICogZnJvbSAnLi9saWIvY29tcG9uZW50cy9maWVsZC1pbnNwZWN0b3IuY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vbGliL2NvbXBvbmVudHMvdGFiLW1hbmFnZXIuY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vbGliL2NvbXBvbmVudHMvcnVsZS1mb3JtLmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9jb21wb25lbnRzL2ZpZWxkLXJ1bGVzLWxpc3QuY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vbGliL2NvbXBvbmVudHMvZW50aXR5LXJlZmVyZW5jZS1jb25maWcuY29tcG9uZW50JztcbmV4cG9ydCAqIGZyb20gJy4vbGliL2NvbXBvbmVudHMvZW50aXR5LWJ1aWxkZXItY2FudmFzLmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9jb21wb25lbnRzL2VudGl0eS1idWlsZGVyLXRyZWUtbm9kZS5jb21wb25lbnQnO1xuXG4vLyBTdG9yZSAocHJvdmlkZWQgcGVyIGJ1aWxkZXIgaW5zdGFuY2UpXG5leHBvcnQgKiBmcm9tICcuL2xpYi9idWlsZGVyLXN0b3JlLnNlcnZpY2UnO1xuXG4vLyBDYXRhbG9nICsgaGVscGVyc1xuZXhwb3J0ICogZnJvbSAnLi9saWIvZmllbGQtY2F0YWxvZyc7XG5cbi8vIFJlLWV4cG9ydCB0aGUgY29yZSB0eXBlcyBhIGNvbnN1bWVyIG9mIHRoZSBidWlsZGVyIG5lZWRzXG5leHBvcnQgdHlwZSB7XG4gIEVudGl0eUZvcm1Db25maWcsXG4gIE5lc3RlZFRhYkNvbmZpZyxcbiAgTmVzdGVkRmllbGRDb25maWcsXG4gIFJpY2hGaWVsZFR5cGUsXG4gIERyb3Bkb3duT3B0aW9uLFxuICBFbnRpdHlQZXJtaXNzaW9ucyxcbiAgRW50aXR5UmVmZXJlbmNlQ29uZmlnLFxuICBBdXRvUGF0Y2hDb25maWcsXG4gIEF1dG9QYXRjaE1hcHBpbmcsXG4gIFBhdGNoT25UcnVlTWFwcGluZyxcbiAgRm9ybVJ1bGUsXG4gIFJ1bGVDb25kaXRpb24sXG4gIFJ1bGVBY3Rpb24sXG4gIFJ1bGVPcGVyYXRvcixcbn0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuIl19
|
package/index.d.ts
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import type { AutoPatchMapping, DropdownOption, EntityFormConfig, EntityPermissions, EntityReferenceConfig, FormRule, NestedFieldConfig, NestedTabConfig, PatchOnTrueMapping, RichFieldType } from '@dynamic-entity/core';
|
|
2
|
-
import { type FlagValidator, type ParamValidator } from './field-catalog';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
export interface BuilderProblem {
|
|
5
|
-
level: 'error' | 'warning';
|
|
6
|
-
message: string;
|
|
7
|
-
fieldId?: string;
|
|
8
|
-
}
|
|
9
|
-
export declare class BuilderStore {
|
|
10
|
-
private readonly _config;
|
|
11
|
-
private readonly _selectedFieldId;
|
|
12
|
-
private readonly _activeLanguage;
|
|
13
|
-
/** Rules live beside the config: they are persisted per form, not inside `EntityFormConfig`. */
|
|
14
|
-
private readonly _rules;
|
|
15
|
-
/**
|
|
16
|
-
* Field ids the author owns — set by an explicit rename, or by loading a saved config
|
|
17
|
-
* whose ids are already live data keys. Ids outside this set are still derived from the
|
|
18
|
-
* field's label. Builder-session state, deliberately not part of the exported config.
|
|
19
|
-
*/
|
|
20
|
-
private readonly manualIds;
|
|
21
|
-
private readonly _isDirty;
|
|
22
|
-
/**
|
|
23
|
-
* Roles of the person using the builder — distinct from `availableRoles`, which is the
|
|
24
|
-
* vocabulary a schema may reference. Needed so the SYSTEM_DEFAULT_CAN_EDIT predicate can
|
|
25
|
-
* be asked a real question; it was previously called with a hardcoded empty array, which
|
|
26
|
-
* made any role-checking predicate answer false for everyone.
|
|
27
|
-
*/
|
|
28
|
-
private readonly _userRoles;
|
|
29
|
-
readonly config: import("@angular/core").Signal<EntityFormConfig>;
|
|
30
|
-
readonly selectedFieldId: import("@angular/core").Signal<string>;
|
|
31
|
-
readonly activeLanguage: import("@angular/core").Signal<string>;
|
|
32
|
-
readonly rules: import("@angular/core").Signal<FormRule[]>;
|
|
33
|
-
readonly isDirty: import("@angular/core").Signal<boolean>;
|
|
34
|
-
readonly userRoles: import("@angular/core").Signal<string[]>;
|
|
35
|
-
readonly tabs: import("@angular/core").Signal<NestedTabConfig[]>;
|
|
36
|
-
readonly fields: import("@angular/core").Signal<NestedFieldConfig[]>;
|
|
37
|
-
readonly selectedField: import("@angular/core").Signal<NestedFieldConfig>;
|
|
38
|
-
readonly problems: import("@angular/core").Signal<BuilderProblem[]>;
|
|
39
|
-
readonly errors: import("@angular/core").Signal<BuilderProblem[]>;
|
|
40
|
-
readonly isValid: import("@angular/core").Signal<boolean>;
|
|
41
|
-
load(config: EntityFormConfig): void;
|
|
42
|
-
reset(entity?: string): void;
|
|
43
|
-
resetDirty(): void;
|
|
44
|
-
private emptyConfig;
|
|
45
|
-
setEntityName(entity: string): void;
|
|
46
|
-
setDefaultLanguage(language: string): void;
|
|
47
|
-
setMaskData(mask: boolean): void;
|
|
48
|
-
setPermission(action: keyof EntityPermissions, roles: string[]): void;
|
|
49
|
-
setActiveLanguage(language: string): void;
|
|
50
|
-
/** Roles of the person using the builder, for SYSTEM_DEFAULT_CAN_EDIT. */
|
|
51
|
-
setUserRoles(roles: string[]): void;
|
|
52
|
-
private getAllFields;
|
|
53
|
-
/**
|
|
54
|
-
* Every tab in the tree, flattened.
|
|
55
|
-
*
|
|
56
|
-
* The structural operations below used to iterate `draft.tabs` directly, which is only
|
|
57
|
-
* the top level. A field on a sub-tab could be selected and edited but never removed,
|
|
58
|
-
* duplicated, moved or reordered — the builder could author nested configs it was then
|
|
59
|
-
* unable to restructure, which is the worst possible state for an authoring tool.
|
|
60
|
-
*/
|
|
61
|
-
private flattenTabs;
|
|
62
|
-
/**
|
|
63
|
-
* Every field id in the config, including `group`/`array` children.
|
|
64
|
-
*
|
|
65
|
-
* Id uniqueness is a whole-config invariant, not a per-tab one: rules, `showWhen`
|
|
66
|
-
* conditions and `autoPatch` mappings all address fields by bare id, so two fields
|
|
67
|
-
* sharing an id anywhere in the tree interfere with each other. Uniqueness checks must
|
|
68
|
-
* therefore see deeper than `fields()`, which stops at a tab's own fields.
|
|
69
|
-
*/
|
|
70
|
-
private allFieldIds;
|
|
71
|
-
private findFieldInTabs;
|
|
72
|
-
addField(type: RichFieldType, targetTabId?: string): string;
|
|
73
|
-
updateField(id: string, patch: Partial<NestedFieldConfig>): void;
|
|
74
|
-
/**
|
|
75
|
-
* Rename a field explicitly, pinning the id so it is no longer derived from the label.
|
|
76
|
-
*
|
|
77
|
-
* Not reachable from the inspector — the id input is read-only by design. This exists for
|
|
78
|
-
* programmatic callers that must match an id to an existing data key.
|
|
79
|
-
*/
|
|
80
|
-
renameField(oldId: string, newId: string): void;
|
|
81
|
-
/** Whether this field's id is pinned (loaded from storage or explicitly renamed). */
|
|
82
|
-
hasManualId(id: string): boolean;
|
|
83
|
-
/**
|
|
84
|
-
* Move a field to a new id and repoint every id-based reference in the config at it.
|
|
85
|
-
*
|
|
86
|
-
* Ids are the wiring between fields — rules, cascades, patches and `showWhen` all address
|
|
87
|
-
* fields by id — so a rename that only touches `field.id` silently breaks that wiring.
|
|
88
|
-
* That was survivable while renaming was a rare manual act; label-derived ids make it
|
|
89
|
-
* routine, so the references move with it.
|
|
90
|
-
*/
|
|
91
|
-
private applyRename;
|
|
92
|
-
removeField(id: string): void;
|
|
93
|
-
duplicateField(id: string): string | null;
|
|
94
|
-
moveField(id: string, direction: -1 | 1): void;
|
|
95
|
-
/** Safe reorder for drag & drop within active tab or flat list */
|
|
96
|
-
reorderField(fromIndex: number, toIndex: number, tabId?: string): void;
|
|
97
|
-
selectField(id: string | null): void;
|
|
98
|
-
/**
|
|
99
|
-
* Set a field's label, and derive the field's id from it: type "Employee Count", get
|
|
100
|
-
* `employeeCount`. The inspector renders the id read-only, so this is the only way a
|
|
101
|
-
* new field's id is set.
|
|
102
|
-
*
|
|
103
|
-
* Two things stop derivation: a config loaded from storage (its ids are live data keys
|
|
104
|
-
* that records are already stored under — see `load`), and an explicit `renameField`
|
|
105
|
-
* call, which remains available to programmatic callers.
|
|
106
|
-
*
|
|
107
|
-
* Only the config's default language drives the id; translating a label must not rename
|
|
108
|
-
* anything.
|
|
109
|
-
*/
|
|
110
|
-
setFieldLabel(id: string, language: string, value: string): void;
|
|
111
|
-
/** `derived`, or `derived_2`, `derived_3`… if another field already holds it. */
|
|
112
|
-
private availableId;
|
|
113
|
-
setFieldPlaceholder(id: string, language: string, value: string): void;
|
|
114
|
-
toggleFlagValidator(id: string, validator: FlagValidator, on: boolean): void;
|
|
115
|
-
setParamValidator(id: string, validator: ParamValidator, value: number | null): void;
|
|
116
|
-
getParamValidator(field: NestedFieldConfig, validator: ParamValidator): number | null;
|
|
117
|
-
hasFlagValidator(field: NestedFieldConfig, validator: FlagValidator): boolean;
|
|
118
|
-
/**
|
|
119
|
-
* Where a choice field's options come from.
|
|
120
|
-
*
|
|
121
|
-
* `entity` is absent on purpose: in this model an entity reference is a field *type*
|
|
122
|
-
* (`entity-ref`), not a data source a dropdown can switch to, so offering it here would mean
|
|
123
|
-
* mutating the field's type — and rebuilding its control — from a source picker. The
|
|
124
|
-
* exclusion that matters within a choice field is inline `options` vs `listName`.
|
|
125
|
-
*/
|
|
126
|
-
fieldDataSource(field: NestedFieldConfig | undefined): 'none' | 'manual' | 'lookup';
|
|
127
|
-
/**
|
|
128
|
-
* Switch a choice field's data source, clearing the one it is leaving.
|
|
129
|
-
*
|
|
130
|
-
* The reference makes these mutually exclusive (doc §4.4) and it has to stay that way here:
|
|
131
|
-
* `optionsFor` resolves inline options first, so a field left holding both would silently
|
|
132
|
-
* ignore its list.
|
|
133
|
-
*/
|
|
134
|
-
setFieldDataSource(fieldId: string, source: 'none' | 'manual' | 'lookup'): void;
|
|
135
|
-
/** Set the named list a choice field reads its options from. */
|
|
136
|
-
setListName(fieldId: string, listName: string): void;
|
|
137
|
-
/** Link a field to a field defined in another entity configuration (Phase 8). */
|
|
138
|
-
linkReferencedField(fieldId: string, sourceEntityKey: string, sourceField: NestedFieldConfig): void;
|
|
139
|
-
/** Unlink a referenced field back to an independent field. */
|
|
140
|
-
unlinkReferencedField(fieldId: string): void;
|
|
141
|
-
/** Sync a drifted referenced field with the updated source field definition. */
|
|
142
|
-
syncReferencedField(fieldId: string, currentSourceField: NestedFieldConfig): void;
|
|
143
|
-
/** Scan all referenced fields in the config and update their hasDrift state against current source configs. */
|
|
144
|
-
checkDrift(sourceConfigs: Record<string, EntityFormConfig>): void;
|
|
145
|
-
addOption(fieldId: string): void;
|
|
146
|
-
/** Merge language keys into an option. `setOptionLabel` is the usual single-language path. */
|
|
147
|
-
updateOption(fieldId: string, index: number, patch: DropdownOption): void;
|
|
148
|
-
/**
|
|
149
|
-
* Set an option's text for one language.
|
|
150
|
-
*
|
|
151
|
-
* An option is a language-keyed object and the displayed text **is** the stored value,
|
|
152
|
-
* so this is the only way to edit one — there is no separate value to set.
|
|
153
|
-
*/
|
|
154
|
-
setOptionLabel(fieldId: string, index: number, language: string, value: string): void;
|
|
155
|
-
removeOption(fieldId: string, index: number): void;
|
|
156
|
-
/** Merge a patch into a field's `entityReference` block, keeping it enabled. */
|
|
157
|
-
updateEntityReference(fieldId: string, patch: Partial<EntityReferenceConfig>): void;
|
|
158
|
-
addAutoPatchMapping(fieldId: string): void;
|
|
159
|
-
setAutoPatchTargetTab(fieldId: string, targetTab: string): void;
|
|
160
|
-
updateAutoPatchMapping(fieldId: string, index: number, patch: Partial<AutoPatchMapping>): void;
|
|
161
|
-
/** Removing the last mapping drops `autoPatch` entirely — no empty config in the export. */
|
|
162
|
-
removeAutoPatchMapping(fieldId: string, index: number): void;
|
|
163
|
-
addPatchOnTrueMapping(fieldId: string): void;
|
|
164
|
-
updatePatchOnTrueMapping(fieldId: string, index: number, patch: Partial<PatchOnTrueMapping>): void;
|
|
165
|
-
removePatchOnTrueMapping(fieldId: string, index: number): void;
|
|
166
|
-
/** Replace a field's `showWhen` map; an empty map removes the condition. */
|
|
167
|
-
setShowWhen(fieldId: string, showWhen: Record<string, unknown> | undefined): void;
|
|
168
|
-
/** Rules for the field currently selected in the inspector. */
|
|
169
|
-
readonly rulesForSelectedField: import("@angular/core").Signal<FormRule[]>;
|
|
170
|
-
loadRules(rules: FormRule[]): void;
|
|
171
|
-
addRule(rule: FormRule): string;
|
|
172
|
-
updateRule(id: string, patch: Partial<FormRule>): void;
|
|
173
|
-
removeRule(id: string): void;
|
|
174
|
-
toggleRule(id: string, enabled: boolean): void;
|
|
175
|
-
/** Move a rule in priority order. Priorities are renumbered 1..n so they stay contiguous. */
|
|
176
|
-
moveRule(id: string, direction: -1 | 1): void;
|
|
177
|
-
exportRules(): FormRule[];
|
|
178
|
-
addTab(): string;
|
|
179
|
-
/** Every tab id in the tree, at any depth. Tab ids must be globally unique — they are paths. */
|
|
180
|
-
private allTabIds;
|
|
181
|
-
addSubTab(parentId: string): string;
|
|
182
|
-
setPrimaryTab(tabId: string): void;
|
|
183
|
-
updateTab(id: string, patch: Partial<NestedTabConfig>): void;
|
|
184
|
-
setTabLabel(id: string, language: string, value: string): void;
|
|
185
|
-
removeTab(id: string): void;
|
|
186
|
-
moveTab(id: string, direction: -1 | 1): void;
|
|
187
|
-
exportConfig(): EntityFormConfig;
|
|
188
|
-
private mutate;
|
|
189
|
-
/**
|
|
190
|
-
* Replace one field, copying only the objects on the path to it.
|
|
191
|
-
*
|
|
192
|
-
* `mutate` deep-clones the entire config, which is right for a structural edit but wrong
|
|
193
|
-
* for the two setters bound to keystroke events: typing a label allocated a full copy of
|
|
194
|
-
* the config per character. Here every tab and field outside the target's chain is reused
|
|
195
|
-
* by reference, so the cost is proportional to nesting depth rather than config size —
|
|
196
|
-
* while the parts that did change are still fresh objects, so change detection and the
|
|
197
|
-
* signal both see a new identity.
|
|
198
|
-
*
|
|
199
|
-
* Returns without touching anything when the field is not found.
|
|
200
|
-
*/
|
|
201
|
-
private mutateField;
|
|
202
|
-
private uniqueId;
|
|
203
|
-
private validate;
|
|
204
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<BuilderStore, never>;
|
|
205
|
-
static ɵprov: i0.ɵɵInjectableDeclaration<BuilderStore>;
|
|
206
|
-
}
|
package/lib/clone.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Deep clone with a JSON fallback.
|
|
3
|
-
*
|
|
4
|
-
* `structuredClone` is not universally available (older browsers, and jsdom before v22),
|
|
5
|
-
* so it must never be called unguarded — an unguarded call throws a ReferenceError and the
|
|
6
|
-
* caller silently does nothing. Config and rule objects are JSON-safe, so the fallback is
|
|
7
|
-
* lossless here.
|
|
8
|
-
*/
|
|
9
|
-
export declare function deepClone<T>(value: T): T;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { CdkDragDrop } from '@angular/cdk/drag-drop';
|
|
2
|
-
import { BuilderStore } from '../builder-store.service';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
export declare class EntityBuilderCanvasComponent {
|
|
5
|
-
protected readonly store: BuilderStore;
|
|
6
|
-
protected onDrop(event: CdkDragDrop<unknown>): void;
|
|
7
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<EntityBuilderCanvasComponent, never>;
|
|
8
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<EntityBuilderCanvasComponent, "ngx-entity-builder-canvas", never, {}, {}, never, never, true, never>;
|
|
9
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { type NestedFieldConfig } from '@dynamic-entity/core';
|
|
2
|
-
import { BuilderStore } from '../builder-store.service';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
export declare class EntityBuilderTreeNodeComponent {
|
|
5
|
-
protected readonly store: BuilderStore;
|
|
6
|
-
field: NestedFieldConfig;
|
|
7
|
-
index: number;
|
|
8
|
-
totalCount: number;
|
|
9
|
-
protected fieldTypeLabel(type: string): string;
|
|
10
|
-
protected fieldTypeIcon(type: string): string;
|
|
11
|
-
protected fieldLabel(field: {
|
|
12
|
-
id: string;
|
|
13
|
-
label?: any;
|
|
14
|
-
}): string;
|
|
15
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<EntityBuilderTreeNodeComponent, never>;
|
|
16
|
-
static ɵcmp: i0.ɵɵ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>;
|
|
17
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { NestedFieldConfig } from '@dynamic-entity/core';
|
|
2
|
-
import { BuilderStore } from '../builder-store.service';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
/**
|
|
5
|
-
* EntityReferenceConfigComponent — authors the `entityReference` block of an entity-ref field:
|
|
6
|
-
* registry key, display fields, static filters, and the parent→child cascade.
|
|
7
|
-
*
|
|
8
|
-
* Also authors `autoPatch`, since the mappings only make sense against the record the
|
|
9
|
-
* selected reference returns.
|
|
10
|
-
*/
|
|
11
|
-
export declare class EntityReferenceConfigComponent {
|
|
12
|
-
protected readonly store: BuilderStore;
|
|
13
|
-
protected readonly field: import("@angular/core").Signal<NestedFieldConfig>;
|
|
14
|
-
/** Sibling fields that can drive a cascade — anything but this field itself. */
|
|
15
|
-
protected readonly parentCandidates: import("@angular/core").Signal<NestedFieldConfig[]>;
|
|
16
|
-
private readonly filtersParseError;
|
|
17
|
-
protected readonly filtersError: import("@angular/core").Signal<string>;
|
|
18
|
-
protected ref(field: NestedFieldConfig): import("@dynamic-entity/core").EntityReferenceConfig;
|
|
19
|
-
protected patchRef(field: NestedFieldConfig, patch: Record<string, unknown>): void;
|
|
20
|
-
protected fieldLabel(field: NestedFieldConfig): string;
|
|
21
|
-
protected tabLabel(tabId: string): string;
|
|
22
|
-
protected displayFieldsText(field: NestedFieldConfig): string;
|
|
23
|
-
protected setDisplayFields(field: NestedFieldConfig, value: string): void;
|
|
24
|
-
protected filtersText(field: NestedFieldConfig): string;
|
|
25
|
-
/** Invalid JSON is reported inline and left unapplied rather than silently dropped. */
|
|
26
|
-
protected setFilters(field: NestedFieldConfig, value: string): void;
|
|
27
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<EntityReferenceConfigComponent, never>;
|
|
28
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<EntityReferenceConfigComponent, "ngx-entity-reference-config", never, {}, {}, never, never, true, never>;
|
|
29
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { DropdownOption, NestedFieldConfig } from '@dynamic-entity/core';
|
|
2
|
-
import { BuilderStore } from '../builder-store.service';
|
|
3
|
-
import { type FieldTypeMeta } from '../field-catalog';
|
|
4
|
-
import * as i0 from "@angular/core";
|
|
5
|
-
/**
|
|
6
|
-
* FieldInspectorComponent — edits every property of the currently selected field.
|
|
7
|
-
*/
|
|
8
|
-
export declare class FieldInspectorComponent {
|
|
9
|
-
protected readonly store: BuilderStore;
|
|
10
|
-
protected readonly field: import("@angular/core").Signal<NestedFieldConfig>;
|
|
11
|
-
protected readonly meta: import("@angular/core").Signal<FieldTypeMeta>;
|
|
12
|
-
protected lang(): string;
|
|
13
|
-
protected toNum(value: unknown): number | null;
|
|
14
|
-
protected labelValue(field: NestedFieldConfig): string;
|
|
15
|
-
protected placeholderValue(field: NestedFieldConfig): string;
|
|
16
|
-
protected optionLabel(option: DropdownOption): string;
|
|
17
|
-
protected showWhenEntries(field: NestedFieldConfig): {
|
|
18
|
-
key: string;
|
|
19
|
-
display: string;
|
|
20
|
-
}[];
|
|
21
|
-
protected addShowWhen(field: NestedFieldConfig): void;
|
|
22
|
-
protected renameShowWhen(field: NestedFieldConfig, oldKey: string, newKey: string): void;
|
|
23
|
-
protected setShowWhenValue(field: NestedFieldConfig, key: string, raw: string): void;
|
|
24
|
-
protected removeShowWhen(field: NestedFieldConfig, key: string): void;
|
|
25
|
-
/**
|
|
26
|
-
* `showWhen` compares with `!==`, so the authored type has to survive the round trip:
|
|
27
|
-
* "true"/"false" become booleans and numeric text becomes a number.
|
|
28
|
-
*/
|
|
29
|
-
private parseShowWhen;
|
|
30
|
-
private stringifyShowWhen;
|
|
31
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<FieldInspectorComponent, never>;
|
|
32
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<FieldInspectorComponent, "ngx-field-inspector", never, {}, {}, never, never, true, never>;
|
|
33
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from '@angular/core';
|
|
2
|
-
import type { RichFieldType } from '@dynamic-entity/core';
|
|
3
|
-
import { type FieldTypeMeta } from '../field-catalog';
|
|
4
|
-
import * as i0 from "@angular/core";
|
|
5
|
-
/**
|
|
6
|
-
* FieldPaletteComponent — the list of buildable field types (Angular Material).
|
|
7
|
-
*/
|
|
8
|
-
export declare class FieldPaletteComponent {
|
|
9
|
-
readonly catalog: readonly FieldTypeMeta[];
|
|
10
|
-
pick: EventEmitter<RichFieldType>;
|
|
11
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<FieldPaletteComponent, never>;
|
|
12
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<FieldPaletteComponent, "ngx-field-palette", never, {}, { "pick": "pick"; }, never, never, true, never>;
|
|
13
|
-
}
|