ngx-dynamic-entity 0.0.1 → 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 +139 -0
- package/esm2022/lib/field-types/array-field.component.mjs +160 -0
- package/esm2022/lib/field-types/boolean-field.component.mjs +100 -0
- package/esm2022/lib/field-types/checkbox-field.component.mjs +49 -41
- package/esm2022/lib/field-types/currency-field.component.mjs +101 -0
- package/esm2022/lib/field-types/date-field.component.mjs +47 -39
- package/esm2022/lib/field-types/dropdown-field.component.mjs +145 -54
- package/esm2022/lib/field-types/email-field.component.mjs +101 -0
- package/esm2022/lib/field-types/entity-ref-field.component.mjs +134 -70
- package/esm2022/lib/field-types/file-field.component.mjs +156 -0
- package/esm2022/lib/field-types/group-field.component.mjs +89 -0
- package/esm2022/lib/field-types/image-field.component.mjs +168 -0
- package/esm2022/lib/field-types/month-year-field.component.mjs +151 -0
- package/esm2022/lib/field-types/multi-select-field.component.mjs +110 -56
- package/esm2022/lib/field-types/number-field.component.mjs +84 -41
- package/esm2022/lib/field-types/password-field.component.mjs +109 -0
- package/esm2022/lib/field-types/radio-field.component.mjs +152 -0
- package/esm2022/lib/field-types/text-field.component.mjs +82 -42
- package/esm2022/lib/field-types/textarea-field.component.mjs +52 -41
- package/esm2022/lib/form/dynamic-field/dynamic-field.component.mjs +44 -26
- package/esm2022/lib/form/dynamic-form.component.mjs +501 -67
- package/esm2022/lib/form/dynamic-record-form.component.mjs +469 -0
- package/esm2022/lib/providers/provide-field-types.mjs +72 -0
- package/esm2022/lib/providers/provide-ngx-dynamic-entity.mjs +3 -5
- package/esm2022/lib/services/cascade-data.service.mjs +129 -0
- package/esm2022/lib/services/config-source.service.mjs +67 -0
- package/esm2022/lib/services/entity-ref-cache.mjs +20 -0
- package/esm2022/lib/services/entity-ref-registry.service.mjs +3 -3
- package/esm2022/lib/services/entity-ref-selection.service.mjs +27 -0
- package/esm2022/lib/services/entity-reference.service.mjs +168 -0
- package/esm2022/lib/services/field-registry.service.mjs +35 -30
- package/esm2022/lib/services/file-upload.service.mjs +89 -0
- package/esm2022/lib/services/lookup-registry.service.mjs +246 -0
- package/esm2022/lib/services/rbac.service.mjs +5 -11
- package/esm2022/lib/services/rules-evaluation.service.mjs +27 -0
- package/esm2022/lib/services/validator-registry.service.mjs +24 -7
- package/esm2022/lib/tokens/injection-tokens.mjs +88 -7
- package/esm2022/public-api.mjs +14 -5
- package/fesm2022/ngx-dynamic-entity.mjs +3985 -876
- package/fesm2022/ngx-dynamic-entity.mjs.map +1 -1
- package/lib/field-types/array-field.component.d.ts +22 -0
- package/lib/field-types/boolean-field.component.d.ts +18 -0
- package/lib/field-types/checkbox-field.component.d.ts +3 -2
- package/lib/field-types/currency-field.component.d.ts +17 -0
- package/lib/field-types/date-field.component.d.ts +3 -2
- package/lib/field-types/dropdown-field.component.d.ts +24 -4
- package/lib/field-types/email-field.component.d.ts +15 -0
- package/lib/field-types/entity-ref-field.component.d.ts +24 -11
- package/lib/field-types/file-field.component.d.ts +25 -0
- package/lib/field-types/group-field.component.d.ts +17 -0
- package/lib/field-types/image-field.component.d.ts +30 -0
- package/lib/field-types/month-year-field.component.d.ts +28 -0
- package/lib/field-types/multi-select-field.component.d.ts +18 -4
- package/lib/field-types/number-field.component.d.ts +5 -2
- package/lib/field-types/password-field.component.d.ts +17 -0
- package/lib/field-types/radio-field.component.d.ts +33 -0
- package/lib/field-types/text-field.component.d.ts +5 -3
- package/lib/field-types/textarea-field.component.d.ts +4 -2
- package/lib/form/dynamic-field/dynamic-field.component.d.ts +20 -7
- package/lib/form/dynamic-form.component.d.ts +111 -19
- package/lib/form/dynamic-record-form.component.d.ts +169 -0
- package/lib/providers/provide-field-types.d.ts +24 -0
- package/lib/providers/provide-ngx-dynamic-entity.d.ts +12 -7
- package/lib/services/cascade-data.service.d.ts +45 -0
- package/lib/services/config-source.service.d.ts +14 -0
- package/lib/services/entity-ref-cache.d.ts +27 -0
- package/lib/services/entity-ref-registry.service.d.ts +4 -3
- package/lib/services/entity-ref-selection.service.d.ts +24 -0
- package/lib/services/entity-reference.service.d.ts +49 -0
- package/lib/services/field-registry.service.d.ts +17 -7
- package/lib/services/file-upload.service.d.ts +27 -0
- package/lib/services/lookup-registry.service.d.ts +94 -0
- package/lib/services/rbac.service.d.ts +4 -9
- package/lib/services/rules-evaluation.service.d.ts +17 -0
- package/lib/services/validator-registry.service.d.ts +5 -4
- package/lib/tokens/injection-tokens.d.ts +90 -7
- package/package.json +14 -3
- package/public-api.d.ts +11 -4
- package/esm2022/lib/services/config.service.mjs +0 -58
- package/esm2022/lib/services/version.service.mjs +0 -40
- package/esm2022/lib/table/dynamic-table.component.mjs +0 -160
- package/lib/services/config.service.d.ts +0 -25
- package/lib/services/version.service.d.ts +0 -26
- package/lib/table/dynamic-table.component.d.ts +0 -56
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import { Component, Input, signal } from '@angular/core';
|
|
1
|
+
import { Component, DestroyRef, Input, inject, signal } from '@angular/core';
|
|
2
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
2
3
|
import { ReactiveFormsModule } from '@angular/forms';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
4
|
+
import { resolveLabel } from '@dynamic-entity/core';
|
|
5
|
+
import { CascadeDataService } from '../services/cascade-data.service';
|
|
6
|
+
import { EntityRefSelectionService } from '../services/entity-ref-selection.service';
|
|
5
7
|
import * as i0 from "@angular/core";
|
|
6
8
|
import * as i1 from "@angular/forms";
|
|
7
9
|
/**
|
|
8
|
-
* EntityRefFieldComponent —
|
|
9
|
-
*
|
|
10
|
-
*
|
|
10
|
+
* EntityRefFieldComponent — a select populated from a consumer-registered loader.
|
|
11
|
+
*
|
|
12
|
+
* Cascades: when `entityReference.parentField` is set, the component watches that sibling
|
|
13
|
+
* control (via `control.parent`) and reloads its own options on every parent change,
|
|
14
|
+
* clearing a now-invalid selection. It publishes the picked record on
|
|
15
|
+
* `EntityRefSelectionService` so the owning form can run `autoPatch`.
|
|
11
16
|
*/
|
|
12
17
|
export class EntityRefFieldComponent {
|
|
13
18
|
field;
|
|
@@ -15,57 +20,110 @@ export class EntityRefFieldComponent {
|
|
|
15
20
|
language = 'en';
|
|
16
21
|
readonly = false;
|
|
17
22
|
masked = false;
|
|
18
|
-
|
|
23
|
+
cascade = inject(CascadeDataService);
|
|
24
|
+
selectionBus = inject(EntityRefSelectionService);
|
|
25
|
+
destroyRef = inject(DestroyRef);
|
|
19
26
|
options = signal([]);
|
|
20
27
|
loading = signal(false);
|
|
21
|
-
|
|
28
|
+
/** True when this field cascades but its parent has no value yet. */
|
|
29
|
+
awaitingParent = signal(false);
|
|
30
|
+
get label() {
|
|
31
|
+
return resolveLabel(this.field?.label, this.language);
|
|
32
|
+
}
|
|
33
|
+
get placeholder() {
|
|
34
|
+
return resolveLabel(this.field?.placeholder, this.language);
|
|
35
|
+
}
|
|
36
|
+
get parentFieldId() {
|
|
37
|
+
return this.field?.entityReference?.parentField;
|
|
38
|
+
}
|
|
39
|
+
ngOnInit() {
|
|
22
40
|
if (this.masked)
|
|
23
|
-
return; // No need to load options if masked
|
|
24
|
-
const entityKey = this.field.component ?? this.field.id;
|
|
25
|
-
const loader = this.entityRefRegistry.resolve(entityKey);
|
|
26
|
-
if (!loader)
|
|
27
41
|
return;
|
|
42
|
+
void this.reload();
|
|
43
|
+
this.watchParent();
|
|
44
|
+
}
|
|
45
|
+
/** Reload options against the parent's current value. */
|
|
46
|
+
async reload() {
|
|
47
|
+
const parentValue = this.parentValue();
|
|
48
|
+
this.awaitingParent.set(!!this.parentFieldId && (parentValue === null || parentValue === undefined || parentValue === ''));
|
|
49
|
+
if (!this.cascade.canLoad(this.field)) {
|
|
50
|
+
this.options.set([]);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
28
53
|
this.loading.set(true);
|
|
29
54
|
try {
|
|
30
|
-
|
|
31
|
-
this.options.set(raw);
|
|
55
|
+
this.options.set(await this.cascade.load(this.field, { parentValue, lang: this.language }));
|
|
32
56
|
}
|
|
33
57
|
finally {
|
|
34
58
|
this.loading.set(false);
|
|
35
59
|
}
|
|
36
60
|
}
|
|
61
|
+
onSelectionChange() {
|
|
62
|
+
const selected = this.options().find(o => String(o.value) === String(this.control.value));
|
|
63
|
+
this.selectionBus.emit(this.field.id, selected ?? null);
|
|
64
|
+
}
|
|
37
65
|
getLabel(value) {
|
|
38
|
-
const option = this.options().find(o => o.value === value);
|
|
66
|
+
const option = this.options().find(o => String(o.value) === String(value));
|
|
39
67
|
return option?.label ?? (value ?? '—');
|
|
40
68
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
69
|
+
parentValue() {
|
|
70
|
+
const parentId = this.parentFieldId;
|
|
71
|
+
if (!parentId)
|
|
72
|
+
return undefined;
|
|
73
|
+
return this.control?.parent?.get(parentId)?.value;
|
|
74
|
+
}
|
|
75
|
+
/** Reload (and drop a stale selection) whenever the parent control changes. */
|
|
76
|
+
watchParent() {
|
|
77
|
+
const parentId = this.parentFieldId;
|
|
78
|
+
if (!parentId)
|
|
79
|
+
return;
|
|
80
|
+
const parentControl = this.control?.parent?.get(parentId);
|
|
81
|
+
if (!parentControl)
|
|
82
|
+
return;
|
|
83
|
+
parentControl.valueChanges
|
|
84
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
85
|
+
.subscribe(() => {
|
|
86
|
+
if (this.control.value) {
|
|
87
|
+
this.control.setValue('', { emitEvent: false });
|
|
88
|
+
this.selectionBus.emit(this.field.id, null);
|
|
61
89
|
}
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
90
|
+
void this.reload();
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EntityRefFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
94
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: EntityRefFieldComponent, isStandalone: true, selector: "ngx-entity-ref-field", inputs: { field: "field", control: "control", language: "language", readonly: "readonly", masked: "masked" }, ngImport: i0, template: `
|
|
95
|
+
<div class="ngx-field ngx-field--entity-ref"
|
|
96
|
+
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
97
|
+
<label class="ngx-field__label" [attr.for]="'field-' + field.id">{{ label }}</label>
|
|
98
|
+
@if (masked) {
|
|
99
|
+
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
100
|
+
} @else if (readonly) {
|
|
101
|
+
<span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-value'">{{ getLabel(control.value) }}</span>
|
|
102
|
+
} @else {
|
|
103
|
+
@if (loading()) {
|
|
104
|
+
<span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-loading'" role="status">Loading…</span>
|
|
105
|
+
} @else {
|
|
106
|
+
<select
|
|
107
|
+
class="ngx-field__input" [attr.data-testid]="'field-' + field.id + '-input'"
|
|
108
|
+
[id]="'field-' + field.id"
|
|
109
|
+
[formControl]="$any(control)"
|
|
110
|
+
[attr.disabled]="field.disabled ? true : null"
|
|
111
|
+
(change)="onSelectionChange()"
|
|
112
|
+
>
|
|
113
|
+
<option value="">{{ placeholder || 'Select...' }}</option>
|
|
114
|
+
@for (option of options(); track option.value) {
|
|
115
|
+
<option [value]="option.value">{{ option.label }}</option>
|
|
116
|
+
}
|
|
117
|
+
</select>
|
|
118
|
+
@if (awaitingParent()) {
|
|
119
|
+
<span class="ngx-field__hint" [attr.data-testid]="'field-' + field.id + '-hint'">Select {{ parentFieldId }} first.</span>
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
@if (control.invalid && control.touched) {
|
|
123
|
+
<span class="ngx-field__error" [attr.data-testid]="'field-' + field.id + '-error'">This field has an error</span>
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
</div>
|
|
69
127
|
`, isInline: true, dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }] });
|
|
70
128
|
}
|
|
71
129
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EntityRefFieldComponent, decorators: [{
|
|
@@ -74,33 +132,39 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
74
132
|
selector: 'ngx-entity-ref-field',
|
|
75
133
|
standalone: true,
|
|
76
134
|
imports: [ReactiveFormsModule],
|
|
77
|
-
template: `
|
|
78
|
-
<div class="ngx-field ngx-field--entity-ref"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
[
|
|
91
|
-
[
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
135
|
+
template: `
|
|
136
|
+
<div class="ngx-field ngx-field--entity-ref"
|
|
137
|
+
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
138
|
+
<label class="ngx-field__label" [attr.for]="'field-' + field.id">{{ label }}</label>
|
|
139
|
+
@if (masked) {
|
|
140
|
+
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
141
|
+
} @else if (readonly) {
|
|
142
|
+
<span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-value'">{{ getLabel(control.value) }}</span>
|
|
143
|
+
} @else {
|
|
144
|
+
@if (loading()) {
|
|
145
|
+
<span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-loading'" role="status">Loading…</span>
|
|
146
|
+
} @else {
|
|
147
|
+
<select
|
|
148
|
+
class="ngx-field__input" [attr.data-testid]="'field-' + field.id + '-input'"
|
|
149
|
+
[id]="'field-' + field.id"
|
|
150
|
+
[formControl]="$any(control)"
|
|
151
|
+
[attr.disabled]="field.disabled ? true : null"
|
|
152
|
+
(change)="onSelectionChange()"
|
|
153
|
+
>
|
|
154
|
+
<option value="">{{ placeholder || 'Select...' }}</option>
|
|
155
|
+
@for (option of options(); track option.value) {
|
|
156
|
+
<option [value]="option.value">{{ option.label }}</option>
|
|
157
|
+
}
|
|
158
|
+
</select>
|
|
159
|
+
@if (awaitingParent()) {
|
|
160
|
+
<span class="ngx-field__hint" [attr.data-testid]="'field-' + field.id + '-hint'">Select {{ parentFieldId }} first.</span>
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
@if (control.invalid && control.touched) {
|
|
164
|
+
<span class="ngx-field__error" [attr.data-testid]="'field-' + field.id + '-error'">This field has an error</span>
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
</div>
|
|
104
168
|
`,
|
|
105
169
|
}]
|
|
106
170
|
}], propDecorators: { field: [{
|
|
@@ -114,4 +178,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
114
178
|
}], masked: [{
|
|
115
179
|
type: Input
|
|
116
180
|
}] } });
|
|
117
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5LXJlZi1maWVsZC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL2ZpZWxkLXR5cGVzL2VudGl0eS1yZWYtZmllbGQuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFVLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNqRSxPQUFPLEVBQW1CLG1CQUFtQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFdEUsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDbkYsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQzs7O0FBRXZDOzs7O0dBSUc7QUFrQ0gsTUFBTSxPQUFPLHVCQUF1QjtJQUN6QixLQUFLLENBQWU7SUFDcEIsT0FBTyxDQUFtQjtJQUMxQixRQUFRLEdBQVcsSUFBSSxDQUFDO0lBQ3hCLFFBQVEsR0FBWSxLQUFLLENBQUM7SUFDMUIsTUFBTSxHQUFZLEtBQUssQ0FBQztJQUVoQixpQkFBaUIsR0FBRyxNQUFNLENBQUMsd0JBQXdCLENBQUMsQ0FBQztJQUU3RCxPQUFPLEdBQUcsTUFBTSxDQUF1QyxFQUFFLENBQUMsQ0FBQztJQUMzRCxPQUFPLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBRWpDLEtBQUssQ0FBQyxRQUFRO1FBQ1osSUFBSSxJQUFJLENBQUMsTUFBTTtZQUFFLE9BQU8sQ0FBQyxvQ0FBb0M7UUFDN0QsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDeEQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUN6RCxJQUFJLENBQUMsTUFBTTtZQUFFLE9BQU87UUFFcEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDdkIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxHQUFHLEdBQUcsTUFBTSxNQUFNLEVBQUUsQ0FBQztZQUMzQixJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN4QixDQUFDO2dCQUFTLENBQUM7WUFDVCxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMxQixDQUFDO0lBQ0gsQ0FBQztJQUVELFFBQVEsQ0FBQyxLQUFVO1FBQ2pCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsS0FBSyxLQUFLLEtBQUssQ0FBQyxDQUFDO1FBQzNELE9BQU8sTUFBTSxFQUFFLEtBQUssSUFBSSxDQUFDLEtBQUssSUFBSSxHQUFHLENBQUMsQ0FBQztJQUN6QyxDQUFDO3dHQTlCVSx1QkFBdUI7NEZBQXZCLHVCQUF1Qiw4TEE3QnhCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EyQlQsMkRBNUJTLG1CQUFtQjs7NEZBOEJsQix1QkFBdUI7a0JBakNuQyxTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSxzQkFBc0I7b0JBQ2hDLFVBQVUsRUFBRSxJQUFJO29CQUNoQixPQUFPLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQztvQkFDOUIsUUFBUSxFQUFFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EyQlQ7aUJBQ0Y7OEJBRVUsS0FBSztzQkFBYixLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBJbnB1dCwgT25Jbml0LCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFic3RyYWN0Q29udHJvbCwgUmVhY3RpdmVGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB0eXBlIHsgRmllbGRDb25maWcgfSBmcm9tICdAZHluYW1pYy1lbnRpdHkvY29yZSc7XG5pbXBvcnQgeyBFbnRpdHlSZWZSZWdpc3RyeVNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy9lbnRpdHktcmVmLXJlZ2lzdHJ5LnNlcnZpY2UnO1xuaW1wb3J0IHsgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbi8qKlxuICogRW50aXR5UmVmRmllbGRDb21wb25lbnQg4oCUIHJlbmRlcnMgYSBkcm9wZG93biBwb3B1bGF0ZWQgYnkgYSBsb2FkZXIgZnJvbSBFbnRpdHlSZWZSZWdpc3RyeVNlcnZpY2UuXG4gKiBBRFItMDA2OiBPcHRpb25zIGNvbWUgT05MWSBmcm9tIHRoZSByZWdpc3RyeS4gTmV2ZXIgdmlhIEBJbnB1dCgpIGxvYWRlci5cbiAqIFVzZXMgZmllbGQuY29tcG9uZW50IChpZiBzZXQpIG9yIGZpZWxkLmlkIGFzIHRoZSByZWdpc3RyeSBsb29rdXAga2V5LlxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduZ3gtZW50aXR5LXJlZi1maWVsZCcsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtSZWFjdGl2ZUZvcm1zTW9kdWxlXSxcbiAgdGVtcGxhdGU6IGBcbiAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkIG5neC1maWVsZC0tZW50aXR5LXJlZlwiIFtjbGFzcy5uZ3gtZmllbGQtLXJlYWRvbmx5XT1cInJlYWRvbmx5XCIgW2NsYXNzLm5neC1maWVsZC0tbWFza2VkXT1cIm1hc2tlZFwiPlxuICAgICAgPGxhYmVsIGNsYXNzPVwibmd4LWZpZWxkX19sYWJlbFwiPnt7IGZpZWxkLmxhYmVsW2xhbmd1YWdlXSB8fCBmaWVsZC5sYWJlbFsnZW4nXSB9fTwvbGFiZWw+XG4gICAgICBAaWYgKG1hc2tlZCkge1xuICAgICAgICA8c3BhbiBjbGFzcz1cIm5neC1maWVsZF9fdmFsdWUgbmd4LWZpZWxkX192YWx1ZS0tbWFza2VkXCI+WFhYWFhYWFhYPC9zcGFuPlxuICAgICAgfSBAZWxzZSBpZiAocmVhZG9ubHkpIHtcbiAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX3ZhbHVlXCI+e3sgZ2V0TGFiZWwoY29udHJvbC52YWx1ZSkgfX08L3NwYW4+XG4gICAgICB9IEBlbHNlIHtcbiAgICAgICAgQGlmIChsb2FkaW5nKCkpIHtcbiAgICAgICAgICA8c3BhbiBjbGFzcz1cIm5neC1maWVsZF9fdmFsdWVcIj5Mb2FkaW5nLi4uPC9zcGFuPlxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICA8c2VsZWN0XG4gICAgICAgICAgICBjbGFzcz1cIm5neC1maWVsZF9faW5wdXRcIlxuICAgICAgICAgICAgW2Zvcm1Db250cm9sXT1cIiRhbnkoY29udHJvbClcIlxuICAgICAgICAgICAgW2F0dHIuZGlzYWJsZWRdPVwiZmllbGQuZGlzYWJsZWQgPyB0cnVlIDogbnVsbFwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAgPG9wdGlvbiB2YWx1ZT1cIlwiPnt7IGZpZWxkLnBsYWNlaG9sZGVyPy5bbGFuZ3VhZ2VdIHx8ICdTZWxlY3QuLi4nIH19PC9vcHRpb24+XG4gICAgICAgICAgICBAZm9yIChvcHRpb24gb2Ygb3B0aW9ucygpOyB0cmFjayBvcHRpb24udmFsdWUpIHtcbiAgICAgICAgICAgICAgPG9wdGlvbiBbdmFsdWVdPVwib3B0aW9uLnZhbHVlXCI+e3sgb3B0aW9uLmxhYmVsIH19PC9vcHRpb24+XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9zZWxlY3Q+XG4gICAgICAgIH1cbiAgICAgICAgQGlmIChjb250cm9sLmludmFsaWQgJiYgY29udHJvbC50b3VjaGVkKSB7XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX2Vycm9yXCI+VGhpcyBmaWVsZCBoYXMgYW4gZXJyb3I8L3NwYW4+XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICA8L2Rpdj5cbiAgYCxcbn0pXG5leHBvcnQgY2xhc3MgRW50aXR5UmVmRmllbGRDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xuICBASW5wdXQoKSBmaWVsZCE6IEZpZWxkQ29uZmlnO1xuICBASW5wdXQoKSBjb250cm9sITogQWJzdHJhY3RDb250cm9sO1xuICBASW5wdXQoKSBsYW5ndWFnZTogc3RyaW5nID0gJ2VuJztcbiAgQElucHV0KCkgcmVhZG9ubHk6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgbWFza2VkOiBib29sZWFuID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBlbnRpdHlSZWZSZWdpc3RyeSA9IGluamVjdChFbnRpdHlSZWZSZWdpc3RyeVNlcnZpY2UpO1xuXG4gIHJlYWRvbmx5IG9wdGlvbnMgPSBzaWduYWw8QXJyYXk8eyB2YWx1ZTogYW55OyBsYWJlbDogc3RyaW5nIH0+PihbXSk7XG4gIHJlYWRvbmx5IGxvYWRpbmcgPSBzaWduYWwoZmFsc2UpO1xuXG4gIGFzeW5jIG5nT25Jbml0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLm1hc2tlZCkgcmV0dXJuOyAvLyBObyBuZWVkIHRvIGxvYWQgb3B0aW9ucyBpZiBtYXNrZWRcbiAgICBjb25zdCBlbnRpdHlLZXkgPSB0aGlzLmZpZWxkLmNvbXBvbmVudCA/PyB0aGlzLmZpZWxkLmlkO1xuICAgIGNvbnN0IGxvYWRlciA9IHRoaXMuZW50aXR5UmVmUmVnaXN0cnkucmVzb2x2ZShlbnRpdHlLZXkpO1xuICAgIGlmICghbG9hZGVyKSByZXR1cm47XG5cbiAgICB0aGlzLmxvYWRpbmcuc2V0KHRydWUpO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByYXcgPSBhd2FpdCBsb2FkZXIoKTtcbiAgICAgIHRoaXMub3B0aW9ucy5zZXQocmF3KTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5sb2FkaW5nLnNldChmYWxzZSk7XG4gICAgfVxuICB9XG5cbiAgZ2V0TGFiZWwodmFsdWU6IGFueSk6IHN0cmluZyB7XG4gICAgY29uc3Qgb3B0aW9uID0gdGhpcy5vcHRpb25zKCkuZmluZChvID0+IG8udmFsdWUgPT09IHZhbHVlKTtcbiAgICByZXR1cm4gb3B0aW9uPy5sYWJlbCA/PyAodmFsdWUgPz8gJ+KAlCcpO1xuICB9XG59XG4iXX0=
|
|
181
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5LXJlZi1maWVsZC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL2ZpZWxkLXR5cGVzL2VudGl0eS1yZWYtZmllbGQuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBVSxNQUFNLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3JGLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2hFLE9BQU8sRUFBbUIsbUJBQW1CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUV0RSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDcEQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDdEUsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sMENBQTBDLENBQUM7OztBQUVyRjs7Ozs7OztHQU9HO0FBd0NILE1BQU0sT0FBTyx1QkFBdUI7SUFDekIsS0FBSyxDQUFxQjtJQUMxQixPQUFPLENBQW1CO0lBQzFCLFFBQVEsR0FBVyxJQUFJLENBQUM7SUFDeEIsUUFBUSxHQUFZLEtBQUssQ0FBQztJQUMxQixNQUFNLEdBQVksS0FBSyxDQUFDO0lBRWhCLE9BQU8sR0FBRyxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQztJQUNyQyxZQUFZLEdBQUcsTUFBTSxDQUFDLHlCQUF5QixDQUFDLENBQUM7SUFDakQsVUFBVSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUV4QyxPQUFPLEdBQUcsTUFBTSxDQUFvQixFQUFFLENBQUMsQ0FBQztJQUN4QyxPQUFPLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2pDLHFFQUFxRTtJQUM1RCxjQUFjLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBRXhDLElBQUks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LE1BQU07c0JBQWQsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgRGVzdHJveVJlZiwgSW5wdXQsIE9uSW5pdCwgaW5qZWN0LCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgdGFrZVVudGlsRGVzdHJveWVkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZS9yeGpzLWludGVyb3AnO1xyXG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIFJlYWN0aXZlRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB0eXBlIHsgTmVzdGVkRmllbGRDb25maWcsIFJlZmVyZW5jZU9wdGlvbiB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcclxuaW1wb3J0IHsgcmVzb2x2ZUxhYmVsIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xyXG5pbXBvcnQgeyBDYXNjYWRlRGF0YVNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy9jYXNjYWRlLWRhdGEuc2VydmljZSc7XHJcbmltcG9ydCB7IEVudGl0eVJlZlNlbGVjdGlvblNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy9lbnRpdHktcmVmLXNlbGVjdGlvbi5zZXJ2aWNlJztcclxuXHJcbi8qKlxyXG4gKiBFbnRpdHlSZWZGaWVsZENvbXBvbmVudCDigJQgYSBzZWxlY3QgcG9wdWxhdGVkIGZyb20gYSBjb25zdW1lci1yZWdpc3RlcmVkIGxvYWRlci5cclxuICpcclxuICogQ2FzY2FkZXM6IHdoZW4gYGVudGl0eVJlZmVyZW5jZS5wYXJlbnRGaWVsZGAgaXMgc2V0LCB0aGUgY29tcG9uZW50IHdhdGNoZXMgdGhhdCBzaWJsaW5nXHJcbiAqIGNvbnRyb2wgKHZpYSBgY29udHJvbC5wYXJlbnRgKSBhbmQgcmVsb2FkcyBpdHMgb3duIG9wdGlvbnMgb24gZXZlcnkgcGFyZW50IGNoYW5nZSxcclxuICogY2xlYXJpbmcgYSBub3ctaW52YWxpZCBzZWxlY3Rpb24uIEl0IHB1Ymxpc2hlcyB0aGUgcGlja2VkIHJlY29yZCBvblxyXG4gKiBgRW50aXR5UmVmU2VsZWN0aW9uU2VydmljZWAgc28gdGhlIG93bmluZyBmb3JtIGNhbiBydW4gYGF1dG9QYXRjaGAuXHJcbiAqL1xyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ25neC1lbnRpdHktcmVmLWZpZWxkJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtSZWFjdGl2ZUZvcm1zTW9kdWxlXSxcclxuICB0ZW1wbGF0ZTogYFxyXG4gICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZCBuZ3gtZmllbGQtLWVudGl0eS1yZWZcIlxyXG4gICAgICBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkXCIgW2F0dHIuZGF0YS1maWVsZC10eXBlXT1cImZpZWxkLnR5cGVcIiBbY2xhc3Mubmd4LWZpZWxkLS1yZWFkb25seV09XCJyZWFkb25seVwiIFtjbGFzcy5uZ3gtZmllbGQtLW1hc2tlZF09XCJtYXNrZWRcIj5cclxuICAgICAgPGxhYmVsIGNsYXNzPVwibmd4LWZpZWxkX19sYWJlbFwiIFthdHRyLmZvcl09XCInZmllbGQtJyArIGZpZWxkLmlkXCI+e3sgbGFiZWwgfX08L2xhYmVsPlxyXG4gICAgICBAaWYgKG1hc2tlZCkge1xyXG4gICAgICAgIDxzcGFuIGNsYXNzPVwibmd4LWZpZWxkX192YWx1ZSBuZ3gtZmllbGRfX3ZhbHVlLS1tYXNrZWRcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy1tYXNrZWQnXCI+WFhYWFhYWFhYPC9zcGFuPlxyXG4gICAgICB9IEBlbHNlIGlmIChyZWFkb25seSkge1xyXG4gICAgICAgIDxzcGFuIGNsYXNzPVwibmd4LWZpZWxkX192YWx1ZVwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLXZhbHVlJ1wiPnt7IGdldExhYmVsKGNvbnRyb2wudmFsdWUpIH19PC9zcGFuPlxyXG4gICAgICB9IEBlbHNlIHtcclxuICAgICAgICBAaWYgKGxvYWRpbmcoKSkge1xyXG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX3ZhbHVlXCIgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZCArICctbG9hZGluZydcIiByb2xlPVwic3RhdHVzXCI+TG9hZGluZ+KApjwvc3Bhbj5cclxuICAgICAgICB9IEBlbHNlIHtcclxuICAgICAgICAgIDxzZWxlY3RcclxuICAgICAgICAgICAgY2xhc3M9XCJuZ3gtZmllbGRfX2lucHV0XCIgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZCArICctaW5wdXQnXCJcclxuICAgICAgICAgICAgW2lkXT1cIidmaWVsZC0nICsgZmllbGQuaWRcIlxyXG4gICAgICAgICAgICBbZm9ybUNvbnRyb2xdPVwiJGFueShjb250cm9sKVwiXHJcbiAgICAgICAgICAgIFthdHRyLmRpc2FibGVkXT1cImZpZWxkLmRpc2FibGVkID8gdHJ1ZSA6IG51bGxcIlxyXG4gICAgICAgICAgICAoY2hhbmdlKT1cIm9uU2VsZWN0aW9uQ2hhbmdlKClcIlxyXG4gICAgICAgICAgPlxyXG4gICAgICAgICAgICA8b3B0aW9uIHZhbHVlPVwiXCI+e3sgcGxhY2Vob2xkZXIgfHwgJ1NlbGVjdC4uLicgfX08L29wdGlvbj5cclxuICAgICAgICAgICAgQGZvciAob3B0aW9uIG9mIG9wdGlvbnMoKTsgdHJhY2sgb3B0aW9uLnZhbHVlKSB7XHJcbiAgICAgICAgICAgICAgPG9wdGlvbiBbdmFsdWVdPVwib3B0aW9uLnZhbHVlXCI+e3sgb3B0aW9uLmxhYmVsIH19PC9vcHRpb24+XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIDwvc2VsZWN0PlxyXG4gICAgICAgICAgQGlmIChhd2FpdGluZ1BhcmVudCgpKSB7XHJcbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibmd4LWZpZWxkX19oaW50XCIgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZCArICctaGludCdcIj5TZWxlY3Qge3sgcGFyZW50RmllbGRJZCB9fSBmaXJzdC48L3NwYW4+XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIEBpZiAoY29udHJvbC5pbnZhbGlkICYmIGNvbnRyb2wudG91Y2hlZCkge1xyXG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX2Vycm9yXCIgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZCArICctZXJyb3InXCI+VGhpcyBmaWVsZCBoYXMgYW4gZXJyb3I8L3NwYW4+XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICA8L2Rpdj5cclxuICBgLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgRW50aXR5UmVmRmllbGRDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xyXG4gIEBJbnB1dCgpIGZpZWxkITogTmVzdGVkRmllbGRDb25maWc7XHJcbiAgQElucHV0KCkgY29udHJvbCE6IEFic3RyYWN0Q29udHJvbDtcclxuICBASW5wdXQoKSBsYW5ndWFnZTogc3RyaW5nID0gJ2VuJztcclxuICBASW5wdXQoKSByZWFkb25seTogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIEBJbnB1dCgpIG1hc2tlZDogYm9vbGVhbiA9IGZhbHNlO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IGNhc2NhZGUgPSBpbmplY3QoQ2FzY2FkZURhdGFTZXJ2aWNlKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IHNlbGVjdGlvbkJ1cyA9IGluamVjdChFbnRpdHlSZWZTZWxlY3Rpb25TZXJ2aWNlKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IGRlc3Ryb3lSZWYgPSBpbmplY3QoRGVzdHJveVJlZik7XHJcblxyXG4gIHJlYWRvbmx5IG9wdGlvbnMgPSBzaWduYWw8UmVmZXJlbmNlT3B0aW9uW10+KFtdKTtcclxuICByZWFkb25seSBsb2FkaW5nID0gc2lnbmFsKGZhbHNlKTtcclxuICAvKiogVHJ1ZSB3aGVuIHRoaXMgZmllbGQgY2FzY2FkZXMgYnV0IGl0cyBwYXJlbnQgaGFzIG5vIHZhbHVlIHlldC4gKi9cclxuICByZWFkb25seSBhd2FpdGluZ1BhcmVudCA9IHNpZ25hbChmYWxzZSk7XHJcblxyXG4gIGdldCBsYWJlbCgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHJlc29sdmVMYWJlbCh0aGlzLmZpZWxkPy5sYWJlbCwgdGhpcy5sYW5ndWFnZSk7XHJcbiAgfVxyXG5cclxuICBnZXQgcGxhY2Vob2xkZXIoKTogc3RyaW5nIHtcclxuICAgIHJldHVybiByZXNvbHZlTGFiZWwodGhpcy5maWVsZD8ucGxhY2Vob2xkZXIsIHRoaXMubGFuZ3VhZ2UpO1xyXG4gIH1cclxuXHJcbiAgZ2V0IHBhcmVudEZpZWxkSWQoKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcclxuICAgIHJldHVybiB0aGlzLmZpZWxkPy5lbnRpdHlSZWZlcmVuY2U/LnBhcmVudEZpZWxkO1xyXG4gIH1cclxuXHJcbiAgbmdPbkluaXQoKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5tYXNrZWQpIHJldHVybjtcclxuICAgIHZvaWQgdGhpcy5yZWxvYWQoKTtcclxuICAgIHRoaXMud2F0Y2hQYXJlbnQoKTtcclxuICB9XHJcblxyXG4gIC8qKiBSZWxvYWQgb3B0aW9ucyBhZ2FpbnN0IHRoZSBwYXJlbnQncyBjdXJyZW50IHZhbHVlLiAqL1xyXG4gIGFzeW5jIHJlbG9hZCgpOiBQcm9taXNlPHZvaWQ+IHtcclxuICAgIGNvbnN0IHBhcmVudFZhbHVlID0gdGhpcy5wYXJlbnRWYWx1ZSgpO1xyXG4gICAgdGhpcy5hd2FpdGluZ1BhcmVudC5zZXQoXHJcbiAgICAgICEhdGhpcy5wYXJlbnRGaWVsZElkICYmIChwYXJlbnRWYWx1ZSA9PT0gbnVsbCB8fCBwYXJlbnRWYWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHBhcmVudFZhbHVlID09PSAnJyksXHJcbiAgICApO1xyXG5cclxuICAgIGlmICghdGhpcy5jYXNjYWRlLmNhbkxvYWQodGhpcy5maWVsZCkpIHtcclxuICAgICAgdGhpcy5vcHRpb25zLnNldChbXSk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLmxvYWRpbmcuc2V0KHRydWUpO1xyXG4gICAgdHJ5IHtcclxuICAgICAgdGhpcy5vcHRpb25zLnNldChcclxuICAgICAgICBhd2FpdCB0aGlzLmNhc2NhZGUubG9hZCh0aGlzLmZpZWxkLCB7IHBhcmVudFZhbHVlLCBsYW5nOiB0aGlzLmxhbmd1YWdlIH0pLFxyXG4gICAgICApO1xyXG4gICAgfSBmaW5hbGx5IHtcclxuICAgICAgdGhpcy5sb2FkaW5nLnNldChmYWxzZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBvblNlbGVjdGlvbkNoYW5nZSgpOiB2b2lkIHtcclxuICAgIGNvbnN0IHNlbGVjdGVkID0gdGhpcy5vcHRpb25zKCkuZmluZChvID0+IFN0cmluZyhvLnZhbHVlKSA9PT0gU3RyaW5nKHRoaXMuY29udHJvbC52YWx1ZSkpO1xyXG4gICAgdGhpcy5zZWxlY3Rpb25CdXMuZW1pdCh0aGlzLmZpZWxkLmlkLCBzZWxlY3RlZCA/PyBudWxsKTtcclxuICB9XHJcblxyXG4gIGdldExhYmVsKHZhbHVlOiBhbnkpOiBzdHJpbmcge1xyXG4gICAgY29uc3Qgb3B0aW9uID0gdGhpcy5vcHRpb25zKCkuZmluZChvID0+IFN0cmluZyhvLnZhbHVlKSA9PT0gU3RyaW5nKHZhbHVlKSk7XHJcbiAgICByZXR1cm4gb3B0aW9uPy5sYWJlbCA/PyAodmFsdWUgPz8gJ+KAlCcpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBwYXJlbnRWYWx1ZSgpOiB1bmtub3duIHtcclxuICAgIGNvbnN0IHBhcmVudElkID0gdGhpcy5wYXJlbnRGaWVsZElkO1xyXG4gICAgaWYgKCFwYXJlbnRJZCkgcmV0dXJuIHVuZGVmaW5lZDtcclxuICAgIHJldHVybiB0aGlzLmNvbnRyb2w/LnBhcmVudD8uZ2V0KHBhcmVudElkKT8udmFsdWU7XHJcbiAgfVxyXG5cclxuICAvKiogUmVsb2FkIChhbmQgZHJvcCBhIHN0YWxlIHNlbGVjdGlvbikgd2hlbmV2ZXIgdGhlIHBhcmVudCBjb250cm9sIGNoYW5nZXMuICovXHJcbiAgcHJpdmF0ZSB3YXRjaFBhcmVudCgpOiB2b2lkIHtcclxuICAgIGNvbnN0IHBhcmVudElkID0gdGhpcy5wYXJlbnRGaWVsZElkO1xyXG4gICAgaWYgKCFwYXJlbnRJZCkgcmV0dXJuO1xyXG4gICAgY29uc3QgcGFyZW50Q29udHJvbCA9IHRoaXMuY29udHJvbD8ucGFyZW50Py5nZXQocGFyZW50SWQpO1xyXG4gICAgaWYgKCFwYXJlbnRDb250cm9sKSByZXR1cm47XHJcblxyXG4gICAgcGFyZW50Q29udHJvbC52YWx1ZUNoYW5nZXNcclxuICAgICAgLnBpcGUodGFrZVVudGlsRGVzdHJveWVkKHRoaXMuZGVzdHJveVJlZikpXHJcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xyXG4gICAgICAgIGlmICh0aGlzLmNvbnRyb2wudmFsdWUpIHtcclxuICAgICAgICAgIHRoaXMuY29udHJvbC5zZXRWYWx1ZSgnJywgeyBlbWl0RXZlbnQ6IGZhbHNlIH0pO1xyXG4gICAgICAgICAgdGhpcy5zZWxlY3Rpb25CdXMuZW1pdCh0aGlzLmZpZWxkLmlkLCBudWxsKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdm9pZCB0aGlzLnJlbG9hZCgpO1xyXG4gICAgICB9KTtcclxuICB9XHJcbn1cclxuIl19
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { Component, inject, Input, signal } from '@angular/core';
|
|
2
|
+
import { fileRefName, resolveLabel } from '@dynamic-entity/core';
|
|
3
|
+
import { FileUploadService } from '../services/file-upload.service';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* File field: file input with filename display and download link.
|
|
7
|
+
* Shares the `FileRef` / `UPLOAD_HANDLER` contract with image-field via FileUploadService.
|
|
8
|
+
*/
|
|
9
|
+
export class FileFieldComponent {
|
|
10
|
+
field;
|
|
11
|
+
control;
|
|
12
|
+
language = 'en';
|
|
13
|
+
readonly = false;
|
|
14
|
+
masked = false;
|
|
15
|
+
uploads = inject(FileUploadService);
|
|
16
|
+
uploading = signal(false);
|
|
17
|
+
uploadError = signal(null);
|
|
18
|
+
get label() {
|
|
19
|
+
return resolveLabel(this.field?.label, this.language);
|
|
20
|
+
}
|
|
21
|
+
get value() {
|
|
22
|
+
return this.control?.value ?? null;
|
|
23
|
+
}
|
|
24
|
+
fileUrl() {
|
|
25
|
+
return this.value?.url ?? null;
|
|
26
|
+
}
|
|
27
|
+
fileName() {
|
|
28
|
+
return fileRefName(this.value) || null;
|
|
29
|
+
}
|
|
30
|
+
async onFileSelect(file) {
|
|
31
|
+
if (!file)
|
|
32
|
+
return;
|
|
33
|
+
this.uploadError.set(null);
|
|
34
|
+
this.uploading.set(true);
|
|
35
|
+
try {
|
|
36
|
+
this.control.setValue(await this.uploads.toFileRef(file));
|
|
37
|
+
this.control.markAsTouched();
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
this.uploadError.set('Upload failed. Please try again.');
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
this.uploading.set(false);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
remove() {
|
|
47
|
+
this.control.setValue(null);
|
|
48
|
+
this.control.markAsTouched();
|
|
49
|
+
}
|
|
50
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FileFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
51
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: FileFieldComponent, isStandalone: true, selector: "ngx-file-field", inputs: { field: "field", control: "control", language: "language", readonly: "readonly", masked: "masked" }, ngImport: i0, template: `
|
|
52
|
+
<div class="ngx-field ngx-field--file"
|
|
53
|
+
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
54
|
+
<label class="ngx-field__label" [attr.for]="'field-' + field.id">{{ label }}</label>
|
|
55
|
+
@if (masked) {
|
|
56
|
+
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
57
|
+
} @else if (readonly) {
|
|
58
|
+
@if (fileUrl()) {
|
|
59
|
+
<a class="ngx-field__file-link" [href]="fileUrl()!" target="_blank" rel="noopener">
|
|
60
|
+
📎 {{ fileName() || 'Download file' }}
|
|
61
|
+
</a>
|
|
62
|
+
} @else {
|
|
63
|
+
<span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-value'">—</span>
|
|
64
|
+
}
|
|
65
|
+
} @else {
|
|
66
|
+
<div class="ngx-field__file-wrap">
|
|
67
|
+
@if (fileName()) {
|
|
68
|
+
<div class="ngx-field__file-selected">
|
|
69
|
+
<span class="ngx-field__file-name">📎 {{ fileName() }}</span>
|
|
70
|
+
<button type="button" class="ngx-field__remove-btn" (click)="remove()" aria-label="Remove file">✕</button>
|
|
71
|
+
</div>
|
|
72
|
+
}
|
|
73
|
+
<label class="ngx-field__upload-btn" [class.ngx-field__upload-btn--loading]="uploading()">
|
|
74
|
+
@if (uploading()) {
|
|
75
|
+
<span>Uploading…</span>
|
|
76
|
+
} @else {
|
|
77
|
+
<span>{{ fileName() ? 'Replace file' : 'Choose file' }}</span>
|
|
78
|
+
<input
|
|
79
|
+
type="file"
|
|
80
|
+
class="ngx-field__file-input"
|
|
81
|
+
[id]="'field-' + field.id"
|
|
82
|
+
[disabled]="field.disabled || uploading()"
|
|
83
|
+
(change)="onFileSelect($any($event.target).files[0])"
|
|
84
|
+
/>
|
|
85
|
+
}
|
|
86
|
+
</label>
|
|
87
|
+
</div>
|
|
88
|
+
@if (uploadError()) {
|
|
89
|
+
<span class="ngx-field__error" [attr.data-testid]="'field-' + field.id + '-error'">{{ uploadError() }}</span>
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
</div>
|
|
93
|
+
`, isInline: true });
|
|
94
|
+
}
|
|
95
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FileFieldComponent, decorators: [{
|
|
96
|
+
type: Component,
|
|
97
|
+
args: [{
|
|
98
|
+
selector: 'ngx-file-field',
|
|
99
|
+
standalone: true,
|
|
100
|
+
imports: [],
|
|
101
|
+
template: `
|
|
102
|
+
<div class="ngx-field ngx-field--file"
|
|
103
|
+
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
104
|
+
<label class="ngx-field__label" [attr.for]="'field-' + field.id">{{ label }}</label>
|
|
105
|
+
@if (masked) {
|
|
106
|
+
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
107
|
+
} @else if (readonly) {
|
|
108
|
+
@if (fileUrl()) {
|
|
109
|
+
<a class="ngx-field__file-link" [href]="fileUrl()!" target="_blank" rel="noopener">
|
|
110
|
+
📎 {{ fileName() || 'Download file' }}
|
|
111
|
+
</a>
|
|
112
|
+
} @else {
|
|
113
|
+
<span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-value'">—</span>
|
|
114
|
+
}
|
|
115
|
+
} @else {
|
|
116
|
+
<div class="ngx-field__file-wrap">
|
|
117
|
+
@if (fileName()) {
|
|
118
|
+
<div class="ngx-field__file-selected">
|
|
119
|
+
<span class="ngx-field__file-name">📎 {{ fileName() }}</span>
|
|
120
|
+
<button type="button" class="ngx-field__remove-btn" (click)="remove()" aria-label="Remove file">✕</button>
|
|
121
|
+
</div>
|
|
122
|
+
}
|
|
123
|
+
<label class="ngx-field__upload-btn" [class.ngx-field__upload-btn--loading]="uploading()">
|
|
124
|
+
@if (uploading()) {
|
|
125
|
+
<span>Uploading…</span>
|
|
126
|
+
} @else {
|
|
127
|
+
<span>{{ fileName() ? 'Replace file' : 'Choose file' }}</span>
|
|
128
|
+
<input
|
|
129
|
+
type="file"
|
|
130
|
+
class="ngx-field__file-input"
|
|
131
|
+
[id]="'field-' + field.id"
|
|
132
|
+
[disabled]="field.disabled || uploading()"
|
|
133
|
+
(change)="onFileSelect($any($event.target).files[0])"
|
|
134
|
+
/>
|
|
135
|
+
}
|
|
136
|
+
</label>
|
|
137
|
+
</div>
|
|
138
|
+
@if (uploadError()) {
|
|
139
|
+
<span class="ngx-field__error" [attr.data-testid]="'field-' + field.id + '-error'">{{ uploadError() }}</span>
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
</div>
|
|
143
|
+
`,
|
|
144
|
+
}]
|
|
145
|
+
}], propDecorators: { field: [{
|
|
146
|
+
type: Input
|
|
147
|
+
}], control: [{
|
|
148
|
+
type: Input
|
|
149
|
+
}], language: [{
|
|
150
|
+
type: Input
|
|
151
|
+
}], readonly: [{
|
|
152
|
+
type: Input
|
|
153
|
+
}], masked: [{
|
|
154
|
+
type: Input
|
|
155
|
+
}] } });
|
|
156
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZS1maWVsZC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL2ZpZWxkLXR5cGVzL2ZpbGUtZmllbGQuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFHakUsT0FBTyxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNqRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQzs7QUFFcEU7OztHQUdHO0FBaURILE1BQU0sT0FBTyxrQkFBa0I7SUFDcEIsS0FBSyxDQUFxQjtJQUMxQixPQUFPLENBQW1CO0lBQzFCLFFBQVEsR0FBVyxJQUFJLENBQUM7SUFDeEIsUUFBUSxHQUFZLEtBQUssQ0FBQztJQUMxQixNQUFNLEdBQVksS0FBSyxDQUFDO0lBRWhCLE9BQU8sR0FBRyxNQUFNLENBQUMsaUJBQWlCLENBQUMsQ0FBQztJQUU1QyxTQUFTLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzFCLFdBQVcsR0FBRyxNQUFNLENBQWdCLElBQUksQ0FBQyxDQUFDO0lBRW5ELElBQUksS0FBSztRQUNQLE9BQU8sWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRUQsSUFBWSxLQUFLO1FBQ2YsT0FBUSxJQUFJLENBQUMsT0FBTyxFQUFFLEtBQXdCLElBQUksSUFBSSxDQUFDO0lBQ3pELENBQUM7SUFFRCxPQUFPO1FBQ0wsT0FBTyxJQUFJLENBQUMsS0FBSyxFQUFFLEdBQUcsSUFBSSxJQUFJLENBQUM7SUFDakMsQ0FBQztJQUVELFFBQVE7UUFDTixPQUFPLFdBQVcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDO0lBQ3pDLENBQUM7SUFFRCxLQUFLLENBQUMsWUFBWSxDQUFDLElBQXNCO1FBQ3ZDLElBQUksQ0FBQyxJQUFJO1lBQUUsT0FBTztRQUNsQixJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMzQixJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN6QixJQUFJLENBQUM7WUFDSCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDMUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUMvQixDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsa0NBQWtDLENBQUMsQ0FBQztRQUMzRCxDQUFDO2dCQUFTLENBQUM7WUFDVCxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM1QixDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU07UUFDSixJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM1QixJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQy9CLENBQUM7d0dBN0NVLGtCQUFrQjs0RkFBbEIsa0JBQWtCLHdMQTVDbkI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTBDVDs7NEZBRVUsa0JBQWtCO2tCQWhEOUIsU0FBUzttQkFBQztvQkFDVCxRQUFRLEVBQUUsZ0JBQWdCO29CQUMxQixVQUFVLEVBQUUsSUFBSTtvQkFDaEIsT0FBTyxFQUFFLEVBQUU7b0JBQ1gsUUFBUSxFQUFFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EwQ1Q7aUJBQ0Y7OEJBRVUsS0FBSztzQkFBYixLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBpbmplY3QsIElucHV0LCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQWJzdHJhY3RDb250cm9sIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xyXG5pbXBvcnQgdHlwZSB7IEZpbGVSZWYsIE5lc3RlZEZpZWxkQ29uZmlnIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xyXG5pbXBvcnQgeyBmaWxlUmVmTmFtZSwgcmVzb2x2ZUxhYmVsIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xyXG5pbXBvcnQgeyBGaWxlVXBsb2FkU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL2ZpbGUtdXBsb2FkLnNlcnZpY2UnO1xyXG5cclxuLyoqXHJcbiAqIEZpbGUgZmllbGQ6IGZpbGUgaW5wdXQgd2l0aCBmaWxlbmFtZSBkaXNwbGF5IGFuZCBkb3dubG9hZCBsaW5rLlxyXG4gKiBTaGFyZXMgdGhlIGBGaWxlUmVmYCAvIGBVUExPQURfSEFORExFUmAgY29udHJhY3Qgd2l0aCBpbWFnZS1maWVsZCB2aWEgRmlsZVVwbG9hZFNlcnZpY2UuXHJcbiAqL1xyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ25neC1maWxlLWZpZWxkJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtdLFxyXG4gIHRlbXBsYXRlOiBgXHJcbiAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkIG5neC1maWVsZC0tZmlsZVwiXHJcbiAgICAgIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWRcIiBbYXR0ci5kYXRhLWZpZWxkLXR5cGVdPVwiZmllbGQudHlwZVwiIFtjbGFzcy5uZ3gtZmllbGQtLXJlYWRvbmx5XT1cInJlYWRvbmx5XCIgW2NsYXNzLm5neC1maWVsZC0tbWFza2VkXT1cIm1hc2tlZFwiPlxyXG4gICAgICA8bGFiZWwgY2xhc3M9XCJuZ3gtZmllbGRfX2xhYmVsXCIgW2F0dHIuZm9yXT1cIidmaWVsZC0nICsgZmllbGQuaWRcIj57eyBsYWJlbCB9fTwvbGFiZWw+XHJcbiAgICAgIEBpZiAobWFza2VkKSB7XHJcbiAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX3ZhbHVlIG5neC1maWVsZF9fdmFsdWUtLW1hc2tlZFwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLW1hc2tlZCdcIj5YWFhYWFhYWFg8L3NwYW4+XHJcbiAgICAgIH0gQGVsc2UgaWYgKHJlYWRvbmx5KSB7XHJcbiAgICAgICAgQGlmIChmaWxlVXJsKCkpIHtcclxuICAgICAgICAgIDxhIGNsYXNzPVwibmd4LWZpZWxkX19maWxlLWxpbmtcIiBbaHJlZl09XCJmaWxlVXJsKCkhXCIgdGFyZ2V0PVwiX2JsYW5rXCIgcmVsPVwibm9vcGVuZXJcIj5cclxuICAgICAgICAgICAg8J+TjiB7eyBmaWxlTmFtZSgpIHx8ICdEb3dubG9hZCBmaWxlJyB9fVxyXG4gICAgICAgICAgPC9hPlxyXG4gICAgICAgIH0gQGVsc2Uge1xyXG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX3ZhbHVlXCIgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZCArICctdmFsdWUnXCI+4oCUPC9zcGFuPlxyXG4gICAgICAgIH1cclxuICAgICAgfSBAZWxzZSB7XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZF9fZmlsZS13cmFwXCI+XHJcbiAgICAgICAgICBAaWYgKGZpbGVOYW1lKCkpIHtcclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZF9fZmlsZS1zZWxlY3RlZFwiPlxyXG4gICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwibmd4LWZpZWxkX19maWxlLW5hbWVcIj7wn5OOIHt7IGZpbGVOYW1lKCkgfX08L3NwYW4+XHJcbiAgICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJuZ3gtZmllbGRfX3JlbW92ZS1idG5cIiAoY2xpY2spPVwicmVtb3ZlKClcIiBhcmlhLWxhYmVsPVwiUmVtb3ZlIGZpbGVcIj7inJU8L2J1dHRvbj5cclxuICAgICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJuZ3gtZmllbGRfX3VwbG9hZC1idG5cIiBbY2xhc3Mubmd4LWZpZWxkX191cGxvYWQtYnRuLS1sb2FkaW5nXT1cInVwbG9hZGluZygpXCI+XHJcbiAgICAgICAgICAgIEBpZiAodXBsb2FkaW5nKCkpIHtcclxuICAgICAgICAgICAgICA8c3Bhbj5VcGxvYWRpbmfigKY8L3NwYW4+XHJcbiAgICAgICAgICAgIH0gQGVsc2Uge1xyXG4gICAgICAgICAgICAgIDxzcGFuPnt7IGZpbGVOYW1lKCkgPyAnUmVwbGFjZSBmaWxlJyA6ICdDaG9vc2UgZmlsZScgfX08L3NwYW4+XHJcbiAgICAgICAgICAgICAgPGlucHV0XHJcbiAgICAgICAgICAgICAgICB0eXBlPVwiZmlsZVwiXHJcbiAgICAgICAgICAgICAgICBjbGFzcz1cIm5neC1maWVsZF9fZmlsZS1pbnB1dFwiXHJcbiAgICAgICAgICAgICAgICBbaWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZFwiXHJcbiAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiZmllbGQuZGlzYWJsZWQgfHwgdXBsb2FkaW5nKClcIlxyXG4gICAgICAgICAgICAgICAgKGNoYW5nZSk9XCJvbkZpbGVTZWxlY3QoJGFueSgkZXZlbnQudGFyZ2V0KS5maWxlc1swXSlcIlxyXG4gICAgICAgICAgICAgIC8+XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIDwvbGFiZWw+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgQGlmICh1cGxvYWRFcnJvcigpKSB7XHJcbiAgICAgICAgICA8c3BhbiBjbGFzcz1cIm5neC1maWVsZF9fZXJyb3JcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy1lcnJvcidcIj57eyB1cGxvYWRFcnJvcigpIH19PC9zcGFuPlxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgPC9kaXY+XHJcbiAgYCxcclxufSlcclxuZXhwb3J0IGNsYXNzIEZpbGVGaWVsZENvbXBvbmVudCB7XHJcbiAgQElucHV0KCkgZmllbGQhOiBOZXN0ZWRGaWVsZENvbmZpZztcclxuICBASW5wdXQoKSBjb250cm9sITogQWJzdHJhY3RDb250cm9sO1xyXG4gIEBJbnB1dCgpIGxhbmd1YWdlOiBzdHJpbmcgPSAnZW4nO1xyXG4gIEBJbnB1dCgpIHJlYWRvbmx5OiBib29sZWFuID0gZmFsc2U7XHJcbiAgQElucHV0KCkgbWFza2VkOiBib29sZWFuID0gZmFsc2U7XHJcblxyXG4gIHByaXZhdGUgcmVhZG9ubHkgdXBsb2FkcyA9IGluamVjdChGaWxlVXBsb2FkU2VydmljZSk7XHJcblxyXG4gIHJlYWRvbmx5IHVwbG9hZGluZyA9IHNpZ25hbChmYWxzZSk7XHJcbiAgcmVhZG9ubHkgdXBsb2FkRXJyb3IgPSBzaWduYWw8c3RyaW5nIHwgbnVsbD4obnVsbCk7XHJcblxyXG4gIGdldCBsYWJlbCgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHJlc29sdmVMYWJlbCh0aGlzLmZpZWxkPy5sYWJlbCwgdGhpcy5sYW5ndWFnZSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGdldCB2YWx1ZSgpOiBGaWxlUmVmIHwgbnVsbCB7XHJcbiAgICByZXR1cm4gKHRoaXMuY29udHJvbD8udmFsdWUgYXMgRmlsZVJlZiB8IG51bGwpID8/IG51bGw7XHJcbiAgfVxyXG5cclxuICBmaWxlVXJsKCk6IHN0cmluZyB8IG51bGwge1xyXG4gICAgcmV0dXJuIHRoaXMudmFsdWU/LnVybCA/PyBudWxsO1xyXG4gIH1cclxuXHJcbiAgZmlsZU5hbWUoKTogc3RyaW5nIHwgbnVsbCB7XHJcbiAgICByZXR1cm4gZmlsZVJlZk5hbWUodGhpcy52YWx1ZSkgfHwgbnVsbDtcclxuICB9XHJcblxyXG4gIGFzeW5jIG9uRmlsZVNlbGVjdChmaWxlOiBGaWxlIHwgdW5kZWZpbmVkKTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICBpZiAoIWZpbGUpIHJldHVybjtcclxuICAgIHRoaXMudXBsb2FkRXJyb3Iuc2V0KG51bGwpO1xyXG4gICAgdGhpcy51cGxvYWRpbmcuc2V0KHRydWUpO1xyXG4gICAgdHJ5IHtcclxuICAgICAgdGhpcy5jb250cm9sLnNldFZhbHVlKGF3YWl0IHRoaXMudXBsb2Fkcy50b0ZpbGVSZWYoZmlsZSkpO1xyXG4gICAgICB0aGlzLmNvbnRyb2wubWFya0FzVG91Y2hlZCgpO1xyXG4gICAgfSBjYXRjaCB7XHJcbiAgICAgIHRoaXMudXBsb2FkRXJyb3Iuc2V0KCdVcGxvYWQgZmFpbGVkLiBQbGVhc2UgdHJ5IGFnYWluLicpO1xyXG4gICAgfSBmaW5hbGx5IHtcclxuICAgICAgdGhpcy51cGxvYWRpbmcuc2V0KGZhbHNlKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHJlbW92ZSgpOiB2b2lkIHtcclxuICAgIHRoaXMuY29udHJvbC5zZXRWYWx1ZShudWxsKTtcclxuICAgIHRoaXMuY29udHJvbC5tYXJrQXNUb3VjaGVkKCk7XHJcbiAgfVxyXG59XHJcbiJdfQ==
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Component, Input, forwardRef } from '@angular/core';
|
|
2
|
+
import { ReactiveFormsModule } from '@angular/forms';
|
|
3
|
+
import { resolveLabel } from '@dynamic-entity/core';
|
|
4
|
+
import { DynamicFieldComponent } from '../form/dynamic-field/dynamic-field.component';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
/** ADR-008: GroupFieldComponent — renders nested fieldset container for group.children */
|
|
7
|
+
export class GroupFieldComponent {
|
|
8
|
+
field;
|
|
9
|
+
control;
|
|
10
|
+
config;
|
|
11
|
+
language = 'en';
|
|
12
|
+
readonly = false;
|
|
13
|
+
masked = false;
|
|
14
|
+
userRoles = [];
|
|
15
|
+
get label() {
|
|
16
|
+
return resolveLabel(this.field?.label, this.language);
|
|
17
|
+
}
|
|
18
|
+
getChildControl(childId) {
|
|
19
|
+
const group = this.control;
|
|
20
|
+
return group?.get(childId);
|
|
21
|
+
}
|
|
22
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: GroupFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
23
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: GroupFieldComponent, isStandalone: true, selector: "ngx-group-field", inputs: { field: "field", control: "control", config: "config", language: "language", readonly: "readonly", masked: "masked", userRoles: "userRoles" }, ngImport: i0, template: `
|
|
24
|
+
<fieldset class="ngx-field ngx-field--group"
|
|
25
|
+
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
26
|
+
<legend class="ngx-field__legend">{{ label }}</legend>
|
|
27
|
+
@if (masked) {
|
|
28
|
+
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
29
|
+
} @else {
|
|
30
|
+
<div class="ngx-field__group-children">
|
|
31
|
+
@for (child of field.children ?? []; track child.id) {
|
|
32
|
+
@if (child.visibility !== false) {
|
|
33
|
+
<ngx-dynamic-field
|
|
34
|
+
[field]="child"
|
|
35
|
+
[control]="getChildControl(child.id)"
|
|
36
|
+
[config]="config"
|
|
37
|
+
[language]="language"
|
|
38
|
+
[readonly]="readonly || !!child.readonly"
|
|
39
|
+
[userRoles]="userRoles"
|
|
40
|
+
/>
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
</div>
|
|
44
|
+
}
|
|
45
|
+
</fieldset>
|
|
46
|
+
`, isInline: true, styles: [".ngx-field--group{border:1px solid #e2e8f0;border-radius:8px;padding:16px;margin-bottom:16px;background:#fafafa}.ngx-field__legend{font-weight:600;font-size:14px;padding:0 8px;color:#334155}.ngx-field__group-children{display:flex;flex-direction:column;gap:12px}\n"], dependencies: [{ kind: "ngmodule", type: i0.forwardRef(() => ReactiveFormsModule) }, { kind: "component", type: i0.forwardRef(() => DynamicFieldComponent), selector: "ngx-dynamic-field", inputs: ["field", "control", "config", "currentTabId", "language", "readonly", "userRoles"] }] });
|
|
47
|
+
}
|
|
48
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: GroupFieldComponent, decorators: [{
|
|
49
|
+
type: Component,
|
|
50
|
+
args: [{ selector: 'ngx-group-field', standalone: true, imports: [ReactiveFormsModule, forwardRef(() => DynamicFieldComponent)], template: `
|
|
51
|
+
<fieldset class="ngx-field ngx-field--group"
|
|
52
|
+
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
53
|
+
<legend class="ngx-field__legend">{{ label }}</legend>
|
|
54
|
+
@if (masked) {
|
|
55
|
+
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
56
|
+
} @else {
|
|
57
|
+
<div class="ngx-field__group-children">
|
|
58
|
+
@for (child of field.children ?? []; track child.id) {
|
|
59
|
+
@if (child.visibility !== false) {
|
|
60
|
+
<ngx-dynamic-field
|
|
61
|
+
[field]="child"
|
|
62
|
+
[control]="getChildControl(child.id)"
|
|
63
|
+
[config]="config"
|
|
64
|
+
[language]="language"
|
|
65
|
+
[readonly]="readonly || !!child.readonly"
|
|
66
|
+
[userRoles]="userRoles"
|
|
67
|
+
/>
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
</div>
|
|
71
|
+
}
|
|
72
|
+
</fieldset>
|
|
73
|
+
`, styles: [".ngx-field--group{border:1px solid #e2e8f0;border-radius:8px;padding:16px;margin-bottom:16px;background:#fafafa}.ngx-field__legend{font-weight:600;font-size:14px;padding:0 8px;color:#334155}.ngx-field__group-children{display:flex;flex-direction:column;gap:12px}\n"] }]
|
|
74
|
+
}], propDecorators: { field: [{
|
|
75
|
+
type: Input
|
|
76
|
+
}], control: [{
|
|
77
|
+
type: Input
|
|
78
|
+
}], config: [{
|
|
79
|
+
type: Input
|
|
80
|
+
}], language: [{
|
|
81
|
+
type: Input
|
|
82
|
+
}], readonly: [{
|
|
83
|
+
type: Input
|
|
84
|
+
}], masked: [{
|
|
85
|
+
type: Input
|
|
86
|
+
}], userRoles: [{
|
|
87
|
+
type: Input
|
|
88
|
+
}] } });
|
|
89
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JvdXAtZmllbGQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9maWVsZC10eXBlcy9ncm91cC1maWVsZC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzdELE9BQU8sRUFBOEIsbUJBQW1CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVqRixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDcEQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sK0NBQStDLENBQUM7O0FBRXRGLDBGQUEwRjtBQW9EMUYsTUFBTSxPQUFPLG1CQUFtQjtJQUNyQixLQUFLLENBQXFCO0lBQzFCLE9BQU8sQ0FBbUI7SUFDMUIsTUFBTSxDQUFvQjtJQUMxQixRQUFRLEdBQVcsSUFBSSxDQUFDO0lBQ3hCLFFBQVEsR0FBWSxLQUFLLENBQUM7SUFDMUIsTUFBTSxHQUFZLEtBQUssQ0FBQztJQUN4QixTQUFTLEdBQWEsRUFBRSxDQUFDO0lBRWxDLElBQUksS0FBSztRQUNQLE9BQU8sWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRUQsZUFBZSxDQUFDLE9BQWU7UUFDN0IsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE9BQW9CLENBQUM7UUFDeEMsT0FBTyxLQUFLLEVBQUUsR0FBRyxDQUFDLE9BQU8sQ0FBb0IsQ0FBQztJQUNoRCxDQUFDO3dHQWhCVSxtQkFBbUI7NEZBQW5CLG1CQUFtQixtT0EvQ3BCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXVCVCxvV0F4QlMsbUJBQW1CLG9EQUFtQixxQkFBcUI7OzRGQWdEMUQsbUJBQW1CO2tCQW5EL0IsU0FBUzsrQkFDRSxpQkFBaUIsY0FDZixJQUFJLFdBQ1AsQ0FBQyxtQkFBbUIsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMscUJBQXFCLENBQUMsQ0FBQyxZQUM3RDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F1QlQ7OEJBeUJRLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIGZvcndhcmRSZWYgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQWJzdHJhY3RDb250cm9sLCBGb3JtR3JvdXAsIFJlYWN0aXZlRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB0eXBlIHsgTmVzdGVkRmllbGRDb25maWcsIEVudGl0eUZvcm1Db25maWcgfSBmcm9tICdAZHluYW1pYy1lbnRpdHkvY29yZSc7XHJcbmltcG9ydCB7IHJlc29sdmVMYWJlbCB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcclxuaW1wb3J0IHsgRHluYW1pY0ZpZWxkQ29tcG9uZW50IH0gZnJvbSAnLi4vZm9ybS9keW5hbWljLWZpZWxkL2R5bmFtaWMtZmllbGQuY29tcG9uZW50JztcclxuXHJcbi8qKiBBRFItMDA4OiBHcm91cEZpZWxkQ29tcG9uZW50IOKAlCByZW5kZXJzIG5lc3RlZCBmaWVsZHNldCBjb250YWluZXIgZm9yIGdyb3VwLmNoaWxkcmVuICovXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnbmd4LWdyb3VwLWZpZWxkJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtSZWFjdGl2ZUZvcm1zTW9kdWxlLCBmb3J3YXJkUmVmKCgpID0+IER5bmFtaWNGaWVsZENvbXBvbmVudCldLFxyXG4gIHRlbXBsYXRlOiBgXHJcbiAgICA8ZmllbGRzZXQgY2xhc3M9XCJuZ3gtZmllbGQgbmd4LWZpZWxkLS1ncm91cFwiXHJcbiAgICAgIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWRcIiBbYXR0ci5kYXRhLWZpZWxkLXR5cGVdPVwiZmllbGQudHlwZVwiIFtjbGFzcy5uZ3gtZmllbGQtLXJlYWRvbmx5XT1cInJlYWRvbmx5XCIgW2NsYXNzLm5neC1maWVsZC0tbWFza2VkXT1cIm1hc2tlZFwiPlxyXG4gICAgICA8bGVnZW5kIGNsYXNzPVwibmd4LWZpZWxkX19sZWdlbmRcIj57eyBsYWJlbCB9fTwvbGVnZW5kPlxyXG4gICAgICBAaWYgKG1hc2tlZCkge1xyXG4gICAgICAgIDxzcGFuIGNsYXNzPVwibmd4LWZpZWxkX192YWx1ZSBuZ3gtZmllbGRfX3ZhbHVlLS1tYXNrZWRcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy1tYXNrZWQnXCI+WFhYWFhYWFhYPC9zcGFuPlxyXG4gICAgICB9IEBlbHNlIHtcclxuICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19ncm91cC1jaGlsZHJlblwiPlxyXG4gICAgICAgICAgQGZvciAoY2hpbGQgb2YgZmllbGQuY2hpbGRyZW4gPz8gW107IHRyYWNrIGNoaWxkLmlkKSB7XHJcbiAgICAgICAgICAgIEBpZiAoY2hpbGQudmlzaWJpbGl0eSAhPT0gZmFsc2UpIHtcclxuICAgICAgICAgICAgICA8bmd4LWR5bmFtaWMtZmllbGRcclxuICAgICAgICAgICAgICAgIFtmaWVsZF09XCJjaGlsZFwiXHJcbiAgICAgICAgICAgICAgICBbY29udHJvbF09XCJnZXRDaGlsZENvbnRyb2woY2hpbGQuaWQpXCJcclxuICAgICAgICAgICAgICAgIFtjb25maWddPVwiY29uZmlnXCJcclxuICAgICAgICAgICAgICAgIFtsYW5ndWFnZV09XCJsYW5ndWFnZVwiXHJcbiAgICAgICAgICAgICAgICBbcmVhZG9ubHldPVwicmVhZG9ubHkgfHwgISFjaGlsZC5yZWFkb25seVwiXHJcbiAgICAgICAgICAgICAgICBbdXNlclJvbGVzXT1cInVzZXJSb2xlc1wiXHJcbiAgICAgICAgICAgICAgLz5cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICB9XHJcbiAgICA8L2ZpZWxkc2V0PlxyXG4gIGAsXHJcbiAgc3R5bGVzOiBbXHJcbiAgICBgXHJcbiAgICAgIC5uZ3gtZmllbGQtLWdyb3VwIHtcclxuICAgICAgICBib3JkZXI6IDFweCBzb2xpZCAjZTJlOGYwO1xyXG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDhweDtcclxuICAgICAgICBwYWRkaW5nOiAxNnB4O1xyXG4gICAgICAgIG1hcmdpbi1ib3R0b206IDE2cHg7XHJcbiAgICAgICAgYmFja2dyb3VuZDogI2ZhZmFmYTtcclxuICAgICAgfVxyXG4gICAgICAubmd4LWZpZWxkX19sZWdlbmQge1xyXG4gICAgICAgIGZvbnQtd2VpZ2h0OiA2MDA7XHJcbiAgICAgICAgZm9udC1zaXplOiAxNHB4O1xyXG4gICAgICAgIHBhZGRpbmc6IDAgOHB4O1xyXG4gICAgICAgIGNvbG9yOiAjMzM0MTU1O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2dyb3VwLWNoaWxkcmVuIHtcclxuICAgICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICAgIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XHJcbiAgICAgICAgZ2FwOiAxMnB4O1xyXG4gICAgICB9XHJcbiAgICBgLFxyXG4gIF0sXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBHcm91cEZpZWxkQ29tcG9uZW50IHtcclxuICBASW5wdXQoKSBmaWVsZCE6IE5lc3RlZEZpZWxkQ29uZmlnO1xyXG4gIEBJbnB1dCgpIGNvbnRyb2whOiBBYnN0cmFjdENvbnRyb2w7XHJcbiAgQElucHV0KCkgY29uZmlnITogRW50aXR5Rm9ybUNvbmZpZztcclxuICBASW5wdXQoKSBsYW5ndWFnZTogc3RyaW5nID0gJ2VuJztcclxuICBASW5wdXQoKSByZWFkb25seTogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIEBJbnB1dCgpIG1hc2tlZDogYm9vbGVhbiA9IGZhbHNlO1xyXG4gIEBJbnB1dCgpIHVzZXJSb2xlczogc3RyaW5nW10gPSBbXTtcclxuXHJcbiAgZ2V0IGxhYmVsKCk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gcmVzb2x2ZUxhYmVsKHRoaXMuZmllbGQ/LmxhYmVsLCB0aGlzLmxhbmd1YWdlKTtcclxuICB9XHJcblxyXG4gIGdldENoaWxkQ29udHJvbChjaGlsZElkOiBzdHJpbmcpOiBBYnN0cmFjdENvbnRyb2wge1xyXG4gICAgY29uc3QgZ3JvdXAgPSB0aGlzLmNvbnRyb2wgYXMgRm9ybUdyb3VwO1xyXG4gICAgcmV0dXJuIGdyb3VwPy5nZXQoY2hpbGRJZCkgYXMgQWJzdHJhY3RDb250cm9sO1xyXG4gIH1cclxufVxyXG4iXX0=
|