ngx-dynamic-entity-builder 1.0.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 +54 -0
- package/esm2022/lib/builder-store.service.mjs +923 -0
- package/esm2022/lib/clone.mjs +14 -0
- package/esm2022/lib/components/connection-source-config.component.mjs +121 -0
- package/esm2022/lib/components/entity-builder-canvas.component.mjs +83 -0
- package/esm2022/lib/components/entity-builder-tree-node.component.mjs +173 -0
- package/esm2022/lib/components/entity-reference-config.component.mjs +405 -0
- package/esm2022/lib/components/field-inspector.component.mjs +139 -0
- package/esm2022/lib/components/field-palette.component.mjs +57 -0
- package/esm2022/lib/components/field-rules-list.component.mjs +224 -0
- package/esm2022/lib/components/referenced-field-config.component.mjs +228 -0
- package/esm2022/lib/components/rule-form.component.mjs +201 -0
- package/esm2022/lib/components/tab-manager.component.mjs +341 -0
- package/esm2022/lib/entity-builder.component.mjs +153 -0
- package/esm2022/lib/field-catalog.mjs +6 -0
- package/esm2022/ngx-dynamic-entity-builder.mjs +5 -0
- package/esm2022/public-api.mjs +17 -0
- package/fesm2022/ngx-dynamic-entity-builder.mjs +2910 -0
- package/fesm2022/ngx-dynamic-entity-builder.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/builder-store.service.d.ts +165 -0
- package/lib/clone.d.ts +9 -0
- package/lib/components/connection-source-config.component.d.ts +16 -0
- package/lib/components/entity-builder-canvas.component.d.ts +9 -0
- package/lib/components/entity-builder-tree-node.component.d.ts +17 -0
- package/lib/components/entity-reference-config.component.d.ts +29 -0
- package/lib/components/field-inspector.component.d.ts +33 -0
- package/lib/components/field-palette.component.d.ts +13 -0
- package/lib/components/field-rules-list.component.d.ts +19 -0
- package/lib/components/referenced-field-config.component.d.ts +18 -0
- package/lib/components/rule-form.component.d.ts +16 -0
- package/lib/components/tab-manager.component.d.ts +19 -0
- package/lib/entity-builder.component.d.ts +42 -0
- package/lib/field-catalog.d.ts +5 -0
- package/package.json +42 -0
- package/public-api.d.ts +13 -0
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { Component, InjectionToken, inject } from '@angular/core';
|
|
2
|
+
import { FormsModule } from '@angular/forms';
|
|
3
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
4
|
+
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
5
|
+
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
6
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
7
|
+
import { MatInputModule } from '@angular/material/input';
|
|
8
|
+
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
|
9
|
+
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
10
|
+
import { resolveLabel } from '@dynamic-entity/core';
|
|
11
|
+
import { BuilderStore } from '../builder-store.service';
|
|
12
|
+
import * as i0 from "@angular/core";
|
|
13
|
+
import * as i1 from "@angular/forms";
|
|
14
|
+
import * as i2 from "@angular/material/button";
|
|
15
|
+
import * as i3 from "@angular/material/checkbox";
|
|
16
|
+
import * as i4 from "@angular/material/form-field";
|
|
17
|
+
import * as i5 from "@angular/material/icon";
|
|
18
|
+
import * as i6 from "@angular/material/input";
|
|
19
|
+
import * as i7 from "@angular/material/tooltip";
|
|
20
|
+
export const SYSTEM_DEFAULT_CAN_EDIT = new InjectionToken('SYSTEM_DEFAULT_CAN_EDIT');
|
|
21
|
+
/**
|
|
22
|
+
* TabManagerComponent — add / rename / reorder / remove tabs & sub-tabs with systemDefault protection.
|
|
23
|
+
*/
|
|
24
|
+
export class TabManagerComponent {
|
|
25
|
+
store = inject(BuilderStore);
|
|
26
|
+
canEditSystemDefaultsFn = inject(SYSTEM_DEFAULT_CAN_EDIT, { optional: true });
|
|
27
|
+
lang() {
|
|
28
|
+
return this.store.activeLanguage();
|
|
29
|
+
}
|
|
30
|
+
tabLabel(tab) {
|
|
31
|
+
return resolveLabel(tab.label, this.lang());
|
|
32
|
+
}
|
|
33
|
+
canEditTab(tab) {
|
|
34
|
+
if (!tab.systemDefault)
|
|
35
|
+
return true;
|
|
36
|
+
if (this.canEditSystemDefaultsFn) {
|
|
37
|
+
return this.canEditSystemDefaultsFn([]);
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TabManagerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
42
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: TabManagerComponent, isStandalone: true, selector: "ngx-tab-manager", ngImport: i0, template: `
|
|
43
|
+
<div class="deb-tabs">
|
|
44
|
+
<div class="deb-tabs__head">
|
|
45
|
+
<span class="deb-section-title">Tabs Manager</span>
|
|
46
|
+
<button mat-stroked-button type="button" (click)="store.addTab()">
|
|
47
|
+
<mat-icon>add</mat-icon> Add Tab
|
|
48
|
+
</button>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
@if (store.tabs().length === 0) {
|
|
52
|
+
<p class="deb-hint">No tabs — all fields render in a single section.</p>
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@for (tab of store.tabs(); track tab.id; let i = $index, count = $count) {
|
|
56
|
+
<div class="deb-tab-card" [class.deb-tab-card--system]="tab.systemDefault">
|
|
57
|
+
<div class="deb-tabs__row" [attr.data-testid]="'tab-row-' + tab.id">
|
|
58
|
+
<mat-form-field appearance="outline" subscriptSizing="dynamic" class="deb-grow">
|
|
59
|
+
<mat-label>{{ tab.id }} {{ tab.systemDefault ? '(System)' : '' }}</mat-label>
|
|
60
|
+
<input
|
|
61
|
+
matInput
|
|
62
|
+
[disabled]="!canEditTab(tab)"
|
|
63
|
+
[ngModel]="tabLabel(tab)"
|
|
64
|
+
(ngModelChange)="store.setTabLabel(tab.id, lang(), $event)"
|
|
65
|
+
/>
|
|
66
|
+
</mat-form-field>
|
|
67
|
+
<button
|
|
68
|
+
mat-icon-button
|
|
69
|
+
type="button"
|
|
70
|
+
[disabled]="i === 0 || !canEditTab(tab)"
|
|
71
|
+
(click)="store.moveTab(tab.id, -1)"
|
|
72
|
+
matTooltip="Move up"
|
|
73
|
+
>
|
|
74
|
+
<mat-icon>arrow_upward</mat-icon>
|
|
75
|
+
</button>
|
|
76
|
+
<button
|
|
77
|
+
mat-icon-button
|
|
78
|
+
type="button"
|
|
79
|
+
[disabled]="i === count - 1 || !canEditTab(tab)"
|
|
80
|
+
(click)="store.moveTab(tab.id, 1)"
|
|
81
|
+
matTooltip="Move down"
|
|
82
|
+
>
|
|
83
|
+
<mat-icon>arrow_downward</mat-icon>
|
|
84
|
+
</button>
|
|
85
|
+
<button
|
|
86
|
+
mat-icon-button
|
|
87
|
+
type="button"
|
|
88
|
+
color="warn"
|
|
89
|
+
[disabled]="!canEditTab(tab)"
|
|
90
|
+
(click)="store.removeTab(tab.id)"
|
|
91
|
+
matTooltip="Remove tab"
|
|
92
|
+
>
|
|
93
|
+
<mat-icon>delete</mat-icon>
|
|
94
|
+
</button>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
<!-- Tab settings row -->
|
|
98
|
+
<div class="deb-tab-settings">
|
|
99
|
+
<mat-checkbox
|
|
100
|
+
[disabled]="!canEditTab(tab)"
|
|
101
|
+
[ngModel]="tab.flatData"
|
|
102
|
+
(ngModelChange)="store.updateTab(tab.id, { flatData: $event })"
|
|
103
|
+
>
|
|
104
|
+
Flat Data
|
|
105
|
+
</mat-checkbox>
|
|
106
|
+
<mat-checkbox
|
|
107
|
+
[disabled]="!canEditTab(tab)"
|
|
108
|
+
[ngModel]="tab.isPrimaryTab"
|
|
109
|
+
(ngModelChange)="$event ? store.setPrimaryTab(tab.id) : store.updateTab(tab.id, { isPrimaryTab: false })"
|
|
110
|
+
>
|
|
111
|
+
Primary Tab
|
|
112
|
+
</mat-checkbox>
|
|
113
|
+
<mat-checkbox
|
|
114
|
+
[disabled]="!canEditTab(tab)"
|
|
115
|
+
[ngModel]="tab.maskData"
|
|
116
|
+
(ngModelChange)="store.updateTab(tab.id, { maskData: $event })"
|
|
117
|
+
>
|
|
118
|
+
Mask Tab Data
|
|
119
|
+
</mat-checkbox>
|
|
120
|
+
<mat-checkbox
|
|
121
|
+
[disabled]="!canEditTab(tab)"
|
|
122
|
+
[ngModel]="tab.systemDefault"
|
|
123
|
+
(ngModelChange)="store.updateTab(tab.id, { systemDefault: $event })"
|
|
124
|
+
>
|
|
125
|
+
System Default
|
|
126
|
+
</mat-checkbox>
|
|
127
|
+
<button
|
|
128
|
+
mat-button
|
|
129
|
+
type="button"
|
|
130
|
+
color="primary"
|
|
131
|
+
[disabled]="!canEditTab(tab)"
|
|
132
|
+
(click)="store.addSubTab(tab.id)"
|
|
133
|
+
>
|
|
134
|
+
+ Sub-tab
|
|
135
|
+
</button>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<!-- Module tab configuration -->
|
|
139
|
+
<div class="deb-tab-module">
|
|
140
|
+
<mat-form-field appearance="outline" subscriptSizing="dynamic" class="deb-grow">
|
|
141
|
+
<mat-label>Consumer Module Name (Optional)</mat-label>
|
|
142
|
+
<input
|
|
143
|
+
matInput
|
|
144
|
+
placeholder="e.g. documents-view"
|
|
145
|
+
[disabled]="!canEditTab(tab)"
|
|
146
|
+
[ngModel]="tab.moduleName"
|
|
147
|
+
(ngModelChange)="store.updateTab(tab.id, { moduleName: $event || undefined })"
|
|
148
|
+
/>
|
|
149
|
+
</mat-form-field>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<!-- Sub-tabs recursive render (Level 2) -->
|
|
153
|
+
@if (tab.children && tab.children.length > 0) {
|
|
154
|
+
<div class="deb-subtabs">
|
|
155
|
+
<span class="deb-subtabs__title">Sub-tabs:</span>
|
|
156
|
+
@for (sub of tab.children; track sub.id) {
|
|
157
|
+
<div class="deb-tabs__row deb-subtab-row" [attr.data-testid]="'subtab-row-' + sub.id">
|
|
158
|
+
<mat-form-field appearance="outline" subscriptSizing="dynamic" class="deb-grow">
|
|
159
|
+
<mat-label>{{ sub.id }}</mat-label>
|
|
160
|
+
<input
|
|
161
|
+
matInput
|
|
162
|
+
[disabled]="!canEditTab(sub)"
|
|
163
|
+
[ngModel]="tabLabel(sub)"
|
|
164
|
+
(ngModelChange)="store.setTabLabel(sub.id, lang(), $event)"
|
|
165
|
+
/>
|
|
166
|
+
</mat-form-field>
|
|
167
|
+
<button
|
|
168
|
+
mat-icon-button
|
|
169
|
+
type="button"
|
|
170
|
+
color="warn"
|
|
171
|
+
[disabled]="!canEditTab(sub)"
|
|
172
|
+
(click)="store.removeTab(sub.id)"
|
|
173
|
+
matTooltip="Remove sub-tab"
|
|
174
|
+
>
|
|
175
|
+
<mat-icon>delete</mat-icon>
|
|
176
|
+
</button>
|
|
177
|
+
</div>
|
|
178
|
+
}
|
|
179
|
+
</div>
|
|
180
|
+
}
|
|
181
|
+
</div>
|
|
182
|
+
}
|
|
183
|
+
</div>
|
|
184
|
+
`, isInline: true, styles: [".deb-tabs__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.deb-tab-card{border:1px solid var(--deb-border, #e5e7eb);border-radius:8px;padding:10px;margin-bottom:10px;background:var(--deb-bg-surface, #ffffff)}.deb-tab-card--system{border-left:4px solid var(--deb-accent, #6366f1)}.deb-tabs__row{display:flex;align-items:center;gap:4px}.deb-tab-settings{display:flex;flex-wrap:wrap;gap:8px 16px;align-items:center;margin-top:8px;font-size:13px}.deb-tab-module{margin-top:8px}.deb-subtabs{margin-top:8px;padding-left:16px;border-left:2px dashed var(--deb-border, #e5e7eb)}.deb-subtabs__title{font-size:12px;font-weight:600;color:var(--deb-muted, #6b7280)}.deb-subtab-row{margin-top:6px}.deb-grow{flex:1}\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: "component", type: i2.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i3.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i6.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: MatSlideToggleModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] });
|
|
185
|
+
}
|
|
186
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TabManagerComponent, decorators: [{
|
|
187
|
+
type: Component,
|
|
188
|
+
args: [{ selector: 'ngx-tab-manager', standalone: true, imports: [
|
|
189
|
+
FormsModule,
|
|
190
|
+
MatButtonModule,
|
|
191
|
+
MatCheckboxModule,
|
|
192
|
+
MatFormFieldModule,
|
|
193
|
+
MatIconModule,
|
|
194
|
+
MatInputModule,
|
|
195
|
+
MatSlideToggleModule,
|
|
196
|
+
MatTooltipModule,
|
|
197
|
+
], template: `
|
|
198
|
+
<div class="deb-tabs">
|
|
199
|
+
<div class="deb-tabs__head">
|
|
200
|
+
<span class="deb-section-title">Tabs Manager</span>
|
|
201
|
+
<button mat-stroked-button type="button" (click)="store.addTab()">
|
|
202
|
+
<mat-icon>add</mat-icon> Add Tab
|
|
203
|
+
</button>
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
@if (store.tabs().length === 0) {
|
|
207
|
+
<p class="deb-hint">No tabs — all fields render in a single section.</p>
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@for (tab of store.tabs(); track tab.id; let i = $index, count = $count) {
|
|
211
|
+
<div class="deb-tab-card" [class.deb-tab-card--system]="tab.systemDefault">
|
|
212
|
+
<div class="deb-tabs__row" [attr.data-testid]="'tab-row-' + tab.id">
|
|
213
|
+
<mat-form-field appearance="outline" subscriptSizing="dynamic" class="deb-grow">
|
|
214
|
+
<mat-label>{{ tab.id }} {{ tab.systemDefault ? '(System)' : '' }}</mat-label>
|
|
215
|
+
<input
|
|
216
|
+
matInput
|
|
217
|
+
[disabled]="!canEditTab(tab)"
|
|
218
|
+
[ngModel]="tabLabel(tab)"
|
|
219
|
+
(ngModelChange)="store.setTabLabel(tab.id, lang(), $event)"
|
|
220
|
+
/>
|
|
221
|
+
</mat-form-field>
|
|
222
|
+
<button
|
|
223
|
+
mat-icon-button
|
|
224
|
+
type="button"
|
|
225
|
+
[disabled]="i === 0 || !canEditTab(tab)"
|
|
226
|
+
(click)="store.moveTab(tab.id, -1)"
|
|
227
|
+
matTooltip="Move up"
|
|
228
|
+
>
|
|
229
|
+
<mat-icon>arrow_upward</mat-icon>
|
|
230
|
+
</button>
|
|
231
|
+
<button
|
|
232
|
+
mat-icon-button
|
|
233
|
+
type="button"
|
|
234
|
+
[disabled]="i === count - 1 || !canEditTab(tab)"
|
|
235
|
+
(click)="store.moveTab(tab.id, 1)"
|
|
236
|
+
matTooltip="Move down"
|
|
237
|
+
>
|
|
238
|
+
<mat-icon>arrow_downward</mat-icon>
|
|
239
|
+
</button>
|
|
240
|
+
<button
|
|
241
|
+
mat-icon-button
|
|
242
|
+
type="button"
|
|
243
|
+
color="warn"
|
|
244
|
+
[disabled]="!canEditTab(tab)"
|
|
245
|
+
(click)="store.removeTab(tab.id)"
|
|
246
|
+
matTooltip="Remove tab"
|
|
247
|
+
>
|
|
248
|
+
<mat-icon>delete</mat-icon>
|
|
249
|
+
</button>
|
|
250
|
+
</div>
|
|
251
|
+
|
|
252
|
+
<!-- Tab settings row -->
|
|
253
|
+
<div class="deb-tab-settings">
|
|
254
|
+
<mat-checkbox
|
|
255
|
+
[disabled]="!canEditTab(tab)"
|
|
256
|
+
[ngModel]="tab.flatData"
|
|
257
|
+
(ngModelChange)="store.updateTab(tab.id, { flatData: $event })"
|
|
258
|
+
>
|
|
259
|
+
Flat Data
|
|
260
|
+
</mat-checkbox>
|
|
261
|
+
<mat-checkbox
|
|
262
|
+
[disabled]="!canEditTab(tab)"
|
|
263
|
+
[ngModel]="tab.isPrimaryTab"
|
|
264
|
+
(ngModelChange)="$event ? store.setPrimaryTab(tab.id) : store.updateTab(tab.id, { isPrimaryTab: false })"
|
|
265
|
+
>
|
|
266
|
+
Primary Tab
|
|
267
|
+
</mat-checkbox>
|
|
268
|
+
<mat-checkbox
|
|
269
|
+
[disabled]="!canEditTab(tab)"
|
|
270
|
+
[ngModel]="tab.maskData"
|
|
271
|
+
(ngModelChange)="store.updateTab(tab.id, { maskData: $event })"
|
|
272
|
+
>
|
|
273
|
+
Mask Tab Data
|
|
274
|
+
</mat-checkbox>
|
|
275
|
+
<mat-checkbox
|
|
276
|
+
[disabled]="!canEditTab(tab)"
|
|
277
|
+
[ngModel]="tab.systemDefault"
|
|
278
|
+
(ngModelChange)="store.updateTab(tab.id, { systemDefault: $event })"
|
|
279
|
+
>
|
|
280
|
+
System Default
|
|
281
|
+
</mat-checkbox>
|
|
282
|
+
<button
|
|
283
|
+
mat-button
|
|
284
|
+
type="button"
|
|
285
|
+
color="primary"
|
|
286
|
+
[disabled]="!canEditTab(tab)"
|
|
287
|
+
(click)="store.addSubTab(tab.id)"
|
|
288
|
+
>
|
|
289
|
+
+ Sub-tab
|
|
290
|
+
</button>
|
|
291
|
+
</div>
|
|
292
|
+
|
|
293
|
+
<!-- Module tab configuration -->
|
|
294
|
+
<div class="deb-tab-module">
|
|
295
|
+
<mat-form-field appearance="outline" subscriptSizing="dynamic" class="deb-grow">
|
|
296
|
+
<mat-label>Consumer Module Name (Optional)</mat-label>
|
|
297
|
+
<input
|
|
298
|
+
matInput
|
|
299
|
+
placeholder="e.g. documents-view"
|
|
300
|
+
[disabled]="!canEditTab(tab)"
|
|
301
|
+
[ngModel]="tab.moduleName"
|
|
302
|
+
(ngModelChange)="store.updateTab(tab.id, { moduleName: $event || undefined })"
|
|
303
|
+
/>
|
|
304
|
+
</mat-form-field>
|
|
305
|
+
</div>
|
|
306
|
+
|
|
307
|
+
<!-- Sub-tabs recursive render (Level 2) -->
|
|
308
|
+
@if (tab.children && tab.children.length > 0) {
|
|
309
|
+
<div class="deb-subtabs">
|
|
310
|
+
<span class="deb-subtabs__title">Sub-tabs:</span>
|
|
311
|
+
@for (sub of tab.children; track sub.id) {
|
|
312
|
+
<div class="deb-tabs__row deb-subtab-row" [attr.data-testid]="'subtab-row-' + sub.id">
|
|
313
|
+
<mat-form-field appearance="outline" subscriptSizing="dynamic" class="deb-grow">
|
|
314
|
+
<mat-label>{{ sub.id }}</mat-label>
|
|
315
|
+
<input
|
|
316
|
+
matInput
|
|
317
|
+
[disabled]="!canEditTab(sub)"
|
|
318
|
+
[ngModel]="tabLabel(sub)"
|
|
319
|
+
(ngModelChange)="store.setTabLabel(sub.id, lang(), $event)"
|
|
320
|
+
/>
|
|
321
|
+
</mat-form-field>
|
|
322
|
+
<button
|
|
323
|
+
mat-icon-button
|
|
324
|
+
type="button"
|
|
325
|
+
color="warn"
|
|
326
|
+
[disabled]="!canEditTab(sub)"
|
|
327
|
+
(click)="store.removeTab(sub.id)"
|
|
328
|
+
matTooltip="Remove sub-tab"
|
|
329
|
+
>
|
|
330
|
+
<mat-icon>delete</mat-icon>
|
|
331
|
+
</button>
|
|
332
|
+
</div>
|
|
333
|
+
}
|
|
334
|
+
</div>
|
|
335
|
+
}
|
|
336
|
+
</div>
|
|
337
|
+
}
|
|
338
|
+
</div>
|
|
339
|
+
`, styles: [".deb-tabs__head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.deb-tab-card{border:1px solid var(--deb-border, #e5e7eb);border-radius:8px;padding:10px;margin-bottom:10px;background:var(--deb-bg-surface, #ffffff)}.deb-tab-card--system{border-left:4px solid var(--deb-accent, #6366f1)}.deb-tabs__row{display:flex;align-items:center;gap:4px}.deb-tab-settings{display:flex;flex-wrap:wrap;gap:8px 16px;align-items:center;margin-top:8px;font-size:13px}.deb-tab-module{margin-top:8px}.deb-subtabs{margin-top:8px;padding-left:16px;border-left:2px dashed var(--deb-border, #e5e7eb)}.deb-subtabs__title{font-size:12px;font-weight:600;color:var(--deb-muted, #6b7280)}.deb-subtab-row{margin-top:6px}.deb-grow{flex:1}\n"] }]
|
|
340
|
+
}] });
|
|
341
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFiLW1hbmFnZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9jb21wb25lbnRzL3RhYi1tYW5hZ2VyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLGNBQWMsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbEUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUMvRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUNsRSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3pELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ3RFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRTdELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNwRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7Ozs7Ozs7OztBQUV4RCxNQUFNLENBQUMsTUFBTSx1QkFBdUIsR0FBRyxJQUFJLGNBQWMsQ0FBK0IseUJBQXlCLENBQUMsQ0FBQztBQUVuSDs7R0FFRztBQWtOSCxNQUFNLE9BQU8sbUJBQW1CO0lBQ1gsS0FBSyxHQUFHLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUMvQix1QkFBdUIsR0FBRyxNQUFNLENBQStCLHVCQUF1QixFQUFFLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFFbkgsSUFBSTtRQUNaLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztJQUNyQyxDQUFDO0lBRVMsUUFBUSxDQUFDLEdBQW9CO1FBQ3JDLE9BQU8sWUFBWSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7SUFDOUMsQ0FBQztJQUVTLFVBQVUsQ0FBQyxHQUFvQjtRQUN2QyxJQUFJLENBQUMsR0FBRyxDQUFDLGFBQWE7WUFBRSxPQUFPLElBQUksQ0FBQztRQUNwQyxJQUFJLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1lBQ2pDLE9BQU8sSUFBSSxDQUFDLHVCQUF1QixDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzFDLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7d0dBbEJVLG1CQUFtQjs0RkFBbkIsbUJBQW1CLDJFQXBNcEI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E4SVQsOHlCQXZKQyxXQUFXLDhtQkFDWCxlQUFlLHdVQUNmLGlCQUFpQiw2V0FDakIsa0JBQWtCLDBTQUNsQixhQUFhLG1MQUNiLGNBQWMsMFdBQ2Qsb0JBQW9CLDhCQUNwQixnQkFBZ0I7OzRGQXNNUCxtQkFBbUI7a0JBak4vQixTQUFTOytCQUNFLGlCQUFpQixjQUNmLElBQUksV0FDUDt3QkFDUCxXQUFXO3dCQUNYLGVBQWU7d0JBQ2YsaUJBQWlCO3dCQUNqQixrQkFBa0I7d0JBQ2xCLGFBQWE7d0JBQ2IsY0FBYzt3QkFDZCxvQkFBb0I7d0JBQ3BCLGdCQUFnQjtxQkFDakIsWUFDUzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQThJVCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5qZWN0aW9uVG9rZW4sIGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0IHsgTWF0QnV0dG9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvYnV0dG9uJztcclxuaW1wb3J0IHsgTWF0Q2hlY2tib3hNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9jaGVja2JveCc7XHJcbmltcG9ydCB7IE1hdEZvcm1GaWVsZE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2Zvcm0tZmllbGQnO1xyXG5pbXBvcnQgeyBNYXRJY29uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvaWNvbic7XHJcbmltcG9ydCB7IE1hdElucHV0TW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvaW5wdXQnO1xyXG5pbXBvcnQgeyBNYXRTbGlkZVRvZ2dsZU1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3NsaWRlLXRvZ2dsZSc7XHJcbmltcG9ydCB7IE1hdFRvb2x0aXBNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC90b29sdGlwJztcclxuaW1wb3J0IHR5cGUgeyBOZXN0ZWRUYWJDb25maWcgfSBmcm9tICdAZHluYW1pYy1lbnRpdHkvY29yZSc7XHJcbmltcG9ydCB7IHJlc29sdmVMYWJlbCB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcclxuaW1wb3J0IHsgQnVpbGRlclN0b3JlIH0gZnJvbSAnLi4vYnVpbGRlci1zdG9yZS5zZXJ2aWNlJztcclxuXHJcbmV4cG9ydCBjb25zdCBTWVNURU1fREVGQVVMVF9DQU5fRURJVCA9IG5ldyBJbmplY3Rpb25Ub2tlbjwocm9sZXM6IHN0cmluZ1tdKSA9PiBib29sZWFuPignU1lTVEVNX0RFRkFVTFRfQ0FOX0VESVQnKTtcclxuXHJcbi8qKlxyXG4gKiBUYWJNYW5hZ2VyQ29tcG9uZW50IOKAlCBhZGQgLyByZW5hbWUgLyByZW9yZGVyIC8gcmVtb3ZlIHRhYnMgJiBzdWItdGFicyB3aXRoIHN5c3RlbURlZmF1bHQgcHJvdGVjdGlvbi5cclxuICovXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnbmd4LXRhYi1tYW5hZ2VyJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtcclxuICAgIEZvcm1zTW9kdWxlLFxyXG4gICAgTWF0QnV0dG9uTW9kdWxlLFxyXG4gICAgTWF0Q2hlY2tib3hNb2R1bGUsXHJcbiAgICBNYXRGb3JtRmllbGRNb2R1bGUsXHJcbiAgICBNYXRJY29uTW9kdWxlLFxyXG4gICAgTWF0SW5wdXRNb2R1bGUsXHJcbiAgICBNYXRTbGlkZVRvZ2dsZU1vZHVsZSxcclxuICAgIE1hdFRvb2x0aXBNb2R1bGUsXHJcbiAgXSxcclxuICB0ZW1wbGF0ZTogYFxyXG4gICAgPGRpdiBjbGFzcz1cImRlYi10YWJzXCI+XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJkZWItdGFic19faGVhZFwiPlxyXG4gICAgICAgIDxzcGFuIGNsYXNzPVwiZGViLXNlY3Rpb24tdGl0bGVcIj5UYWJzIE1hbmFnZXI8L3NwYW4+XHJcbiAgICAgICAgPGJ1dHRvbiBtYXQtc3Ryb2tlZC1idXR0b24gdHlwZT1cImJ1dHRvblwiIChjbGljayk9XCJzdG9yZS5hZGRUYWIoKVwiPlxyXG4gICAgICAgICAgPG1hdC1pY29uPmFkZDwvbWF0LWljb24+IEFkZCBUYWJcclxuICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgPC9kaXY+XHJcblxyXG4gICAgICBAaWYgKHN0b3JlLnRhYnMoKS5sZW5ndGggPT09IDApIHtcclxuICAgICAgICA8cCBjbGFzcz1cImRlYi1oaW50XCI+Tm8gdGFicyDigJQgYWxsIGZpZWxkcyByZW5kZXIgaW4gYSBzaW5nbGUgc2VjdGlvbi48L3A+XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIEBmb3IgKHRhYiBvZiBzdG9yZS50YWJzKCk7IHRyYWNrIHRhYi5pZDsgbGV0IGkgPSAkaW5kZXgsIGNvdW50ID0gJGNvdW50KSB7XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cImRlYi10YWItY2FyZFwiIFtjbGFzcy5kZWItdGFiLWNhcmQtLXN5c3RlbV09XCJ0YWIuc3lzdGVtRGVmYXVsdFwiPlxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cImRlYi10YWJzX19yb3dcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCIndGFiLXJvdy0nICsgdGFiLmlkXCI+XHJcbiAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIiBjbGFzcz1cImRlYi1ncm93XCI+XHJcbiAgICAgICAgICAgICAgPG1hdC1sYWJlbD57eyB0YWIuaWQgfX0ge3sgdGFiLnN5c3RlbURlZmF1bHQgPyAnKFN5c3RlbSknIDogJycgfX08L21hdC1sYWJlbD5cclxuICAgICAgICAgICAgICA8aW5wdXRcclxuICAgICAgICAgICAgICAgIG1hdElucHV0XHJcbiAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiIWNhbkVkaXRUYWIodGFiKVwiXHJcbiAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJ0YWJMYWJlbCh0YWIpXCJcclxuICAgICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnNldFRhYkxhYmVsKHRhYi5pZCwgbGFuZygpLCAkZXZlbnQpXCJcclxuICAgICAgICAgICAgICAvPlxyXG4gICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG4gICAgICAgICAgICA8YnV0dG9uXHJcbiAgICAgICAgICAgICAgbWF0LWljb24tYnV0dG9uXHJcbiAgICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXHJcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cImkgPT09IDAgfHwgIWNhbkVkaXRUYWIodGFiKVwiXHJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cInN0b3JlLm1vdmVUYWIodGFiLmlkLCAtMSlcIlxyXG4gICAgICAgICAgICAgIG1hdFRvb2x0aXA9XCJNb3ZlIHVwXCJcclxuICAgICAgICAgICAgPlxyXG4gICAgICAgICAgICAgIDxtYXQtaWNvbj5hcnJvd191cHdhcmQ8L21hdC1pY29uPlxyXG4gICAgICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgICAgICAgPGJ1dHRvblxyXG4gICAgICAgICAgICAgIG1hdC1pY29uLWJ1dHRvblxyXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxyXG4gICAgICAgICAgICAgIFtkaXNhYmxlZF09XCJpID09PSBjb3VudCAtIDEgfHwgIWNhbkVkaXRUYWIodGFiKVwiXHJcbiAgICAgICAgICAgICAgKGNsaWNrKT1cInN0b3JlLm1vdmVUYWIodGFiLmlkLCAxKVwiXHJcbiAgICAgICAgICAgICAgbWF0VG9vbHRpcD1cIk1vdmUgZG93blwiXHJcbiAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICA8bWF0LWljb24+YXJyb3dfZG93bndhcmQ8L21hdC1pY29uPlxyXG4gICAgICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgICAgICAgPGJ1dHRvblxyXG4gICAgICAgICAgICAgIG1hdC1pY29uLWJ1dHRvblxyXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxyXG4gICAgICAgICAgICAgIGNvbG9yPVwid2FyblwiXHJcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFjYW5FZGl0VGFiKHRhYilcIlxyXG4gICAgICAgICAgICAgIChjbGljayk9XCJzdG9yZS5yZW1vdmVUYWIodGFiLmlkKVwiXHJcbiAgICAgICAgICAgICAgbWF0VG9vbHRpcD1cIlJlbW92ZSB0YWJcIlxyXG4gICAgICAgICAgICA+XHJcbiAgICAgICAgICAgICAgPG1hdC1pY29uPmRlbGV0ZTwvbWF0LWljb24+XHJcbiAgICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgICAgPC9kaXY+XHJcblxyXG4gICAgICAgICAgPCEtLSBUYWIgc2V0dGluZ3Mgcm93IC0tPlxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cImRlYi10YWItc2V0dGluZ3NcIj5cclxuICAgICAgICAgICAgPG1hdC1jaGVja2JveFxyXG4gICAgICAgICAgICAgIFtkaXNhYmxlZF09XCIhY2FuRWRpdFRhYih0YWIpXCJcclxuICAgICAgICAgICAgICBbbmdNb2RlbF09XCJ0YWIuZmxhdERhdGFcIlxyXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnVwZGF0ZVRhYih0YWIuaWQsIHsgZmxhdERhdGE6ICRldmVudCB9KVwiXHJcbiAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICBGbGF0IERhdGFcclxuICAgICAgICAgICAgPC9tYXQtY2hlY2tib3g+XHJcbiAgICAgICAgICAgIDxtYXQtY2hlY2tib3hcclxuICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiIWNhbkVkaXRUYWIodGFiKVwiXHJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwidGFiLmlzUHJpbWFyeVRhYlwiXHJcbiAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwiJGV2ZW50ID8gc3RvcmUuc2V0UHJpbWFyeVRhYih0YWIuaWQpIDogc3RvcmUudXBkYXRlVGFiKHRhYi5pZCwgeyBpc1ByaW1hcnlUYWI6IGZhbHNlIH0pXCJcclxuICAgICAgICAgICAgPlxyXG4gICAgICAgICAgICAgIFByaW1hcnkgVGFiXHJcbiAgICAgICAgICAgIDwvbWF0LWNoZWNrYm94PlxyXG4gICAgICAgICAgICA8bWF0LWNoZWNrYm94XHJcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFjYW5FZGl0VGFiKHRhYilcIlxyXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cInRhYi5tYXNrRGF0YVwiXHJcbiAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3RvcmUudXBkYXRlVGFiKHRhYi5pZCwgeyBtYXNrRGF0YTogJGV2ZW50IH0pXCJcclxuICAgICAgICAgICAgPlxyXG4gICAgICAgICAgICAgIE1hc2sgVGFiIERhdGFcclxuICAgICAgICAgICAgPC9tYXQtY2hlY2tib3g+XHJcbiAgICAgICAgICAgIDxtYXQtY2hlY2tib3hcclxuICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiIWNhbkVkaXRUYWIodGFiKVwiXHJcbiAgICAgICAgICAgICAgW25nTW9kZWxdPVwidGFiLnN5c3RlbURlZmF1bHRcIlxyXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnVwZGF0ZVRhYih0YWIuaWQsIHsgc3lzdGVtRGVmYXVsdDogJGV2ZW50IH0pXCJcclxuICAgICAgICAgICAgPlxyXG4gICAgICAgICAgICAgIFN5c3RlbSBEZWZhdWx0XHJcbiAgICAgICAgICAgIDwvbWF0LWNoZWNrYm94PlxyXG4gICAgICAgICAgICA8YnV0dG9uXHJcbiAgICAgICAgICAgICAgbWF0LWJ1dHRvblxyXG4gICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxyXG4gICAgICAgICAgICAgIGNvbG9yPVwicHJpbWFyeVwiXHJcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFjYW5FZGl0VGFiKHRhYilcIlxyXG4gICAgICAgICAgICAgIChjbGljayk9XCJzdG9yZS5hZGRTdWJUYWIodGFiLmlkKVwiXHJcbiAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICArIFN1Yi10YWJcclxuICAgICAgICAgICAgPC9idXR0b24+XHJcbiAgICAgICAgICA8L2Rpdj5cclxuXHJcbiAgICAgICAgICA8IS0tIE1vZHVsZSB0YWIgY29uZmlndXJhdGlvbiAtLT5cclxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJkZWItdGFiLW1vZHVsZVwiPlxyXG4gICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgYXBwZWFyYW5jZT1cIm91dGxpbmVcIiBzdWJzY3JpcHRTaXppbmc9XCJkeW5hbWljXCIgY2xhc3M9XCJkZWItZ3Jvd1wiPlxyXG4gICAgICAgICAgICAgIDxtYXQtbGFiZWw+Q29uc3VtZXIgTW9kdWxlIE5hbWUgKE9wdGlvbmFsKTwvbWF0LWxhYmVsPlxyXG4gICAgICAgICAgICAgIDxpbnB1dFxyXG4gICAgICAgICAgICAgICAgbWF0SW5wdXRcclxuICAgICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiZS5nLiBkb2N1bWVudHMtdmlld1wiXHJcbiAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiIWNhbkVkaXRUYWIodGFiKVwiXHJcbiAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJ0YWIubW9kdWxlTmFtZVwiXHJcbiAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS51cGRhdGVUYWIodGFiLmlkLCB7IG1vZHVsZU5hbWU6ICRldmVudCB8fCB1bmRlZmluZWQgfSlcIlxyXG4gICAgICAgICAgICAgIC8+XHJcbiAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XHJcbiAgICAgICAgICA8L2Rpdj5cclxuXHJcbiAgICAgICAgICA8IS0tIFN1Yi10YWJzIHJlY3Vyc2l2ZSByZW5kZXIgKExldmVsIDIpIC0tPlxyXG4gICAgICAgICAgQGlmICh0YWIuY2hpbGRyZW4gJiYgdGFiLmNoaWxkcmVuLmxlbmd0aCA+IDApIHtcclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImRlYi1zdWJ0YWJzXCI+XHJcbiAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJkZWItc3VidGFic19fdGl0bGVcIj5TdWItdGFiczo8L3NwYW4+XHJcbiAgICAgICAgICAgICAgQGZvciAoc3ViIG9mIHRhYi5jaGlsZHJlbjsgdHJhY2sgc3ViLmlkKSB7XHJcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwiZGViLXRhYnNfX3JvdyBkZWItc3VidGFiLXJvd1wiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidzdWJ0YWItcm93LScgKyBzdWIuaWRcIj5cclxuICAgICAgICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgc3Vic2NyaXB0U2l6aW5nPVwiZHluYW1pY1wiIGNsYXNzPVwiZGViLWdyb3dcIj5cclxuICAgICAgICAgICAgICAgICAgICA8bWF0LWxhYmVsPnt7IHN1Yi5pZCB9fTwvbWF0LWxhYmVsPlxyXG4gICAgICAgICAgICAgICAgICAgIDxpbnB1dFxyXG4gICAgICAgICAgICAgICAgICAgICAgbWF0SW5wdXRcclxuICAgICAgICAgICAgICAgICAgICAgIFtkaXNhYmxlZF09XCIhY2FuRWRpdFRhYihzdWIpXCJcclxuICAgICAgICAgICAgICAgICAgICAgIFtuZ01vZGVsXT1cInRhYkxhYmVsKHN1YilcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwic3RvcmUuc2V0VGFiTGFiZWwoc3ViLmlkLCBsYW5nKCksICRldmVudClcIlxyXG4gICAgICAgICAgICAgICAgICAgIC8+XHJcbiAgICAgICAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XHJcbiAgICAgICAgICAgICAgICAgIDxidXR0b25cclxuICAgICAgICAgICAgICAgICAgICBtYXQtaWNvbi1idXR0b25cclxuICAgICAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcclxuICAgICAgICAgICAgICAgICAgICBjb2xvcj1cIndhcm5cIlxyXG4gICAgICAgICAgICAgICAgICAgIFtkaXNhYmxlZF09XCIhY2FuRWRpdFRhYihzdWIpXCJcclxuICAgICAgICAgICAgICAgICAgICAoY2xpY2spPVwic3RvcmUucmVtb3ZlVGFiKHN1Yi5pZClcIlxyXG4gICAgICAgICAgICAgICAgICAgIG1hdFRvb2x0aXA9XCJSZW1vdmUgc3ViLXRhYlwiXHJcbiAgICAgICAgICAgICAgICAgID5cclxuICAgICAgICAgICAgICAgICAgICA8bWF0LWljb24+ZGVsZXRlPC9tYXQtaWNvbj5cclxuICAgICAgICAgICAgICAgICAgPC9idXR0b24+XHJcbiAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICB9XHJcbiAgICA8L2Rpdj5cclxuICBgLFxyXG4gIHN0eWxlczogW1xyXG4gICAgYFxyXG4gICAgICAuZGViLXRhYnNfX2hlYWQge1xyXG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgICAgICAgbWFyZ2luLWJvdHRvbTogMTJweDtcclxuICAgICAgfVxyXG4gICAgICAuZGViLXRhYi1jYXJkIHtcclxuICAgICAgICBib3JkZXI6IDFweCBzb2xpZCB2YXIoLS1kZWItYm9yZGVyLCAjZTVlN2ViKTtcclxuICAgICAgICBib3JkZXItcmFkaXVzOiA4cHg7XHJcbiAgICAgICAgcGFkZGluZzogMTBweDtcclxuICAgICAgICBtYXJnaW4tYm90dG9tOiAxMHB4O1xyXG4gICAgICAgIGJhY2tncm91bmQ6IHZhcigtLWRlYi1iZy1zdXJmYWNlLCAjZmZmZmZmKTtcclxuICAgICAgfVxyXG4gICAgICAuZGViLXRhYi1jYXJkLS1zeXN0ZW0ge1xyXG4gICAgICAgIGJvcmRlci1sZWZ0OiA0cHggc29saWQgdmFyKC0tZGViLWFjY2VudCwgIzYzNjZmMSk7XHJcbiAgICAgIH1cclxuICAgICAgLmRlYi10YWJzX19yb3cge1xyXG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgICAgICBnYXA6IDRweDtcclxuICAgICAgfVxyXG4gICAgICAuZGViLXRhYi1zZXR0aW5ncyB7XHJcbiAgICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgICBmbGV4LXdyYXA6IHdyYXA7XHJcbiAgICAgICAgZ2FwOiA4cHggMTZweDtcclxuICAgICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICAgIG1hcmdpbi10b3A6IDhweDtcclxuICAgICAgICBmb250LXNpemU6IDEzcHg7XHJcbiAgICAgIH1cclxuICAgICAgLmRlYi10YWItbW9kdWxlIHtcclxuICAgICAgICBtYXJnaW4tdG9wOiA4cHg7XHJcbiAgICAgIH1cclxuICAgICAgLmRlYi1zdWJ0YWJzIHtcclxuICAgICAgICBtYXJnaW4tdG9wOiA4cHg7XHJcbiAgICAgICAgcGFkZGluZy1sZWZ0OiAxNnB4O1xyXG4gICAgICAgIGJvcmRlci1sZWZ0OiAycHggZGFzaGVkIHZhcigtLWRlYi1ib3JkZXIsICNlNWU3ZWIpO1xyXG4gICAgICB9XHJcbiAgICAgIC5kZWItc3VidGFic19fdGl0bGUge1xyXG4gICAgICAgIGZvbnQtc2l6ZTogMTJweDtcclxuICAgICAgICBmb250LXdlaWdodDogNjAwO1xyXG4gICAgICAgIGNvbG9yOiB2YXIoLS1kZWItbXV0ZWQsICM2YjcyODApO1xyXG4gICAgICB9XHJcbiAgICAgIC5kZWItc3VidGFiLXJvdyB7XHJcbiAgICAgICAgbWFyZ2luLXRvcDogNnB4O1xyXG4gICAgICB9XHJcbiAgICAgIC5kZWItZ3JvdyB7XHJcbiAgICAgICAgZmxleDogMTtcclxuICAgICAgfVxyXG4gICAgYCxcclxuICBdLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgVGFiTWFuYWdlckNvbXBvbmVudCB7XHJcbiAgcHJvdGVjdGVkIHJlYWRvbmx5IHN0b3JlID0gaW5qZWN0KEJ1aWxkZXJTdG9yZSk7XHJcbiAgcHJpdmF0ZSByZWFkb25seSBjYW5FZGl0U3lzdGVtRGVmYXVsdHNGbiA9IGluamVjdDwocm9sZXM6IHN0cmluZ1tdKSA9PiBib29sZWFuPihTWVNURU1fREVGQVVMVF9DQU5fRURJVCwgeyBvcHRpb25hbDogdHJ1ZSB9KTtcclxuXHJcbiAgcHJvdGVjdGVkIGxhbmcoKTogc3RyaW5nIHtcclxuICAgIHJldHVybiB0aGlzLnN0b3JlLmFjdGl2ZUxhbmd1YWdlKCk7XHJcbiAgfVxyXG5cclxuICBwcm90ZWN0ZWQgdGFiTGFiZWwodGFiOiB7IGxhYmVsPzogYW55IH0pOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHJlc29sdmVMYWJlbCh0YWIubGFiZWwsIHRoaXMubGFuZygpKTtcclxuICB9XHJcblxyXG4gIHByb3RlY3RlZCBjYW5FZGl0VGFiKHRhYjogTmVzdGVkVGFiQ29uZmlnKTogYm9vbGVhbiB7XHJcbiAgICBpZiAoIXRhYi5zeXN0ZW1EZWZhdWx0KSByZXR1cm4gdHJ1ZTtcclxuICAgIGlmICh0aGlzLmNhbkVkaXRTeXN0ZW1EZWZhdWx0c0ZuKSB7XHJcbiAgICAgIHJldHVybiB0aGlzLmNhbkVkaXRTeXN0ZW1EZWZhdWx0c0ZuKFtdKTtcclxuICAgIH1cclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH1cclxufVxyXG4iXX0=
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { Component, EventEmitter, Input, Output, effect, inject, } from '@angular/core';
|
|
2
|
+
import { FormsModule } from '@angular/forms';
|
|
3
|
+
import { DragDropModule } from '@angular/cdk/drag-drop';
|
|
4
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
5
|
+
import { MatCardModule } from '@angular/material/card';
|
|
6
|
+
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
7
|
+
import { MatExpansionModule } from '@angular/material/expansion';
|
|
8
|
+
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
9
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
10
|
+
import { MatInputModule } from '@angular/material/input';
|
|
11
|
+
import { MatSelectModule } from '@angular/material/select';
|
|
12
|
+
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
|
|
13
|
+
import { MatToolbarModule } from '@angular/material/toolbar';
|
|
14
|
+
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
15
|
+
import { COMMON_MODULES, resolveLabel, } from '@dynamic-entity/core';
|
|
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 { getFieldTypeMeta } from './field-catalog';
|
|
22
|
+
import * as i0 from "@angular/core";
|
|
23
|
+
import * as i1 from "@angular/forms";
|
|
24
|
+
import * as i2 from "@angular/material/button";
|
|
25
|
+
import * as i3 from "@angular/material/card";
|
|
26
|
+
import * as i4 from "@angular/material/expansion";
|
|
27
|
+
import * as i5 from "@angular/material/form-field";
|
|
28
|
+
import * as i6 from "@angular/material/icon";
|
|
29
|
+
import * as i7 from "@angular/material/input";
|
|
30
|
+
import * as i8 from "@angular/material/select";
|
|
31
|
+
import * as i9 from "@angular/material/core";
|
|
32
|
+
import * as i10 from "@angular/material/slide-toggle";
|
|
33
|
+
import * as i11 from "@angular/material/toolbar";
|
|
34
|
+
import * as i12 from "@angular/material/tooltip";
|
|
35
|
+
/** RBAC actions surfaced in the settings panel. */
|
|
36
|
+
const RBAC_ACTIONS = ['view', 'edit', 'delete'];
|
|
37
|
+
/** Shared stable empty array — never allocate a fresh [] per change-detection (mat-select loops). */
|
|
38
|
+
const EMPTY_ROLES = Object.freeze([]);
|
|
39
|
+
/**
|
|
40
|
+
* EntityBuilderComponent — the top-level visual builder for an EntityFormConfig.
|
|
41
|
+
*/
|
|
42
|
+
export class EntityBuilderComponent {
|
|
43
|
+
store = inject(BuilderStore);
|
|
44
|
+
/** Existing config to edit. When omitted, the builder starts blank. */
|
|
45
|
+
config;
|
|
46
|
+
/** Languages available for label/placeholder editing. First entry is the default. */
|
|
47
|
+
languages = ['en'];
|
|
48
|
+
/** Optional role list — enables multi-select role pickers for RBAC instead of free text. */
|
|
49
|
+
availableRoles = [];
|
|
50
|
+
/** Optional common-module definitions for module tabs; defaults to the built-in list from core. */
|
|
51
|
+
commonModules = COMMON_MODULES;
|
|
52
|
+
/** Emitted on every change to the working config. */
|
|
53
|
+
configChange = new EventEmitter();
|
|
54
|
+
/** Emitted when the user clicks Save. Carries a clean, deep-cloned config. */
|
|
55
|
+
save = new EventEmitter();
|
|
56
|
+
rbacActions = RBAC_ACTIONS;
|
|
57
|
+
constructor() {
|
|
58
|
+
effect(() => this.configChange.emit(this.store.config()), { allowSignalWrites: true });
|
|
59
|
+
}
|
|
60
|
+
ngOnChanges(changes) {
|
|
61
|
+
if (changes['config'] && changes['config'].currentValue !== changes['config'].previousValue) {
|
|
62
|
+
if (this.config)
|
|
63
|
+
this.store.load(this.config);
|
|
64
|
+
else if (changes['config'].isFirstChange())
|
|
65
|
+
this.store.reset();
|
|
66
|
+
}
|
|
67
|
+
if (changes['languages'] && this.languages.length) {
|
|
68
|
+
const active = this.store.activeLanguage();
|
|
69
|
+
if (!this.languages.includes(active))
|
|
70
|
+
this.store.setActiveLanguage(this.languages[0]);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// ─── Field canvas ─────────────────────────────────────────────────────────
|
|
74
|
+
onDrop(event) {
|
|
75
|
+
this.store.reorderField(event.previousIndex, event.currentIndex);
|
|
76
|
+
}
|
|
77
|
+
fieldTypeLabel(type) {
|
|
78
|
+
return getFieldTypeMeta(type)?.label ?? type;
|
|
79
|
+
}
|
|
80
|
+
fieldTypeIcon(type) {
|
|
81
|
+
return getFieldTypeMeta(type)?.icon ?? 'help_outline';
|
|
82
|
+
}
|
|
83
|
+
fieldLabel(field) {
|
|
84
|
+
const lang = this.store.activeLanguage();
|
|
85
|
+
return resolveLabel(field.label, lang) || field.id;
|
|
86
|
+
}
|
|
87
|
+
// ─── Toolbar actions ──────────────────────────────────────────────────────
|
|
88
|
+
doSave() {
|
|
89
|
+
this.save.emit(this.store.exportConfig());
|
|
90
|
+
}
|
|
91
|
+
get json() {
|
|
92
|
+
return JSON.stringify(this.store.exportConfig(), null, 2);
|
|
93
|
+
}
|
|
94
|
+
copyJson() {
|
|
95
|
+
if (typeof navigator !== 'undefined' && navigator.clipboard) {
|
|
96
|
+
void navigator.clipboard.writeText(this.json);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
// ─── RBAC settings ────────────────────────────────────────────────────────
|
|
100
|
+
rolesFor(action) {
|
|
101
|
+
// Return the stored array (stable ref between mutations) or a shared empty — NOT a fresh [],
|
|
102
|
+
// which would make the bound mat-select re-evaluate every CD and loop forever.
|
|
103
|
+
return this.store.config().permissions?.[action] ?? EMPTY_ROLES;
|
|
104
|
+
}
|
|
105
|
+
setRoles(action, roles) {
|
|
106
|
+
this.store.setPermission(action, roles);
|
|
107
|
+
}
|
|
108
|
+
/** Parse a comma-separated role string into a trimmed, de-duplicated array. */
|
|
109
|
+
setRolesFromText(action, text) {
|
|
110
|
+
const roles = Array.from(new Set(text
|
|
111
|
+
.split(',')
|
|
112
|
+
.map(r => r.trim())
|
|
113
|
+
.filter(Boolean)));
|
|
114
|
+
this.store.setPermission(action, roles);
|
|
115
|
+
}
|
|
116
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EntityBuilderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
117
|
+
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", commonModules: "commonModules" }, outputs: { configChange: "configChange", save: "save" }, providers: [BuilderStore], usesOnChanges: true, ngImport: i0, template: "<mat-toolbar class=\"deb-toolbar\" color=\"primary\">\r\n <mat-icon>dashboard_customize</mat-icon>\r\n <span class=\"deb-toolbar__title\">Entity Builder</span>\r\n <span class=\"deb-spacer\"></span>\r\n\r\n @if (store.problems().length) {\r\n <button\r\n mat-button\r\n type=\"button\"\r\n class=\"deb-problems\"\r\n [class.deb-problems--error]=\"!store.isValid()\"\r\n [matTooltip]=\"store.problems().length + ' issue(s) \u2014 hover items in the list'\"\r\n >\r\n <mat-icon>{{ store.isValid() ? 'warning' : 'error' }}</mat-icon>\r\n {{ store.errors().length }} / {{ store.problems().length }}\r\n </button>\r\n }\r\n\r\n <button mat-button type=\"button\" (click)=\"copyJson()\">\r\n <mat-icon>content_copy</mat-icon> Copy JSON\r\n </button>\r\n <button mat-flat-button color=\"accent\" type=\"button\" [disabled]=\"!store.isValid()\" (click)=\"doSave()\">\r\n <mat-icon>save</mat-icon> Save\r\n </button>\r\n</mat-toolbar>\r\n\r\n<div class=\"deb-body\">\r\n <!-- \u2500\u2500\u2500 Left: settings, palette, tabs \u2500\u2500\u2500 -->\r\n <div class=\"deb-col deb-col--left\">\r\n <mat-card>\r\n <mat-card-content>\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>Entity name</mat-label>\r\n <input\r\n matInput\r\n [ngModel]=\"store.config().entity\"\r\n (ngModelChange)=\"store.setEntityName($event)\"\r\n placeholder=\"e.g. clients\"\r\n />\r\n </mat-form-field>\r\n\r\n <div class=\"deb-row\">\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-grow\">\r\n <mat-label>Editing language</mat-label>\r\n <mat-select\r\n [ngModel]=\"store.activeLanguage()\"\r\n (ngModelChange)=\"store.setActiveLanguage($event)\"\r\n >\r\n @for (l of languages; track l) {\r\n <mat-option [value]=\"l\">{{ l }}</mat-option>\r\n }\r\n </mat-select>\r\n </mat-form-field>\r\n </div>\r\n\r\n <mat-slide-toggle\r\n [ngModel]=\"store.config().maskData ?? false\"\r\n (ngModelChange)=\"store.setMaskData($event)\"\r\n >Mask this entity (RBAC)</mat-slide-toggle>\r\n\r\n <mat-expansion-panel class=\"deb-rbac\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>Permissions</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n @for (action of rbacActions; track action) {\r\n @if (availableRoles.length) {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>{{ action }} roles</mat-label>\r\n <mat-select multiple [ngModel]=\"rolesFor(action)\" (ngModelChange)=\"setRoles(action, $event)\">\r\n @for (role of availableRoles; track role) {\r\n <mat-option [value]=\"role\">{{ role }}</mat-option>\r\n }\r\n </mat-select>\r\n </mat-form-field>\r\n } @else {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>{{ action }} roles (comma-separated)</mat-label>\r\n <input\r\n matInput\r\n [ngModel]=\"rolesFor(action).join(', ')\"\r\n (ngModelChange)=\"setRolesFromText(action, $event)\"\r\n />\r\n </mat-form-field>\r\n }\r\n }\r\n <p class=\"deb-hint\">Empty = no restriction for that action.</p>\r\n </mat-expansion-panel>\r\n </mat-card-content>\r\n </mat-card>\r\n\r\n <mat-card>\r\n <mat-card-header><mat-card-title>Add field</mat-card-title></mat-card-header>\r\n <mat-card-content>\r\n <ngx-field-palette (pick)=\"store.addField($event)\"></ngx-field-palette>\r\n </mat-card-content>\r\n </mat-card>\r\n\r\n <mat-card>\r\n <mat-card-content>\r\n <ngx-tab-manager></ngx-tab-manager>\r\n </mat-card-content>\r\n </mat-card>\r\n </div>\r\n\r\n <!-- \u2500\u2500\u2500 Center: field canvas \u2500\u2500\u2500 -->\r\n <div class=\"deb-col deb-col--center\">\r\n <ngx-entity-builder-canvas />\r\n </div>\r\n\r\n <!-- \u2500\u2500\u2500 Right: inspector \u2500\u2500\u2500 -->\r\n <div class=\"deb-col deb-col--right\">\r\n <mat-card>\r\n <mat-card-header><mat-card-title>Field properties</mat-card-title></mat-card-header>\r\n <mat-card-content>\r\n <ngx-field-inspector></ngx-field-inspector>\r\n </mat-card-content>\r\n </mat-card>\r\n </div>\r\n</div>\r\n\r\n<!-- \u2500\u2500\u2500 Footer: JSON + optional live preview \u2500\u2500\u2500 -->\r\n<div class=\"deb-footer\">\r\n <mat-expansion-panel>\r\n <mat-expansion-panel-header>\r\n <mat-panel-title><mat-icon>data_object</mat-icon> Config JSON</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <pre class=\"deb-json\">{{ json }}</pre>\r\n </mat-expansion-panel>\r\n\r\n <div class=\"deb-preview-slot\">\r\n <ng-content select=\"[ngxBuilderPreview]\"></ng-content>\r\n </div>\r\n</div>\r\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:#0f172a}.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: DragDropModule }, { 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" }] });
|
|
118
|
+
}
|
|
119
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EntityBuilderComponent, decorators: [{
|
|
120
|
+
type: Component,
|
|
121
|
+
args: [{ selector: 'ngx-entity-builder', standalone: true, providers: [BuilderStore], imports: [
|
|
122
|
+
FormsModule,
|
|
123
|
+
DragDropModule,
|
|
124
|
+
MatButtonModule,
|
|
125
|
+
MatCardModule,
|
|
126
|
+
MatCheckboxModule,
|
|
127
|
+
MatExpansionModule,
|
|
128
|
+
MatFormFieldModule,
|
|
129
|
+
MatIconModule,
|
|
130
|
+
MatInputModule,
|
|
131
|
+
MatSelectModule,
|
|
132
|
+
MatSlideToggleModule,
|
|
133
|
+
MatToolbarModule,
|
|
134
|
+
MatTooltipModule,
|
|
135
|
+
FieldPaletteComponent,
|
|
136
|
+
TabManagerComponent,
|
|
137
|
+
FieldInspectorComponent,
|
|
138
|
+
EntityBuilderCanvasComponent,
|
|
139
|
+
], template: "<mat-toolbar class=\"deb-toolbar\" color=\"primary\">\r\n <mat-icon>dashboard_customize</mat-icon>\r\n <span class=\"deb-toolbar__title\">Entity Builder</span>\r\n <span class=\"deb-spacer\"></span>\r\n\r\n @if (store.problems().length) {\r\n <button\r\n mat-button\r\n type=\"button\"\r\n class=\"deb-problems\"\r\n [class.deb-problems--error]=\"!store.isValid()\"\r\n [matTooltip]=\"store.problems().length + ' issue(s) \u2014 hover items in the list'\"\r\n >\r\n <mat-icon>{{ store.isValid() ? 'warning' : 'error' }}</mat-icon>\r\n {{ store.errors().length }} / {{ store.problems().length }}\r\n </button>\r\n }\r\n\r\n <button mat-button type=\"button\" (click)=\"copyJson()\">\r\n <mat-icon>content_copy</mat-icon> Copy JSON\r\n </button>\r\n <button mat-flat-button color=\"accent\" type=\"button\" [disabled]=\"!store.isValid()\" (click)=\"doSave()\">\r\n <mat-icon>save</mat-icon> Save\r\n </button>\r\n</mat-toolbar>\r\n\r\n<div class=\"deb-body\">\r\n <!-- \u2500\u2500\u2500 Left: settings, palette, tabs \u2500\u2500\u2500 -->\r\n <div class=\"deb-col deb-col--left\">\r\n <mat-card>\r\n <mat-card-content>\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>Entity name</mat-label>\r\n <input\r\n matInput\r\n [ngModel]=\"store.config().entity\"\r\n (ngModelChange)=\"store.setEntityName($event)\"\r\n placeholder=\"e.g. clients\"\r\n />\r\n </mat-form-field>\r\n\r\n <div class=\"deb-row\">\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-grow\">\r\n <mat-label>Editing language</mat-label>\r\n <mat-select\r\n [ngModel]=\"store.activeLanguage()\"\r\n (ngModelChange)=\"store.setActiveLanguage($event)\"\r\n >\r\n @for (l of languages; track l) {\r\n <mat-option [value]=\"l\">{{ l }}</mat-option>\r\n }\r\n </mat-select>\r\n </mat-form-field>\r\n </div>\r\n\r\n <mat-slide-toggle\r\n [ngModel]=\"store.config().maskData ?? false\"\r\n (ngModelChange)=\"store.setMaskData($event)\"\r\n >Mask this entity (RBAC)</mat-slide-toggle>\r\n\r\n <mat-expansion-panel class=\"deb-rbac\">\r\n <mat-expansion-panel-header>\r\n <mat-panel-title>Permissions</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n @for (action of rbacActions; track action) {\r\n @if (availableRoles.length) {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>{{ action }} roles</mat-label>\r\n <mat-select multiple [ngModel]=\"rolesFor(action)\" (ngModelChange)=\"setRoles(action, $event)\">\r\n @for (role of availableRoles; track role) {\r\n <mat-option [value]=\"role\">{{ role }}</mat-option>\r\n }\r\n </mat-select>\r\n </mat-form-field>\r\n } @else {\r\n <mat-form-field appearance=\"outline\" subscriptSizing=\"dynamic\" class=\"deb-full\">\r\n <mat-label>{{ action }} roles (comma-separated)</mat-label>\r\n <input\r\n matInput\r\n [ngModel]=\"rolesFor(action).join(', ')\"\r\n (ngModelChange)=\"setRolesFromText(action, $event)\"\r\n />\r\n </mat-form-field>\r\n }\r\n }\r\n <p class=\"deb-hint\">Empty = no restriction for that action.</p>\r\n </mat-expansion-panel>\r\n </mat-card-content>\r\n </mat-card>\r\n\r\n <mat-card>\r\n <mat-card-header><mat-card-title>Add field</mat-card-title></mat-card-header>\r\n <mat-card-content>\r\n <ngx-field-palette (pick)=\"store.addField($event)\"></ngx-field-palette>\r\n </mat-card-content>\r\n </mat-card>\r\n\r\n <mat-card>\r\n <mat-card-content>\r\n <ngx-tab-manager></ngx-tab-manager>\r\n </mat-card-content>\r\n </mat-card>\r\n </div>\r\n\r\n <!-- \u2500\u2500\u2500 Center: field canvas \u2500\u2500\u2500 -->\r\n <div class=\"deb-col deb-col--center\">\r\n <ngx-entity-builder-canvas />\r\n </div>\r\n\r\n <!-- \u2500\u2500\u2500 Right: inspector \u2500\u2500\u2500 -->\r\n <div class=\"deb-col deb-col--right\">\r\n <mat-card>\r\n <mat-card-header><mat-card-title>Field properties</mat-card-title></mat-card-header>\r\n <mat-card-content>\r\n <ngx-field-inspector></ngx-field-inspector>\r\n </mat-card-content>\r\n </mat-card>\r\n </div>\r\n</div>\r\n\r\n<!-- \u2500\u2500\u2500 Footer: JSON + optional live preview \u2500\u2500\u2500 -->\r\n<div class=\"deb-footer\">\r\n <mat-expansion-panel>\r\n <mat-expansion-panel-header>\r\n <mat-panel-title><mat-icon>data_object</mat-icon> Config JSON</mat-panel-title>\r\n </mat-expansion-panel-header>\r\n <pre class=\"deb-json\">{{ json }}</pre>\r\n </mat-expansion-panel>\r\n\r\n <div class=\"deb-preview-slot\">\r\n <ng-content select=\"[ngxBuilderPreview]\"></ng-content>\r\n </div>\r\n</div>\r\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:#0f172a}.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"] }]
|
|
140
|
+
}], ctorParameters: () => [], propDecorators: { config: [{
|
|
141
|
+
type: Input
|
|
142
|
+
}], languages: [{
|
|
143
|
+
type: Input
|
|
144
|
+
}], availableRoles: [{
|
|
145
|
+
type: Input
|
|
146
|
+
}], commonModules: [{
|
|
147
|
+
type: Input
|
|
148
|
+
}], configChange: [{
|
|
149
|
+
type: Output
|
|
150
|
+
}], save: [{
|
|
151
|
+
type: Output
|
|
152
|
+
}] } });
|
|
153
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5LWJ1aWxkZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xpYi9lbnRpdHktYnVpbGRlci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi9zcmMvbGliL2VudGl0eS1idWlsZGVyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBQ1QsWUFBWSxFQUNaLEtBQUssRUFFTCxNQUFNLEVBRU4sTUFBTSxFQUNOLE1BQU0sR0FDUCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFlLGNBQWMsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFDL0QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDakUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDbEUsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDM0QsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDdEUsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDN0QsT0FBTyxFQUNMLGNBQWMsRUFJZCxZQUFZLEdBQ2IsTUFBTSxz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Z0JBRUcsY0FBYztzQkFBdEIsS0FBSztnQkFFRyxhQUFhO3NCQUFyQixLQUFLO2dCQUdJLFlBQVk7c0JBQXJCLE1BQU07Z0JBRUcsSUFBSTtzQkFBYixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICBDb21wb25lbnQsXHJcbiAgRXZlbnRFbWl0dGVyLFxyXG4gIElucHV0LFxyXG4gIE9uQ2hhbmdlcyxcclxuICBPdXRwdXQsXHJcbiAgU2ltcGxlQ2hhbmdlcyxcclxuICBlZmZlY3QsXHJcbiAgaW5qZWN0LFxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0IHsgQ2RrRHJhZ0Ryb3AsIERyYWdEcm9wTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL2RyYWctZHJvcCc7XHJcbmltcG9ydCB7IE1hdEJ1dHRvbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2J1dHRvbic7XHJcbmltcG9ydCB7IE1hdENhcmRNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9jYXJkJztcclxuaW1wb3J0IHsgTWF0Q2hlY2tib3hNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9jaGVja2JveCc7XHJcbmltcG9ydCB7IE1hdEV4cGFuc2lvbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2V4cGFuc2lvbic7XHJcbmltcG9ydCB7IE1hdEZvcm1GaWVsZE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL2Zvcm0tZmllbGQnO1xyXG5pbXBvcnQgeyBNYXRJY29uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvaWNvbic7XHJcbmltcG9ydCB7IE1hdElucHV0TW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvaW5wdXQnO1xyXG5pbXBvcnQgeyBNYXRTZWxlY3RNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9zZWxlY3QnO1xyXG5pbXBvcnQgeyBNYXRTbGlkZVRvZ2dsZU1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3NsaWRlLXRvZ2dsZSc7XHJcbmltcG9ydCB7IE1hdFRvb2xiYXJNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC90b29sYmFyJztcclxuaW1wb3J0IHsgTWF0VG9vbHRpcE1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL3Rvb2x0aXAnO1xyXG5pbXBvcnQge1xyXG4gIENPTU1PTl9NT0RVTEVTLFxyXG4gIHR5cGUgQ29tbW9uTW9kdWxlRW50cnksXHJcbiAgdHlwZSBFbnRpdHlGb3JtQ29uZmlnLFxyXG4gIHR5cGUgRW50aXR5UGVybWlzc2lvbnMsXHJcbiAgcmVzb2x2ZUxhYmVsLFxyXG59IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcclxuaW1wb3J0IHsgQnVpbGRlclN0b3JlIH0gZnJvbSAnLi9idWlsZGVyLXN0b3JlLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBGaWVsZEluc3BlY3RvckNvbXBvbmVudCB9IGZyb20gJy4vY29tcG9uZW50cy9maWVsZC1pbnNwZWN0b3IuY29tcG9uZW50JztcclxuaW1wb3J0IHsgRmllbGRQYWxldHRlQ29tcG9uZW50IH0gZnJvbSAnLi9jb21wb25lbnRzL2ZpZWxkLXBhbGV0dGUuY29tcG9uZW50JztcclxuaW1wb3J0IHsgVGFiTWFuYWdlckNvbXBvbmVudCB9IGZyb20gJy4vY29tcG9uZW50cy90YWItbWFuYWdlci5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBFbnRpdHlCdWlsZGVyQ2FudmFzQ29tcG9uZW50IH0gZnJvbSAnLi9jb21wb25lbnRzL2VudGl0eS1idWlsZGVyLWNhbnZhcy5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBnZXRGaWVsZFR5cGVNZXRhIH0gZnJvbSAnLi9maWVsZC1jYXRhbG9nJztcclxuXHJcbi8qKiBSQkFDIGFjdGlvbnMgc3VyZmFjZWQgaW4gdGhlIHNldHRpbmdzIHBhbmVsLiAqL1xyXG5jb25zdCBSQkFDX0FDVElPTlM6IChrZXlvZiBFbnRpdHlQZXJtaXNzaW9ucylbXSA9IFsndmlldycsICdlZGl0JywgJ2RlbGV0ZSddO1xyXG5cclxuLyoqIFNoYXJlZCBzdGFibGUgZW1wdHkgYXJyYXkg4oCUIG5ldmVyIGFsbG9jYXRlIGEgZnJlc2ggW10gcGVyIGNoYW5nZS1kZXRlY3Rpb24gKG1hdC1zZWxlY3QgbG9vcHMpLiAqL1xyXG5jb25zdCBFTVBUWV9ST0xFUzogcmVhZG9ubHkgc3RyaW5nW10gPSBPYmplY3QuZnJlZXplKFtdKTtcclxuXHJcbi8qKlxyXG4gKiBFbnRpdHlCdWlsZGVyQ29tcG9uZW50IOKAlCB0aGUgdG9wLWxldmVsIHZpc3VhbCBidWlsZGVyIGZvciBhbiBFbnRpdHlGb3JtQ29uZmlnLlxyXG4gKi9cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICduZ3gtZW50aXR5LWJ1aWxkZXInLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgcHJvdmlkZXJzOiBbQnVpbGRlclN0b3JlXSxcclxuICBpbXBvcnRzOiBbXHJcbiAgICBGb3Jtc01vZHVsZSxcclxuICAgIERyYWdEcm9wTW9kdWxlLFxyXG4gICAgTWF0QnV0dG9uTW9kdWxlLFxyXG4gICAgTWF0Q2FyZE1vZHVsZSxcclxuICAgIE1hdENoZWNrYm94TW9kdWxlLFxyXG4gICAgTWF0RXhwYW5zaW9uTW9kdWxlLFxyXG4gICAgTWF0Rm9ybUZpZWxkTW9kdWxlLFxyXG4gICAgTWF0SWNvbk1vZHVsZSxcclxuICAgIE1hdElucHV0TW9kdWxlLFxyXG4gICAgTWF0U2VsZWN0TW9kdWxlLFxyXG4gICAgTWF0U2xpZGVUb2dnbGVNb2R1bGUsXHJcbiAgICBNYXRUb29sYmFyTW9kdWxlLFxyXG4gICAgTWF0VG9vbHRpcE1vZHVsZSxcclxuICAgIEZpZWxkUGFsZXR0ZUNvbXBvbmVudCxcclxuICAgIFRhYk1hbmFnZXJDb21wb25lbnQsXHJcbiAgICBGaWVsZEluc3BlY3RvckNvbXBvbmVudCxcclxuICAgIEVudGl0eUJ1aWxkZXJDYW52YXNDb21wb25lbnQsXHJcbiAgXSxcclxuICB0ZW1wbGF0ZVVybDogJy4vZW50aXR5LWJ1aWxkZXIuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0eWxlVXJsOiAnLi9lbnRpdHktYnVpbGRlci5jb21wb25lbnQuY3NzJyxcclxufSlcclxuZXhwb3J0IGNsYXNzIEVudGl0eUJ1aWxkZXJDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMge1xyXG4gIHByb3RlY3RlZCByZWFkb25seSBzdG9yZSA9IGluamVjdChCdWlsZGVyU3RvcmUpO1xyXG5cclxuICAvKiogRXhpc3RpbmcgY29uZmlnIHRvIGVkaXQuIFdoZW4gb21pdHRlZCwgdGhlIGJ1aWxkZXIgc3RhcnRzIGJsYW5rLiAqL1xyXG4gIEBJbnB1dCgpIGNvbmZpZz86IEVudGl0eUZvcm1Db25maWc7XHJcbiAgLyoqIExhbmd1YWdlcyBhdmFpbGFibGUgZm9yIGxhYmVsL3BsYWNlaG9sZGVyIGVkaXRpbmcuIEZpcnN0IGVudHJ5IGlzIHRoZSBkZWZhdWx0LiAqL1xyXG4gIEBJbnB1dCgpIGxhbmd1YWdlczogc3RyaW5nW10gPSBbJ2VuJ107XHJcbiAgLyoqIE9wdGlvbmFsIHJvbGUgbGlzdCDigJQgZW5hYmxlcyBtdWx0aS1zZWxlY3Qgcm9sZSBwaWNrZXJzIGZvciBSQkFDIGluc3RlYWQgb2YgZnJlZSB0ZXh0LiAqL1xyXG4gIEBJbnB1dCgpIGF2YWlsYWJsZVJvbGVzOiBzdHJpbmdbXSA9IFtdO1xyXG4gIC8qKiBPcHRpb25hbCBjb21tb24tbW9kdWxlIGRlZmluaXRpb25zIGZvciBtb2R1bGUgdGFiczsgZGVmYXVsdHMgdG8gdGhlIGJ1aWx0LWluIGxpc3QgZnJvbSBjb3JlLiAqL1xyXG4gIEBJbnB1dCgpIGNvbW1vbk1vZHVsZXM6IHJlYWRvbmx5IENvbW1vbk1vZHVsZUVudHJ5W10gPSBDT01NT05fTU9EVUxFUztcclxuXHJcbiAgLyoqIEVtaXR0ZWQgb24gZXZlcnkgY2hhbmdlIHRvIHRoZSB3b3JraW5nIGNvbmZpZy4gKi9cclxuICBAT3V0cHV0KCkgY29uZmlnQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxFbnRpdHlGb3JtQ29uZmlnPigpO1xyXG4gIC8qKiBFbWl0dGVkIHdoZW4gdGhlIHVzZXIgY2xpY2tzIFNhdmUuIENhcnJpZXMgYSBjbGVhbiwgZGVlcC1jbG9uZWQgY29uZmlnLiAqL1xyXG4gIEBPdXRwdXQoKSBzYXZlID0gbmV3IEV2ZW50RW1pdHRlcjxFbnRpdHlGb3JtQ29uZmlnPigpO1xyXG5cclxuICBwcm90ZWN0ZWQgcmVhZG9ubHkgcmJhY0FjdGlvbnMgPSBSQkFDX0FDVElPTlM7XHJcblxyXG4gIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgZWZmZWN0KCgpID0+IHRoaXMuY29uZmlnQ2hhbmdlLmVtaXQodGhpcy5zdG9yZS5jb25maWcoKSksIHsgYWxsb3dTaWduYWxXcml0ZXM6IHRydWUgfSk7XHJcbiAgfVxyXG5cclxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XHJcbiAgICBpZiAoY2hhbmdlc1snY29uZmlnJ10gJiYgY2hhbmdlc1snY29uZmlnJ10uY3VycmVudFZhbHVlICE9PSBjaGFuZ2VzWydjb25maWcnXS5wcmV2aW91c1ZhbHVlKSB7XHJcbiAgICAgIGlmICh0aGlzLmNvbmZpZykgdGhpcy5zdG9yZS5sb2FkKHRoaXMuY29uZmlnKTtcclxuICAgICAgZWxzZSBpZiAoY2hhbmdlc1snY29uZmlnJ10uaXNGaXJzdENoYW5nZSgpKSB0aGlzLnN0b3JlLnJlc2V0KCk7XHJcbiAgICB9XHJcbiAgICBpZiAoY2hhbmdlc1snbGFuZ3VhZ2VzJ10gJiYgdGhpcy5sYW5ndWFnZXMubGVuZ3RoKSB7XHJcbiAgICAgIGNvbnN0IGFjdGl2ZSA9IHRoaXMuc3RvcmUuYWN0aXZlTGFuZ3VhZ2UoKTtcclxuICAgICAgaWYgKCF0aGlzLmxhbmd1YWdlcy5pbmNsdWRlcyhhY3RpdmUpKSB0aGlzLnN0b3JlLnNldEFjdGl2ZUxhbmd1YWdlKHRoaXMubGFuZ3VhZ2VzWzBdKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIOKUgOKUgOKUgCBGaWVsZCBjYW52YXMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXHJcblxyXG4gIHByb3RlY3RlZCBvbkRyb3AoZXZlbnQ6IENka0RyYWdEcm9wPHVua25vd24+KTogdm9pZCB7XHJcbiAgICB0aGlzLnN0b3JlLnJlb3JkZXJGaWVsZChldmVudC5wcmV2aW91c0luZGV4LCBldmVudC5jdXJyZW50SW5kZXgpO1xyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIGZpZWxkVHlwZUxhYmVsKHR5cGU6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gZ2V0RmllbGRUeXBlTWV0YSh0eXBlKT8ubGFiZWwgPz8gdHlwZTtcclxuICB9XHJcblxyXG4gIHByb3RlY3RlZCBmaWVsZFR5cGVJY29uKHR5cGU6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gZ2V0RmllbGRUeXBlTWV0YSh0eXBlKT8uaWNvbiA/PyAnaGVscF9vdXRsaW5lJztcclxuICB9XHJcblxyXG4gIHByb3RlY3RlZCBmaWVsZExhYmVsKGZpZWxkOiB7IGlkOiBzdHJpbmc7IGxhYmVsPzogYW55IH0pOiBzdHJpbmcge1xyXG4gICAgY29uc3QgbGFuZyA9IHRoaXMuc3RvcmUuYWN0aXZlTGFuZ3VhZ2UoKTtcclxuICAgIHJldHVybiByZXNvbHZlTGFiZWwoZmllbGQubGFiZWwsIGxhbmcpIHx8IGZpZWxkLmlkO1xyXG4gIH1cclxuXHJcbiAgLy8g4pSA4pSA4pSAIFRvb2xiYXIgYWN0aW9ucyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcclxuXHJcbiAgcHJvdGVjdGVkIGRvU2F2ZSgpOiB2b2lkIHtcclxuICAgIHRoaXMuc2F2ZS5lbWl0KHRoaXMuc3RvcmUuZXhwb3J0Q29uZmlnKCkpO1xyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIGdldCBqc29uKCk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodGhpcy5zdG9yZS5leHBvcnRDb25maWcoKSwgbnVsbCwgMik7XHJcbiAgfVxyXG5cclxuICBwcm90ZWN0ZWQgY29weUpzb24oKTogdm9pZCB7XHJcbiAgICBpZiAodHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcgJiYgbmF2aWdhdG9yLmNsaXBib2FyZCkge1xyXG4gICAgICB2b2lkIG5hdmlnYXRvci5jbGlwYm9hcmQud3JpdGVUZXh0KHRoaXMuanNvbik7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyDilIDilIDilIAgUkJBQyBzZXR0aW5ncyDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcclxuXHJcbiAgcHJvdGVjdGVkIHJvbGVzRm9yKGFjdGlvbjoga2V5b2YgRW50aXR5UGVybWlzc2lvbnMpOiByZWFkb25seSBzdHJpbmdbXSB7XHJcbiAgICAvLyBSZXR1cm4gdGhlIHN0b3JlZCBhcnJheSAoc3RhYmxlIHJlZiBiZXR3ZWVuIG11dGF0aW9ucykgb3IgYSBzaGFyZWQgZW1wdHkg4oCUIE5PVCBhIGZyZXNoIFtdLFxyXG4gICAgLy8gd2hpY2ggd291bGQgbWFrZSB0aGUgYm91bmQgbWF0LXNlbGVjdCByZS1ldmFsdWF0ZSBldmVyeSBDRCBhbmQgbG9vcCBmb3JldmVyLlxyXG4gICAgcmV0dXJuIHRoaXMuc3RvcmUuY29uZmlnKCkucGVybWlzc2lvbnM/LlthY3Rpb25dID8/IEVNUFRZX1JPTEVTO1xyXG4gIH1cclxuXHJcbiAgcHJvdGVjdGVkIHNldFJvbGVzKGFjdGlvbjoga2V5b2YgRW50aXR5UGVybWlzc2lvbnMsIHJvbGVzOiBzdHJpbmdbXSk6IHZvaWQge1xyXG4gICAgdGhpcy5zdG9yZS5zZXRQZXJtaXNzaW9uKGFjdGlvbiwgcm9sZXMpO1xyXG4gIH1cclxuXHJcbiAgLyoqIFBhcnNlIGEgY29tbWEtc2VwYXJhdGVkIHJvbGUgc3RyaW5nIGludG8gYSB0cmltbWVkLCBkZS1kdXBsaWNhdGVkIGFycmF5LiAqL1xyXG4gIHByb3RlY3RlZCBzZXRSb2xlc0Zyb21UZXh0KGFjdGlvbjoga2V5b2YgRW50aXR5UGVybWlzc2lvbnMsIHRleHQ6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgY29uc3Qgcm9sZXMgPSBBcnJheS5mcm9tKFxyXG4gICAgICBuZXcgU2V0KFxyXG4gICAgICAgIHRleHRcclxuICAgICAgICAgIC5zcGxpdCgnLCcpXHJcbiAgICAgICAgICAubWFwKHIgPT4gci50cmltKCkpXHJcbiAgICAgICAgICAuZmlsdGVyKEJvb2xlYW4pLFxyXG4gICAgICApLFxyXG4gICAgKTtcclxuICAgIHRoaXMuc3RvcmUuc2V0UGVybWlzc2lvbihhY3Rpb24sIHJvbGVzKTtcclxuICB9XHJcbn1cclxuIiwiPG1hdC10b29sYmFyIGNsYXNzPVwiZGViLXRvb2xiYXJcIiBjb2xvcj1cInByaW1hcnlcIj5cclxuICA8bWF0LWljb24+ZGFzaGJvYXJkX2N1c3RvbWl6ZTwvbWF0LWljb24+XHJcbiAgPHNwYW4gY2xhc3M9XCJkZWItdG9vbGJhcl9fdGl0bGVcIj5FbnRpdHkgQnVpbGRlcjwvc3Bhbj5cclxuICA8c3BhbiBjbGFzcz1cImRlYi1zcGFjZXJcIj48L3NwYW4+XHJcblxyXG4gIEBpZiAoc3RvcmUucHJvYmxlbXMoKS5sZW5ndGgpIHtcclxuICAgIDxidXR0b25cclxuICAgICAgbWF0LWJ1dHRvblxyXG4gICAgICB0eXBlPVwiYnV0dG9uXCJcclxuICAgICAgY2xhc3M9XCJkZWItcHJvYmxlbXNcIlxyXG4gICAgICBbY2xhc3MuZGViLXByb2JsZW1zLS1lcnJvcl09XCIhc3RvcmUuaXNWYWxpZCgpXCJcclxuICAgICAgW21hdFRvb2x0aXBdPVwic3RvcmUucHJvYmxlbXMoKS5sZW5ndGggKyAnIGlzc3VlKHMpIOKAlCBob3ZlciBpdGVtcyBpbiB0aGUgbGlzdCdcIlxyXG4gICAgPlxyXG4gICAgICA8bWF0LWljb24+e3sgc3RvcmUuaXNWYWxpZCgpID8gJ3dhcm5pbmcnIDogJ2Vycm9yJyB9fTwvbWF0LWljb24+XHJcbiAgICAgIHt7IHN0b3JlLmVycm9ycygpLmxlbmd0aCB9fSAvIHt7IHN0b3JlLnByb2JsZW1zKCkubGVuZ3RoIH19XHJcbiAgICA8L2J1dHRvbj5cclxuICB9XHJcblxyXG4gIDxidXR0b24gbWF0LWJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgKGNsaWNrKT1cImNvcHlKc29uKClcIj5cclxuICAgIDxtYXQtaWNvbj5jb250ZW50X2NvcHk8L21hdC1pY29uPiBDb3B5IEpTT05cclxuICA8L2J1dHRvbj5cclxuICA8YnV0dG9uIG1hdC1mbGF0LWJ1dHRvbiBjb2xvcj1cImFjY2VudFwiIHR5cGU9XCJidXR0b25cIiBbZGlzYWJsZWRdPVwiIXN0b3JlLmlzVmFsaWQoKVwiIChjbGljayk9XCJkb1NhdmUoKVwiPlxyXG4gICAgPG1hdC1pY29uPnNhdmU8L21hdC1pY29uPiBTYXZlXHJcbiAgPC9idXR0b24+XHJcbjwvbWF0LXRvb2xiYXI+XHJcblxyXG48ZGl2IGNsYXNzPVwiZGViLWJvZHlcIj5cclxuICA8IS0tIOKUgOKUgOKUgCBMZWZ0OiBzZXR0aW5ncywgcGFsZXR0ZSwgdGFicyDilIDilIDilIAgLS0+XHJcbiAgPGRpdiBjbGFzcz1cImRlYi1jb2wgZGViLWNvbC0tbGVmdFwiPlxyXG4gICAgPG1hdC1jYXJkPlxyXG4gICAgICA8bWF0LWNhcmQtY29udGVudD5cclxuICAgICAgICA8bWF0LWZvcm0tZmllbGQgYXBwZWFyYW5jZT1cIm91dGxpbmVcIiBzdWJzY3JpcHRTaXppbmc9XCJkeW5hbWljXCIgY2xhc3M9XCJkZWItZnVsbFwiPlxyXG4gICAgICAgICAgPG1hdC1sYWJlbD5FbnRpdHkgbmFtZTwvbWF0LWxhYmVsPlxyXG4gICAgICAgICAgPGlucHV0XHJcbiAgICAgICAgICAgIG1hdElucHV0XHJcbiAgICAgICAgICAgIFtuZ01vZGVsXT1cInN0b3JlLmNvbmZpZygpLmVudGl0eVwiXHJcbiAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnNldEVudGl0eU5hbWUoJGV2ZW50KVwiXHJcbiAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwiZS5nLiBjbGllbnRzXCJcclxuICAgICAgICAgIC8+XHJcbiAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cclxuXHJcbiAgICAgICAgPGRpdiBjbGFzcz1cImRlYi1yb3dcIj5cclxuICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN1YnNjcmlwdFNpemluZz1cImR5bmFtaWNcIiBjbGFzcz1cImRlYi1ncm93XCI+XHJcbiAgICAgICAgICAgIDxtYXQtbGFiZWw+RWRpdGluZyBsYW5ndWFnZTwvbWF0LWxhYmVsPlxyXG4gICAgICAgICAgICA8bWF0LXNlbGVjdFxyXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cInN0b3JlLmFjdGl2ZUxhbmd1YWdlKClcIlxyXG4gICAgICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cInN0b3JlLnNldEFjdGl2ZUxhbmd1YWdlKCRldmVudClcIlxyXG4gICAgICAgICAgICA+XHJcbiAgICAgICAgICAgICAgQGZvciAobCBvZiBsYW5ndWFnZXM7IHRyYWNrIGwpIHtcclxuICAgICAgICAgICAgICAgIDxtYXQtb3B0aW9uIFt2YWx1ZV09XCJsXCI+e3sgbCB9fTwvbWF0LW9wdGlvbj5cclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIDwvbWF0LXNlbGVjdD5cclxuICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XHJcbiAgICAgICAgPC9kaXY+XHJcblxyXG4gICAgICAgIDxtYXQtc2xpZGUtdG9nZ2xlXHJcbiAgICAgICAgICBbbmdNb2RlbF09XCJzdG9yZS5jb25maWcoKS5tYXNrRGF0YSA/PyBmYWxzZVwiXHJcbiAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzdG9yZS5zZXRNYXNrRGF0YSgkZXZlbnQpXCJcclxuICAgICAgICA+TWFzayB0aGlzIGVudGl0eSAoUkJBQyk8L21hdC1zbGlkZS10b2dnbGU+XHJcblxyXG4gICAgICAgIDxtYXQtZXhwYW5zaW9uLXBhbmVsIGNsYXNzPVwiZGViLXJiYWNcIj5cclxuICAgICAgICAgIDxtYXQtZXhwYW5zaW9uLXBhbmVsLWhlYWRlcj5cclxuICAgICAgICAgICAgPG1hdC1wYW5lbC10aXRsZT5QZXJtaXNzaW9uczwvbWF0LXBhbmVsLXRpdGxlPlxyXG4gICAgICAgICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsLWhlYWRlcj5cclxuICAgICAgICAgIEBmb3IgKGFjdGlvbiBvZiByYmFjQWN0aW9uczsgdHJhY2sgYWN0aW9uKSB7XHJcbiAgICAgICAgICAgIEBpZiAoYXZhaWxhYmxlUm9sZXMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCIgc3Vic2NyaXB0U2l6aW5nPVwiZHluYW1pY1wiIGNsYXNzPVwiZGViLWZ1bGxcIj5cclxuICAgICAgICAgICAgICAgIDxtYXQtbGFiZWw+e3sgYWN0aW9uIH19IHJvbGVzPC9tYXQtbGFiZWw+XHJcbiAgICAgICAgICAgICAgICA8bWF0LXNlbGVjdCBtdWx0aXBsZSBbbmdNb2RlbF09XCJyb2xlc0ZvcihhY3Rpb24pXCIgKG5nTW9kZWxDaGFuZ2UpPVwic2V0Um9sZXMoYWN0aW9uLCAkZXZlbnQpXCI+XHJcbiAgICAgICAgICAgICAgICAgIEBmb3IgKHJvbGUgb2YgYXZhaWxhYmxlUm9sZXM7IHRyYWNrIHJvbGUpIHtcclxuICAgICAgICAgICAgICAgICAgICA8bWF0LW9wdGlvbiBbdmFsdWVdPVwicm9sZVwiPnt7IHJvbGUgfX08L21hdC1vcHRpb24+XHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIDwvbWF0LXNlbGVjdD5cclxuICAgICAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxyXG4gICAgICAgICAgICB9IEBlbHNlIHtcclxuICAgICAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgYXBwZWFyYW5jZT1cIm91dGxpbmVcIiBzdWJzY3JpcHRTaXppbmc9XCJkeW5hbWljXCIgY2xhc3M9XCJkZWItZnVsbFwiPlxyXG4gICAgICAgICAgICAgICAgPG1hdC1sYWJlbD57eyBhY3Rpb24gfX0gcm9sZXMgKGNvbW1hLXNlcGFyYXRlZCk8L21hdC1sYWJlbD5cclxuICAgICAgICAgICAgICAgIDxpbnB1dFxyXG4gICAgICAgICAgICAgICAgICBtYXRJbnB1dFxyXG4gICAgICAgICAgICAgICAgICBbbmdNb2RlbF09XCJyb2xlc0ZvcihhY3Rpb24pLmpvaW4oJywgJylcIlxyXG4gICAgICAgICAgICAgICAgICAobmdNb2RlbENoYW5nZSk9XCJzZXRSb2xlc0Zyb21UZXh0KGFjdGlvbiwgJGV2ZW50KVwiXHJcbiAgICAgICAgICAgICAgICAvPlxyXG4gICAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICAgIDxwIGNsYXNzPVwiZGViLWhpbnRcIj5FbXB0eSA9IG5vIHJlc3RyaWN0aW9uIGZvciB0aGF0IGFjdGlvbi48L3A+XHJcbiAgICAgICAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsPlxyXG4gICAgICA8L21hdC1jYXJkLWNvbnRlbnQ+XHJcbiAgICA8L21hdC1jYXJkPlxyXG5cclxuICAgIDxtYXQtY2FyZD5cclxuICAgICAgPG1hdC1jYXJkLWhlYWRlcj48bWF0LWNhcmQtdGl0bGU+QWRkIGZpZWxkPC9tYXQtY2FyZC10aXRsZT48L21hdC1jYXJkLWhlYWRlcj5cclxuICAgICAgPG1hdC1jYXJkLWNvbnRlbnQ+XHJcbiAgICAgICAgPG5neC1maWVsZC1wYWxldHRlIChwaWNrKT1cInN0b3JlLmFkZEZpZWxkKCRldmVudClcIj48L25neC1maWVsZC1wYWxldHRlPlxyXG4gICAgICA8L21hdC1jYXJkLWNvbnRlbnQ+XHJcbiAgICA8L21hdC1jYXJkPlxyXG5cclxuICAgIDxtYXQtY2FyZD5cclxuICAgICAgPG1hdC1jYXJkLWNvbnRlbnQ+XHJcbiAgICAgICAgPG5neC10YWItbWFuYWdlcj48L25neC10YWItbWFuYWdlcj5cclxuICAgICAgPC9tYXQtY2FyZC1jb250ZW50PlxyXG4gICAgPC9tYXQtY2FyZD5cclxuICA8L2Rpdj5cclxuXHJcbiAgPCEtLSDilIDilIDilIAgQ2VudGVyOiBmaWVsZCBjYW52YXMg4pSA4pSA4pSAIC0tPlxyXG4gIDxkaXYgY2xhc3M9XCJkZWItY29sIGRlYi1jb2wtLWNlbnRlclwiPlxyXG4gICAgPG5neC1lbnRpdHktYnVpbGRlci1jYW52YXMgLz5cclxuICA8L2Rpdj5cclxuXHJcbiAgPCEtLSDilIDilIDilIAgUmlnaHQ6IGluc3BlY3RvciDilIDilIDilIAgLS0+XHJcbiAgPGRpdiBjbGFzcz1cImRlYi1jb2wgZGViLWNvbC0tcmlnaHRcIj5cclxuICAgIDxtYXQtY2FyZD5cclxuICAgICAgPG1hdC1jYXJkLWhlYWRlcj48bWF0LWNhcmQtdGl0bGU+RmllbGQgcHJvcGVydGllczwvbWF0LWNhcmQtdGl0bGU+PC9tYXQtY2FyZC1oZWFkZXI+XHJcbiAgICAgIDxtYXQtY2FyZC1jb250ZW50PlxyXG4gICAgICAgIDxuZ3gtZmllbGQtaW5zcGVjdG9yPjwvbmd4LWZpZWxkLWluc3BlY3Rvcj5cclxuICAgICAgPC9tYXQtY2FyZC1jb250ZW50PlxyXG4gICAgPC9tYXQtY2FyZD5cclxuICA8L2Rpdj5cclxuPC9kaXY+XHJcblxyXG48IS0tIOKUgOKUgOKUgCBGb290ZXI6IEpTT04gKyBvcHRpb25hbCBsaXZlIHByZXZpZXcg4pSA4pSA4pSAIC0tPlxyXG48ZGl2IGNsYXNzPVwiZGViLWZvb3RlclwiPlxyXG4gIDxtYXQtZXhwYW5zaW9uLXBhbmVsPlxyXG4gICAgPG1hdC1leHBhbnNpb24tcGFuZWwtaGVhZGVyPlxyXG4gICAgICA8bWF0LXBhbmVsLXRpdGxlPjxtYXQtaWNvbj5kYXRhX29iamVjdDwvbWF0LWljb24+Jm5ic3A7Q29uZmlnIEpTT048L21hdC1wYW5lbC10aXRsZT5cclxuICAgIDwvbWF0LWV4cGFuc2lvbi1wYW5lbC1oZWFkZXI+XHJcbiAgICA8cHJlIGNsYXNzPVwiZGViLWpzb25cIj57eyBqc29uIH19PC9wcmU+XHJcbiAgPC9tYXQtZXhwYW5zaW9uLXBhbmVsPlxyXG5cclxuICA8ZGl2IGNsYXNzPVwiZGViLXByZXZpZXctc2xvdFwiPlxyXG4gICAgPG5nLWNvbnRlbnQgc2VsZWN0PVwiW25neEJ1aWxkZXJQcmV2aWV3XVwiPjwvbmctY29udGVudD5cclxuICA8L2Rpdj5cclxuPC9kaXY+XHJcbiJdfQ==
|