ngx-dynamic-entity 1.0.0 → 1.2.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 +129 -139
- package/esm2022/lib/field-types/array-field.component.mjs +112 -104
- package/esm2022/lib/field-types/boolean-field.component.mjs +62 -61
- package/esm2022/lib/field-types/checkbox-field.component.mjs +48 -47
- package/esm2022/lib/field-types/currency-field.component.mjs +54 -53
- package/esm2022/lib/field-types/date-field.component.mjs +46 -45
- package/esm2022/lib/field-types/dropdown-field.component.mjs +89 -87
- package/esm2022/lib/field-types/email-field.component.mjs +64 -63
- package/esm2022/lib/field-types/entity-ref-field.component.mjs +85 -71
- package/esm2022/lib/field-types/field-component.contract.mjs +2 -0
- package/esm2022/lib/field-types/file-field.component.mjs +88 -87
- package/esm2022/lib/field-types/group-field.component.mjs +50 -50
- package/esm2022/lib/field-types/image-field.component.mjs +92 -91
- package/esm2022/lib/field-types/month-year-field.component.mjs +80 -79
- package/esm2022/lib/field-types/multi-select-field.component.mjs +66 -65
- package/esm2022/lib/field-types/number-field.component.mjs +71 -75
- package/esm2022/lib/field-types/password-field.component.mjs +68 -67
- package/esm2022/lib/field-types/radio-field.component.mjs +66 -65
- package/esm2022/lib/field-types/text-field.component.mjs +81 -74
- package/esm2022/lib/field-types/textarea-field.component.mjs +48 -47
- package/esm2022/lib/form/dynamic-field/dynamic-field.component.mjs +53 -6
- package/esm2022/lib/form/dynamic-form.component.mjs +309 -20
- package/esm2022/lib/form/dynamic-record-form.component.mjs +36 -11
- package/esm2022/lib/providers/provide-field-types.mjs +1 -1
- package/esm2022/lib/providers/provide-ngx-dynamic-entity.mjs +8 -2
- package/esm2022/lib/services/cascade-data.service.mjs +2 -2
- package/esm2022/lib/services/entity-ref-cache.mjs +1 -1
- package/esm2022/lib/services/entity-ref-registry.service.mjs +2 -2
- package/esm2022/lib/services/entity-ref-selection.service.mjs +1 -1
- package/esm2022/lib/services/entity-reference.service.mjs +1 -1
- package/esm2022/lib/services/field-registry.service.mjs +1 -1
- package/esm2022/lib/services/file-upload.service.mjs +1 -1
- package/esm2022/lib/services/lookup-registry.service.mjs +2 -2
- package/esm2022/lib/services/rbac.service.mjs +1 -1
- package/esm2022/lib/services/validation-messages.service.mjs +56 -0
- package/esm2022/lib/services/validator-registry.service.mjs +35 -2
- package/esm2022/lib/tokens/injection-tokens.mjs +35 -6
- package/esm2022/public-api.mjs +23 -2
- package/fesm2022/ngx-dynamic-entity.mjs +1754 -1236
- package/fesm2022/ngx-dynamic-entity.mjs.map +1 -1
- package/lib/field-types/array-field.component.d.ts +7 -1
- package/lib/field-types/dropdown-field.component.d.ts +2 -1
- package/lib/field-types/entity-ref-field.component.d.ts +12 -2
- package/lib/field-types/field-component.contract.d.ts +49 -0
- package/lib/field-types/group-field.component.d.ts +1 -1
- package/lib/field-types/multi-select-field.component.d.ts +1 -1
- package/lib/field-types/number-field.component.d.ts +1 -0
- package/lib/field-types/radio-field.component.d.ts +1 -1
- package/lib/field-types/text-field.component.d.ts +10 -2
- package/lib/form/dynamic-field/dynamic-field.component.d.ts +39 -4
- package/lib/form/dynamic-form.component.d.ts +155 -8
- package/lib/form/dynamic-record-form.component.d.ts +13 -2
- package/lib/providers/provide-ngx-dynamic-entity.d.ts +25 -3
- package/lib/services/cascade-data.service.d.ts +1 -1
- package/lib/services/entity-ref-registry.service.d.ts +1 -1
- package/lib/services/lookup-registry.service.d.ts +1 -1
- package/lib/services/validation-messages.service.d.ts +43 -0
- package/lib/services/validator-registry.service.d.ts +13 -1
- package/lib/tokens/injection-tokens.d.ts +42 -7
- package/package.json +17 -18
- package/public-api.d.ts +12 -0
- package/styles.css +579 -0
package/README.md
CHANGED
|
@@ -1,139 +1,129 @@
|
|
|
1
|
-
# ngx-dynamic-entity
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
## Installation
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
| Token | Purpose |
|
|
131
|
-
|---|---|
|
|
132
|
-
| `MASKED_ROLES` | Roles that see `XXXXXXXXX` for masked fields |
|
|
133
|
-
| `FIELD_TYPE_REGISTRY` | Consumer overrides: field type → component (highest priority) |
|
|
134
|
-
| `FIELD_TYPE_SETS` | Multi: field-type sets contributed by `provideFieldTypes()` |
|
|
135
|
-
| `ENTITY_REF_REGISTRY` | Entity key → `EntityReferenceLoader` |
|
|
136
|
-
| `VALIDATOR_REGISTRY` | Validator name → `ValidatorFn` |
|
|
137
|
-
| `HOOK_REGISTRY` | Hook key → handler (e.g. `entity:beforeSave`) |
|
|
138
|
-
| `COMMON_MODULES_REGISTRY` | Consumer-provided shared tab modules |
|
|
139
|
-
| `UPLOAD_HANDLER` | `(file) => UploadResult \| Promise \| Observable` |
|
|
1
|
+
# ngx-dynamic-entity
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/ngx-dynamic-entity)
|
|
4
|
+
[](../../LICENSE)
|
|
5
|
+
|
|
6
|
+
Angular dynamic form renderer and tabbed record editor, powered by `@dynamic-entity/core`. Supports Angular 17 through 22.
|
|
7
|
+
|
|
8
|
+
> This package renders **forms**. It ships no data table — rendering a table over your records is the consumer's choice.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 📦 Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install ngx-dynamic-entity @dynamic-entity/core
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
No Angular Material required. This package has no dependency on Material or the CDK.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## ✨ Features
|
|
23
|
+
|
|
24
|
+
- **`DynamicFormComponent`** — tabbed dynamic forms generated from an `EntityFormConfig`, built on Angular Reactive Forms.
|
|
25
|
+
- **`DynamicRecordFormComponent`** — record editor with summary drawer (`showOnMinimize`), profile header, and per-section saving.
|
|
26
|
+
- **Reactive rules** — real-time condition evaluation driving field/tab visibility, validation errors and warnings, and info banners.
|
|
27
|
+
- **Entity references & cascades** — consumer-registered loaders, parent→child dropdown filtering, and `autoPatch` record copying.
|
|
28
|
+
- **19 field types** — each a standalone component, registered explicitly so unused types are never bundled.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## 🚀 Setup & Registration
|
|
33
|
+
|
|
34
|
+
Field types are **not** registered automatically. Without this step the form renders no fields.
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
// app.config.ts
|
|
38
|
+
import { ApplicationConfig } from '@angular/core';
|
|
39
|
+
import { provideNgxDynamicEntity, provideBuiltInFieldTypes } from 'ngx-dynamic-entity';
|
|
40
|
+
|
|
41
|
+
export const appConfig: ApplicationConfig = {
|
|
42
|
+
providers: [
|
|
43
|
+
provideNgxDynamicEntity({
|
|
44
|
+
maskedRoles: ['IT_SUPPORT'],
|
|
45
|
+
entityRefs: {
|
|
46
|
+
countries: () => fetch('/api/countries').then(res => res.json()),
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
provideBuiltInFieldTypes(),
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
To bundle only the types you use, register them individually instead:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { provideFieldTypes, TextFieldComponent, DropdownFieldComponent } from 'ngx-dynamic-entity';
|
|
58
|
+
|
|
59
|
+
provideFieldTypes({ text: TextFieldComponent, dropdown: DropdownFieldComponent });
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Multiple `provideFieldTypes` calls merge; on a key collision the later registration wins. Pass your own component for a key to override a built-in, or add a key of your own for a custom type.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 💡 Usage
|
|
67
|
+
|
|
68
|
+
```html
|
|
69
|
+
<ngx-dynamic-form
|
|
70
|
+
[config]="formConfig"
|
|
71
|
+
[initialData]="record"
|
|
72
|
+
[userRoles]="['editor']"
|
|
73
|
+
[language]="'en'"
|
|
74
|
+
(formSubmit)="onSave($event)"
|
|
75
|
+
/>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Inputs
|
|
79
|
+
|
|
80
|
+
| Input | Type | Notes |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| `config` | `EntityFormConfig` | Required. |
|
|
83
|
+
| `initialData` | `Record<string, any>` | See **Record shape** below. |
|
|
84
|
+
| `userRoles` | `string[]` | Drives permission and masking checks. Defaults to `[]`. |
|
|
85
|
+
| `language` | `string` | Defaults to `'en'`. |
|
|
86
|
+
| `rules` | `FormRule[]` | Optional reactive rules. |
|
|
87
|
+
| `originalData` | `Record<string, any>` | Baseline for the `VALUE_CHANGED` operator. |
|
|
88
|
+
| `readonly` | `boolean` | Renders the whole form read-only. |
|
|
89
|
+
| `readOnlyFields` | `string[]` | Read-only by field id. |
|
|
90
|
+
| `loading` / `error` | `boolean` / `string \| null` | Render loading and error states. |
|
|
91
|
+
|
|
92
|
+
### Outputs
|
|
93
|
+
|
|
94
|
+
| Output | Payload |
|
|
95
|
+
|---|---|
|
|
96
|
+
| `formSubmit` | `Record<string, any>` |
|
|
97
|
+
| `formChange` | `Record<string, any>` |
|
|
98
|
+
| `formReset` | `void` |
|
|
99
|
+
| `activeTabChange` | `string` (tab id) |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## 🗂 Record shape
|
|
104
|
+
|
|
105
|
+
A record is **nested by tab id** by default:
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
const record = { general: { firstName: 'Alice' }, billing: { vatNumber: 'GB123' } };
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Set `flatData: true` on a tab to store that tab's fields at the record root:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
const record = { firstName: 'Alice', lastName: 'Smith' };
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
This applies in both directions — `initialData` is read with it and `formSubmit` emits with it. **Passing a flat record to a tab that is not marked `flatData` leaves those fields empty**, with no error.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 🔐 Security
|
|
122
|
+
|
|
123
|
+
`userRoles`, `EntityPermissions`, and `maskData` affect **rendering only**. A masked field displays `XXXXXXXXX` while the real value stays in the form control and is included in the `formSubmit` payload. Enforce authorization on the server and never send a user data they may not see.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 🎨 Styling
|
|
128
|
+
|
|
129
|
+
This package ships no CSS. Field components emit `ngx-field`, `ngx-field__label`, `ngx-field__input`, and `ngx-field__error` for you to style. See `packages/demo-angular/src/styles.css` in the repository for a working reference.
|
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
import { Component, Input, inject, forwardRef } from '@angular/core';
|
|
1
|
+
import { Component, Input, inject, forwardRef, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
|
2
2
|
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
|
|
3
3
|
import { resolveLabel } from '@dynamic-entity/core';
|
|
4
4
|
import { DynamicFieldComponent } from '../form/dynamic-field/dynamic-field.component';
|
|
5
5
|
import { ValidatorRegistryService } from '../services/validator-registry.service';
|
|
6
6
|
import * as i0 from "@angular/core";
|
|
7
|
-
/**
|
|
7
|
+
/** Renders repeating rows for a FormArray, with Add Item and Remove. */
|
|
8
8
|
export class ArrayFieldComponent {
|
|
9
|
+
/**
|
|
10
|
+
* addItem/removeItem are public and may be called from outside this component's template,
|
|
11
|
+
* which under OnPush would not re-render. The host also watches the control, but this
|
|
12
|
+
* keeps the component correct on its own.
|
|
13
|
+
*/
|
|
14
|
+
cdr = inject(ChangeDetectorRef);
|
|
9
15
|
field;
|
|
10
16
|
control;
|
|
11
17
|
config;
|
|
@@ -32,115 +38,117 @@ export class ArrayFieldComponent {
|
|
|
32
38
|
}
|
|
33
39
|
const group = this.fb.group(controls);
|
|
34
40
|
this.formArray.push(group);
|
|
41
|
+
this.cdr.markForCheck();
|
|
35
42
|
}
|
|
36
43
|
removeItem(index) {
|
|
37
44
|
this.formArray.removeAt(index);
|
|
45
|
+
this.cdr.markForCheck();
|
|
38
46
|
}
|
|
39
47
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ArrayFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
40
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: ArrayFieldComponent, isStandalone: true, selector: "ngx-array-field", inputs: { field: "field", control: "control", config: "config", language: "language", readonly: "readonly", masked: "masked", userRoles: "userRoles" }, ngImport: i0, template: `
|
|
41
|
-
<div class="ngx-field ngx-field--array"
|
|
42
|
-
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
43
|
-
<div class="ngx-field__array-header">
|
|
44
|
-
<label class="ngx-field__label">{{ label }}</label>
|
|
45
|
-
@if (!readonly && !masked) {
|
|
46
|
-
<button type="button" class="ngx-field__array-add-btn"
|
|
47
|
-
[attr.data-testid]="'field-' + field.id + '-add'" (click)="addItem()">
|
|
48
|
-
+ Add Item
|
|
49
|
-
</button>
|
|
50
|
-
}
|
|
51
|
-
</div>
|
|
52
|
-
|
|
53
|
-
@if (masked) {
|
|
54
|
-
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
55
|
-
} @else {
|
|
56
|
-
<div class="ngx-field__array-list">
|
|
57
|
-
@for (itemGroup of formArray.controls; track idx; let idx = $index) {
|
|
58
|
-
<div class="ngx-field__array-item" [attr.data-testid]="'field-' + field.id + '-row'">
|
|
59
|
-
<div class="ngx-field__array-item-header">
|
|
60
|
-
<span class="ngx-field__array-item-title">Item #{{ idx + 1 }}</span>
|
|
61
|
-
@if (!readonly) {
|
|
62
|
-
<button type="button" class="ngx-field__array-remove-btn"
|
|
63
|
-
[attr.data-testid]="'field-' + field.id + '-remove-' + idx" (click)="removeItem(idx)">
|
|
64
|
-
Remove
|
|
65
|
-
</button>
|
|
66
|
-
}
|
|
67
|
-
</div>
|
|
68
|
-
<div class="ngx-field__array-item-fields">
|
|
69
|
-
@for (child of field.children ?? []; track child.id) {
|
|
70
|
-
@if (child.visibility !== false) {
|
|
71
|
-
<ngx-dynamic-field
|
|
72
|
-
[field]="child"
|
|
73
|
-
[control]="getItemChildControl(itemGroup, child.id)"
|
|
74
|
-
[config]="config"
|
|
75
|
-
[language]="language"
|
|
76
|
-
[readonly]="readonly || !!child.readonly"
|
|
77
|
-
[userRoles]="userRoles"
|
|
78
|
-
/>
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
</div>
|
|
82
|
-
</div>
|
|
83
|
-
}
|
|
84
|
-
@if (formArray.controls.length === 0) {
|
|
85
|
-
<div class="ngx-field__array-empty" [attr.data-testid]="'field-' + field.id + '-empty'">No items added yet.</div>
|
|
86
|
-
}
|
|
87
|
-
</div>
|
|
88
|
-
}
|
|
89
|
-
</div>
|
|
90
|
-
`, isInline: true, styles: [".ngx-field--array{border:1px solid #e2e8f0;border-radius:8px;padding:16px;margin-bottom:16px;background:#f8fafc}.ngx-field__array-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.ngx-field__array-add-btn{background:#2563eb;color:#fff;border:none;padding:6px 12px;border-radius:4px;font-weight:500;cursor:pointer}.ngx-field__array-add-btn:hover{background:#1d4ed8}.ngx-field__array-list{display:flex;flex-direction:column;gap:12px}.ngx-field__array-item{background:#fff;border:1px solid #cbd5e1;border-radius:6px;padding:12px}.ngx-field__array-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;border-bottom:1px solid #f1f5f9;padding-bottom:6px}.ngx-field__array-item-title{font-weight:600;font-size:13px;color:#475569}.ngx-field__array-remove-btn{background:#ef4444;color:#fff;border:none;padding:4px 8px;border-radius:4px;font-size:12px;cursor:pointer}.ngx-field__array-empty{color:#94a3b8;font-style:italic;font-size:13px}\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"] }] });
|
|
48
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: ArrayFieldComponent, isStandalone: true, selector: "ngx-array-field", inputs: { field: "field", control: "control", config: "config", language: "language", readonly: "readonly", masked: "masked", userRoles: "userRoles" }, ngImport: i0, template: `
|
|
49
|
+
<div class="ngx-field ngx-field--array"
|
|
50
|
+
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
51
|
+
<div class="ngx-field__array-header">
|
|
52
|
+
<label class="ngx-field__label">{{ label }}</label>
|
|
53
|
+
@if (!readonly && !masked) {
|
|
54
|
+
<button type="button" class="ngx-field__array-add-btn"
|
|
55
|
+
[attr.data-testid]="'field-' + field.id + '-add'" (click)="addItem()">
|
|
56
|
+
+ Add Item
|
|
57
|
+
</button>
|
|
58
|
+
}
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
@if (masked) {
|
|
62
|
+
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
63
|
+
} @else {
|
|
64
|
+
<div class="ngx-field__array-list">
|
|
65
|
+
@for (itemGroup of formArray.controls; track idx; let idx = $index) {
|
|
66
|
+
<div class="ngx-field__array-item" [attr.data-testid]="'field-' + field.id + '-row'">
|
|
67
|
+
<div class="ngx-field__array-item-header">
|
|
68
|
+
<span class="ngx-field__array-item-title">Item #{{ idx + 1 }}</span>
|
|
69
|
+
@if (!readonly) {
|
|
70
|
+
<button type="button" class="ngx-field__array-remove-btn"
|
|
71
|
+
[attr.data-testid]="'field-' + field.id + '-remove-' + idx" (click)="removeItem(idx)">
|
|
72
|
+
Remove
|
|
73
|
+
</button>
|
|
74
|
+
}
|
|
75
|
+
</div>
|
|
76
|
+
<div class="ngx-field__array-item-fields">
|
|
77
|
+
@for (child of field.children ?? []; track child.id) {
|
|
78
|
+
@if (child.visibility !== false) {
|
|
79
|
+
<ngx-dynamic-field
|
|
80
|
+
[field]="child"
|
|
81
|
+
[control]="getItemChildControl(itemGroup, child.id)"
|
|
82
|
+
[config]="config"
|
|
83
|
+
[language]="language"
|
|
84
|
+
[readonly]="readonly || !!child.readonly"
|
|
85
|
+
[userRoles]="userRoles"
|
|
86
|
+
/>
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
}
|
|
92
|
+
@if (formArray.controls.length === 0) {
|
|
93
|
+
<div class="ngx-field__array-empty" [attr.data-testid]="'field-' + field.id + '-empty'">No items added yet.</div>
|
|
94
|
+
}
|
|
95
|
+
</div>
|
|
96
|
+
}
|
|
97
|
+
</div>
|
|
98
|
+
`, isInline: true, styles: [".ngx-field--array{border:1px solid #e2e8f0;border-radius:8px;padding:16px;margin-bottom:16px;background:#f8fafc}.ngx-field__array-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.ngx-field__array-add-btn{background:#2563eb;color:#fff;border:none;padding:6px 12px;border-radius:4px;font-weight:500;cursor:pointer}.ngx-field__array-add-btn:hover{background:#1d4ed8}.ngx-field__array-list{display:flex;flex-direction:column;gap:12px}.ngx-field__array-item{background:#fff;border:1px solid #cbd5e1;border-radius:6px;padding:12px}.ngx-field__array-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;border-bottom:1px solid #f1f5f9;padding-bottom:6px}.ngx-field__array-item-title{font-weight:600;font-size:13px;color:#475569}.ngx-field__array-remove-btn{background:#ef4444;color:#fff;border:none;padding:4px 8px;border-radius:4px;font-size:12px;cursor:pointer}.ngx-field__array-empty{color:#94a3b8;font-style:italic;font-size:13px}\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 });
|
|
91
99
|
}
|
|
92
100
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ArrayFieldComponent, decorators: [{
|
|
93
101
|
type: Component,
|
|
94
|
-
args: [{ selector: 'ngx-array-field', standalone: true, imports: [ReactiveFormsModule, forwardRef(() => DynamicFieldComponent)], template: `
|
|
95
|
-
<div class="ngx-field ngx-field--array"
|
|
96
|
-
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
97
|
-
<div class="ngx-field__array-header">
|
|
98
|
-
<label class="ngx-field__label">{{ label }}</label>
|
|
99
|
-
@if (!readonly && !masked) {
|
|
100
|
-
<button type="button" class="ngx-field__array-add-btn"
|
|
101
|
-
[attr.data-testid]="'field-' + field.id + '-add'" (click)="addItem()">
|
|
102
|
-
+ Add Item
|
|
103
|
-
</button>
|
|
104
|
-
}
|
|
105
|
-
</div>
|
|
106
|
-
|
|
107
|
-
@if (masked) {
|
|
108
|
-
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
109
|
-
} @else {
|
|
110
|
-
<div class="ngx-field__array-list">
|
|
111
|
-
@for (itemGroup of formArray.controls; track idx; let idx = $index) {
|
|
112
|
-
<div class="ngx-field__array-item" [attr.data-testid]="'field-' + field.id + '-row'">
|
|
113
|
-
<div class="ngx-field__array-item-header">
|
|
114
|
-
<span class="ngx-field__array-item-title">Item #{{ idx + 1 }}</span>
|
|
115
|
-
@if (!readonly) {
|
|
116
|
-
<button type="button" class="ngx-field__array-remove-btn"
|
|
117
|
-
[attr.data-testid]="'field-' + field.id + '-remove-' + idx" (click)="removeItem(idx)">
|
|
118
|
-
Remove
|
|
119
|
-
</button>
|
|
120
|
-
}
|
|
121
|
-
</div>
|
|
122
|
-
<div class="ngx-field__array-item-fields">
|
|
123
|
-
@for (child of field.children ?? []; track child.id) {
|
|
124
|
-
@if (child.visibility !== false) {
|
|
125
|
-
<ngx-dynamic-field
|
|
126
|
-
[field]="child"
|
|
127
|
-
[control]="getItemChildControl(itemGroup, child.id)"
|
|
128
|
-
[config]="config"
|
|
129
|
-
[language]="language"
|
|
130
|
-
[readonly]="readonly || !!child.readonly"
|
|
131
|
-
[userRoles]="userRoles"
|
|
132
|
-
/>
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
}
|
|
138
|
-
@if (formArray.controls.length === 0) {
|
|
139
|
-
<div class="ngx-field__array-empty" [attr.data-testid]="'field-' + field.id + '-empty'">No items added yet.</div>
|
|
140
|
-
}
|
|
141
|
-
</div>
|
|
142
|
-
}
|
|
143
|
-
</div>
|
|
102
|
+
args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ngx-array-field', standalone: true, imports: [ReactiveFormsModule, forwardRef(() => DynamicFieldComponent)], template: `
|
|
103
|
+
<div class="ngx-field ngx-field--array"
|
|
104
|
+
[attr.data-testid]="'field-' + field.id" [attr.data-field-type]="field.type" [class.ngx-field--readonly]="readonly" [class.ngx-field--masked]="masked">
|
|
105
|
+
<div class="ngx-field__array-header">
|
|
106
|
+
<label class="ngx-field__label">{{ label }}</label>
|
|
107
|
+
@if (!readonly && !masked) {
|
|
108
|
+
<button type="button" class="ngx-field__array-add-btn"
|
|
109
|
+
[attr.data-testid]="'field-' + field.id + '-add'" (click)="addItem()">
|
|
110
|
+
+ Add Item
|
|
111
|
+
</button>
|
|
112
|
+
}
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
@if (masked) {
|
|
116
|
+
<span class="ngx-field__value ngx-field__value--masked" [attr.data-testid]="'field-' + field.id + '-masked'">XXXXXXXXX</span>
|
|
117
|
+
} @else {
|
|
118
|
+
<div class="ngx-field__array-list">
|
|
119
|
+
@for (itemGroup of formArray.controls; track idx; let idx = $index) {
|
|
120
|
+
<div class="ngx-field__array-item" [attr.data-testid]="'field-' + field.id + '-row'">
|
|
121
|
+
<div class="ngx-field__array-item-header">
|
|
122
|
+
<span class="ngx-field__array-item-title">Item #{{ idx + 1 }}</span>
|
|
123
|
+
@if (!readonly) {
|
|
124
|
+
<button type="button" class="ngx-field__array-remove-btn"
|
|
125
|
+
[attr.data-testid]="'field-' + field.id + '-remove-' + idx" (click)="removeItem(idx)">
|
|
126
|
+
Remove
|
|
127
|
+
</button>
|
|
128
|
+
}
|
|
129
|
+
</div>
|
|
130
|
+
<div class="ngx-field__array-item-fields">
|
|
131
|
+
@for (child of field.children ?? []; track child.id) {
|
|
132
|
+
@if (child.visibility !== false) {
|
|
133
|
+
<ngx-dynamic-field
|
|
134
|
+
[field]="child"
|
|
135
|
+
[control]="getItemChildControl(itemGroup, child.id)"
|
|
136
|
+
[config]="config"
|
|
137
|
+
[language]="language"
|
|
138
|
+
[readonly]="readonly || !!child.readonly"
|
|
139
|
+
[userRoles]="userRoles"
|
|
140
|
+
/>
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
}
|
|
146
|
+
@if (formArray.controls.length === 0) {
|
|
147
|
+
<div class="ngx-field__array-empty" [attr.data-testid]="'field-' + field.id + '-empty'">No items added yet.</div>
|
|
148
|
+
}
|
|
149
|
+
</div>
|
|
150
|
+
}
|
|
151
|
+
</div>
|
|
144
152
|
`, styles: [".ngx-field--array{border:1px solid #e2e8f0;border-radius:8px;padding:16px;margin-bottom:16px;background:#f8fafc}.ngx-field__array-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}.ngx-field__array-add-btn{background:#2563eb;color:#fff;border:none;padding:6px 12px;border-radius:4px;font-weight:500;cursor:pointer}.ngx-field__array-add-btn:hover{background:#1d4ed8}.ngx-field__array-list{display:flex;flex-direction:column;gap:12px}.ngx-field__array-item{background:#fff;border:1px solid #cbd5e1;border-radius:6px;padding:12px}.ngx-field__array-item-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;border-bottom:1px solid #f1f5f9;padding-bottom:6px}.ngx-field__array-item-title{font-weight:600;font-size:13px;color:#475569}.ngx-field__array-remove-btn{background:#ef4444;color:#fff;border:none;padding:4px 8px;border-radius:4px;font-size:12px;cursor:pointer}.ngx-field__array-empty{color:#94a3b8;font-style:italic;font-size:13px}\n"] }]
|
|
145
153
|
}], propDecorators: { field: [{
|
|
146
154
|
type: Input
|
|
@@ -157,4 +165,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
157
165
|
}], userRoles: [{
|
|
158
166
|
type: Input
|
|
159
167
|
}] } });
|
|
160
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJyYXktZmllbGQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9maWVsZC10eXBlcy9hcnJheS1maWVsZC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNyRSxPQUFPLEVBQThCLFdBQVcsRUFBYSxtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXpHLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNwRCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQztBQUN0RixPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQzs7QUFFbEYscUdBQXFHO0FBNEhyRyxNQUFNLE9BQU8sbUJBQW1CO0lBQ3JCLEtBQUssQ0FBcUI7SUFDMUIsT0FBTyxDQUFtQjtJQUMxQixNQUFNLENBQW9CO0lBQzFCLFFBQVEsR0FBVyxJQUFJLENBQUM7SUFDeEIsUUFBUSxHQUFZLEtBQUssQ0FBQztJQUMxQixNQUFNLEdBQVksS0FBSyxDQUFDO0lBQ3hCLFNBQVMsR0FBYSxFQUFFLENBQUM7SUFFakIsRUFBRSxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUN6QixpQkFBaUIsR0FBRyxNQUFNLENBQUMsd0JBQXdCLENBQUMsQ0FBQztJQUV0RSxJQUFJLEtBQUs7UUFDUCxPQUFPLFlBQVksQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDeEQsQ0FBQztJQUVELElBQUksU0FBUztRQUNYLE9BQU8sSUFBSSxDQUFDLE9BQW9CLENBQUM7SUFDbkMsQ0FBQztJQUVELG1CQUFtQixDQUFDLFNBQTBCLEVBQUUsT0FBZTtRQUM3RCxPQUFRLFNBQXVCLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBb0IsQ0FBQztJQUNsRSxDQUFDO0lBRUQsT0FBTztRQUNMLE1BQU0sUUFBUSxHQUF3QixFQUFFLENBQUM7UUFDekMsS0FBSyxNQUFNLEtBQUssSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsSUFBSSxFQUFFLEVBQUUsQ0FBQztZQUM5QyxNQUFNLFVBQVUsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsaUJBQWlCLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQzlFLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsWUFBWSxJQUFJLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQztRQUNoRSxDQUFDO1FBQ0QsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDdEMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUVELFVBQVUsQ0FBQyxLQUFhO1FBQ3RCLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2pDLENBQUM7d0dBcENVLG1CQUFtQjs0RkFBbkIsbUJBQW1CLG1PQXZIcEI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0RULDZrQ0FuRFMsbUJBQW1CLG9EQUFtQixxQkFBcUI7OzRGQXdIMUQsbUJBQW1CO2tCQTNIL0IsU0FBUzsrQkFDRSxpQkFBaUIsY0FDZixJQUFJLFdBQ1AsQ0FBQyxtQkFBbUIsRUFBRSxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMscUJBQXFCLENBQUMsQ0FBQyxZQUM3RDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrRFQ7OEJBc0VRLEtBQUs7c0JBQWIsS0FBSztnQkFDRyxPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csTUFBTTtzQkFBZCxLQUFLO2dCQUNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csU0FBUztzQkFBakIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIGluamVjdCwgZm9yd2FyZFJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIEZvcm1BcnJheSwgRm9ybUJ1aWxkZXIsIEZvcm1Hcm91cCwgUmVhY3RpdmVGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0IHR5cGUgeyBOZXN0ZWRGaWVsZENvbmZpZywgRW50aXR5Rm9ybUNvbmZpZyB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcclxuaW1wb3J0IHsgcmVzb2x2ZUxhYmVsIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xyXG5pbXBvcnQgeyBEeW5hbWljRmllbGRDb21wb25lbnQgfSBmcm9tICcuLi9mb3JtL2R5bmFtaWMtZmllbGQvZHluYW1pYy1maWVsZC5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBWYWxpZGF0b3JSZWdpc3RyeVNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy92YWxpZGF0b3ItcmVnaXN0cnkuc2VydmljZSc7XHJcblxyXG4vKiogQURSLTAwODogQXJyYXlGaWVsZENvbXBvbmVudCDigJQgcmVuZGVycyByZXBlYXRpbmcgcm93cyBmb3IgRm9ybUFycmF5IHdpdGggKyBBZGQgSXRlbSBhbmQgUmVtb3ZlICovXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAnbmd4LWFycmF5LWZpZWxkJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtSZWFjdGl2ZUZvcm1zTW9kdWxlLCBmb3J3YXJkUmVmKCgpID0+IER5bmFtaWNGaWVsZENvbXBvbmVudCldLFxyXG4gIHRlbXBsYXRlOiBgXHJcbiAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkIG5neC1maWVsZC0tYXJyYXlcIlxyXG4gICAgICBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkXCIgW2F0dHIuZGF0YS1maWVsZC10eXBlXT1cImZpZWxkLnR5cGVcIiBbY2xhc3Mubmd4LWZpZWxkLS1yZWFkb25seV09XCJyZWFkb25seVwiIFtjbGFzcy5uZ3gtZmllbGQtLW1hc2tlZF09XCJtYXNrZWRcIj5cclxuICAgICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktaGVhZGVyXCI+XHJcbiAgICAgICAgPGxhYmVsIGNsYXNzPVwibmd4LWZpZWxkX19sYWJlbFwiPnt7IGxhYmVsIH19PC9sYWJlbD5cclxuICAgICAgICBAaWYgKCFyZWFkb25seSAmJiAhbWFza2VkKSB7XHJcbiAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktYWRkLWJ0blwiXHJcbiAgICAgICAgICAgIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLWFkZCdcIiAoY2xpY2spPVwiYWRkSXRlbSgpXCI+XHJcbiAgICAgICAgICAgICsgQWRkIEl0ZW1cclxuICAgICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICAgIH1cclxuICAgICAgPC9kaXY+XHJcblxyXG4gICAgICBAaWYgKG1hc2tlZCkge1xyXG4gICAgICAgIDxzcGFuIGNsYXNzPVwibmd4LWZpZWxkX192YWx1ZSBuZ3gtZmllbGRfX3ZhbHVlLS1tYXNrZWRcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy1tYXNrZWQnXCI+WFhYWFhYWFhYPC9zcGFuPlxyXG4gICAgICB9IEBlbHNlIHtcclxuICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19hcnJheS1saXN0XCI+XHJcbiAgICAgICAgICBAZm9yIChpdGVtR3JvdXAgb2YgZm9ybUFycmF5LmNvbnRyb2xzOyB0cmFjayBpZHg7IGxldCBpZHggPSAkaW5kZXgpIHtcclxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktaXRlbVwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLXJvdydcIj5cclxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19hcnJheS1pdGVtLWhlYWRlclwiPlxyXG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX2FycmF5LWl0ZW0tdGl0bGVcIj5JdGVtICN7eyBpZHggKyAxIH19PC9zcGFuPlxyXG4gICAgICAgICAgICAgICAgQGlmICghcmVhZG9ubHkpIHtcclxuICAgICAgICAgICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJuZ3gtZmllbGRfX2FycmF5LXJlbW92ZS1idG5cIlxyXG4gICAgICAgICAgICAgICAgICAgIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLXJlbW92ZS0nICsgaWR4XCIgKGNsaWNrKT1cInJlbW92ZUl0ZW0oaWR4KVwiPlxyXG4gICAgICAgICAgICAgICAgICAgIFJlbW92ZVxyXG4gICAgICAgICAgICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19hcnJheS1pdGVtLWZpZWxkc1wiPlxyXG4gICAgICAgICAgICAgICAgQGZvciAoY2hpbGQgb2YgZmllbGQuY2hpbGRyZW4gPz8gW107IHRyYWNrIGNoaWxkLmlkKSB7XHJcbiAgICAgICAgICAgICAgICAgIEBpZiAoY2hpbGQudmlzaWJpbGl0eSAhPT0gZmFsc2UpIHtcclxuICAgICAgICAgICAgICAgICAgICA8bmd4LWR5bmFtaWMtZmllbGRcclxuICAgICAgICAgICAgICAgICAgICAgIFtmaWVsZF09XCJjaGlsZFwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBbY29udHJvbF09XCJnZXRJdGVtQ2hpbGRDb250cm9sKGl0ZW1Hcm91cCwgY2hpbGQuaWQpXCJcclxuICAgICAgICAgICAgICAgICAgICAgIFtjb25maWddPVwiY29uZmlnXCJcclxuICAgICAgICAgICAgICAgICAgICAgIFtsYW5ndWFnZV09XCJsYW5ndWFnZVwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBbcmVhZG9ubHldPVwicmVhZG9ubHkgfHwgISFjaGlsZC5yZWFkb25seVwiXHJcbiAgICAgICAgICAgICAgICAgICAgICBbdXNlclJvbGVzXT1cInVzZXJSb2xlc1wiXHJcbiAgICAgICAgICAgICAgICAgICAgLz5cclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgIH1cclxuICAgICAgICAgIEBpZiAoZm9ybUFycmF5LmNvbnRyb2xzLmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwibmd4LWZpZWxkX19hcnJheS1lbXB0eVwiIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLWVtcHR5J1wiPk5vIGl0ZW1zIGFkZGVkIHlldC48L2Rpdj5cclxuICAgICAgICAgIH1cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgfVxyXG4gICAgPC9kaXY+XHJcbiAgYCxcclxuICBzdHlsZXM6IFtcclxuICAgIGBcclxuICAgICAgLm5neC1maWVsZC0tYXJyYXkge1xyXG4gICAgICAgIGJvcmRlcjogMXB4IHNvbGlkICNlMmU4ZjA7XHJcbiAgICAgICAgYm9yZGVyLXJhZGl1czogOHB4O1xyXG4gICAgICAgIHBhZGRpbmc6IDE2cHg7XHJcbiAgICAgICAgbWFyZ2luLWJvdHRvbTogMTZweDtcclxuICAgICAgICBiYWNrZ3JvdW5kOiAjZjhmYWZjO1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWhlYWRlciB7XHJcbiAgICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XHJcbiAgICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgICAgICBtYXJnaW4tYm90dG9tOiAxMnB4O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWFkZC1idG4ge1xyXG4gICAgICAgIGJhY2tncm91bmQ6ICMyNTYzZWI7XHJcbiAgICAgICAgY29sb3I6ICNmZmY7XHJcbiAgICAgICAgYm9yZGVyOiBub25lO1xyXG4gICAgICAgIHBhZGRpbmc6IDZweCAxMnB4O1xyXG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDRweDtcclxuICAgICAgICBmb250LXdlaWdodDogNTAwO1xyXG4gICAgICAgIGN1cnNvcjogcG9pbnRlcjtcclxuICAgICAgfVxyXG4gICAgICAubmd4LWZpZWxkX19hcnJheS1hZGQtYnRuOmhvdmVyIHtcclxuICAgICAgICBiYWNrZ3JvdW5kOiAjMWQ0ZWQ4O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWxpc3Qge1xyXG4gICAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcclxuICAgICAgICBnYXA6IDEycHg7XHJcbiAgICAgIH1cclxuICAgICAgLm5neC1maWVsZF9fYXJyYXktaXRlbSB7XHJcbiAgICAgICAgYmFja2dyb3VuZDogI2ZmZjtcclxuICAgICAgICBib3JkZXI6IDFweCBzb2xpZCAjY2JkNWUxO1xyXG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDZweDtcclxuICAgICAgICBwYWRkaW5nOiAxMnB4O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWl0ZW0taGVhZGVyIHtcclxuICAgICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICAgIGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjtcclxuICAgICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICAgIG1hcmdpbi1ib3R0b206IDhweDtcclxuICAgICAgICBib3JkZXItYm90dG9tOiAxcHggc29saWQgI2YxZjVmOTtcclxuICAgICAgICBwYWRkaW5nLWJvdHRvbTogNnB4O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWl0ZW0tdGl0bGUge1xyXG4gICAgICAgIGZvbnQtd2VpZ2h0OiA2MDA7XHJcbiAgICAgICAgZm9udC1zaXplOiAxM3B4O1xyXG4gICAgICAgIGNvbG9yOiAjNDc1NTY5O1xyXG4gICAgICB9XHJcbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LXJlbW92ZS1idG4ge1xyXG4gICAgICAgIGJhY2tncm91bmQ6ICNlZjQ0NDQ7XHJcbiAgICAgICAgY29sb3I6ICNmZmY7XHJcbiAgICAgICAgYm9yZGVyOiBub25lO1xyXG4gICAgICAgIHBhZGRpbmc6IDRweCA4cHg7XHJcbiAgICAgICAgYm9yZGVyLXJhZGl1czogNHB4O1xyXG4gICAgICAgIGZvbnQtc2l6ZTogMTJweDtcclxuICAgICAgICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgICAgIH1cclxuICAgICAgLm5neC1maWVsZF9fYXJyYXktZW1wdHkge1xyXG4gICAgICAgIGNvbG9yOiAjOTRhM2I4O1xyXG4gICAgICAgIGZvbnQtc3R5bGU6IGl0YWxpYztcclxuICAgICAgICBmb250LXNpemU6IDEzcHg7XHJcbiAgICAgIH1cclxuICAgIGAsXHJcbiAgXSxcclxufSlcclxuZXhwb3J0IGNsYXNzIEFycmF5RmllbGRDb21wb25lbnQge1xyXG4gIEBJbnB1dCgpIGZpZWxkITogTmVzdGVkRmllbGRDb25maWc7XHJcbiAgQElucHV0KCkgY29udHJvbCE6IEFic3RyYWN0Q29udHJvbDtcclxuICBASW5wdXQoKSBjb25maWchOiBFbnRpdHlGb3JtQ29uZmlnO1xyXG4gIEBJbnB1dCgpIGxhbmd1YWdlOiBzdHJpbmcgPSAnZW4nO1xyXG4gIEBJbnB1dCgpIHJlYWRvbmx5OiBib29sZWFuID0gZmFsc2U7XHJcbiAgQElucHV0KCkgbWFza2VkOiBib29sZWFuID0gZmFsc2U7XHJcbiAgQElucHV0KCkgdXNlclJvbGVzOiBzdHJpbmdbXSA9IFtdO1xyXG5cclxuICBwcml2YXRlIHJlYWRvbmx5IGZiID0gaW5qZWN0KEZvcm1CdWlsZGVyKTtcclxuICBwcml2YXRlIHJlYWRvbmx5IHZhbGlkYXRvclJlZ2lzdHJ5ID0gaW5qZWN0KFZhbGlkYXRvclJlZ2lzdHJ5U2VydmljZSk7XHJcblxyXG4gIGdldCBsYWJlbCgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHJlc29sdmVMYWJlbCh0aGlzLmZpZWxkPy5sYWJlbCwgdGhpcy5sYW5ndWFnZSk7XHJcbiAgfVxyXG5cclxuICBnZXQgZm9ybUFycmF5KCk6IEZvcm1BcnJheSB7XHJcbiAgICByZXR1cm4gdGhpcy5jb250cm9sIGFzIEZvcm1BcnJheTtcclxuICB9XHJcblxyXG4gIGdldEl0ZW1DaGlsZENvbnRyb2woaXRlbUdyb3VwOiBBYnN0cmFjdENvbnRyb2wsIGNoaWxkSWQ6IHN0cmluZyk6IEFic3RyYWN0Q29udHJvbCB7XHJcbiAgICByZXR1cm4gKGl0ZW1Hcm91cCBhcyBGb3JtR3JvdXApLmdldChjaGlsZElkKSBhcyBBYnN0cmFjdENvbnRyb2w7XHJcbiAgfVxyXG5cclxuICBhZGRJdGVtKCk6IHZvaWQge1xyXG4gICAgY29uc3QgY29udHJvbHM6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcclxuICAgIGZvciAoY29uc3QgY2hpbGQgb2YgdGhpcy5maWVsZC5jaGlsZHJlbiA/PyBbXSkge1xyXG4gICAgICBjb25zdCB2YWxpZGF0b3JzID0gdGhpcy52YWxpZGF0b3JSZWdpc3RyeS5yZXNvbHZlRnJvbUNvbmZpZyhjaGlsZC52YWxpZGF0b3JzKTtcclxuICAgICAgY29udHJvbHNbY2hpbGQuaWRdID0gW2NoaWxkLmRlZmF1bHRWYWx1ZSA/PyBudWxsLCB2YWxpZGF0b3JzXTtcclxuICAgIH1cclxuICAgIGNvbnN0IGdyb3VwID0gdGhpcy5mYi5ncm91cChjb250cm9scyk7XHJcbiAgICB0aGlzLmZvcm1BcnJheS5wdXNoKGdyb3VwKTtcclxuICB9XHJcblxyXG4gIHJlbW92ZUl0ZW0oaW5kZXg6IG51bWJlcik6IHZvaWQge1xyXG4gICAgdGhpcy5mb3JtQXJyYXkucmVtb3ZlQXQoaW5kZXgpO1xyXG4gIH1cclxufVxyXG4iXX0=
|
|
168
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXJyYXktZmllbGQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9maWVsZC10eXBlcy9hcnJheS1maWVsZC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSx1QkFBdUIsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNqSCxPQUFPLEVBQThCLFdBQVcsRUFBYSxtQkFBbUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXpHLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNwRCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwrQ0FBK0MsQ0FBQztBQUN0RixPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQzs7QUFFbEYsd0VBQXdFO0FBNkh4RSxNQUFNLE9BQU8sbUJBQW1CO0lBQzlCOzs7O09BSUc7SUFDYyxHQUFHLEdBQUcsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUM7SUFDeEMsS0FBSyxDQUFxQjtJQUMxQixPQUFPLENBQW1CO0lBQzFCLE1BQU0sQ0FBb0I7SUFDMUIsUUFBUSxHQUFXLElBQUksQ0FBQztJQUN4QixRQUFRLEdBQVksS0FBSyxDQUFDO0lBQzFCLE1BQU0sR0FBWSxLQUFLLENBQUM7SUFDeEIsU0FBUyxHQUFhLEVBQUUsQ0FBQztJQUVqQixFQUFFLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3pCLGlCQUFpQixHQUFHLE1BQU0sQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO0lBRXRFLElBQUksS0FBSztRQUNQLE9BQU8sWUFBWSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRUQsSUFBSSxTQUFTO1FBQ1gsT0FBTyxJQUFJLENBQUMsT0FBb0IsQ0FBQztJQUNuQyxDQUFDO0lBRUQsbUJBQW1CLENBQUMsU0FBMEIsRUFBRSxPQUFlO1FBQzdELE9BQVEsU0FBdUIsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFvQixDQUFDO0lBQ2xFLENBQUM7SUFFRCxPQUFPO1FBQ0wsTUFBTSxRQUFRLEdBQXdCLEVBQUUsQ0FBQztRQUN6QyxLQUFLLE1BQU0sS0FBSyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxJQUFJLEVBQUUsRUFBRSxDQUFDO1lBQzlDLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDOUUsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxZQUFZLElBQUksSUFBSSxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQ2hFLENBQUM7UUFDRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUN0QyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMzQixJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQzFCLENBQUM7SUFFRCxVQUFVLENBQUMsS0FBYTtRQUN0QixJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMvQixJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQzFCLENBQUM7d0dBNUNVLG1CQUFtQjs0RkFBbkIsbUJBQW1CLG1PQXZIcEI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0RULDZrQ0FuRFMsbUJBQW1CLG9EQUFtQixxQkFBcUI7OzRGQXdIMUQsbUJBQW1CO2tCQTVIL0IsU0FBUztzQ0FDUyx1QkFBdUIsQ0FBQyxNQUFNLFlBQ3JDLGlCQUFpQixjQUNmLElBQUksV0FDUCxDQUFDLG1CQUFtQixFQUFFLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLFlBQzdEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtEVDs4QkE0RVEsS0FBSztzQkFBYixLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBQ0csUUFBUTtzQkFBaEIsS0FBSztnQkFDRyxRQUFRO3NCQUFoQixLQUFLO2dCQUNHLE1BQU07c0JBQWQsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBJbnB1dCwgaW5qZWN0LCBmb3J3YXJkUmVmLCBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSwgQ2hhbmdlRGV0ZWN0b3JSZWYgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEFic3RyYWN0Q29udHJvbCwgRm9ybUFycmF5LCBGb3JtQnVpbGRlciwgRm9ybUdyb3VwLCBSZWFjdGl2ZUZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHR5cGUgeyBOZXN0ZWRGaWVsZENvbmZpZywgRW50aXR5Rm9ybUNvbmZpZyB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcbmltcG9ydCB7IHJlc29sdmVMYWJlbCB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcbmltcG9ydCB7IER5bmFtaWNGaWVsZENvbXBvbmVudCB9IGZyb20gJy4uL2Zvcm0vZHluYW1pYy1maWVsZC9keW5hbWljLWZpZWxkLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBWYWxpZGF0b3JSZWdpc3RyeVNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy92YWxpZGF0b3ItcmVnaXN0cnkuc2VydmljZSc7XG5cbi8qKiBSZW5kZXJzIHJlcGVhdGluZyByb3dzIGZvciBhIEZvcm1BcnJheSwgd2l0aCBBZGQgSXRlbSBhbmQgUmVtb3ZlLiAqL1xuQENvbXBvbmVudCh7XG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBzZWxlY3RvcjogJ25neC1hcnJheS1maWVsZCcsXG4gIHN0YW5kYWxvbmU6IHRydWUsXG4gIGltcG9ydHM6IFtSZWFjdGl2ZUZvcm1zTW9kdWxlLCBmb3J3YXJkUmVmKCgpID0+IER5bmFtaWNGaWVsZENvbXBvbmVudCldLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxkaXYgY2xhc3M9XCJuZ3gtZmllbGQgbmd4LWZpZWxkLS1hcnJheVwiXG4gICAgICBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkXCIgW2F0dHIuZGF0YS1maWVsZC10eXBlXT1cImZpZWxkLnR5cGVcIiBbY2xhc3Mubmd4LWZpZWxkLS1yZWFkb25seV09XCJyZWFkb25seVwiIFtjbGFzcy5uZ3gtZmllbGQtLW1hc2tlZF09XCJtYXNrZWRcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJuZ3gtZmllbGRfX2FycmF5LWhlYWRlclwiPlxuICAgICAgICA8bGFiZWwgY2xhc3M9XCJuZ3gtZmllbGRfX2xhYmVsXCI+e3sgbGFiZWwgfX08L2xhYmVsPlxuICAgICAgICBAaWYgKCFyZWFkb25seSAmJiAhbWFza2VkKSB7XG4gICAgICAgICAgPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJuZ3gtZmllbGRfX2FycmF5LWFkZC1idG5cIlxuICAgICAgICAgICAgW2F0dHIuZGF0YS10ZXN0aWRdPVwiJ2ZpZWxkLScgKyBmaWVsZC5pZCArICctYWRkJ1wiIChjbGljayk9XCJhZGRJdGVtKClcIj5cbiAgICAgICAgICAgICsgQWRkIEl0ZW1cbiAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgfVxuICAgICAgPC9kaXY+XG5cbiAgICAgIEBpZiAobWFza2VkKSB7XG4gICAgICAgIDxzcGFuIGNsYXNzPVwibmd4LWZpZWxkX192YWx1ZSBuZ3gtZmllbGRfX3ZhbHVlLS1tYXNrZWRcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy1tYXNrZWQnXCI+WFhYWFhYWFhYPC9zcGFuPlxuICAgICAgfSBAZWxzZSB7XG4gICAgICAgIDxkaXYgY2xhc3M9XCJuZ3gtZmllbGRfX2FycmF5LWxpc3RcIj5cbiAgICAgICAgICBAZm9yIChpdGVtR3JvdXAgb2YgZm9ybUFycmF5LmNvbnRyb2xzOyB0cmFjayBpZHg7IGxldCBpZHggPSAkaW5kZXgpIHtcbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJuZ3gtZmllbGRfX2FycmF5LWl0ZW1cIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy1yb3cnXCI+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJuZ3gtZmllbGRfX2FycmF5LWl0ZW0taGVhZGVyXCI+XG4gICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJuZ3gtZmllbGRfX2FycmF5LWl0ZW0tdGl0bGVcIj5JdGVtICN7eyBpZHggKyAxIH19PC9zcGFuPlxuICAgICAgICAgICAgICAgIEBpZiAoIXJlYWRvbmx5KSB7XG4gICAgICAgICAgICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktcmVtb3ZlLWJ0blwiXG4gICAgICAgICAgICAgICAgICAgIFthdHRyLmRhdGEtdGVzdGlkXT1cIidmaWVsZC0nICsgZmllbGQuaWQgKyAnLXJlbW92ZS0nICsgaWR4XCIgKGNsaWNrKT1cInJlbW92ZUl0ZW0oaWR4KVwiPlxuICAgICAgICAgICAgICAgICAgICBSZW1vdmVcbiAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJuZ3gtZmllbGRfX2FycmF5LWl0ZW0tZmllbGRzXCI+XG4gICAgICAgICAgICAgICAgQGZvciAoY2hpbGQgb2YgZmllbGQuY2hpbGRyZW4gPz8gW107IHRyYWNrIGNoaWxkLmlkKSB7XG4gICAgICAgICAgICAgICAgICBAaWYgKGNoaWxkLnZpc2liaWxpdHkgIT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgICAgIDxuZ3gtZHluYW1pYy1maWVsZFxuICAgICAgICAgICAgICAgICAgICAgIFtmaWVsZF09XCJjaGlsZFwiXG4gICAgICAgICAgICAgICAgICAgICAgW2NvbnRyb2xdPVwiZ2V0SXRlbUNoaWxkQ29udHJvbChpdGVtR3JvdXAsIGNoaWxkLmlkKVwiXG4gICAgICAgICAgICAgICAgICAgICAgW2NvbmZpZ109XCJjb25maWdcIlxuICAgICAgICAgICAgICAgICAgICAgIFtsYW5ndWFnZV09XCJsYW5ndWFnZVwiXG4gICAgICAgICAgICAgICAgICAgICAgW3JlYWRvbmx5XT1cInJlYWRvbmx5IHx8ICEhY2hpbGQucmVhZG9ubHlcIlxuICAgICAgICAgICAgICAgICAgICAgIFt1c2VyUm9sZXNdPVwidXNlclJvbGVzXCJcbiAgICAgICAgICAgICAgICAgICAgLz5cbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgfVxuICAgICAgICAgIEBpZiAoZm9ybUFycmF5LmNvbnRyb2xzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm5neC1maWVsZF9fYXJyYXktZW1wdHlcIiBbYXR0ci5kYXRhLXRlc3RpZF09XCInZmllbGQtJyArIGZpZWxkLmlkICsgJy1lbXB0eSdcIj5ObyBpdGVtcyBhZGRlZCB5ZXQuPC9kaXY+XG4gICAgICAgICAgfVxuICAgICAgICA8L2Rpdj5cbiAgICAgIH1cbiAgICA8L2Rpdj5cbiAgYCxcbiAgc3R5bGVzOiBbXG4gICAgYFxuICAgICAgLm5neC1maWVsZC0tYXJyYXkge1xuICAgICAgICBib3JkZXI6IDFweCBzb2xpZCAjZTJlOGYwO1xuICAgICAgICBib3JkZXItcmFkaXVzOiA4cHg7XG4gICAgICAgIHBhZGRpbmc6IDE2cHg7XG4gICAgICAgIG1hcmdpbi1ib3R0b206IDE2cHg7XG4gICAgICAgIGJhY2tncm91bmQ6ICNmOGZhZmM7XG4gICAgICB9XG4gICAgICAubmd4LWZpZWxkX19hcnJheS1oZWFkZXIge1xuICAgICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG4gICAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gICAgICAgIG1hcmdpbi1ib3R0b206IDEycHg7XG4gICAgICB9XG4gICAgICAubmd4LWZpZWxkX19hcnJheS1hZGQtYnRuIHtcbiAgICAgICAgYmFja2dyb3VuZDogIzI1NjNlYjtcbiAgICAgICAgY29sb3I6ICNmZmY7XG4gICAgICAgIGJvcmRlcjogbm9uZTtcbiAgICAgICAgcGFkZGluZzogNnB4IDEycHg7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDRweDtcbiAgICAgICAgZm9udC13ZWlnaHQ6IDUwMDtcbiAgICAgICAgY3Vyc29yOiBwb2ludGVyO1xuICAgICAgfVxuICAgICAgLm5neC1maWVsZF9fYXJyYXktYWRkLWJ0bjpob3ZlciB7XG4gICAgICAgIGJhY2tncm91bmQ6ICMxZDRlZDg7XG4gICAgICB9XG4gICAgICAubmd4LWZpZWxkX19hcnJheS1saXN0IHtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgICAgICAgZ2FwOiAxMnB4O1xuICAgICAgfVxuICAgICAgLm5neC1maWVsZF9fYXJyYXktaXRlbSB7XG4gICAgICAgIGJhY2tncm91bmQ6ICNmZmY7XG4gICAgICAgIGJvcmRlcjogMXB4IHNvbGlkICNjYmQ1ZTE7XG4gICAgICAgIGJvcmRlci1yYWRpdXM6IDZweDtcbiAgICAgICAgcGFkZGluZzogMTJweDtcbiAgICAgIH1cbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWl0ZW0taGVhZGVyIHtcbiAgICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgICAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuICAgICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xuICAgICAgICBtYXJnaW4tYm90dG9tOiA4cHg7XG4gICAgICAgIGJvcmRlci1ib3R0b206IDFweCBzb2xpZCAjZjFmNWY5O1xuICAgICAgICBwYWRkaW5nLWJvdHRvbTogNnB4O1xuICAgICAgfVxuICAgICAgLm5neC1maWVsZF9fYXJyYXktaXRlbS10aXRsZSB7XG4gICAgICAgIGZvbnQtd2VpZ2h0OiA2MDA7XG4gICAgICAgIGZvbnQtc2l6ZTogMTNweDtcbiAgICAgICAgY29sb3I6ICM0NzU1Njk7XG4gICAgICB9XG4gICAgICAubmd4LWZpZWxkX19hcnJheS1yZW1vdmUtYnRuIHtcbiAgICAgICAgYmFja2dyb3VuZDogI2VmNDQ0NDtcbiAgICAgICAgY29sb3I6ICNmZmY7XG4gICAgICAgIGJvcmRlcjogbm9uZTtcbiAgICAgICAgcGFkZGluZzogNHB4IDhweDtcbiAgICAgICAgYm9yZGVyLXJhZGl1czogNHB4O1xuICAgICAgICBmb250LXNpemU6IDEycHg7XG4gICAgICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICAgIH1cbiAgICAgIC5uZ3gtZmllbGRfX2FycmF5LWVtcHR5IHtcbiAgICAgICAgY29sb3I6ICM5NGEzYjg7XG4gICAgICAgIGZvbnQtc3R5bGU6IGl0YWxpYztcbiAgICAgICAgZm9udC1zaXplOiAxM3B4O1xuICAgICAgfVxuICAgIGAsXG4gIF0sXG59KVxuZXhwb3J0IGNsYXNzIEFycmF5RmllbGRDb21wb25lbnQge1xuICAvKipcbiAgICogYWRkSXRlbS9yZW1vdmVJdGVtIGFyZSBwdWJsaWMgYW5kIG1heSBiZSBjYWxsZWQgZnJvbSBvdXRzaWRlIHRoaXMgY29tcG9uZW50J3MgdGVtcGxhdGUsXG4gICAqIHdoaWNoIHVuZGVyIE9uUHVzaCB3b3VsZCBub3QgcmUtcmVuZGVyLiBUaGUgaG9zdCBhbHNvIHdhdGNoZXMgdGhlIGNvbnRyb2wsIGJ1dCB0aGlzXG4gICAqIGtlZXBzIHRoZSBjb21wb25lbnQgY29ycmVjdCBvbiBpdHMgb3duLlxuICAgKi9cbiAgcHJpdmF0ZSByZWFkb25seSBjZHIgPSBpbmplY3QoQ2hhbmdlRGV0ZWN0b3JSZWYpO1xuICBASW5wdXQoKSBmaWVsZCE6IE5lc3RlZEZpZWxkQ29uZmlnO1xuICBASW5wdXQoKSBjb250cm9sITogQWJzdHJhY3RDb250cm9sO1xuICBASW5wdXQoKSBjb25maWchOiBFbnRpdHlGb3JtQ29uZmlnO1xuICBASW5wdXQoKSBsYW5ndWFnZTogc3RyaW5nID0gJ2VuJztcbiAgQElucHV0KCkgcmVhZG9ubHk6IGJvb2xlYW4gPSBmYWxzZTtcbiAgQElucHV0KCkgbWFza2VkOiBib29sZWFuID0gZmFsc2U7XG4gIEBJbnB1dCgpIHVzZXJSb2xlczogc3RyaW5nW10gPSBbXTtcblxuICBwcml2YXRlIHJlYWRvbmx5IGZiID0gaW5qZWN0KEZvcm1CdWlsZGVyKTtcbiAgcHJpdmF0ZSByZWFkb25seSB2YWxpZGF0b3JSZWdpc3RyeSA9IGluamVjdChWYWxpZGF0b3JSZWdpc3RyeVNlcnZpY2UpO1xuXG4gIGdldCBsYWJlbCgpOiBzdHJpbmcge1xuICAgIHJldHVybiByZXNvbHZlTGFiZWwodGhpcy5maWVsZD8ubGFiZWwsIHRoaXMubGFuZ3VhZ2UpO1xuICB9XG5cbiAgZ2V0IGZvcm1BcnJheSgpOiBGb3JtQXJyYXkge1xuICAgIHJldHVybiB0aGlzLmNvbnRyb2wgYXMgRm9ybUFycmF5O1xuICB9XG5cbiAgZ2V0SXRlbUNoaWxkQ29udHJvbChpdGVtR3JvdXA6IEFic3RyYWN0Q29udHJvbCwgY2hpbGRJZDogc3RyaW5nKTogQWJzdHJhY3RDb250cm9sIHtcbiAgICByZXR1cm4gKGl0ZW1Hcm91cCBhcyBGb3JtR3JvdXApLmdldChjaGlsZElkKSBhcyBBYnN0cmFjdENvbnRyb2w7XG4gIH1cblxuICBhZGRJdGVtKCk6IHZvaWQge1xuICAgIGNvbnN0IGNvbnRyb2xzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+ID0ge307XG4gICAgZm9yIChjb25zdCBjaGlsZCBvZiB0aGlzLmZpZWxkLmNoaWxkcmVuID8/IFtdKSB7XG4gICAgICBjb25zdCB2YWxpZGF0b3JzID0gdGhpcy52YWxpZGF0b3JSZWdpc3RyeS5yZXNvbHZlRnJvbUNvbmZpZyhjaGlsZC52YWxpZGF0b3JzKTtcbiAgICAgIGNvbnRyb2xzW2NoaWxkLmlkXSA9IFtjaGlsZC5kZWZhdWx0VmFsdWUgPz8gbnVsbCwgdmFsaWRhdG9yc107XG4gICAgfVxuICAgIGNvbnN0IGdyb3VwID0gdGhpcy5mYi5ncm91cChjb250cm9scyk7XG4gICAgdGhpcy5mb3JtQXJyYXkucHVzaChncm91cCk7XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICByZW1vdmVJdGVtKGluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLmZvcm1BcnJheS5yZW1vdmVBdChpbmRleCk7XG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cbn1cbiJdfQ==
|