ngx-dynamic-entity 1.3.0 → 1.5.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 +14 -0
- package/fesm2022/ngx-dynamic-entity.mjs +255 -157
- package/fesm2022/ngx-dynamic-entity.mjs.map +1 -1
- package/package.json +6 -7
- package/types/ngx-dynamic-entity.d.ts +1730 -0
- package/esm2022/lib/field-types/array-field.component.mjs +0 -168
- package/esm2022/lib/field-types/boolean-field.component.mjs +0 -101
- package/esm2022/lib/field-types/checkbox-field.component.mjs +0 -82
- package/esm2022/lib/field-types/currency-field.component.mjs +0 -102
- package/esm2022/lib/field-types/date-field.component.mjs +0 -91
- package/esm2022/lib/field-types/date-time-field.component.mjs +0 -138
- package/esm2022/lib/field-types/dropdown-field.component.mjs +0 -176
- package/esm2022/lib/field-types/email-field.component.mjs +0 -102
- package/esm2022/lib/field-types/entity-ref-field.component.mjs +0 -195
- package/esm2022/lib/field-types/field-component.contract.mjs +0 -2
- package/esm2022/lib/field-types/file-field.component.mjs +0 -157
- package/esm2022/lib/field-types/group-field.component.mjs +0 -89
- package/esm2022/lib/field-types/image-field.component.mjs +0 -169
- package/esm2022/lib/field-types/month-year-field.component.mjs +0 -152
- package/esm2022/lib/field-types/multi-select-field.component.mjs +0 -146
- package/esm2022/lib/field-types/number-field.component.mjs +0 -112
- package/esm2022/lib/field-types/password-field.component.mjs +0 -110
- package/esm2022/lib/field-types/radio-field.component.mjs +0 -153
- package/esm2022/lib/field-types/text-field.component.mjs +0 -121
- package/esm2022/lib/field-types/textarea-field.component.mjs +0 -85
- package/esm2022/lib/field-types/time-field.component.mjs +0 -96
- package/esm2022/lib/form/dynamic-field/dynamic-field.component.mjs +0 -152
- package/esm2022/lib/form/dynamic-form.component.mjs +0 -899
- package/esm2022/lib/form/dynamic-record-form.component.mjs +0 -531
- package/esm2022/lib/providers/provide-field-types.mjs +0 -75
- package/esm2022/lib/providers/provide-ngx-dynamic-entity.mjs +0 -27
- package/esm2022/lib/services/cascade-data.service.mjs +0 -129
- package/esm2022/lib/services/config-source.service.mjs +0 -67
- package/esm2022/lib/services/entity-ref-cache.mjs +0 -20
- package/esm2022/lib/services/entity-ref-registry.service.mjs +0 -31
- package/esm2022/lib/services/entity-ref-selection.service.mjs +0 -27
- package/esm2022/lib/services/entity-reference.service.mjs +0 -168
- package/esm2022/lib/services/field-registry.service.mjs +0 -55
- package/esm2022/lib/services/file-upload.service.mjs +0 -89
- package/esm2022/lib/services/hook-registry.service.mjs +0 -26
- package/esm2022/lib/services/lookup-registry.service.mjs +0 -246
- package/esm2022/lib/services/rbac.service.mjs +0 -46
- package/esm2022/lib/services/rules-evaluation.service.mjs +0 -27
- package/esm2022/lib/services/validation-messages.service.mjs +0 -56
- package/esm2022/lib/services/validator-registry.service.mjs +0 -99
- package/esm2022/lib/tokens/injection-tokens.mjs +0 -126
- package/esm2022/ngx-dynamic-entity.mjs +0 -5
- package/esm2022/public-api.mjs +0 -58
- package/index.d.ts +0 -5
- package/lib/field-types/array-field.component.d.ts +0 -28
- package/lib/field-types/boolean-field.component.d.ts +0 -18
- package/lib/field-types/checkbox-field.component.d.ts +0 -13
- package/lib/field-types/currency-field.component.d.ts +0 -17
- package/lib/field-types/date-field.component.d.ts +0 -15
- package/lib/field-types/date-time-field.component.d.ts +0 -30
- package/lib/field-types/dropdown-field.component.d.ts +0 -34
- package/lib/field-types/email-field.component.d.ts +0 -15
- package/lib/field-types/entity-ref-field.component.d.ts +0 -49
- package/lib/field-types/field-component.contract.d.ts +0 -49
- package/lib/field-types/file-field.component.d.ts +0 -25
- package/lib/field-types/group-field.component.d.ts +0 -17
- package/lib/field-types/image-field.component.d.ts +0 -30
- package/lib/field-types/month-year-field.component.d.ts +0 -28
- package/lib/field-types/multi-select-field.component.d.ts +0 -27
- package/lib/field-types/number-field.component.d.ts +0 -16
- package/lib/field-types/password-field.component.d.ts +0 -17
- package/lib/field-types/radio-field.component.d.ts +0 -33
- package/lib/field-types/text-field.component.d.ts +0 -23
- package/lib/field-types/textarea-field.component.d.ts +0 -14
- package/lib/field-types/time-field.component.d.ts +0 -27
- package/lib/form/dynamic-field/dynamic-field.component.d.ts +0 -78
- package/lib/form/dynamic-form.component.d.ts +0 -293
- package/lib/form/dynamic-record-form.component.d.ts +0 -199
- package/lib/providers/provide-field-types.d.ts +0 -24
- package/lib/providers/provide-ngx-dynamic-entity.d.ts +0 -56
- package/lib/services/cascade-data.service.d.ts +0 -45
- package/lib/services/config-source.service.d.ts +0 -14
- package/lib/services/entity-ref-cache.d.ts +0 -27
- package/lib/services/entity-ref-registry.service.d.ts +0 -21
- package/lib/services/entity-ref-selection.service.d.ts +0 -24
- package/lib/services/entity-reference.service.d.ts +0 -49
- package/lib/services/field-registry.service.d.ts +0 -32
- package/lib/services/file-upload.service.d.ts +0 -27
- package/lib/services/hook-registry.service.d.ts +0 -12
- package/lib/services/lookup-registry.service.d.ts +0 -94
- package/lib/services/rbac.service.d.ts +0 -27
- package/lib/services/rules-evaluation.service.d.ts +0 -17
- package/lib/services/validation-messages.service.d.ts +0 -43
- package/lib/services/validator-registry.service.d.ts +0 -32
- package/lib/tokens/injection-tokens.d.ts +0 -134
- package/public-api.d.ts +0 -42
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import { Component, DestroyRef, Input, inject, signal, ChangeDetectionStrategy } from '@angular/core';
|
|
2
|
-
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
3
|
-
import { ReactiveFormsModule } from '@angular/forms';
|
|
4
|
-
import { resolveLabel } from '@dynamic-entity/core';
|
|
5
|
-
import { CascadeDataService } from '../services/cascade-data.service';
|
|
6
|
-
import { EntityRefSelectionService } from '../services/entity-ref-selection.service';
|
|
7
|
-
import * as i0 from "@angular/core";
|
|
8
|
-
import * as i1 from "@angular/forms";
|
|
9
|
-
/**
|
|
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`.
|
|
16
|
-
*/
|
|
17
|
-
export class EntityRefFieldComponent {
|
|
18
|
-
field;
|
|
19
|
-
control;
|
|
20
|
-
language = 'en';
|
|
21
|
-
readonly = false;
|
|
22
|
-
masked = false;
|
|
23
|
-
cascade = inject(CascadeDataService);
|
|
24
|
-
selectionBus = inject(EntityRefSelectionService);
|
|
25
|
-
destroyRef = inject(DestroyRef);
|
|
26
|
-
options = signal([]);
|
|
27
|
-
loading = signal(false);
|
|
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() {
|
|
40
|
-
if (this.masked)
|
|
41
|
-
return;
|
|
42
|
-
void this.reload();
|
|
43
|
-
this.watchParent();
|
|
44
|
-
this.control?.valueChanges
|
|
45
|
-
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
46
|
-
.subscribe(value => this.publishSelection(String(value ?? '')));
|
|
47
|
-
}
|
|
48
|
-
/** Reload options against the parent's current value. */
|
|
49
|
-
async reload() {
|
|
50
|
-
const parentValue = this.parentValue();
|
|
51
|
-
this.awaitingParent.set(!!this.parentFieldId && (parentValue === null || parentValue === undefined || parentValue === ''));
|
|
52
|
-
if (!this.cascade.canLoad(this.field)) {
|
|
53
|
-
this.options.set([]);
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
this.loading.set(true);
|
|
57
|
-
try {
|
|
58
|
-
this.options.set(await this.cascade.load(this.field, { parentValue, lang: this.language }));
|
|
59
|
-
}
|
|
60
|
-
finally {
|
|
61
|
-
this.loading.set(false);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Publish the selected option so autoPatch can copy from its record.
|
|
66
|
-
*
|
|
67
|
-
* Driven from `valueChanges` rather than the select's `change` event: that event is the
|
|
68
|
-
* same one the `formControl` directive listens to, so reading the control inside a
|
|
69
|
-
* template `(change)` handler can see the previous value. `valueChanges` fires after the
|
|
70
|
-
* model has updated — including Playwright `selectOption`, which updates the control
|
|
71
|
-
* through the value accessor.
|
|
72
|
-
*/
|
|
73
|
-
onSelectionChange(value) {
|
|
74
|
-
this.publishSelection(value ?? String(this.control?.value ?? ''));
|
|
75
|
-
}
|
|
76
|
-
publishSelection(current) {
|
|
77
|
-
const selected = this.options().find(o => String(o.value) === current);
|
|
78
|
-
this.selectionBus.emit(this.field.id, selected ?? null);
|
|
79
|
-
}
|
|
80
|
-
getLabel(value) {
|
|
81
|
-
const option = this.options().find(o => String(o.value) === String(value));
|
|
82
|
-
return option?.label ?? (value ?? '—');
|
|
83
|
-
}
|
|
84
|
-
parentValue() {
|
|
85
|
-
const parentId = this.parentFieldId;
|
|
86
|
-
if (!parentId)
|
|
87
|
-
return undefined;
|
|
88
|
-
return this.control?.parent?.get(parentId)?.value;
|
|
89
|
-
}
|
|
90
|
-
/** Reload (and drop a stale selection) whenever the parent control changes. */
|
|
91
|
-
watchParent() {
|
|
92
|
-
const parentId = this.parentFieldId;
|
|
93
|
-
if (!parentId)
|
|
94
|
-
return;
|
|
95
|
-
const parentControl = this.control?.parent?.get(parentId);
|
|
96
|
-
if (!parentControl)
|
|
97
|
-
return;
|
|
98
|
-
parentControl.valueChanges
|
|
99
|
-
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
100
|
-
.subscribe(() => {
|
|
101
|
-
if (this.control.value) {
|
|
102
|
-
this.control.setValue('', { emitEvent: false });
|
|
103
|
-
this.selectionBus.emit(this.field.id, null);
|
|
104
|
-
}
|
|
105
|
-
void this.reload();
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EntityRefFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
109
|
-
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: `
|
|
110
|
-
<div class="ngx-field ngx-field--entity-ref"
|
|
111
|
-
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
112
|
-
<label class="ngx-field__label" [attr.for]="'field-' + field.id">{{ label }}</label>
|
|
113
|
-
@if (masked) {
|
|
114
|
-
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
115
|
-
} @else if (readonly) {
|
|
116
|
-
<span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-value'">{{ getLabel(control.value) }}</span>
|
|
117
|
-
} @else {
|
|
118
|
-
@if (loading()) {
|
|
119
|
-
<span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-loading'" role="status">Loading…</span>
|
|
120
|
-
} @else {
|
|
121
|
-
<select
|
|
122
|
-
class="ngx-field__input" [attr.data-testid]="'field-' + field.id + '-input'"
|
|
123
|
-
[id]="'field-' + field.id"
|
|
124
|
-
[formControl]="$any(control)"
|
|
125
|
-
[attr.disabled]="field.disabled ? true : null"
|
|
126
|
-
>
|
|
127
|
-
<option value="">{{ placeholder || 'Select...' }}</option>
|
|
128
|
-
@for (option of options(); track option.value) {
|
|
129
|
-
<option [value]="option.value">{{ option.label }}</option>
|
|
130
|
-
}
|
|
131
|
-
</select>
|
|
132
|
-
@if (awaitingParent()) {
|
|
133
|
-
<span class="ngx-field__hint" [attr.data-testid]="'field-' + field.id + '-hint'">Select {{ parentFieldId }} first.</span>
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
@if (control.invalid && control.touched) {
|
|
137
|
-
<span class="ngx-field__error" [attr.data-testid]="'field-' + field.id + '-error'">This field has an error</span>
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
</div>
|
|
141
|
-
`, 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
142
|
-
}
|
|
143
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EntityRefFieldComponent, decorators: [{
|
|
144
|
-
type: Component,
|
|
145
|
-
args: [{
|
|
146
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
147
|
-
selector: 'ngx-entity-ref-field',
|
|
148
|
-
standalone: true,
|
|
149
|
-
imports: [ReactiveFormsModule],
|
|
150
|
-
template: `
|
|
151
|
-
<div class="ngx-field ngx-field--entity-ref"
|
|
152
|
-
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
153
|
-
<label class="ngx-field__label" [attr.for]="'field-' + field.id">{{ label }}</label>
|
|
154
|
-
@if (masked) {
|
|
155
|
-
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
156
|
-
} @else if (readonly) {
|
|
157
|
-
<span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-value'">{{ getLabel(control.value) }}</span>
|
|
158
|
-
} @else {
|
|
159
|
-
@if (loading()) {
|
|
160
|
-
<span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-loading'" role="status">Loading…</span>
|
|
161
|
-
} @else {
|
|
162
|
-
<select
|
|
163
|
-
class="ngx-field__input" [attr.data-testid]="'field-' + field.id + '-input'"
|
|
164
|
-
[id]="'field-' + field.id"
|
|
165
|
-
[formControl]="$any(control)"
|
|
166
|
-
[attr.disabled]="field.disabled ? true : null"
|
|
167
|
-
>
|
|
168
|
-
<option value="">{{ placeholder || 'Select...' }}</option>
|
|
169
|
-
@for (option of options(); track option.value) {
|
|
170
|
-
<option [value]="option.value">{{ option.label }}</option>
|
|
171
|
-
}
|
|
172
|
-
</select>
|
|
173
|
-
@if (awaitingParent()) {
|
|
174
|
-
<span class="ngx-field__hint" [attr.data-testid]="'field-' + field.id + '-hint'">Select {{ parentFieldId }} first.</span>
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
@if (control.invalid && control.touched) {
|
|
178
|
-
<span class="ngx-field__error" [attr.data-testid]="'field-' + field.id + '-error'">This field has an error</span>
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
</div>
|
|
182
|
-
`,
|
|
183
|
-
}]
|
|
184
|
-
}], propDecorators: { field: [{
|
|
185
|
-
type: Input
|
|
186
|
-
}], control: [{
|
|
187
|
-
type: Input
|
|
188
|
-
}], language: [{
|
|
189
|
-
type: Input
|
|
190
|
-
}], readonly: [{
|
|
191
|
-
type: Input
|
|
192
|
-
}], masked: [{
|
|
193
|
-
type: Input
|
|
194
|
-
}] } });
|
|
195
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5LXJlZi1maWVsZC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL2ZpZWxkLXR5cGVzL2VudGl0eS1yZWYtZmllbGQuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBVSxNQUFNLEVBQUUsTUFBTSxFQUFFLHVCQUF1QixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzlHLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2hFLE9BQU8sRUFBbUIsbUJBQW1CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUV0RSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDcEQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDdEUsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sMENBQTBDLENBQUM7OztBQUVyRjs7Ozs7OztHQU9HO0FBd0NILE1BQU0sT0FBTyx1QkFBdUI7SUFDekIsS0FBSyxDQUFxQjtJQUMxQixPQUFPLENBQW1CO0lBQzFCLFFBQVEsR0FBVyxJQUFJLENBQUM7SUFDeEIsUUFBUSxHQUFZLEtBQUssQ0FBQztJQUMxQixNQUFNLEdBQVksS0FBSyxDQUFDO0lBRWhCLE9BQU8sR0FBRyxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQztJQUNyQyxZQUFZLEdBQUcsTUFBTSxDQUFDLHlCQUF5QixDQUFDLENBQUM7SUFDakQsVUFBVSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUV4QyxPQUFPLEdBQUcsTUFBTSxDQUFvQixFQUFFLENBQUMsQ0FBQztJQUN4QyxPQUFPLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2pDLHFFQUFxRTtJQUM1RCxjQUFjLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFD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Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWdDVCwyREFqQ1MsbUJBQW1COzs0RkFtQ2xCLHVCQUF1QjtrQkF2Q25DLFNBQVM7bUJBQUM7b0JBQ1QsZUFBZSxFQUFFLHVCQUF1QixDQUFDLE1BQU07b0JBQy9DLFFBQVEsRUFBRSxzQkFBc0I7b0JBQ2hDLFVBQVUsRUFBRSxJQUFJO29CQUNoQixPQUFPLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQztvQkFDOUIsUUFBUSxFQUFFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWdDVDtpQkFDRjs4QkFFVSxLQUFLO3NCQUFiLEtBQUs7Z0JBQ0csT0FBTztzQkFBZixLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIERlc3Ryb3lSZWYsIElucHV0LCBPbkluaXQsIGluamVjdCwgc2lnbmFsLCBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgdGFrZVVudGlsRGVzdHJveWVkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZS9yeGpzLWludGVyb3AnO1xuaW1wb3J0IHsgQWJzdHJhY3RDb250cm9sLCBSZWFjdGl2ZUZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHR5cGUgeyBOZXN0ZWRGaWVsZENvbmZpZywgUmVmZXJlbmNlT3B0aW9uIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgcmVzb2x2ZUxhYmVsIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgQ2FzY2FkZURhdGFTZXJ2aWNlIH0gZnJvbSAnLi4vc2VydmljZXMvY2FzY2FkZS1kYXRhLnNlcnZpY2UnO1xuaW1wb3J0IHsgRW50aXR5UmVmU2VsZWN0aW9uU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL2VudGl0eS1yZWYtc2VsZWN0aW9uLnNlcnZpY2UnO1xuXG4vKipcbiAqIEVudGl0eVJlZkZpZWxkQ29tcG9uZW50IOKAlCBhIHNlbGVjdCBwb3B1bGF0ZWQgZnJvbSBhIGNvbnN1bWVyLXJlZ2lzdGVyZWQgbG9hZGVyLlxuICpcbiAqIENhc2NhZGVzOiB3aGVuIGBlbnRpdHlSZWZlcmVuY2UucGFyZW50RmllbGRgIGlzIHNldCwgdGhlIGNvbXBvbmVudCB3YXRjaGVzIHRoYXQgc2libGluZ1xuICogY29udHJvbCAodmlhIGBjb250cm9sLnBhcmVudGApIGFuZCByZWxvYWRzIGl0cyBvd24gb3B0aW9ucyBvbiBldmVyeSBwYXJlbnQgY2hhbmdlLFxuICogY2xlYXJpbmcgYSBub3ctaW52YWxpZCBzZWxlY3Rpb24uIEl0IHB1Ymxpc2hlcyB0aGUgcGlja2VkIHJlY29yZCBvblxuICogYEVudGl0eVJlZlNlbGVjdGlvblNlcnZpY2VgIHNvIHRoZSBvd25pbmcgZm9ybSBjYW4gcnVuIGBhdXRvUGF0Y2hgLlxuICovXG5AQ29tcG9uZW50KHtcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIHNlbGVjdG9yOiAnbmd4LWVudGl0eS1yZWYtZmllbGQnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbUmVhY3RpdmVGb3Jtc01vZHVsZV0sXG4gIHRlbXBsYXRlOiBgXG4gICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZCBuZ3gtZmllbGQtLWVudGl0eS1yZWZcIlxuICAgICAgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZFwiIFthdHRyLmRhdGEtZmllbGQtdHlwZV09XCJmaWVsZC50eXBlXCIgW2NsYXNzLm5neC1maWVsZC0tcmVhZG9ubHldPVwicmVhZG9ubHlcIiBbY2xhc3Mubmd4LWZpZWxkLS1tYXNrZWRdPVwibWFza2VkXCI+XG4gICAgICA8bGFiZWwgY2xhc3M9XCJuZ3gtZmllbGRfX2xhYmVsXCIgW2F0dHIuZm9yXT1cIidmaWVsZC0nICsgZmllbGQuaWRcIj57eyBsYWJlbCB9fTwvbGFiZWw+XG4gICAgICBAaWYgKG1hc2tlZCkge1xuICAgICAgICA8c3BhbiBjbGFzcz1cIm5neC1maWVsZF9fdmFsdWUgbmd4LWZpZWxkX192YWx1ZS0tbWFza2VkXCIgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZCArICctbWFza2VkJ1wiPlhYWFhYWFhYWDwvc3Bhbj5cbiAgICAgIH0gQGVsc2UgaWYgKHJlYWRvbmx5KSB7XG4gICAgICAgIDxzcGFuIGNsYXNzPVwibmd4LWZpZWxkX192YWx1ZVwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLXZhbHVlJ1wiPnt7IGdldExhYmVsKGNvbnRyb2wudmFsdWUpIH19PC9zcGFuPlxuICAgICAgfSBAZWxzZSB7XG4gICAgICAgIEBpZiAobG9hZGluZygpKSB7XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX3ZhbHVlXCIgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZCArICctbG9hZGluZydcIiByb2xlPVwic3RhdHVzXCI+TG9hZGluZ+KApjwvc3Bhbj5cbiAgICAgICAgfSBAZWxzZSB7XG4gICAgICAgICAgPHNlbGVjdFxuICAgICAgICAgICAgY2xhc3M9XCJuZ3gtZmllbGRfX2lucHV0XCIgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZCArICctaW5wdXQnXCJcbiAgICAgICAgICAgIFtpZF09XCInZmllbGQtJyArIGZpZWxkLmlkXCJcbiAgICAgICAgICAgIFtmb3JtQ29udHJvbF09XCIkYW55KGNvbnRyb2wpXCJcbiAgICAgICAgICAgIFthdHRyLmRpc2FibGVkXT1cImZpZWxkLmRpc2FibGVkID8gdHJ1ZSA6IG51bGxcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxvcHRpb24gdmFsdWU9XCJcIj57eyBwbGFjZWhvbGRlciB8fCAnU2VsZWN0Li4uJyB9fTwvb3B0aW9uPlxuICAgICAgICAgICAgQGZvciAob3B0aW9uIG9mIG9wdGlvbnMoKTsgdHJhY2sgb3B0aW9uLnZhbHVlKSB7XG4gICAgICAgICAgICAgIDxvcHRpb24gW3ZhbHVlXT1cIm9wdGlvbi52YWx1ZVwiPnt7IG9wdGlvbi5sYWJlbCB9fTwvb3B0aW9uPlxuICAgICAgICAgICAgfVxuICAgICAgICAgIDwvc2VsZWN0PlxuICAgICAgICAgIEBpZiAoYXdhaXRpbmdQYXJlbnQoKSkge1xuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX2hpbnRcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy1oaW50J1wiPlNlbGVjdCB7eyBwYXJlbnRGaWVsZElkIH19IGZpcnN0Ljwvc3Bhbj5cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgQGlmIChjb250cm9sLmludmFsaWQgJiYgY29udHJvbC50b3VjaGVkKSB7XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX2Vycm9yXCIgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZCArICctZXJyb3InXCI+VGhpcyBmaWVsZCBoYXMgYW4gZXJyb3I8L3NwYW4+XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICA8L2Rpdj5cbiAgYCxcbn0pXG5leHBvcnQgY2xhc3MgRW50aXR5UmVmRmllbGRDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xuICBASW5wdXQoKSBmaWVsZCE6IE5lc3RlZEZpZWxkQ29uZmlnO1xuICBASW5wdXQoKSBjb250cm9sITogQWJzdHJhY3RDb250cm9sO1xuICBASW5wdXQoKSBsYW5ndWFnZTogc3RyaW5nID0gJ2VuJztcbiAgQElucHV0KCkgcmVhZG9ubHk6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgbWFza2VkOiBib29sZWFuID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBjYXNjYWRlID0gaW5qZWN0KENhc2NhZGVEYXRhU2VydmljZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgc2VsZWN0aW9uQnVzID0gaW5qZWN0KEVudGl0eVJlZlNlbGVjdGlvblNlcnZpY2UpO1xuICBwcml2YXRlIHJlYWRvbmx5IGRlc3Ryb3lSZWYgPSBpbmplY3QoRGVzdHJveVJlZik7XG5cbiAgcmVhZG9ubHkgb3B0aW9ucyA9IHNpZ25hbDxSZWZlcmVuY2VPcHRpb25bXT4oW10pO1xuICByZWFkb25seSBsb2FkaW5nID0gc2lnbmFsKGZhbHNlKTtcbiAgLyoqIFRydWUgd2hlbiB0aGlzIGZpZWxkIGNhc2NhZGVzIGJ1dCBpdHMgcGFyZW50IGhhcyBubyB2YWx1ZSB5ZXQuICovXG4gIHJlYWRvbmx5IGF3YWl0aW5nUGFyZW50ID0gc2lnbmFsKGZhbHNlKTtcblxuICBnZXQgbGFiZWwoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gcmVzb2x2ZUxhYmVsKHRoaXMuZmllbGQ/LmxhYmVsLCB0aGlzLmxhbmd1YWdlKTtcbiAgfVxuXG4gIGdldCBwbGFjZWhvbGRlcigpOiBzdHJpbmcge1xuICAgIHJldHVybiByZXNvbHZlTGFiZWwodGhpcy5maWVsZD8ucGxhY2Vob2xkZXIsIHRoaXMubGFuZ3VhZ2UpO1xuICB9XG5cbiAgZ2V0IHBhcmVudEZpZWxkSWQoKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5maWVsZD8uZW50aXR5UmVmZXJlbmNlPy5wYXJlbnRGaWVsZDtcbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIGlmICh0aGlzLm1hc2tlZCkgcmV0dXJuO1xuICAgIHZvaWQgdGhpcy5yZWxvYWQoKTtcbiAgICB0aGlzLndhdGNoUGFyZW50KCk7XG4gICAgdGhpcy5jb250cm9sPy52YWx1ZUNoYW5nZXNcbiAgICAgIC5waXBlKHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLmRlc3Ryb3lSZWYpKVxuICAgICAgLnN1YnNjcmliZSh2YWx1ZSA9PiB0aGlzLnB1Ymxpc2hTZWxlY3Rpb24oU3RyaW5nKHZhbHVlID8/ICcnKSkpO1xuICB9XG5cbiAgLyoqIFJlbG9hZCBvcHRpb25zIGFnYWluc3QgdGhlIHBhcmVudCdzIGN1cnJlbnQgdmFsdWUuICovXG4gIGFzeW5jIHJlbG9hZCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBwYXJlbnRWYWx1ZSA9IHRoaXMucGFyZW50VmFsdWUoKTtcbiAgICB0aGlzLmF3YWl0aW5nUGFyZW50LnNldChcbiAgICAgICEhdGhpcy5wYXJlbnRGaWVsZElkICYmIChwYXJlbnRWYWx1ZSA9PT0gbnVsbCB8fCBwYXJlbnRWYWx1ZSA9PT0gdW5kZWZpbmVkIHx8IHBhcmVudFZhbHVlID09PSAnJyksXG4gICAgKTtcblxuICAgIGlmICghdGhpcy5jYXNjYWRlLmNhbkxvYWQodGhpcy5maWVsZCkpIHtcbiAgICAgIHRoaXMub3B0aW9ucy5zZXQoW10pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMubG9hZGluZy5zZXQodHJ1ZSk7XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMub3B0aW9ucy5zZXQoXG4gICAgICAgIGF3YWl0IHRoaXMuY2FzY2FkZS5sb2FkKHRoaXMuZmllbGQsIHsgcGFyZW50VmFsdWUsIGxhbmc6IHRoaXMubGFuZ3VhZ2UgfSksXG4gICAgICApO1xuICAgIH0gZmluYWxseSB7XG4gICAgICB0aGlzLmxvYWRpbmcuc2V0KGZhbHNlKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUHVibGlzaCB0aGUgc2VsZWN0ZWQgb3B0aW9uIHNvIGF1dG9QYXRjaCBjYW4gY29weSBmcm9tIGl0cyByZWNvcmQuXG4gICAqXG4gICAqIERyaXZlbiBmcm9tIGB2YWx1ZUNoYW5nZXNgIHJhdGhlciB0aGFuIHRoZSBzZWxlY3QncyBgY2hhbmdlYCBldmVudDogdGhhdCBldmVudCBpcyB0aGVcbiAgICogc2FtZSBvbmUgdGhlIGBmb3JtQ29udHJvbGAgZGlyZWN0aXZlIGxpc3RlbnMgdG8sIHNvIHJlYWRpbmcgdGhlIGNvbnRyb2wgaW5zaWRlIGFcbiAgICogdGVtcGxhdGUgYChjaGFuZ2UpYCBoYW5kbGVyIGNhbiBzZWUgdGhlIHByZXZpb3VzIHZhbHVlLiBgdmFsdWVDaGFuZ2VzYCBmaXJlcyBhZnRlciB0aGVcbiAgICogbW9kZWwgaGFzIHVwZGF0ZWQg4oCUIGluY2x1ZGluZyBQbGF5d3JpZ2h0IGBzZWxlY3RPcHRpb25gLCB3aGljaCB1cGRhdGVzIHRoZSBjb250cm9sXG4gICAqIHRocm91Z2ggdGhlIHZhbHVlIGFjY2Vzc29yLlxuICAgKi9cbiAgb25TZWxlY3Rpb25DaGFuZ2UodmFsdWU/OiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLnB1Ymxpc2hTZWxlY3Rpb24odmFsdWUgPz8gU3RyaW5nKHRoaXMuY29udHJvbD8udmFsdWUgPz8gJycpKTtcbiAgfVxuXG4gIHByaXZhdGUgcHVibGlzaFNlbGVjdGlvbihjdXJyZW50OiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBzZWxlY3RlZCA9IHRoaXMub3B0aW9ucygpLmZpbmQobyA9PiBTdHJpbmcoby52YWx1ZSkgPT09IGN1cnJlbnQpO1xuICAgIHRoaXMuc2VsZWN0aW9uQnVzLmVtaXQodGhpcy5maWVsZC5pZCwgc2VsZWN0ZWQgPz8gbnVsbCk7XG4gIH1cblxuICBnZXRMYWJlbCh2YWx1ZTogYW55KTogc3RyaW5nIHtcbiAgICBjb25zdCBvcHRpb24gPSB0aGlzLm9wdGlvbnMoKS5maW5kKG8gPT4gU3RyaW5nKG8udmFsdWUpID09PSBTdHJpbmcodmFsdWUpKTtcbiAgICByZXR1cm4gb3B0aW9uPy5sYWJlbCA/PyAodmFsdWUgPz8gJ+KAlCcpO1xuICB9XG5cbiAgcHJpdmF0ZSBwYXJlbnRWYWx1ZSgpOiB1bmtub3duIHtcbiAgICBjb25zdCBwYXJlbnRJZCA9IHRoaXMucGFyZW50RmllbGRJZDtcbiAgICBpZiAoIXBhcmVudElkKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIHJldHVybiB0aGlzLmNvbnRyb2w/LnBhcmVudD8uZ2V0KHBhcmVudElkKT8udmFsdWU7XG4gIH1cblxuICAvKiogUmVsb2FkIChhbmQgZHJvcCBhIHN0YWxlIHNlbGVjdGlvbikgd2hlbmV2ZXIgdGhlIHBhcmVudCBjb250cm9sIGNoYW5nZXMuICovXG4gIHByaXZhdGUgd2F0Y2hQYXJlbnQoKTogdm9pZCB7XG4gICAgY29uc3QgcGFyZW50SWQgPSB0aGlzLnBhcmVudEZpZWxkSWQ7XG4gICAgaWYgKCFwYXJlbnRJZCkgcmV0dXJuO1xuICAgIGNvbnN0IHBhcmVudENvbnRyb2wgPSB0aGlzLmNvbnRyb2w/LnBhcmVudD8uZ2V0KHBhcmVudElkKTtcbiAgICBpZiAoIXBhcmVudENvbnRyb2wpIHJldHVybjtcblxuICAgIHBhcmVudENvbnRyb2wudmFsdWVDaGFuZ2VzXG4gICAgICAucGlwZSh0YWtlVW50aWxEZXN0cm95ZWQodGhpcy5kZXN0cm95UmVmKSlcbiAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgICBpZiAodGhpcy5jb250cm9sLnZhbHVlKSB7XG4gICAgICAgICAgdGhpcy5jb250cm9sLnNldFZhbHVlKCcnLCB7IGVtaXRFdmVudDogZmFsc2UgfSk7XG4gICAgICAgICAgdGhpcy5zZWxlY3Rpb25CdXMuZW1pdCh0aGlzLmZpZWxkLmlkLCBudWxsKTtcbiAgICAgICAgfVxuICAgICAgICB2b2lkIHRoaXMucmVsb2FkKCk7XG4gICAgICB9KTtcbiAgfVxufVxuIl19
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
export {};
|
|
2
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmllbGQtY29tcG9uZW50LmNvbnRyYWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9maWVsZC10eXBlcy9maWVsZC1jb21wb25lbnQuY29udHJhY3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgQWJzdHJhY3RDb250cm9sIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHR5cGUgeyBOZXN0ZWRGaWVsZENvbmZpZyB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcblxuLyoqXG4gKiBXaGF0IGEgZmllbGQgY29tcG9uZW50IG11c3QgYWNjZXB0IHRvIGJlIHJlZ2lzdGVyZWQgd2l0aCBgcHJvdmlkZUZpZWxkVHlwZXNgLlxuICpcbiAqIFRoZSByZW5kZXJlciBpbnN0YW50aWF0ZXMgYSBmaWVsZCBjb21wb25lbnQgZHluYW1pY2FsbHkgYW5kIGFzc2lnbnMgZXhhY3RseSB0aGVzZSBmaXZlXG4gKiBpbnB1dHMg4oCUIG5vIG1vcmUsIG5vIGxlc3Mg4oCUIHNvIGFueSBjb21wb25lbnQgc2F0aXNmeWluZyB0aGlzIGludGVyZmFjZSBjYW4gc3RhbmQgaW4gZm9yIGFcbiAqIGJ1aWx0LWluIHR5cGUgb3IgYWRkIGEgbmV3IG9uZS5cbiAqXG4gKiBJbXBsZW1lbnQgaXQgZXhwbGljaXRseSBhbmQgVHlwZVNjcmlwdCB3aWxsIHRlbGwgeW91IHdoZW4geW91IGhhdmUgbWlzc2VkIG9uZTpcbiAqXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBAQ29tcG9uZW50KHtcbiAqICAgc2VsZWN0b3I6ICdhcHAtc2lnbmF0dXJlLWZpZWxkJyxcbiAqICAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAqICAgdGVtcGxhdGU6IGA8Y2FudmFzIFthdHRyLmFyaWEtbGFiZWxdPVwiZmllbGQuaWRcIj48L2NhbnZhcz5gLFxuICogfSlcbiAqIGV4cG9ydCBjbGFzcyBTaWduYXR1cmVGaWVsZENvbXBvbmVudCBpbXBsZW1lbnRzIER5bmFtaWNGaWVsZENvbXBvbmVudENvbnRyYWN0IHtcbiAqICAgQElucHV0KCkgZmllbGQhOiBOZXN0ZWRGaWVsZENvbmZpZztcbiAqICAgQElucHV0KCkgY29udHJvbCE6IEFic3RyYWN0Q29udHJvbDtcbiAqICAgQElucHV0KCkgbGFuZ3VhZ2UgPSAnZW4nO1xuICogICBASW5wdXQoKSByZWFkb25seSA9IGZhbHNlO1xuICogICBASW5wdXQoKSBtYXNrZWQgPSBmYWxzZTtcbiAqIH1cbiAqXG4gKiBwcm92aWRlRmllbGRUeXBlcyh7IHNpZ25hdHVyZTogU2lnbmF0dXJlRmllbGRDb21wb25lbnQgfSk7XG4gKiBgYGBcbiAqXG4gKiBUd28gaW1wbGVtZW50YXRpb24gbm90ZXMgdGhhdCBhcmUgZWFzeSB0byBnZXQgd3Jvbmc6XG4gKlxuICogLSBEZWNsYXJlIHRoZSBpbnB1dHMgd2l0aCBkZWZpbml0ZSBhc3NpZ25tZW50IChgZmllbGQhOiDigKZgKSBvciBhbiBpbml0aWFsaXNlci4gVGhlXG4gKiAgIHJlbmRlcmVyIHNldHMgdGhlbSB0aHJvdWdoIGBDb21wb25lbnRSZWYuc2V0SW5wdXQoKWAgYWZ0ZXIgY29uc3RydWN0aW9uLCBzbyB0aGV5IGFyZVxuICogICBnZW51aW5lbHkgdW5kZWZpbmVkIHVudGlsIHRoZSBmaXJzdCBhc3NpZ25tZW50LlxuICogLSBgbWFza2VkYCBtZWFucyB0aGUgdmFsdWUgbXVzdCBub3QgYmUgZGlzcGxheWVkLiBSZW5kZXIgYSBwbGFjZWhvbGRlciByYXRoZXIgdGhhbiB0aGVcbiAqICAgY29udHJvbCdzIHZhbHVlLiBUaGlzIGlzIHByZXNlbnRhdGlvbmFsOiB0aGUgcmVhbCB2YWx1ZSBzdGF5cyBpbiB0aGUgY29udHJvbCBhbmQgaXNcbiAqICAgaW5jbHVkZWQgaW4gdGhlIHN1Ym1pdHRlZCByZWNvcmQsIHNvIGl0IGlzIG5vdCBhbiBhY2Nlc3MtY29udHJvbCBib3VuZGFyeS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEeW5hbWljRmllbGRDb21wb25lbnRDb250cmFjdCB7XG4gIC8qKiBUaGUgZmllbGQncyBzY2hlbWEgZW50cnk6IGlkLCB0eXBlLCBsYWJlbCwgdmFsaWRhdG9ycywgb3B0aW9ucywgYW5kIHNvIG9uLiAqL1xuICBmaWVsZDogTmVzdGVkRmllbGRDb25maWc7XG5cbiAgLyoqIFRoZSByZWFjdGl2ZSBjb250cm9sIGJhY2tpbmcgdGhpcyBmaWVsZC4gQSBgRm9ybUdyb3VwYCBmb3IgYGdyb3VwYCwgYEZvcm1BcnJheWAgZm9yIGBhcnJheWAuICovXG4gIGNvbnRyb2w6IEFic3RyYWN0Q29udHJvbDtcblxuICAvKiogQWN0aXZlIGxhbmd1YWdlLCBmb3IgcmVzb2x2aW5nIGBMb2NhbGl6ZWRUZXh0YCBsYWJlbHMsIHBsYWNlaG9sZGVycyBhbmQgb3B0aW9ucy4gKi9cbiAgbGFuZ3VhZ2U6IHN0cmluZztcblxuICAvKiogUmVuZGVyIHRoZSB2YWx1ZSBhcyB0ZXh0IHJhdGhlciB0aGFuIGFuIGVkaXRhYmxlIGNvbnRyb2wuICovXG4gIHJlYWRvbmx5OiBib29sZWFuO1xuXG4gIC8qKiBIaWRlIHRoZSB2YWx1ZSBmcm9tIGRpc3BsYXkuIFNlZSB0aGUgbm90ZSBhYm92ZSDigJQgcHJlc2VudGF0aW9uYWwgb25seS4gKi9cbiAgbWFza2VkOiBib29sZWFuO1xufVxuIl19
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { Component, inject, Input, signal, ChangeDetectionStrategy } 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, changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
94
|
-
}
|
|
95
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FileFieldComponent, decorators: [{
|
|
96
|
-
type: Component,
|
|
97
|
-
args: [{
|
|
98
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
99
|
-
selector: 'ngx-file-field',
|
|
100
|
-
standalone: true,
|
|
101
|
-
imports: [],
|
|
102
|
-
template: `
|
|
103
|
-
<div class="ngx-field ngx-field--file"
|
|
104
|
-
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
105
|
-
<label class="ngx-field__label" [attr.for]="'field-' + field.id">{{ label }}</label>
|
|
106
|
-
@if (masked) {
|
|
107
|
-
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
108
|
-
} @else if (readonly) {
|
|
109
|
-
@if (fileUrl()) {
|
|
110
|
-
<a class="ngx-field__file-link" [href]="fileUrl()!" target="_blank" rel="noopener">
|
|
111
|
-
📎 {{ fileName() || 'Download file' }}
|
|
112
|
-
</a>
|
|
113
|
-
} @else {
|
|
114
|
-
<span class="ngx-field__value" [attr.data-testid]="'field-' + field.id + '-value'">—</span>
|
|
115
|
-
}
|
|
116
|
-
} @else {
|
|
117
|
-
<div class="ngx-field__file-wrap">
|
|
118
|
-
@if (fileName()) {
|
|
119
|
-
<div class="ngx-field__file-selected">
|
|
120
|
-
<span class="ngx-field__file-name">📎 {{ fileName() }}</span>
|
|
121
|
-
<button type="button" class="ngx-field__remove-btn" (click)="remove()" aria-label="Remove file">✕</button>
|
|
122
|
-
</div>
|
|
123
|
-
}
|
|
124
|
-
<label class="ngx-field__upload-btn" [class.ngx-field__upload-btn--loading]="uploading()">
|
|
125
|
-
@if (uploading()) {
|
|
126
|
-
<span>Uploading…</span>
|
|
127
|
-
} @else {
|
|
128
|
-
<span>{{ fileName() ? 'Replace file' : 'Choose file' }}</span>
|
|
129
|
-
<input
|
|
130
|
-
type="file"
|
|
131
|
-
class="ngx-field__file-input"
|
|
132
|
-
[id]="'field-' + field.id"
|
|
133
|
-
[disabled]="field.disabled || uploading()"
|
|
134
|
-
(change)="onFileSelect($any($event.target).files[0])"
|
|
135
|
-
/>
|
|
136
|
-
}
|
|
137
|
-
</label>
|
|
138
|
-
</div>
|
|
139
|
-
@if (uploadError()) {
|
|
140
|
-
<span class="ngx-field__error" [attr.data-testid]="'field-' + field.id + '-error'">{{ uploadError() }}</span>
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
</div>
|
|
144
|
-
`,
|
|
145
|
-
}]
|
|
146
|
-
}], propDecorators: { field: [{
|
|
147
|
-
type: Input
|
|
148
|
-
}], control: [{
|
|
149
|
-
type: Input
|
|
150
|
-
}], language: [{
|
|
151
|
-
type: Input
|
|
152
|
-
}], readonly: [{
|
|
153
|
-
type: Input
|
|
154
|
-
}], masked: [{
|
|
155
|
-
type: Input
|
|
156
|
-
}] } });
|
|
157
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZS1maWVsZC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL2ZpZWxkLXR5cGVzL2ZpbGUtZmllbGQuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFHMUYsT0FBTyxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNqRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQzs7QUFFcEU7OztHQUdHO0FBa0RILE1BQU0sT0FBTyxrQkFBa0I7SUFDcEIsS0FBSyxDQUFxQjtJQUMxQixPQUFPLENBQW1CO0lBQzFCLFFBQVEsR0FBVyxJQUFJLENBQUM7SUFDeEIsUUFBUSxHQUFZLEtBQUssQ0FBQztJQUMxQixNQUFNLEdBQVksS0FBSyxDQUFDO0lBRWhCLE9BQU8sR0FBRyxNQUFNLENBQUMsaUJBQWlCLENBQUMsQ0FBQztJQUU1QyxTQUFTLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzFCLFdBQVcsR0FBRyxNQUFNLENBQWdCLElBQUksQ0FBQyxDQUFDO0lBRW5ELElBQUksS0FBSztRQUNQLE9BQU8sWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRUQsSUFBWSxLQUFLO1FBQ2YsT0FBUSxJQUFJLENBQUMsT0FBTyxFQUFFLEtBQXdCLElBQUksSUFBSSxDQUFDO0lBQ3pELENBQUM7SUFFRCxPQUFPO1FBQ0wsT0FBTyxJQUFJLENBQUMsS0FBSyxFQUFFLEdBQUcsSUFBSSxJQUFJLENBQUM7SUFDakMsQ0FBQztJQUVELFFBQVE7UUFDTixPQUFPLFdBQVcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksSUFBSSxDQUFDO0lBQ3pDLENBQUM7SUFFRCxLQUFLLENBQUMsWUFBWSxDQUFDLElBQXNCO1FBQ3ZDLElBQUksQ0FBQyxJQUFJO1lBQUUsT0FBTztRQUNsQixJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMzQixJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN6QixJQUFJLENBQUM7WUFDSCxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7WUFDMUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUMvQixDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsa0NBQWtDLENBQUMsQ0FBQztRQUMzRCxDQUFDO2dCQUFTLENBQUM7WUFDVCxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM1QixDQUFDO0lBQ0gsQ0FBQztJQUVELE1BQU07UUFDSixJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM1QixJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBQy9CLENBQUM7d0dBN0NVLGtCQUFrQjs0RkFBbEIsa0JBQWtCLHdMQTVDbkI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTBDVDs7NEZBRVUsa0JBQWtCO2tCQWpEOUIsU0FBUzttQkFBQztvQkFDVCxlQUFlLEVBQUUsdUJBQXVCLENBQUMsTUFBTTtvQkFDL0MsUUFBUSxFQUFFLGdCQUFnQjtvQkFDMUIsVUFBVSxFQUFFLElBQUk7b0JBQ2hCLE9BQU8sRUFBRSxFQUFFO29CQUNYLFFBQVEsRUFBRTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBMENUO2lCQUNGOzhCQUVVLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLE1BQU07c0JBQWQsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgaW5qZWN0LCBJbnB1dCwgc2lnbmFsLCBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQWJzdHJhY3RDb250cm9sIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHR5cGUgeyBGaWxlUmVmLCBOZXN0ZWRGaWVsZENvbmZpZyB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcbmltcG9ydCB7IGZpbGVSZWZOYW1lLCByZXNvbHZlTGFiZWwgfSBmcm9tICdAZHluYW1pYy1lbnRpdHkvY29yZSc7XG5pbXBvcnQgeyBGaWxlVXBsb2FkU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL2ZpbGUtdXBsb2FkLnNlcnZpY2UnO1xuXG4vKipcbiAqIEZpbGUgZmllbGQ6IGZpbGUgaW5wdXQgd2l0aCBmaWxlbmFtZSBkaXNwbGF5IGFuZCBkb3dubG9hZCBsaW5rLlxuICogU2hhcmVzIHRoZSBgRmlsZVJlZmAgLyBgVVBMT0FEX0hBTkRMRVJgIGNvbnRyYWN0IHdpdGggaW1hZ2UtZmllbGQgdmlhIEZpbGVVcGxvYWRTZXJ2aWNlLlxuICovXG5AQ29tcG9uZW50KHtcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gIHNlbGVjdG9yOiAnbmd4LWZpbGUtZmllbGQnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbXSxcbiAgdGVtcGxhdGU6IGBcbiAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkIG5neC1maWVsZC0tZmlsZVwiXG4gICAgICBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkXCIgW2F0dHIuZGF0YS1maWVsZC10eXBlXT1cImZpZWxkLnR5cGVcIiBbY2xhc3Mubmd4LWZpZWxkLS1yZWFkb25seV09XCJyZWFkb25seVwiIFtjbGFzcy5uZ3gtZmllbGQtLW1hc2tlZF09XCJtYXNrZWRcIj5cbiAgICAgIDxsYWJlbCBjbGFzcz1cIm5neC1maWVsZF9fbGFiZWxcIiBbYXR0ci5mb3JdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZFwiPnt7IGxhYmVsIH19PC9sYWJlbD5cbiAgICAgIEBpZiAobWFza2VkKSB7XG4gICAgICAgIDxzcGFuIGNsYXNzPVwibmd4LWZpZWxkX192YWx1ZSBuZ3gtZmllbGRfX3ZhbHVlLS1tYXNrZWRcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy1tYXNrZWQnXCI+WFhYWFhYWFhYPC9zcGFuPlxuICAgICAgfSBAZWxzZSBpZiAocmVhZG9ubHkpIHtcbiAgICAgICAgQGlmIChmaWxlVXJsKCkpIHtcbiAgICAgICAgICA8YSBjbGFzcz1cIm5neC1maWVsZF9fZmlsZS1saW5rXCIgW2hyZWZdPVwiZmlsZVVybCgpIVwiIHRhcmdldD1cIl9ibGFua1wiIHJlbD1cIm5vb3BlbmVyXCI+XG4gICAgICAgICAgICDwn5OOIHt7IGZpbGVOYW1lKCkgfHwgJ0Rvd25sb2FkIGZpbGUnIH19XG4gICAgICAgICAgPC9hPlxuICAgICAgICB9IEBlbHNlIHtcbiAgICAgICAgICA8c3BhbiBjbGFzcz1cIm5neC1maWVsZF9fdmFsdWVcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy12YWx1ZSdcIj7igJQ8L3NwYW4+XG4gICAgICAgIH1cbiAgICAgIH0gQGVsc2Uge1xuICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19maWxlLXdyYXBcIj5cbiAgICAgICAgICBAaWYgKGZpbGVOYW1lKCkpIHtcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJuZ3gtZmllbGRfX2ZpbGUtc2VsZWN0ZWRcIj5cbiAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX2ZpbGUtbmFtZVwiPvCfk44ge3sgZmlsZU5hbWUoKSB9fTwvc3Bhbj5cbiAgICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJuZ3gtZmllbGRfX3JlbW92ZS1idG5cIiAoY2xpY2spPVwicmVtb3ZlKClcIiBhcmlhLWxhYmVsPVwiUmVtb3ZlIGZpbGVcIj7inJU8L2J1dHRvbj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgIH1cbiAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJuZ3gtZmllbGRfX3VwbG9hZC1idG5cIiBbY2xhc3Mubmd4LWZpZWxkX191cGxvYWQtYnRuLS1sb2FkaW5nXT1cInVwbG9hZGluZygpXCI+XG4gICAgICAgICAgICBAaWYgKHVwbG9hZGluZygpKSB7XG4gICAgICAgICAgICAgIDxzcGFuPlVwbG9hZGluZ+KApjwvc3Bhbj5cbiAgICAgICAgICAgIH0gQGVsc2Uge1xuICAgICAgICAgICAgICA8c3Bhbj57eyBmaWxlTmFtZSgpID8gJ1JlcGxhY2UgZmlsZScgOiAnQ2hvb3NlIGZpbGUnIH19PC9zcGFuPlxuICAgICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgICB0eXBlPVwiZmlsZVwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJuZ3gtZmllbGRfX2ZpbGUtaW5wdXRcIlxuICAgICAgICAgICAgICAgIFtpZF09XCInZmllbGQtJyArIGZpZWxkLmlkXCJcbiAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwiZmllbGQuZGlzYWJsZWQgfHwgdXBsb2FkaW5nKClcIlxuICAgICAgICAgICAgICAgIChjaGFuZ2UpPVwib25GaWxlU2VsZWN0KCRhbnkoJGV2ZW50LnRhcmdldCkuZmlsZXNbMF0pXCJcbiAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgQGlmICh1cGxvYWRFcnJvcigpKSB7XG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX2Vycm9yXCIgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZCArICctZXJyb3InXCI+e3sgdXBsb2FkRXJyb3IoKSB9fTwvc3Bhbj5cbiAgICAgICAgfVxuICAgICAgfVxuICAgIDwvZGl2PlxuICBgLFxufSlcbmV4cG9ydCBjbGFzcyBGaWxlRmllbGRDb21wb25lbnQge1xuICBASW5wdXQoKSBmaWVsZCE6IE5lc3RlZEZpZWxkQ29uZmlnO1xuICBASW5wdXQoKSBjb250cm9sITogQWJzdHJhY3RDb250cm9sO1xuICBASW5wdXQoKSBsYW5ndWFnZTogc3RyaW5nID0gJ2VuJztcbiAgQElucHV0KCkgcmVhZG9ubHk6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgbWFza2VkOiBib29sZWFuID0gZmFsc2U7XG5cbiAgcHJpdmF0ZSByZWFkb25seSB1cGxvYWRzID0gaW5qZWN0KEZpbGVVcGxvYWRTZXJ2aWNlKTtcblxuICByZWFkb25seSB1cGxvYWRpbmcgPSBzaWduYWwoZmFsc2UpO1xuICByZWFkb25seSB1cGxvYWRFcnJvciA9IHNpZ25hbDxzdHJpbmcgfCBudWxsPihudWxsKTtcblxuICBnZXQgbGFiZWwoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gcmVzb2x2ZUxhYmVsKHRoaXMuZmllbGQ/LmxhYmVsLCB0aGlzLmxhbmd1YWdlKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0IHZhbHVlKCk6IEZpbGVSZWYgfCBudWxsIHtcbiAgICByZXR1cm4gKHRoaXMuY29udHJvbD8udmFsdWUgYXMgRmlsZVJlZiB8IG51bGwpID8/IG51bGw7XG4gIH1cblxuICBmaWxlVXJsKCk6IHN0cmluZyB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLnZhbHVlPy51cmwgPz8gbnVsbDtcbiAgfVxuXG4gIGZpbGVOYW1lKCk6IHN0cmluZyB8IG51bGwge1xuICAgIHJldHVybiBmaWxlUmVmTmFtZSh0aGlzLnZhbHVlKSB8fCBudWxsO1xuICB9XG5cbiAgYXN5bmMgb25GaWxlU2VsZWN0KGZpbGU6IEZpbGUgfCB1bmRlZmluZWQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBpZiAoIWZpbGUpIHJldHVybjtcbiAgICB0aGlzLnVwbG9hZEVycm9yLnNldChudWxsKTtcbiAgICB0aGlzLnVwbG9hZGluZy5zZXQodHJ1ZSk7XG4gICAgdHJ5IHtcbiAgICAgIHRoaXMuY29udHJvbC5zZXRWYWx1ZShhd2FpdCB0aGlzLnVwbG9hZHMudG9GaWxlUmVmKGZpbGUpKTtcbiAgICAgIHRoaXMuY29udHJvbC5tYXJrQXNUb3VjaGVkKCk7XG4gICAgfSBjYXRjaCB7XG4gICAgICB0aGlzLnVwbG9hZEVycm9yLnNldCgnVXBsb2FkIGZhaWxlZC4gUGxlYXNlIHRyeSBhZ2Fpbi4nKTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy51cGxvYWRpbmcuc2V0KGZhbHNlKTtcbiAgICB9XG4gIH1cblxuICByZW1vdmUoKTogdm9pZCB7XG4gICAgdGhpcy5jb250cm9sLnNldFZhbHVlKG51bGwpO1xuICAgIHRoaXMuY29udHJvbC5tYXJrQXNUb3VjaGVkKCk7XG4gIH1cbn1cbiJdfQ==
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import { Component, Input, forwardRef, ChangeDetectionStrategy } 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
|
-
/** Renders a nested fieldset container for a group field's 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
47
|
-
}
|
|
48
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: GroupFieldComponent, decorators: [{
|
|
49
|
-
type: Component,
|
|
50
|
-
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JvdXAtZmllbGQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9maWVsZC10eXBlcy9ncm91cC1maWVsZC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLHVCQUF1QixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3RGLE9BQU8sRUFBOEIsbUJBQW1CLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUVqRixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDcEQsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sK0NBQStDLENBQUM7O0FBRXRGLHdFQUF3RTtBQXFEeEUsTUFBTSxPQUFPLG1CQUFtQjtJQUNyQixLQUFLLENBQXFCO0lBQzFCLE9BQU8sQ0FBbUI7SUFDMUIsTUFBTSxDQUFvQjtJQUMxQixRQUFRLEdBQVcsSUFBSSxDQUFDO0lBQ3hCLFFBQVEsR0FBWSxLQUFLLENBQUM7SUFDMUIsTUFBTSxHQUFZLEtBQUssQ0FBQztJQUN4QixTQUFTLEdBQWEsRUFBRSxDQUFDO0lBRWxDLElBQUksS0FBSztRQUNQLE9BQU8sWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRUQsZUFBZSxDQUFDLE9BQWU7UUFDN0IsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE9BQW9CLENBQUM7UUFDeEMsT0FBTyxLQUFLLEVBQUUsR0FBRyxDQUFDLE9BQU8sQ0FBb0IsQ0FBQztJQUNoRCxDQUFDO3dHQWhCVSxtQkFBbUI7NEZBQW5CLG1CQUFtQixtT0EvQ3BCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXVCVCxvV0F4QlMsbUJBQW1CLG9EQUFtQixxQkFBcUI7OzRGQWdEMUQsbUJBQW1CO2tCQXBEL0IsU0FBUztzQ0FDUyx1QkFBdUIsQ0FBQyxNQUFNLFlBQ3JDLGlCQUFpQixjQUNmLElBQUksV0FDUCxDQUFDLG1CQUFtQixFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLFlBQzdEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXVCVDs4QkF5QlEsS0FBSztzQkFBYixLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLE1BQU07c0JBQWQsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBJbnB1dCwgZm9yd2FyZFJlZiwgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFic3RyYWN0Q29udHJvbCwgRm9ybUdyb3VwLCBSZWFjdGl2ZUZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHR5cGUgeyBOZXN0ZWRGaWVsZENvbmZpZywgRW50aXR5Rm9ybUNvbmZpZyB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcbmltcG9ydCB7IHJlc29sdmVMYWJlbCB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcbmltcG9ydCB7IER5bmFtaWNGaWVsZENvbXBvbmVudCB9IGZyb20gJy4uL2Zvcm0vZHluYW1pYy1maWVsZC9keW5hbWljLWZpZWxkLmNvbXBvbmVudCc7XG5cbi8qKiBSZW5kZXJzIGEgbmVzdGVkIGZpZWxkc2V0IGNvbnRhaW5lciBmb3IgYSBncm91cCBmaWVsZCdzIGNoaWxkcmVuLiAqL1xuQENvbXBvbmVudCh7XG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBzZWxlY3RvcjogJ25neC1ncm91cC1maWVsZCcsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtSZWFjdGl2ZUZvcm1zTW9kdWxlLCBmb3J3YXJkUmVmKCgpID0+IER5bmFtaWNGaWVsZENvbXBvbmVudCldLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxmaWVsZHNldCBjbGFzcz1cIm5neC1maWVsZCBuZ3gtZmllbGQtLWdyb3VwXCJcbiAgICAgIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWRcIiBbYXR0ci5kYXRhLWZpZWxkLXR5cGVdPVwiZmllbGQudHlwZVwiIFtjbGFzcy5uZ3gtZmllbGQtLXJlYWRvbmx5XT1cInJlYWRvbmx5XCIgW2NsYXNzLm5neC1maWVsZC0tbWFza2VkXT1cIm1hc2tlZFwiPlxuICAgICAgPGxlZ2VuZCBjbGFzcz1cIm5neC1maWVsZF9fbGVnZW5kXCI+e3sgbGFiZWwgfX08L2xlZ2VuZD5cbiAgICAgIEBpZiAobWFza2VkKSB7XG4gICAgICAgIDxzcGFuIGNsYXNzPVwibmd4LWZpZWxkX192YWx1ZSBuZ3gtZmllbGRfX3ZhbHVlLS1tYXNrZWRcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy1tYXNrZWQnXCI+WFhYWFhYWFhYPC9zcGFuPlxuICAgICAgfSBAZWxzZSB7XG4gICAgICAgIDxkaXYgY2xhc3M9XCJuZ3gtZmllbGRfX2dyb3VwLWNoaWxkcmVuXCI+XG4gICAgICAgICAgQGZvciAoY2hpbGQgb2YgZmllbGQuY2hpbGRyZW4gPz8gW107IHRyYWNrIGNoaWxkLmlkKSB7XG4gICAgICAgICAgICBAaWYgKGNoaWxkLnZpc2liaWxpdHkgIT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgIDxuZ3gtZHluYW1pYy1maWVsZFxuICAgICAgICAgICAgICAgIFtmaWVsZF09XCJjaGlsZFwiXG4gICAgICAgICAgICAgICAgW2NvbnRyb2xdPVwiZ2V0Q2hpbGRDb250cm9sKGNoaWxkLmlkKVwiXG4gICAgICAgICAgICAgICAgW2NvbmZpZ109XCJjb25maWdcIlxuICAgICAgICAgICAgICAgIFtsYW5ndWFnZV09XCJsYW5ndWFnZVwiXG4gICAgICAgICAgICAgICAgW3JlYWRvbmx5XT1cInJlYWRvbmx5IHx8ICEhY2hpbGQucmVhZG9ubHlcIlxuICAgICAgICAgICAgICAgIFt1c2VyUm9sZXNdPVwidXNlclJvbGVzXCJcbiAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIDwvZGl2PlxuICAgICAgfVxuICAgIDwvZmllbGRzZXQ+XG4gIGAsXG4gIHN0eWxlczogW1xuICAgIGBcbiAgICAgIC5uZ3gtZmllbGQtLWdyb3VwIHtcbiAgICAgICAgYm9yZGVyOiAxcHggc29saWQgI2UyZThmMDtcbiAgICAgICAgYm9yZGVyLXJhZGl1czogOHB4O1xuICAgICAgICBwYWRkaW5nOiAxNnB4O1xuICAgICAgICBtYXJnaW4tYm90dG9tOiAxNnB4O1xuICAgICAgICBiYWNrZ3JvdW5kOiAjZmFmYWZhO1xuICAgICAgfVxuICAgICAgLm5neC1maWVsZF9fbGVnZW5kIHtcbiAgICAgICAgZm9udC13ZWlnaHQ6IDYwMDtcbiAgICAgICAgZm9udC1zaXplOiAxNHB4O1xuICAgICAgICBwYWRkaW5nOiAwIDhweDtcbiAgICAgICAgY29sb3I6ICMzMzQxNTU7XG4gICAgICB9XG4gICAgICAubmd4LWZpZWxkX19ncm91cC1jaGlsZHJlbiB7XG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICAgIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gICAgICAgIGdhcDogMTJweDtcbiAgICAgIH1cbiAgICBgLFxuICBdLFxufSlcbmV4cG9ydCBjbGFzcyBHcm91cEZpZWxkQ29tcG9uZW50IHtcbiAgQElucHV0KCkgZmllbGQhOiBOZXN0ZWRGaWVsZENvbmZpZztcbiAgQElucHV0KCkgY29udHJvbCE6IEFic3RyYWN0Q29udHJvbDtcbiAgQElucHV0KCkgY29uZmlnITogRW50aXR5Rm9ybUNvbmZpZztcbiAgQElucHV0KCkgbGFuZ3VhZ2U6IHN0cmluZyA9ICdlbic7XG4gIEBJbnB1dCgpIHJlYWRvbmx5OiBib29sZWFuID0gZmFsc2U7XG4gIEBJbnB1dCgpIG1hc2tlZDogYm9vbGVhbiA9IGZhbHNlO1xuICBASW5wdXQoKSB1c2VyUm9sZXM6IHN0cmluZ1tdID0gW107XG5cbiAgZ2V0IGxhYmVsKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHJlc29sdmVMYWJlbCh0aGlzLmZpZWxkPy5sYWJlbCwgdGhpcy5sYW5ndWFnZSk7XG4gIH1cblxuICBnZXRDaGlsZENvbnRyb2woY2hpbGRJZDogc3RyaW5nKTogQWJzdHJhY3RDb250cm9sIHtcbiAgICBjb25zdCBncm91cCA9IHRoaXMuY29udHJvbCBhcyBGb3JtR3JvdXA7XG4gICAgcmV0dXJuIGdyb3VwPy5nZXQoY2hpbGRJZCkgYXMgQWJzdHJhY3RDb250cm9sO1xuICB9XG59XG4iXX0=
|