@competer/primeng-table 0.0.0-stage → 14.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 +279 -3
- package/esm2020/competer-primeng-table.mjs +5 -0
- package/esm2020/lib/components/column-selector/column-selector.mjs +147 -0
- package/esm2020/lib/components/ecs-primeng-table/ecs-primeng-table.mjs +1411 -0
- package/esm2020/lib/components/ecs-primeng-table/ecs-primeng-table.service.mjs +222 -0
- package/esm2020/lib/components/export-excel/export-excel.mjs +153 -0
- package/esm2020/lib/components/export-excel/export-excel.service.mjs +23 -0
- package/esm2020/lib/components/table-button/table-button.mjs +63 -0
- package/esm2020/lib/components/table-cell/table-cell.mjs +159 -0
- package/esm2020/lib/components/table-predefined-filters/table-predefined-filters.mjs +94 -0
- package/esm2020/lib/components/views-management/views-management.mjs +117 -0
- package/esm2020/lib/enums/cell-display.enum.mjs +7 -0
- package/esm2020/lib/enums/cell-overflow-behaviour.enum.mjs +14 -0
- package/esm2020/lib/enums/data-align-horizontal.enum.mjs +16 -0
- package/esm2020/lib/enums/data-align-vertical.enum.mjs +16 -0
- package/esm2020/lib/enums/data-type.enum.enum.mjs +21 -0
- package/esm2020/lib/enums/device-type.enum.mjs +8 -0
- package/esm2020/lib/enums/frozen-column-align.enum.mjs +17 -0
- package/esm2020/lib/enums/index.mjs +9 -0
- package/esm2020/lib/enums/table-view-save-mode.enum.mjs +19 -0
- package/esm2020/lib/interfaces/columns-metadata.interface.mjs +2 -0
- package/esm2020/lib/interfaces/excel-export-request.interface.mjs +2 -0
- package/esm2020/lib/interfaces/index.mjs +11 -0
- package/esm2020/lib/interfaces/predefined-filter.interface.mjs +2 -0
- package/esm2020/lib/interfaces/table-button.interface.mjs +2 -0
- package/esm2020/lib/interfaces/table-configuration.interface.mjs +2 -0
- package/esm2020/lib/interfaces/table-options.interface.mjs +107 -0
- package/esm2020/lib/interfaces/table-paged-response.interface.mjs +2 -0
- package/esm2020/lib/interfaces/table-query-request.interface.mjs +2 -0
- package/esm2020/lib/interfaces/table-view-data.interface.mjs +2 -0
- package/esm2020/lib/interfaces/table-view.interface.mjs +2 -0
- package/esm2020/lib/pipes/ui-translate.pipe.mjs +21 -0
- package/esm2020/lib/services/http.service.mjs +18 -0
- package/esm2020/lib/services/i18n.service.mjs +61 -0
- package/esm2020/lib/services/index.mjs +5 -0
- package/esm2020/lib/services/notification.service.mjs +17 -0
- package/esm2020/lib/services/table-state.service.mjs +38 -0
- package/esm2020/lib/utils/create-table-options.mjs +37 -0
- package/esm2020/lib/utils/data-align-horizontal-as-text.mjs +23 -0
- package/esm2020/lib/utils/data-align-vertical-as-text.mjs +23 -0
- package/esm2020/lib/utils/data-type-as-text.mjs +25 -0
- package/esm2020/lib/utils/frozen-column-align-as-text.mjs +21 -0
- package/esm2020/lib/utils/highlight-text.mjs +36 -0
- package/esm2020/lib/utils/index.mjs +7 -0
- package/esm2020/lib/utils/tree-table-state.mjs +239 -0
- package/esm2020/public-api.mjs +19 -0
- package/fesm2015/competer-primeng-table.mjs +3119 -0
- package/fesm2015/competer-primeng-table.mjs.map +1 -0
- package/fesm2020/competer-primeng-table.mjs +3049 -0
- package/fesm2020/competer-primeng-table.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/components/column-selector/column-selector.d.ts +55 -0
- package/lib/components/ecs-primeng-table/ecs-primeng-table.d.ts +256 -0
- package/lib/components/ecs-primeng-table/ecs-primeng-table.service.d.ts +52 -0
- package/lib/components/export-excel/export-excel.d.ts +51 -0
- package/lib/components/export-excel/export-excel.service.d.ts +6 -0
- package/lib/components/table-button/table-button.d.ts +16 -0
- package/lib/components/table-cell/table-cell.d.ts +69 -0
- package/lib/components/table-predefined-filters/table-predefined-filters.d.ts +39 -0
- package/lib/components/views-management/views-management.d.ts +34 -0
- package/lib/enums/cell-display.enum.d.ts +5 -0
- package/lib/enums/cell-overflow-behaviour.enum.d.ts +12 -0
- package/lib/enums/data-align-horizontal.enum.d.ts +14 -0
- package/lib/enums/data-align-vertical.enum.d.ts +14 -0
- package/lib/enums/data-type.enum.enum.d.ts +19 -0
- package/lib/enums/device-type.enum.d.ts +6 -0
- package/lib/enums/frozen-column-align.enum.d.ts +15 -0
- package/lib/enums/index.d.ts +8 -0
- package/lib/enums/table-view-save-mode.enum.d.ts +17 -0
- package/lib/interfaces/columns-metadata.interface.d.ts +66 -0
- package/lib/interfaces/excel-export-request.interface.d.ts +20 -0
- package/lib/interfaces/index.d.ts +10 -0
- package/lib/interfaces/predefined-filter.interface.d.ts +101 -0
- package/lib/interfaces/table-button.interface.d.ts +75 -0
- package/lib/interfaces/table-configuration.interface.d.ts +23 -0
- package/lib/interfaces/table-options.interface.d.ts +604 -0
- package/lib/interfaces/table-paged-response.interface.d.ts +16 -0
- package/lib/interfaces/table-query-request.interface.d.ts +28 -0
- package/lib/interfaces/table-view-data.interface.d.ts +28 -0
- package/lib/interfaces/table-view.interface.d.ts +15 -0
- package/lib/pipes/ui-translate.pipe.d.ts +13 -0
- package/lib/services/http.service.d.ts +34 -0
- package/lib/services/i18n.service.d.ts +20 -0
- package/lib/services/index.d.ts +4 -0
- package/lib/services/notification.service.d.ts +23 -0
- package/lib/services/table-state.service.d.ts +31 -0
- package/lib/utils/create-table-options.d.ts +5 -0
- package/lib/utils/data-align-horizontal-as-text.d.ts +11 -0
- package/lib/utils/data-align-vertical-as-text.d.ts +11 -0
- package/lib/utils/data-type-as-text.d.ts +11 -0
- package/lib/utils/frozen-column-align-as-text.d.ts +11 -0
- package/lib/utils/highlight-text.d.ts +17 -0
- package/lib/utils/index.d.ts +6 -0
- package/lib/utils/tree-table-state.d.ts +66 -0
- package/package.json +58 -3
- package/public-api.d.ts +10 -0
package/README.md
CHANGED
|
@@ -1,3 +1,279 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# Optional Tree Grid
|
|
2
|
+
|
|
3
|
+
Omit `tree` to keep the flat grid unchanged. Opt in with ordinary flat records:
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { createTableOptions } from '@competer/primeng-table';
|
|
7
|
+
|
|
8
|
+
readonly tableOptions = createTableOptions({
|
|
9
|
+
tree: {
|
|
10
|
+
keyExpr: 'id', parentIdExpr: 'parentId', rootValue: 0,
|
|
11
|
+
hasItemsExpr: 'hasChildren', column: 'text', loadMode: 'onDemand'
|
|
12
|
+
},
|
|
13
|
+
urlTableConfiguration: 'TreeDemo/GetTableConfiguration',
|
|
14
|
+
urlTableData: 'TreeDemo/GetTableData',
|
|
15
|
+
excelReport: { url: 'TreeDemo/GenerateExcel' }
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Add `ECSPrimengTable` from the same package to your standalone component's
|
|
20
|
+
`imports` and set `standalone: true` explicitly (required in Angular 14), then bind the options in its template:
|
|
21
|
+
|
|
22
|
+
```html
|
|
23
|
+
<ecs-primeng-table [tableOptions]="tableOptions"></ecs-primeng-table>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The API returns ordinary records, not nested `children` arrays. For example,
|
|
27
|
+
the following records describe a root, a child and a grandchild:
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
[
|
|
31
|
+
{ "id": 1, "parentId": 0, "hasChildren": true, "text": "Project", "rowID": 1 },
|
|
32
|
+
{ "id": 2, "parentId": 1, "hasChildren": true, "text": "Task", "rowID": 2 },
|
|
33
|
+
{ "id": 3, "parentId": 2, "hasChildren": false, "text": "Subtask", "rowID": 3 }
|
|
34
|
+
]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`keyExpr` and `parentIdExpr` identify the relationship, `rootValue` marks root
|
|
38
|
+
parents, `hasItemsExpr` indicates whether a node can expand in remote modes,
|
|
39
|
+
and `column` selects the field containing the indentation and expand control.
|
|
40
|
+
These records are the response's `data`, not the complete response envelope;
|
|
41
|
+
remote modes return only the requested siblings. Keep the existing table
|
|
42
|
+
configuration endpoint for column metadata, filtering and display options.
|
|
43
|
+
|
|
44
|
+
`loadMode` accepts `all`, `onDemand` (default) or `pagedChildren`.
|
|
45
|
+
`rootValue` defaults to `0`; use `null` explicitly for nullable root parents.
|
|
46
|
+
Remote modes require a boolean `hasItemsExpr`. Keys are unique finite numbers
|
|
47
|
+
or nonempty strings. Preserve structural fields and the independent selection
|
|
48
|
+
alias `rowID`, even when hidden. Use a distinct state-persistence key per mode,
|
|
49
|
+
provide `ECSPrimengTableStateService` on the parent route component, and remount
|
|
50
|
+
the table when changing mode. The `/tree` demo illustrates this pattern.
|
|
51
|
+
|
|
52
|
+
Root queries send `roots`, `parentId`, `loadMode`, `page` and `pageSize` alongside
|
|
53
|
+
the existing filters/sorts. Responses remain flat and add `ancestorKeys` to open
|
|
54
|
+
matching paths. Page counts describe roots; expanded children are not a second
|
|
55
|
+
root page. Paged children expose a load-more row. Expansion caches are invalidated
|
|
56
|
+
by a fresh query. Views/navigation persist `treeExpandedKeys` and `treeChildPages`;
|
|
57
|
+
selection is independent and does not cascade. Saved views restore into the
|
|
58
|
+
currently configured mode; the demo's mode choice lives in its parent settings.
|
|
59
|
+
|
|
60
|
+
Tree Excel endpoints must export the complete retained hierarchy, independent
|
|
61
|
+
of expansion/loading. The demo backend uses in-memory validation/querying rather
|
|
62
|
+
than a SQL recursive query. See the repository's `Backend/ECS.PrimengTable/TREE.md`
|
|
63
|
+
for the full API contract, authorization constraints and memory limits.
|
|
64
|
+
|
|
65
|
+
Translate `Expand node`, `Collapse node`, `Load more children` and
|
|
66
|
+
`Showing {{count}} root nodes of {{total}} available root nodes` in the consuming
|
|
67
|
+
application's dictionaries. Without ngx-translate providers they remain English.
|
|
68
|
+
|
|
69
|
+
For a step-by-step walkthrough and a screenshot of the running example, see
|
|
70
|
+
[Try the tree demo](https://github.com/competergiga/ECSPrimengTable/blob/Angular19-publish/README.md#try-the-tree-demo).
|
|
71
|
+
The example shows the three load modes, deep filtering, saved views and returning
|
|
72
|
+
from a detail route without losing the expanded branches.
|
|
73
|
+
|
|
74
|
+
# Group Headers
|
|
75
|
+
|
|
76
|
+
Set `HeaderGroup` on backend column attributes:
|
|
77
|
+
|
|
78
|
+
```csharp
|
|
79
|
+
[ColumnAttributes("Name", HeaderGroup = "Group1")]
|
|
80
|
+
public string Name { get; set; } = "";
|
|
81
|
+
|
|
82
|
+
[ColumnAttributes("Age", dataType: DataType.Numeric, HeaderGroup = "Group1")]
|
|
83
|
+
public int Age { get; set; }
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Consecutive visible columns sharing `headerGroup` receive a centered spanning header. Reordering or hiding columns recalculates the runs, repeating the label when a group is split. Ungrouped columns leave a blank space; no extra row is rendered when no visible column has a group. Frozen alignment boundaries split runs to preserve scrolling alignment. Labels support translation keys just like `header`.
|
|
87
|
+
|
|
88
|
+
Use `ColumnMetadataOverrideModel.HeaderGroup` for dynamic overrides; an empty string removes a group. The `/progress` example groups the first three columns under `Grupo1` and the last two under `Grupo2`.
|
|
89
|
+
|
|
90
|
+
# ECS PrimeNG table
|
|
91
|
+
|
|
92
|
+
This NPM package contains ECS PrimeNG table.
|
|
93
|
+
For full documentation, usage instructions, examples, and updates, please visit the official GitHub repository:
|
|
94
|
+
[https://github.com/competergiga/ECSPrimengTable/tree/Angular19-publish](https://github.com/competergiga/ECSPrimengTable/tree/Angular19-publish)
|
|
95
|
+
|
|
96
|
+
> **Note:** Make sure to check the GitHub README for detailed guidance on how to integrate and use this component in your projects.
|
|
97
|
+
## Column header translations (Angular 14)
|
|
98
|
+
|
|
99
|
+
Install `@ngx-translate/core@14` in the consuming application and configure
|
|
100
|
+
`TranslateModule.forRoot` once in its application providers. If your application
|
|
101
|
+
already uses ngx-translate, reuse its existing provider and dictionaries.
|
|
102
|
+
|
|
103
|
+
The table and column selector render `header | translate`. The selector searches
|
|
104
|
+
and sorts the translated labels and updates when the language changes. No metadata
|
|
105
|
+
is overwritten: `field`, cell values, filters, saved views and server-side Excel
|
|
106
|
+
exports keep their existing behavior. Other grid UI labels also support translation.
|
|
107
|
+
|
|
108
|
+
The consuming application loads its dictionaries from JSON files. The demo uses
|
|
109
|
+
`src/assets/i18n/es.json`, `en.json`, `fr.json` and `it.json`, copied to `assets/i18n/`
|
|
110
|
+
by the existing Angular assets configuration. Keys match the existing backend
|
|
111
|
+
headers, so no backend changes are required.
|
|
112
|
+
|
|
113
|
+
For example, `es.json` contains:
|
|
114
|
+
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"Username": "Usuario",
|
|
118
|
+
"Age": "Edad"
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Install the loader in the application (the table library only needs core):
|
|
123
|
+
|
|
124
|
+
```sh
|
|
125
|
+
npm install @ngx-translate/core@14 @ngx-translate/http-loader@7
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Configure it once in `app.config.ts` using Angular 14's module providers:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { importProvidersFrom } from '@angular/core';
|
|
132
|
+
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
|
133
|
+
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
|
|
134
|
+
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
|
|
135
|
+
|
|
136
|
+
export function translateLoader(http: HttpClient): TranslateHttpLoader {
|
|
137
|
+
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export const appConfig = {
|
|
141
|
+
providers: [importProvidersFrom(
|
|
142
|
+
HttpClientModule,
|
|
143
|
+
TranslateModule.forRoot({
|
|
144
|
+
defaultLanguage: 'en',
|
|
145
|
+
loader: { provide: TranslateLoader, useFactory: translateLoader, deps: [HttpClient] }
|
|
146
|
+
})
|
|
147
|
+
)]
|
|
148
|
+
};
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Import `TranslateModule` in each standalone component that uses the `translate`
|
|
152
|
+
pipe; do not import `TranslatePipe` or `TranslateDirective` directly in Angular 14.
|
|
153
|
+
Call `TranslateService.use('es')` during application initialization to select the
|
|
154
|
+
initial language. `setDefaultLang('en')` sets the fallback language in ngx-translate 14.
|
|
155
|
+
For an NgModule application, put `HttpClientModule` and `TranslateModule.forRoot(...)`
|
|
156
|
+
in the root module's `imports`, and `TranslateModule` in feature modules.
|
|
157
|
+
PrimeNG 14 uses `PrimeNGConfig` from `primeng/api` and CSS themes from
|
|
158
|
+
`primeng/resources/themes`; it does not use `providePrimeNG` or `@primeng/themes` presets.
|
|
159
|
+
|
|
160
|
+
If the application already uses ngx-translate, reuse its provider and add the
|
|
161
|
+
header keys to its existing JSON dictionaries instead of configuring another loader.
|
|
162
|
+
|
|
163
|
+
Call `TranslateService.use('en')`, `use('es')`, `use('fr')` or `use('it')` to switch languages without fetching
|
|
164
|
+
the table configuration again. Missing translations use the fallback language,
|
|
165
|
+
then the original key with ngx-translate's default missing-translation handler.
|
|
166
|
+
|
|
167
|
+
Alternatively, return `header: 'columns.username'` from the backend and define
|
|
168
|
+
`{ "columns": { "username": "Usuario" } }` in the Spanish JSON file.
|
|
169
|
+
|
|
170
|
+
The Angular 14 setup above replaces the provider APIs shown in the upstream Angular 19 guide.
|
|
171
|
+
|
|
172
|
+
## Optional navigation state
|
|
173
|
+
|
|
174
|
+
Set `statePersistence: { enabled: true, key: "people-list" }` in `createTableOptions` to preserve filters, global search, sorting and pagination when returning from a detail page. It is disabled by default. Provide `ECSPrimengTableStateService` on the parent component containing both list and detail routes. Leaving that component clears its in-memory state. Do not provide it at application root or on the list itself.
|
|
175
|
+
|
|
176
|
+
See the [scope setup and navigation examples](https://github.com/competergiga/ECSPrimengTable/blob/Angular19-publish/README.md#419-optional-state-when-returning-from-a-detail-page).
|
|
177
|
+
|
|
178
|
+
### Enable or disable
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
tableOptions = createTableOptions({
|
|
182
|
+
statePersistence: {
|
|
183
|
+
enabled: true, // Set false or omit this option to disable.
|
|
184
|
+
key: 'people-list'
|
|
185
|
+
}
|
|
186
|
+
// Add your existing endpoints and other table options.
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Register `providers: [ECSPrimengTableStateService]` on a parent component with a
|
|
191
|
+
`<router-outlet></router-outlet>` and put both list and detail routes under it. Use Angular
|
|
192
|
+
Router navigation between them. An enabled table requires a non-empty key and
|
|
193
|
+
this scope provider.
|
|
194
|
+
|
|
195
|
+
Returning from a detail restores the query and fetches fresh rows. Leaving the
|
|
196
|
+
scope for another section discards that query, as does a browser reload. Setting
|
|
197
|
+
`enabled` to false does not clear filters currently on screen; it prevents their
|
|
198
|
+
preservation for the next navigation. Explicitly saved startup views remain
|
|
199
|
+
independent of this option.
|
|
200
|
+
|
|
201
|
+
The `/home` demo includes a checkbox for enabled/disabled behavior, a row edit
|
|
202
|
+
button opening a navigation-only detail and an **Ir a otra sección** link to
|
|
203
|
+
leave the scope. Run `npm run test:state` from the frontend workspace for the
|
|
204
|
+
automated tests.
|
|
205
|
+
|
|
206
|
+
## Responsive options
|
|
207
|
+
|
|
208
|
+
Header and row menus are optional and disabled by default. Enable `responsive.headerMenu` and `responsive.rowMenu`. The optional DTO attribute `VisibleOnlyIn` sets initial visibility by viewport while keeping columns available in the selector.
|
|
209
|
+
|
|
210
|
+
See [configuration, precedence and examples](https://github.com/competergiga/ECSPrimengTable/blob/Angular19-publish/README.md#10-responsive-menus-and-initial-column-visibility).
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
### Translating all grid interface text
|
|
214
|
+
|
|
215
|
+
Use the same ngx-translate JSON dictionaries for headers, buttons, tooltips, descriptions, menus, dialogs, validation messages and counters. Built-in texts use their original English string as the key; configurable button labels/tooltips and descriptions may also use your own translation keys. Changing `TranslateService.use('fr')` updates the UI, including open menus and dialogs.
|
|
216
|
+
|
|
217
|
+
Example entries in `assets/i18n/es.json`:
|
|
218
|
+
|
|
219
|
+
```json
|
|
220
|
+
{
|
|
221
|
+
"Actions": "Acciones",
|
|
222
|
+
"Selected": "Seleccionado",
|
|
223
|
+
"CREATE": "CREAR",
|
|
224
|
+
"--- Select a view ---": "--- Selecciona una vista ---",
|
|
225
|
+
"MODIFY COLUMNS": "MODIFICAR COLUMNAS",
|
|
226
|
+
"Search keyword": "Buscar",
|
|
227
|
+
"Cancel changes": "Cancelar cambios",
|
|
228
|
+
"Save changes": "Guardar cambios",
|
|
229
|
+
"Showing {{count}} records of {{total}} available records": "Mostrando {{count}} registros de {{total}} disponibles",
|
|
230
|
+
"primeng": {
|
|
231
|
+
"startsWith": "Empieza por",
|
|
232
|
+
"contains": "Contiene",
|
|
233
|
+
"clear": "Limpiar",
|
|
234
|
+
"apply": "Aplicar",
|
|
235
|
+
"aria": { "nextPageLabel": "Página siguiente" }
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Keep interpolation names such as `{{count}}` and `{{total}}` unchanged. Missing UI translations fall back to the configured fallback language, then to the original text. Existing applications do not need to add every key at once.
|
|
241
|
+
|
|
242
|
+
The optional `primeng` section translates PrimeNG controls (filter operators, calendars, pagination and accessibility labels). The grid synchronizes this section with the **shared application PrimeNG configuration**, so it also affects other PrimeNG components. Unspecified entries retain the configuration captured at grid initialization; without this section the grid leaves the application's locale alone. Date formats and table data culture remain separately configured.
|
|
243
|
+
|
|
244
|
+
The demo provides complete examples in `src/assets/i18n/en.json`, `es.json`, `fr.json` and `it.json`, plus a language selector. Copy/merge the entries you need into your application's dictionaries. No additional npm dependencies are introduced by this extension.
|
|
245
|
+
|
|
246
|
+
Cell data, predefined-filter values, saved view aliases, user-entered text and backend field identifiers are not translated. A default export filename is translated when opening the export dialog; the filename subsequently entered by the user is preserved. Excel headers generated on the server remain the backend's responsibility.
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
### Per-item list tooltips
|
|
250
|
+
|
|
251
|
+
For `DataType.List` columns, `dataTooltipCustomColumnSource` references a semicolon-separated string in the same row. Each tooltip matches the item at the same position. For example:
|
|
252
|
+
|
|
253
|
+
```text
|
|
254
|
+
EmploymentStatusNameList = "Freelance;Military;Student"
|
|
255
|
+
ESList_tooltip = "Independent work;Military service;In education"
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Set `dataTooltipCustomColumnSource: "ESList_tooltip"` on the `EmploymentStatusNameList` attribute. The auxiliary property can be `string?`, with `dataType: DataType.Text` and `sendColumnAttributes: false`; it needs neither a visible column nor list metadata. The backend includes properties marked `sendColumnAttributes: false` in the returned row data.
|
|
259
|
+
|
|
260
|
+
This applies to predefined-filter tags and plain text lists. Positions are preserved, including duplicate items and empty entries. Missing properties or positions fall back to the item itself; an empty position suppresses its tooltip. Extra tooltips are ignored. `dataTooltipShow: false` still disables tooltips. Tooltip text remains untranslated data.
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
### Progress bars
|
|
264
|
+
|
|
265
|
+
Keep `DataType.Numeric` and set `cellDisplay: CellDisplay.ProgressBar` to display a bar on a 0–100 scale:
|
|
266
|
+
|
|
267
|
+
```csharp
|
|
268
|
+
[ColumnAttributes("Progress", dataType: DataType.Numeric,
|
|
269
|
+
cellDisplay: CellDisplay.ProgressBar, initialWidth: 160)]
|
|
270
|
+
public decimal? Progress { get; set; }
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
The backend sends `cellDisplay: 1` in column metadata and a number in row data, for example `"progress": 15.5`. For TypeScript configurations, import `CellDisplay` from the package and use `cellDisplay: CellDisplay.ProgressBar` with `dataType: DataType.Numeric`.
|
|
274
|
+
|
|
275
|
+
The bar has no inner label; the default tooltip shows `15.5 %`. Both `dataTooltipShow` and `dataTooltipCustomColumnSource` are respected. Zero displays an empty bar; null or nonnumeric values leave the cell empty. Only the visual fill is clamped to 0–100: filtering, sorting and Excel preserve the original number (15.5 exports as 15.5, not 0.155). Decimal values and dynamic metadata via `ColumnMetadataOverrideModel.CellDisplay` are supported.
|
|
276
|
+
|
|
277
|
+
`CellDisplay.Default` (0), or omitted frontend metadata, preserves existing presentation. `ProgressBar` applies only to numeric columns and takes precedence over predefined-filter tags. Update both the npm and NuGet packages to use this option.
|
|
278
|
+
|
|
279
|
+
The demo navigation switches between the full people example (`/home`) and progress bars (`/progress`). Each table has separate endpoints and views. The progress demo uses in-memory data in `ProgressDemoController`, independent of the people database.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated bundle index. Do not edit.
|
|
3
|
+
*/
|
|
4
|
+
export * from './public-api';
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcGV0ZXItcHJpbWVuZy10YWJsZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL2Vjcy1wcmltZW5nLXRhYmxlL3NyYy9jb21wZXRlci1wcmltZW5nLXRhYmxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxjQUFjLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEdlbmVyYXRlZCBidW5kbGUgaW5kZXguIERvIG5vdCBlZGl0LlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vcHVibGljLWFwaSc7XG4iXX0=
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { ECSTableTranslatePipe } from '../../pipes/ui-translate.pipe';
|
|
2
|
+
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
|
|
3
|
+
import { TranslateModule } from '@ngx-translate/core';
|
|
4
|
+
import { merge, Subject, takeUntil } from 'rxjs';
|
|
5
|
+
import { CommonModule } from '@angular/common';
|
|
6
|
+
import { FormsModule } from '@angular/forms';
|
|
7
|
+
import { DialogModule } from 'primeng/dialog';
|
|
8
|
+
import { TableModule } from 'primeng/table';
|
|
9
|
+
import { CheckboxModule } from 'primeng/checkbox';
|
|
10
|
+
import { ButtonModule } from 'primeng/button';
|
|
11
|
+
import { SelectButtonModule } from 'primeng/selectbutton';
|
|
12
|
+
import { CellOverflowBehaviour, DataAlignHorizontal, DataAlignVertical } from '../../enums';
|
|
13
|
+
import { InputTextModule } from 'primeng/inputtext';
|
|
14
|
+
import { TooltipModule } from 'primeng/tooltip';
|
|
15
|
+
import * as i0 from "@angular/core";
|
|
16
|
+
import * as i1 from "@ngx-translate/core";
|
|
17
|
+
import * as i2 from "primeng/dialog";
|
|
18
|
+
import * as i3 from "primeng/api";
|
|
19
|
+
import * as i4 from "primeng/table";
|
|
20
|
+
import * as i5 from "primeng/checkbox";
|
|
21
|
+
import * as i6 from "primeng/button";
|
|
22
|
+
import * as i7 from "primeng/selectbutton";
|
|
23
|
+
import * as i8 from "@angular/common";
|
|
24
|
+
import * as i9 from "@angular/forms";
|
|
25
|
+
import * as i10 from "primeng/inputtext";
|
|
26
|
+
import * as i11 from "primeng/tooltip";
|
|
27
|
+
export class ColumnSelector {
|
|
28
|
+
constructor(translate, changeDetector) {
|
|
29
|
+
this.translate = translate;
|
|
30
|
+
this.destroy$ = new Subject();
|
|
31
|
+
this.orderByHeader = false;
|
|
32
|
+
this.visible = false;
|
|
33
|
+
this.columnModalData = [];
|
|
34
|
+
this.filteredColumnData = [];
|
|
35
|
+
this.visibleChange = new EventEmitter();
|
|
36
|
+
this.applyChanges = new EventEmitter();
|
|
37
|
+
this.cellOverflowBehaviourOptions = [
|
|
38
|
+
{ icon: 'pi pi-minus', val: CellOverflowBehaviour.Hidden, name: "Hidden" },
|
|
39
|
+
{ icon: 'pi pi-equals', val: CellOverflowBehaviour.Wrap, name: "Wrap" } /*,
|
|
40
|
+
{icon: 'pi pi-ellipsis-h', val: CellOverflowBehaviour.Ellipsis, name: "Ellipsis"}*/
|
|
41
|
+
];
|
|
42
|
+
this.dataAlignHorizontalOptions = [
|
|
43
|
+
{ icon: 'pi pi-align-left', val: DataAlignHorizontal.Left, name: "Left" },
|
|
44
|
+
{ icon: 'pi pi-align-center', val: DataAlignHorizontal.Center, name: "Center" },
|
|
45
|
+
{ icon: 'pi pi-align-right', val: DataAlignHorizontal.Right, name: "Right" }
|
|
46
|
+
];
|
|
47
|
+
this.dataAlignVerticalOptions = [
|
|
48
|
+
{ icon: 'pi pi-angle-up', val: DataAlignVertical.Top, name: "Top" },
|
|
49
|
+
{ icon: 'pi pi-align-justify', val: DataAlignVertical.Middle, name: "Middle" },
|
|
50
|
+
{ icon: 'pi pi-angle-down', val: DataAlignVertical.Bottom, name: "Bottom" }
|
|
51
|
+
];
|
|
52
|
+
this.globalSearchText = null; // The text used by the global search
|
|
53
|
+
this.globalSearchMaxLength = 50;
|
|
54
|
+
merge(translate.onLangChange, translate.onTranslationChange, translate.onDefaultLangChange)
|
|
55
|
+
.pipe(takeUntil(this.destroy$))
|
|
56
|
+
.subscribe(() => {
|
|
57
|
+
this.updateVisibleColumns();
|
|
58
|
+
changeDetector.markForCheck();
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
ngOnChanges() {
|
|
62
|
+
if (!this.visible)
|
|
63
|
+
this.globalSearchText = null;
|
|
64
|
+
this.updateVisibleColumns();
|
|
65
|
+
}
|
|
66
|
+
ngOnDestroy() {
|
|
67
|
+
this.destroy$.next();
|
|
68
|
+
this.destroy$.complete();
|
|
69
|
+
}
|
|
70
|
+
updateVisibleColumns() {
|
|
71
|
+
const search = (this.globalSearchText ?? '').toLocaleLowerCase();
|
|
72
|
+
const label = (column) => column.header ? this.translate.instant(column.header) : '';
|
|
73
|
+
this.filteredColumnData = this.columnModalData.filter(column => label(column).toLocaleLowerCase().includes(search));
|
|
74
|
+
if (this.orderByHeader) {
|
|
75
|
+
this.filteredColumnData.sort((a, b) => label(a).localeCompare(label(b)));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
translatedOptions(options) {
|
|
79
|
+
return options.map(option => ({ ...option, name: this.translate.instant(option.name) }));
|
|
80
|
+
}
|
|
81
|
+
allColumnsCheckboxActive() {
|
|
82
|
+
return this.columnModalData.every(column => column.selected);
|
|
83
|
+
}
|
|
84
|
+
allColumnsCheckboxClick(event) {
|
|
85
|
+
if (event.checked) {
|
|
86
|
+
this.columnModalData.forEach(column => { column.selected = true; });
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
this.columnModalData.forEach(column => {
|
|
90
|
+
if (!column.selectDisabled) {
|
|
91
|
+
column.selected = false;
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
filterColumnModal(event) {
|
|
97
|
+
this.globalSearchText = event.target.value;
|
|
98
|
+
this.updateVisibleColumns();
|
|
99
|
+
}
|
|
100
|
+
applyColumnModalChanges() {
|
|
101
|
+
const selected = this.columnModalData.filter(c => c.selected && !c.selectDisabled);
|
|
102
|
+
this.applyChanges.emit(selected);
|
|
103
|
+
this.closeModal();
|
|
104
|
+
}
|
|
105
|
+
clearGlobalFilter(dt) {
|
|
106
|
+
this.globalSearchText = null;
|
|
107
|
+
this.updateVisibleColumns();
|
|
108
|
+
}
|
|
109
|
+
closeModal() {
|
|
110
|
+
this.globalSearchText = null;
|
|
111
|
+
this.visibleChange.emit(false);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
ColumnSelector.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: ColumnSelector, deps: [{ token: i1.TranslateService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
115
|
+
ColumnSelector.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.12", type: ColumnSelector, isStandalone: true, selector: "ecs-column-selector", inputs: { orderByHeader: "orderByHeader", visible: "visible", columnModalData: "columnModalData", filteredColumnData: "filteredColumnData" }, outputs: { visibleChange: "visibleChange", applyChanges: "applyChanges" }, viewQueries: [{ propertyName: "dt_columnDialog", first: true, predicate: ["dt_columnDialog"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!--COLUMN MODAL DIALOG-->\r\n<p-dialog [(visible)]=\"visible\" [modal]=\"true\" [draggable]=\"false\" [resizable]=\"false\" [closeOnEscape]=\"false\" [closable]=\"false\" [maximizable]=\"false\" [style]=\"{'min-width': '65vw', 'max-width': '65vw'}\">\r\n <ng-template pTemplate=\"header\">\r\n <span class=\"white-space-nowrap\"><b>{{ 'MODIFY COLUMNS' | ecsTranslate }}</b></span>\r\n </ng-template>\r\n <div style=\"padding: 10px;\">\r\n <p-table #dt_columnDialog [value]=\"filteredColumnData\" [scrollable]=\"true\" size=\"small\" showGridlines stripedRows\r\n scrollHeight=\"calc(80vh - 220px)\">\r\n <ng-template pTemplate=\"caption\">\r\n <div style=\"display: flex; justify-content: space-between; align-items: center;\">\r\n <div style=\"display: flex; align-items: center; gap: 10px\">\r\n <p-checkbox inputId=\"selectAll\" [binary]=\"true\" [ngModel]=\"allColumnsCheckboxActive()\" (onChange)=\"allColumnsCheckboxClick($event)\"></p-checkbox>\r\n <label for=\"selectAll\">{{ 'Select all columns' | ecsTranslate }}</label>\r\n </div>\r\n <div style=\"display: flex; align-items: center;\">\r\n <span class=\"ecs-global-search\">\r\n <span class=\"ecs-input-icon\">\r\n <i class=\"pi pi-search\"></i>\r\n </span>\r\n <input pInputText type=\"text\" \r\n (input)=\"filterColumnModal($event)\" autocomplete=\"off\" \r\n [maxlength]=\"globalSearchMaxLength\" [placeholder]=\"'Search column name' | ecsTranslate\" [(ngModel)]=\"globalSearchText\"\r\n style=\"width: 220px;\"/>\r\n <!-- Right icon (only if there is text) -->\r\n <ng-container *ngIf=\"globalSearchText\">\r\n <span class=\"ecs-input-icon\" position=\"right\">\r\n <i class=\"pi pi-times\" style=\"cursor: pointer;\" (click)=\"clearGlobalFilter(dt_columnDialog); $event.stopPropagation()\"></i>\r\n </span>\r\n </ng-container>\r\n </span>\r\n </div>\r\n </div>\r\n </ng-template>\r\n <ng-template pTemplate=\"header\">\r\n <tr>\r\n <th pFrozenColumn style=\"max-width: 100px; min-width: 100px; width: 100px; text-align: center;\">{{ 'Show column' | ecsTranslate }}</th>\r\n <th pFrozenColumn style=\"max-width: 250px; min-width: 250px; width: 250px; text-align: center;\">{{ 'Column name' | ecsTranslate }}</th>\r\n <th style=\"max-width: 150px; min-width: 150px; width: 150px; text-align: center;\">{{ 'Cell overflow behaviour' | ecsTranslate }}</th>\r\n <th style=\"max-width: 160px; min-width: 160px; width: 160px; text-align: center;\">{{ 'Horizontal alignment' | ecsTranslate }}</th>\r\n <th style=\"max-width: 150px; min-width: 150px; width: 150px; text-align: center;\">{{ 'Vertical alignment' | ecsTranslate }}</th>\r\n </tr>\r\n </ng-template>\r\n <ng-template pTemplate=\"body\" let-rowData>\r\n <tr>\r\n <td pFrozenColumn style=\"max-width: 100px; min-width: 100px; width: 100px; text-align: center;\">\r\n <p-checkbox \r\n [(ngModel)]=\"rowData.selected\" \r\n [binary]=\"true\"\r\n [disabled]=\"rowData.selectDisabled\"></p-checkbox>\r\n </td>\r\n <td pFrozenColumn style=\"max-width: 250px; min-width: 250px; width: 250px;\">{{rowData.header | translate}}</td>\r\n <td style=\"max-width: 150px; min-width: 150px; width: 150px; text-align: center;\">\r\n <p-selectButton [(ngModel)]=\"rowData.cellOverflowBehaviour\" [options]=\"translatedOptions(cellOverflowBehaviourOptions)\" optionValue=\"val\" optionLabel=\"name\" [disabled]=\"rowData.cellOverflowBehaviourDisabled\" allowEmpty=\"false\">\r\n <ng-template pTemplate=\"item\" let-item>\r\n <i [class]=\"item.icon\" style=\"margin: -20px;\" [pTooltip]=\"(item.name) | ecsTranslate\" [showDelay]=\"400\" tooltipPosition=\"top\"></i>\r\n </ng-template>\r\n </p-selectButton>\r\n </td>\r\n <td style=\"max-width: 160px; min-width: 160px; width: 160px; text-align: center;\">\r\n <p-selectButton [(ngModel)]=\"rowData.dataAlignHorizontal\" [options]=\"translatedOptions(dataAlignHorizontalOptions)\" optionValue=\"val\" optionLabel=\"name\" [disabled]=\"rowData.dataAlignHorizontalDisabled\" allowEmpty=\"false\">\r\n <ng-template pTemplate=\"item\" let-item>\r\n <i [class]=\"item.icon\" style=\"margin: -20px;\" [pTooltip]=\"(item.name) | ecsTranslate\" [showDelay]=\"400\" tooltipPosition=\"top\"></i>\r\n </ng-template>\r\n </p-selectButton>\r\n </td>\r\n <td style=\"max-width: 150px; min-width: 150px; width: 150px; text-align: center;\">\r\n <p-selectButton [(ngModel)]=\"rowData.dataAlignVertical\" [options]=\"translatedOptions(dataAlignVerticalOptions)\" optionValue=\"val\" optionLabel=\"name\" [disabled]=\"rowData.dataAlignVerticalDisabled\" allowEmpty=\"false\">\r\n <ng-template pTemplate=\"item\" let-item>\r\n <i [class]=\"item.icon\" style=\"margin: -20px;\" [pTooltip]=\"(item.name) | ecsTranslate\" [showDelay]=\"400\" tooltipPosition=\"top\"></i>\r\n </ng-template>\r\n </p-selectButton>\r\n </td>\r\n </tr>\r\n </ng-template>\r\n <ng-template pTemplate=\"emptymessage\">\r\n <tr>\r\n <td colspan=\"999\">{{ 'There are no columns' | ecsTranslate }}</td>\r\n </tr>\r\n </ng-template>\r\n </p-table>\r\n <div style=\"display: flex; flex-direction: row; justify-content: space-between; align-items: center; margin-top: 10px;\">\r\n {{ 'Showing {{count}} columns of {{total}} available columns' | ecsTranslate: { count: filteredColumnData ? filteredColumnData.length : 0, total: columnModalData ? columnModalData.length : 0 } }}\r\n </div>\r\n </div>\r\n <ng-template pTemplate=\"footer\" style=\"display: flex; justify-content: space-between; align-items: center;\">\r\n <p-button (click)=\"closeModal()\" [label]=\"'Cancel changes' | ecsTranslate\" outlined=\"true\" [style]=\"{'margin-top': '10px'}\"></p-button>\r\n <p-button (click)=\"applyColumnModalChanges()\" [label]=\"'Save changes' | ecsTranslate\" [style]=\"{'margin-top': '10px'}\"></p-button>\r\n </ng-template>\r\n</p-dialog>", dependencies: [{ kind: "pipe", type: ECSTableTranslatePipe, name: "ecsTranslate" }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: DialogModule }, { kind: "component", type: i2.Dialog, selector: "p-dialog", inputs: ["header", "draggable", "resizable", "positionLeft", "positionTop", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "responsive", "appendTo", "breakpoints", "styleClass", "maskStyleClass", "showHeader", "breakpoint", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "visible", "style", "position"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: TableModule }, { kind: "component", type: i4.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "style", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "scrollDirection", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "responsive", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "autoLayout", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "groupRowsByOrder", "responsiveLayout", "breakpoint", "virtualRowHeight", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["selectAllChange", "selectionChange", "contextMenuSelectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i4.FrozenColumn, selector: "[pFrozenColumn]", inputs: ["frozen", "alignFrozen"] }, { kind: "ngmodule", type: CheckboxModule }, { kind: "component", type: i5.Checkbox, selector: "p-checkbox", inputs: ["value", "name", "disabled", "binary", "label", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "styleClass", "labelStyleClass", "formControl", "checkboxIcon", "readonly", "required", "trueValue", "falseValue"], outputs: ["onChange"] }, { kind: "ngmodule", type: ButtonModule }, { kind: "component", type: i6.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "style", "styleClass", "badgeClass", "ariaLabel"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "ngmodule", type: SelectButtonModule }, { kind: "component", type: i7.SelectButton, selector: "p-selectButton", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "tabindex", "multiple", "style", "styleClass", "ariaLabelledBy", "disabled", "dataKey"], outputs: ["onOptionClick", "onChange"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i8.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i9.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i9.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i9.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i9.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i10.InputText, selector: "[pInputText]" }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i11.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "fitContent", "pTooltip", "tooltipDisabled", "tooltipOptions"] }] });
|
|
116
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.12", ngImport: i0, type: ColumnSelector, decorators: [{
|
|
117
|
+
type: Component,
|
|
118
|
+
args: [{ selector: 'ecs-column-selector', imports: [
|
|
119
|
+
ECSTableTranslatePipe,
|
|
120
|
+
TranslateModule,
|
|
121
|
+
DialogModule,
|
|
122
|
+
TableModule,
|
|
123
|
+
CheckboxModule,
|
|
124
|
+
ButtonModule,
|
|
125
|
+
SelectButtonModule,
|
|
126
|
+
CommonModule,
|
|
127
|
+
FormsModule,
|
|
128
|
+
InputTextModule,
|
|
129
|
+
TooltipModule
|
|
130
|
+
], standalone: true, template: "<!--COLUMN MODAL DIALOG-->\r\n<p-dialog [(visible)]=\"visible\" [modal]=\"true\" [draggable]=\"false\" [resizable]=\"false\" [closeOnEscape]=\"false\" [closable]=\"false\" [maximizable]=\"false\" [style]=\"{'min-width': '65vw', 'max-width': '65vw'}\">\r\n <ng-template pTemplate=\"header\">\r\n <span class=\"white-space-nowrap\"><b>{{ 'MODIFY COLUMNS' | ecsTranslate }}</b></span>\r\n </ng-template>\r\n <div style=\"padding: 10px;\">\r\n <p-table #dt_columnDialog [value]=\"filteredColumnData\" [scrollable]=\"true\" size=\"small\" showGridlines stripedRows\r\n scrollHeight=\"calc(80vh - 220px)\">\r\n <ng-template pTemplate=\"caption\">\r\n <div style=\"display: flex; justify-content: space-between; align-items: center;\">\r\n <div style=\"display: flex; align-items: center; gap: 10px\">\r\n <p-checkbox inputId=\"selectAll\" [binary]=\"true\" [ngModel]=\"allColumnsCheckboxActive()\" (onChange)=\"allColumnsCheckboxClick($event)\"></p-checkbox>\r\n <label for=\"selectAll\">{{ 'Select all columns' | ecsTranslate }}</label>\r\n </div>\r\n <div style=\"display: flex; align-items: center;\">\r\n <span class=\"ecs-global-search\">\r\n <span class=\"ecs-input-icon\">\r\n <i class=\"pi pi-search\"></i>\r\n </span>\r\n <input pInputText type=\"text\" \r\n (input)=\"filterColumnModal($event)\" autocomplete=\"off\" \r\n [maxlength]=\"globalSearchMaxLength\" [placeholder]=\"'Search column name' | ecsTranslate\" [(ngModel)]=\"globalSearchText\"\r\n style=\"width: 220px;\"/>\r\n <!-- Right icon (only if there is text) -->\r\n <ng-container *ngIf=\"globalSearchText\">\r\n <span class=\"ecs-input-icon\" position=\"right\">\r\n <i class=\"pi pi-times\" style=\"cursor: pointer;\" (click)=\"clearGlobalFilter(dt_columnDialog); $event.stopPropagation()\"></i>\r\n </span>\r\n </ng-container>\r\n </span>\r\n </div>\r\n </div>\r\n </ng-template>\r\n <ng-template pTemplate=\"header\">\r\n <tr>\r\n <th pFrozenColumn style=\"max-width: 100px; min-width: 100px; width: 100px; text-align: center;\">{{ 'Show column' | ecsTranslate }}</th>\r\n <th pFrozenColumn style=\"max-width: 250px; min-width: 250px; width: 250px; text-align: center;\">{{ 'Column name' | ecsTranslate }}</th>\r\n <th style=\"max-width: 150px; min-width: 150px; width: 150px; text-align: center;\">{{ 'Cell overflow behaviour' | ecsTranslate }}</th>\r\n <th style=\"max-width: 160px; min-width: 160px; width: 160px; text-align: center;\">{{ 'Horizontal alignment' | ecsTranslate }}</th>\r\n <th style=\"max-width: 150px; min-width: 150px; width: 150px; text-align: center;\">{{ 'Vertical alignment' | ecsTranslate }}</th>\r\n </tr>\r\n </ng-template>\r\n <ng-template pTemplate=\"body\" let-rowData>\r\n <tr>\r\n <td pFrozenColumn style=\"max-width: 100px; min-width: 100px; width: 100px; text-align: center;\">\r\n <p-checkbox \r\n [(ngModel)]=\"rowData.selected\" \r\n [binary]=\"true\"\r\n [disabled]=\"rowData.selectDisabled\"></p-checkbox>\r\n </td>\r\n <td pFrozenColumn style=\"max-width: 250px; min-width: 250px; width: 250px;\">{{rowData.header | translate}}</td>\r\n <td style=\"max-width: 150px; min-width: 150px; width: 150px; text-align: center;\">\r\n <p-selectButton [(ngModel)]=\"rowData.cellOverflowBehaviour\" [options]=\"translatedOptions(cellOverflowBehaviourOptions)\" optionValue=\"val\" optionLabel=\"name\" [disabled]=\"rowData.cellOverflowBehaviourDisabled\" allowEmpty=\"false\">\r\n <ng-template pTemplate=\"item\" let-item>\r\n <i [class]=\"item.icon\" style=\"margin: -20px;\" [pTooltip]=\"(item.name) | ecsTranslate\" [showDelay]=\"400\" tooltipPosition=\"top\"></i>\r\n </ng-template>\r\n </p-selectButton>\r\n </td>\r\n <td style=\"max-width: 160px; min-width: 160px; width: 160px; text-align: center;\">\r\n <p-selectButton [(ngModel)]=\"rowData.dataAlignHorizontal\" [options]=\"translatedOptions(dataAlignHorizontalOptions)\" optionValue=\"val\" optionLabel=\"name\" [disabled]=\"rowData.dataAlignHorizontalDisabled\" allowEmpty=\"false\">\r\n <ng-template pTemplate=\"item\" let-item>\r\n <i [class]=\"item.icon\" style=\"margin: -20px;\" [pTooltip]=\"(item.name) | ecsTranslate\" [showDelay]=\"400\" tooltipPosition=\"top\"></i>\r\n </ng-template>\r\n </p-selectButton>\r\n </td>\r\n <td style=\"max-width: 150px; min-width: 150px; width: 150px; text-align: center;\">\r\n <p-selectButton [(ngModel)]=\"rowData.dataAlignVertical\" [options]=\"translatedOptions(dataAlignVerticalOptions)\" optionValue=\"val\" optionLabel=\"name\" [disabled]=\"rowData.dataAlignVerticalDisabled\" allowEmpty=\"false\">\r\n <ng-template pTemplate=\"item\" let-item>\r\n <i [class]=\"item.icon\" style=\"margin: -20px;\" [pTooltip]=\"(item.name) | ecsTranslate\" [showDelay]=\"400\" tooltipPosition=\"top\"></i>\r\n </ng-template>\r\n </p-selectButton>\r\n </td>\r\n </tr>\r\n </ng-template>\r\n <ng-template pTemplate=\"emptymessage\">\r\n <tr>\r\n <td colspan=\"999\">{{ 'There are no columns' | ecsTranslate }}</td>\r\n </tr>\r\n </ng-template>\r\n </p-table>\r\n <div style=\"display: flex; flex-direction: row; justify-content: space-between; align-items: center; margin-top: 10px;\">\r\n {{ 'Showing {{count}} columns of {{total}} available columns' | ecsTranslate: { count: filteredColumnData ? filteredColumnData.length : 0, total: columnModalData ? columnModalData.length : 0 } }}\r\n </div>\r\n </div>\r\n <ng-template pTemplate=\"footer\" style=\"display: flex; justify-content: space-between; align-items: center;\">\r\n <p-button (click)=\"closeModal()\" [label]=\"'Cancel changes' | ecsTranslate\" outlined=\"true\" [style]=\"{'margin-top': '10px'}\"></p-button>\r\n <p-button (click)=\"applyColumnModalChanges()\" [label]=\"'Save changes' | ecsTranslate\" [style]=\"{'margin-top': '10px'}\"></p-button>\r\n </ng-template>\r\n</p-dialog>" }]
|
|
131
|
+
}], ctorParameters: function () { return [{ type: i1.TranslateService }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { orderByHeader: [{
|
|
132
|
+
type: Input
|
|
133
|
+
}], dt_columnDialog: [{
|
|
134
|
+
type: ViewChild,
|
|
135
|
+
args: ['dt_columnDialog']
|
|
136
|
+
}], visible: [{
|
|
137
|
+
type: Input
|
|
138
|
+
}], columnModalData: [{
|
|
139
|
+
type: Input
|
|
140
|
+
}], filteredColumnData: [{
|
|
141
|
+
type: Input
|
|
142
|
+
}], visibleChange: [{
|
|
143
|
+
type: Output
|
|
144
|
+
}], applyChanges: [{
|
|
145
|
+
type: Output
|
|
146
|
+
}] } });
|
|
147
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29sdW1uLXNlbGVjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZWNzLXByaW1lbmctdGFibGUvc3JjL2xpYi9jb21wb25lbnRzL2NvbHVtbi1zZWxlY3Rvci9jb2x1bW4tc2VsZWN0b3IudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9lY3MtcHJpbWVuZy10YWJsZS9zcmMvbGliL2NvbXBvbmVudHMvY29sdW1uLXNlbGVjdG9yL2NvbHVtbi1zZWxlY3Rvci5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ3RFLE9BQU8sRUFBcUIsU0FBUyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQXdCLE1BQU0sRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0gsT0FBTyxFQUFFLGVBQWUsRUFBb0IsTUFBTSxxQkFBcUIsQ0FBQztBQUN4RSxPQUFPLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDakQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUMsT0FBTyxFQUFTLFdBQVcsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNuRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDbEQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzFELE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxtQkFBbUIsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUM1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LHNSQUNaLGtCQUFrQiw2U0FDbEIsWUFBWSxrSUFDWixXQUFXLGl4QkFDWCxlQUFlLG9HQUNmLGFBQWE7NEZBS0osY0FBYztrQkFsQjFCLFNBQVM7K0JBQ0UscUJBQXFCLFdBQ3RCO3dCQUNQLHFCQUFxQjt3QkFDckIsZUFBZTt3QkFDZixZQUFZO3dCQUNaLFdBQVc7d0JBQ1gsY0FBYzt3QkFDZCxZQUFZO3dCQUNaLGtCQUFrQjt3QkFDbEIsWUFBWTt3QkFDWixXQUFXO3dCQUNYLGVBQWU7d0JBQ2YsYUFBYTtxQkFDZCxjQUNXLElBQUk7dUlBS1AsYUFBYTtzQkFBckIsS0FBSztnQkFnQ3dCLGVBQWU7c0JBQTVDLFNBQVM7dUJBQUMsaUJBQWlCO2dCQUVuQixPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csZUFBZTtzQkFBdkIsS0FBSztnQkFDRyxrQkFBa0I7c0JBQTFCLEtBQUs7Z0JBRUksYUFBYTtzQkFBdEIsTUFBTTtnQkFDRyxZQUFZO3NCQUFyQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRUNTVGFibGVUcmFuc2xhdGVQaXBlIH0gZnJvbSAnLi4vLi4vcGlwZXMvdWktdHJhbnNsYXRlLnBpcGUnO1xyXG5pbXBvcnQgeyBDaGFuZ2VEZXRlY3RvclJlZiwgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIElucHV0LCBPbkNoYW5nZXMsIE9uRGVzdHJveSwgT3V0cHV0LCBWaWV3Q2hpbGQgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgVHJhbnNsYXRlTW9kdWxlLCBUcmFuc2xhdGVTZXJ2aWNlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XHJcbmltcG9ydCB7IG1lcmdlLCBTdWJqZWN0LCB0YWtlVW50aWwgfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcclxuaW1wb3J0IHsgRm9ybXNNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7IERpYWxvZ01vZHVsZSB9IGZyb20gJ3ByaW1lbmcvZGlhbG9nJztcclxuaW1wb3J0IHsgVGFibGUsIFRhYmxlTW9kdWxlIH0gZnJvbSAncHJpbWVuZy90YWJsZSc7XHJcbmltcG9ydCB7IENoZWNrYm94TW9kdWxlIH0gZnJvbSAncHJpbWVuZy9jaGVja2JveCc7XHJcbmltcG9ydCB7IEJ1dHRvbk1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvYnV0dG9uJztcclxuaW1wb3J0IHsgU2VsZWN0QnV0dG9uTW9kdWxlIH0gZnJvbSAncHJpbWVuZy9zZWxlY3RidXR0b24nO1xyXG5pbXBvcnQgeyBDZWxsT3ZlcmZsb3dCZWhhdmlvdXIsIERhdGFBbGlnbkhvcml6b250YWwsIERhdGFBbGlnblZlcnRpY2FsIH0gZnJvbSAnLi4vLi4vZW51bXMnO1xyXG5pbXBvcnQgeyBJbnB1dFRleHRNb2R1bGUgfSBmcm9tICdwcmltZW5nL2lucHV0dGV4dCc7XHJcbmltcG9ydCB7IElDb2x1bW5NZXRhZGF0YSB9IGZyb20gJy4uLy4uL2ludGVyZmFjZXMnO1xyXG5pbXBvcnQgeyBUb29sdGlwTW9kdWxlIH0gZnJvbSAncHJpbWVuZy90b29sdGlwJztcclxuXHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ2Vjcy1jb2x1bW4tc2VsZWN0b3InLFxyXG4gIGltcG9ydHM6IFtcclxuICAgIEVDU1RhYmxlVHJhbnNsYXRlUGlwZSxcclxuICAgIFRyYW5zbGF0ZU1vZHVsZSxcclxuICAgIERpYWxvZ01vZHVsZSxcclxuICAgIFRhYmxlTW9kdWxlLFxyXG4gICAgQ2hlY2tib3hNb2R1bGUsXHJcbiAgICBCdXR0b25Nb2R1bGUsXHJcbiAgICBTZWxlY3RCdXR0b25Nb2R1bGUsXHJcbiAgICBDb21tb25Nb2R1bGUsXHJcbiAgICBGb3Jtc01vZHVsZSxcclxuICAgIElucHV0VGV4dE1vZHVsZSxcclxuICAgIFRvb2x0aXBNb2R1bGVcclxuICBdLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgdGVtcGxhdGVVcmw6ICcuL2NvbHVtbi1zZWxlY3Rvci5odG1sJ1xyXG59KVxyXG5leHBvcnQgY2xhc3MgQ29sdW1uU2VsZWN0b3IgaW1wbGVtZW50cyBPbkNoYW5nZXMsIE9uRGVzdHJveSB7XHJcbiAgcHJpdmF0ZSByZWFkb25seSBkZXN0cm95JCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XHJcbiAgQElucHV0KCkgb3JkZXJCeUhlYWRlciA9IGZhbHNlO1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHRyYW5zbGF0ZTogVHJhbnNsYXRlU2VydmljZSwgY2hhbmdlRGV0ZWN0b3I6IENoYW5nZURldGVjdG9yUmVmKSB7XHJcbiAgICBtZXJnZSh0cmFuc2xhdGUub25MYW5nQ2hhbmdlLCB0cmFuc2xhdGUub25UcmFuc2xhdGlvbkNoYW5nZSwgdHJhbnNsYXRlLm9uRGVmYXVsdExhbmdDaGFuZ2UpXHJcbiAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcclxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XHJcbiAgICAgICAgdGhpcy51cGRhdGVWaXNpYmxlQ29sdW1ucygpO1xyXG4gICAgICAgIGNoYW5nZURldGVjdG9yLm1hcmtGb3JDaGVjaygpO1xyXG4gICAgICB9KTtcclxuICB9XHJcblxyXG4gIG5nT25DaGFuZ2VzKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLnZpc2libGUpIHRoaXMuZ2xvYmFsU2VhcmNoVGV4dCA9IG51bGw7XHJcbiAgICB0aGlzLnVwZGF0ZVZpc2libGVDb2x1bW5zKCk7XHJcbiAgfVxyXG5cclxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcclxuICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xyXG4gICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB1cGRhdGVWaXNpYmxlQ29sdW1ucygpOiB2b2lkIHtcclxuICAgIGNvbnN0IHNlYXJjaCA9ICh0aGlzLmdsb2JhbFNlYXJjaFRleHQgPz8gJycpLnRvTG9jYWxlTG93ZXJDYXNlKCk7XHJcbiAgICBjb25zdCBsYWJlbCA9IChjb2x1bW46IGFueSk6IHN0cmluZyA9PiBjb2x1bW4uaGVhZGVyID8gdGhpcy50cmFuc2xhdGUuaW5zdGFudChjb2x1bW4uaGVhZGVyKSA6ICcnO1xyXG4gICAgdGhpcy5maWx0ZXJlZENvbHVtbkRhdGEgPSB0aGlzLmNvbHVtbk1vZGFsRGF0YS5maWx0ZXIoY29sdW1uID0+XHJcbiAgICAgIGxhYmVsKGNvbHVtbikudG9Mb2NhbGVMb3dlckNhc2UoKS5pbmNsdWRlcyhzZWFyY2gpXHJcbiAgICApO1xyXG4gICAgaWYgKHRoaXMub3JkZXJCeUhlYWRlcikge1xyXG4gICAgICB0aGlzLmZpbHRlcmVkQ29sdW1uRGF0YS5zb3J0KChhLCBiKSA9PiBsYWJlbChhKS5sb2NhbGVDb21wYXJlKGxhYmVsKGIpKSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBAVmlld0NoaWxkKCdkdF9jb2x1bW5EaWFsb2cnKSBkdF9jb2x1bW5EaWFsb2chOiBUYWJsZTtcclxuICBcclxuICBASW5wdXQoKSB2aXNpYmxlOiBib29sZWFuID0gZmFsc2U7XHJcbiAgQElucHV0KCkgY29sdW1uTW9kYWxEYXRhOiBhbnlbXSA9IFtdO1xyXG4gIEBJbnB1dCgpIGZpbHRlcmVkQ29sdW1uRGF0YTogYW55W10gPSBbXTtcclxuXHJcbiAgQE91dHB1dCgpIHZpc2libGVDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XHJcbiAgQE91dHB1dCgpIGFwcGx5Q2hhbmdlcyA9IG5ldyBFdmVudEVtaXR0ZXI8SUNvbHVtbk1ldGFkYXRhW10+KCk7IFxyXG5cclxuICBjZWxsT3ZlcmZsb3dCZWhhdmlvdXJPcHRpb25zID0gW1xyXG4gICAge2ljb246ICdwaSBwaS1taW51cycsIHZhbDogQ2VsbE92ZXJmbG93QmVoYXZpb3VyLkhpZGRlbiwgbmFtZTogXCJIaWRkZW5cIn0sXHJcbiAgICB7aWNvbjogJ3BpIHBpLWVxdWFscycsIHZhbDogQ2VsbE92ZXJmbG93QmVoYXZpb3VyLldyYXAsIG5hbWU6IFwiV3JhcFwifS8qLFxyXG4gICAge2ljb246ICdwaSBwaS1lbGxpcHNpcy1oJywgdmFsOiBDZWxsT3ZlcmZsb3dCZWhhdmlvdXIuRWxsaXBzaXMsIG5hbWU6IFwiRWxsaXBzaXNcIn0qL1xyXG4gIF07XHJcbiAgZGF0YUFsaWduSG9yaXpvbnRhbE9wdGlvbnMgPSBbXHJcbiAgICB7aWNvbjogJ3BpIHBpLWFsaWduLWxlZnQnLCB2YWw6IERhdGFBbGlnbkhvcml6b250YWwuTGVmdCwgbmFtZTogXCJMZWZ0XCJ9LFxyXG4gICAge2ljb246ICdwaSBwaS1hbGlnbi1jZW50ZXInLCB2YWw6IERhdGFBbGlnbkhvcml6b250YWwuQ2VudGVyLCBuYW1lOiBcIkNlbnRlclwifSxcclxuICAgIHtpY29uOiAncGkgcGktYWxpZ24tcmlnaHQnLCB2YWw6IERhdGFBbGlnbkhvcml6b250YWwuUmlnaHQsIG5hbWU6IFwiUmlnaHRcIn1cclxuICBdO1xyXG4gIGRhdGFBbGlnblZlcnRpY2FsT3B0aW9ucyA9IFtcclxuICAgIHtpY29uOiAncGkgcGktYW5nbGUtdXAnLCB2YWw6IERhdGFBbGlnblZlcnRpY2FsLlRvcCwgbmFtZTogXCJUb3BcIn0sXHJcbiAgICB7aWNvbjogJ3BpIHBpLWFsaWduLWp1c3RpZnknLCB2YWw6IERhdGFBbGlnblZlcnRpY2FsLk1pZGRsZSwgbmFtZTogXCJNaWRkbGVcIn0sXHJcbiAgICB7aWNvbjogJ3BpIHBpLWFuZ2xlLWRvd24nLCB2YWw6IERhdGFBbGlnblZlcnRpY2FsLkJvdHRvbSwgbmFtZTogXCJCb3R0b21cIn1cclxuICBdO1xyXG5cclxuICB0cmFuc2xhdGVkT3B0aW9ucyhvcHRpb25zOiB7IG5hbWU6IHN0cmluZzsgaWNvbjogc3RyaW5nOyB2YWw6IG51bWJlciB9W10pIHtcclxuICAgIHJldHVybiBvcHRpb25zLm1hcChvcHRpb24gPT4gKHsgLi4ub3B0aW9uLCBuYW1lOiB0aGlzLnRyYW5zbGF0ZS5pbnN0YW50KG9wdGlvbi5uYW1lKSB9KSk7XHJcbiAgfVxyXG5cclxuICBnbG9iYWxTZWFyY2hUZXh0OiBzdHJpbmcgfCBudWxsID0gbnVsbDsgLy8gVGhlIHRleHQgdXNlZCBieSB0aGUgZ2xvYmFsIHNlYXJjaFxyXG4gIGdsb2JhbFNlYXJjaE1heExlbmd0aDogbnVtYmVyID0gNTA7XHJcbiAgYWxsQ29sdW1uc0NoZWNrYm94QWN0aXZlKCk6IGJvb2xlYW57XHJcbiAgICByZXR1cm4gdGhpcy5jb2x1bW5Nb2RhbERhdGEuZXZlcnkoY29sdW1uID0+IGNvbHVtbi5zZWxlY3RlZCk7XHJcbiAgfVxyXG5cclxuICBhbGxDb2x1bW5zQ2hlY2tib3hDbGljayhldmVudDogYW55KTogdm9pZHtcclxuICAgIGlmKGV2ZW50LmNoZWNrZWQpe1xyXG4gICAgICB0aGlzLmNvbHVtbk1vZGFsRGF0YS5mb3JFYWNoKGNvbHVtbiA9PiB7Y29sdW1uLnNlbGVjdGVkID0gdHJ1ZTt9KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMuY29sdW1uTW9kYWxEYXRhLmZvckVhY2goY29sdW1uID0+IHtcclxuICAgICAgICBpZiAoIWNvbHVtbi5zZWxlY3REaXNhYmxlZCkge1xyXG4gICAgICAgICAgY29sdW1uLnNlbGVjdGVkID0gZmFsc2U7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGZpbHRlckNvbHVtbk1vZGFsKGV2ZW50OiBhbnkpIHtcclxuICAgIHRoaXMuZ2xvYmFsU2VhcmNoVGV4dCA9IGV2ZW50LnRhcmdldC52YWx1ZTtcclxuICAgIHRoaXMudXBkYXRlVmlzaWJsZUNvbHVtbnMoKTtcclxuICB9XHJcblxyXG4gIGFwcGx5Q29sdW1uTW9kYWxDaGFuZ2VzKCl7XHJcbiAgICBjb25zdCBzZWxlY3RlZCA9IHRoaXMuY29sdW1uTW9kYWxEYXRhLmZpbHRlcihjID0+IGMuc2VsZWN0ZWQgJiYgIWMuc2VsZWN0RGlzYWJsZWQpO1xyXG4gICAgdGhpcy5hcHBseUNoYW5nZXMuZW1pdChzZWxlY3RlZCk7XHJcbiAgICB0aGlzLmNsb3NlTW9kYWwoKTtcclxuICB9XHJcbiAgY2xlYXJHbG9iYWxGaWx0ZXIoZHQ6IFRhYmxlKXtcclxuICAgIHRoaXMuZ2xvYmFsU2VhcmNoVGV4dD1udWxsO1xyXG4gICAgdGhpcy51cGRhdGVWaXNpYmxlQ29sdW1ucygpO1xyXG4gIH1cclxuICBjbG9zZU1vZGFsKCl7XHJcbiAgICB0aGlzLmdsb2JhbFNlYXJjaFRleHQ9bnVsbDtcclxuICAgIHRoaXMudmlzaWJsZUNoYW5nZS5lbWl0KGZhbHNlKTtcclxuICB9XHJcbn1cclxuIiwiPCEtLUNPTFVNTiBNT0RBTCBESUFMT0ctLT5cclxuPHAtZGlhbG9nIFsodmlzaWJsZSldPVwidmlzaWJsZVwiIFttb2RhbF09XCJ0cnVlXCIgW2RyYWdnYWJsZV09XCJmYWxzZVwiIFtyZXNpemFibGVdPVwiZmFsc2VcIiBbY2xvc2VPbkVzY2FwZV09XCJmYWxzZVwiIFtjbG9zYWJsZV09XCJmYWxzZVwiIFttYXhpbWl6YWJsZV09XCJmYWxzZVwiIFtzdHlsZV09XCJ7J21pbi13aWR0aCc6ICc2NXZ3JywgJ21heC13aWR0aCc6ICc2NXZ3J31cIj5cclxuICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJoZWFkZXJcIj5cclxuICAgICAgICA8c3BhbiBjbGFzcz1cIndoaXRlLXNwYWNlLW5vd3JhcFwiPjxiPnt7ICdNT0RJRlkgQ09MVU1OUycgfCBlY3NUcmFuc2xhdGUgfX08L2I+PC9zcGFuPlxyXG4gICAgPC9uZy10ZW1wbGF0ZT5cclxuICAgIDxkaXYgc3R5bGU9XCJwYWRkaW5nOiAxMHB4O1wiPlxyXG4gICAgICAgIDxwLXRhYmxlICNkdF9jb2x1bW5EaWFsb2cgW3ZhbHVlXT1cImZpbHRlcmVkQ29sdW1uRGF0YVwiIFtzY3JvbGxhYmxlXT1cInRydWVcIiBzaXplPVwic21hbGxcIiBzaG93R3JpZGxpbmVzIHN0cmlwZWRSb3dzXHJcbiAgICAgICAgICAgIHNjcm9sbEhlaWdodD1cImNhbGMoODB2aCAtIDIyMHB4KVwiPlxyXG4gICAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiY2FwdGlvblwiPlxyXG4gICAgICAgICAgICAgICAgPGRpdiBzdHlsZT1cImRpc3BsYXk6IGZsZXg7IGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjsgYWxpZ24taXRlbXM6IGNlbnRlcjtcIj5cclxuICAgICAgICAgICAgICAgICAgICA8ZGl2IHN0eWxlPVwiZGlzcGxheTogZmxleDsgYWxpZ24taXRlbXM6IGNlbnRlcjsgZ2FwOiAxMHB4XCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxwLWNoZWNrYm94IGlucHV0SWQ9XCJzZWxlY3RBbGxcIiBbYmluYXJ5XT1cInRydWVcIiBbbmdNb2RlbF09XCJhbGxDb2x1bW5zQ2hlY2tib3hBY3RpdmUoKVwiIChvbkNoYW5nZSk9XCJhbGxDb2x1bW5zQ2hlY2tib3hDbGljaygkZXZlbnQpXCI+PC9wLWNoZWNrYm94PlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8bGFiZWwgZm9yPVwic2VsZWN0QWxsXCI+e3sgJ1NlbGVjdCBhbGwgY29sdW1ucycgfCBlY3NUcmFuc2xhdGUgfX08L2xhYmVsPlxyXG4gICAgICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICAgICAgICAgIDxkaXYgc3R5bGU9XCJkaXNwbGF5OiBmbGV4OyBhbGlnbi1pdGVtczogY2VudGVyO1wiPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImVjcy1nbG9iYWwtc2VhcmNoXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cImVjcy1pbnB1dC1pY29uXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGkgY2xhc3M9XCJwaSBwaS1zZWFyY2hcIj48L2k+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L3NwYW4+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8aW5wdXQgcElucHV0VGV4dCB0eXBlPVwidGV4dFwiIFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChpbnB1dCk9XCJmaWx0ZXJDb2x1bW5Nb2RhbCgkZXZlbnQpXCIgYXV0b2NvbXBsZXRlPVwib2ZmXCIgXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW21heGxlbmd0aF09XCJnbG9iYWxTZWFyY2hNYXhMZW5ndGhcIiBbcGxhY2Vob2xkZXJdPVwiJ1NlYXJjaCBjb2x1bW4gbmFtZScgfCBlY3NUcmFuc2xhdGVcIiBbKG5nTW9kZWwpXT1cImdsb2JhbFNlYXJjaFRleHRcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0eWxlPVwid2lkdGg6IDIyMHB4O1wiLz5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwhLS0gUmlnaHQgaWNvbiAob25seSBpZiB0aGVyZSBpcyB0ZXh0KSAtLT5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxuZy1jb250YWluZXIgKm5nSWY9XCJnbG9iYWxTZWFyY2hUZXh0XCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJlY3MtaW5wdXQtaWNvblwiIHBvc2l0aW9uPVwicmlnaHRcIj5cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGkgY2xhc3M9XCJwaSBwaS10aW1lc1wiIHN0eWxlPVwiY3Vyc29yOiBwb2ludGVyO1wiIChjbGljayk9XCJjbGVhckdsb2JhbEZpbHRlcihkdF9jb2x1bW5EaWFsb2cpOyAkZXZlbnQuc3RvcFByb3BhZ2F0aW9uKClcIj48L2k+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9zcGFuPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPC9uZy1jb250YWluZXI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDwvc3Bhbj5cclxuICAgICAgICAgICAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxyXG4gICAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiaGVhZGVyXCI+XHJcbiAgICAgICAgICAgICAgICA8dHI+XHJcbiAgICAgICAgICAgICAgICAgICAgPHRoIHBGcm96ZW5Db2x1bW4gc3R5bGU9XCJtYXgtd2lkdGg6IDEwMHB4OyBtaW4td2lkdGg6IDEwMHB4OyB3aWR0aDogMTAwcHg7IHRleHQtYWxpZ246IGNlbnRlcjtcIj57eyAnU2hvdyBjb2x1bW4nIHwgZWNzVHJhbnNsYXRlIH19PC90aD5cclxuICAgICAgICAgICAgICAgICAgICA8dGggcEZyb3plbkNvbHVtbiBzdHlsZT1cIm1heC13aWR0aDogMjUwcHg7IG1pbi13aWR0aDogMjUwcHg7IHdpZHRoOiAyNTBweDsgdGV4dC1hbGlnbjogY2VudGVyO1wiPnt7ICdDb2x1bW4gbmFtZScgfCBlY3NUcmFuc2xhdGUgfX08L3RoPlxyXG4gICAgICAgICAgICAgICAgICAgIDx0aCBzdHlsZT1cIm1heC13aWR0aDogMTUwcHg7IG1pbi13aWR0aDogMTUwcHg7IHdpZHRoOiAxNTBweDsgdGV4dC1hbGlnbjogY2VudGVyO1wiPnt7ICdDZWxsIG92ZXJmbG93IGJlaGF2aW91cicgfCBlY3NUcmFuc2xhdGUgfX08L3RoPlxyXG4gICAgICAgICAgICAgICAgICAgIDx0aCBzdHlsZT1cIm1heC13aWR0aDogMTYwcHg7IG1pbi13aWR0aDogMTYwcHg7IHdpZHRoOiAxNjBweDsgdGV4dC1hbGlnbjogY2VudGVyO1wiPnt7ICdIb3Jpem9udGFsIGFsaWdubWVudCcgfCBlY3NUcmFuc2xhdGUgfX08L3RoPlxyXG4gICAgICAgICAgICAgICAgICAgIDx0aCBzdHlsZT1cIm1heC13aWR0aDogMTUwcHg7IG1pbi13aWR0aDogMTUwcHg7IHdpZHRoOiAxNTBweDsgdGV4dC1hbGlnbjogY2VudGVyO1wiPnt7ICdWZXJ0aWNhbCBhbGlnbm1lbnQnIHwgZWNzVHJhbnNsYXRlIH19PC90aD5cclxuICAgICAgICAgICAgICAgIDwvdHI+XHJcbiAgICAgICAgICAgIDwvbmctdGVtcGxhdGU+XHJcbiAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSBwVGVtcGxhdGU9XCJib2R5XCIgbGV0LXJvd0RhdGE+XHJcbiAgICAgICAgICAgICAgICA8dHI+XHJcbiAgICAgICAgICAgICAgICAgICAgPHRkIHBGcm96ZW5Db2x1bW4gc3R5bGU9XCJtYXgtd2lkdGg6IDEwMHB4OyBtaW4td2lkdGg6IDEwMHB4OyB3aWR0aDogMTAwcHg7IHRleHQtYWxpZ246IGNlbnRlcjtcIj5cclxuICAgICAgICAgICAgICAgICAgICAgICAgPHAtY2hlY2tib3ggXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBbKG5nTW9kZWwpXT1cInJvd0RhdGEuc2VsZWN0ZWRcIiBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtiaW5hcnldPVwidHJ1ZVwiXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBbZGlzYWJsZWRdPVwicm93RGF0YS5zZWxlY3REaXNhYmxlZFwiPjwvcC1jaGVja2JveD5cclxuICAgICAgICAgICAgICAgICAgICA8L3RkPlxyXG4gICAgICAgICAgICAgICAgICAgIDx0ZCBwRnJvemVuQ29sdW1uIHN0eWxlPVwibWF4LXdpZHRoOiAyNTBweDsgbWluLXdpZHRoOiAyNTBweDsgd2lkdGg6IDI1MHB4O1wiPnt7cm93RGF0YS5oZWFkZXIgfCB0cmFuc2xhdGV9fTwvdGQ+XHJcbiAgICAgICAgICAgICAgICAgICAgPHRkIHN0eWxlPVwibWF4LXdpZHRoOiAxNTBweDsgbWluLXdpZHRoOiAxNTBweDsgd2lkdGg6IDE1MHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7XCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxwLXNlbGVjdEJ1dHRvbiBbKG5nTW9kZWwpXT1cInJvd0RhdGEuY2VsbE92ZXJmbG93QmVoYXZpb3VyXCIgW29wdGlvbnNdPVwidHJhbnNsYXRlZE9wdGlvbnMoY2VsbE92ZXJmbG93QmVoYXZpb3VyT3B0aW9ucylcIiBvcHRpb25WYWx1ZT1cInZhbFwiIG9wdGlvbkxhYmVsPVwibmFtZVwiIFtkaXNhYmxlZF09XCJyb3dEYXRhLmNlbGxPdmVyZmxvd0JlaGF2aW91ckRpc2FibGVkXCIgYWxsb3dFbXB0eT1cImZhbHNlXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiaXRlbVwiIGxldC1pdGVtPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxpIFtjbGFzc109XCJpdGVtLmljb25cIiBzdHlsZT1cIm1hcmdpbjogLTIwcHg7XCIgW3BUb29sdGlwXT1cIihpdGVtLm5hbWUpIHwgZWNzVHJhbnNsYXRlXCIgW3Nob3dEZWxheV09XCI0MDBcIiB0b29sdGlwUG9zaXRpb249XCJ0b3BcIj48L2k+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8L3Atc2VsZWN0QnV0dG9uPlxyXG4gICAgICAgICAgICAgICAgICAgIDwvdGQ+XHJcbiAgICAgICAgICAgICAgICAgICAgPHRkIHN0eWxlPVwibWF4LXdpZHRoOiAxNjBweDsgbWluLXdpZHRoOiAxNjBweDsgd2lkdGg6IDE2MHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7XCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxwLXNlbGVjdEJ1dHRvbiBbKG5nTW9kZWwpXT1cInJvd0RhdGEuZGF0YUFsaWduSG9yaXpvbnRhbFwiIFtvcHRpb25zXT1cInRyYW5zbGF0ZWRPcHRpb25zKGRhdGFBbGlnbkhvcml6b250YWxPcHRpb25zKVwiIG9wdGlvblZhbHVlPVwidmFsXCIgb3B0aW9uTGFiZWw9XCJuYW1lXCIgW2Rpc2FibGVkXT1cInJvd0RhdGEuZGF0YUFsaWduSG9yaXpvbnRhbERpc2FibGVkXCIgYWxsb3dFbXB0eT1cImZhbHNlXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiaXRlbVwiIGxldC1pdGVtPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxpIFtjbGFzc109XCJpdGVtLmljb25cIiBzdHlsZT1cIm1hcmdpbjogLTIwcHg7XCIgW3BUb29sdGlwXT1cIihpdGVtLm5hbWUpIHwgZWNzVHJhbnNsYXRlXCIgW3Nob3dEZWxheV09XCI0MDBcIiB0b29sdGlwUG9zaXRpb249XCJ0b3BcIj48L2k+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8L3Atc2VsZWN0QnV0dG9uPlxyXG4gICAgICAgICAgICAgICAgICAgIDwvdGQ+XHJcbiAgICAgICAgICAgICAgICAgICAgPHRkIHN0eWxlPVwibWF4LXdpZHRoOiAxNTBweDsgbWluLXdpZHRoOiAxNTBweDsgd2lkdGg6IDE1MHB4OyB0ZXh0LWFsaWduOiBjZW50ZXI7XCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIDxwLXNlbGVjdEJ1dHRvbiBbKG5nTW9kZWwpXT1cInJvd0RhdGEuZGF0YUFsaWduVmVydGljYWxcIiBbb3B0aW9uc109XCJ0cmFuc2xhdGVkT3B0aW9ucyhkYXRhQWxpZ25WZXJ0aWNhbE9wdGlvbnMpXCIgb3B0aW9uVmFsdWU9XCJ2YWxcIiBvcHRpb25MYWJlbD1cIm5hbWVcIiBbZGlzYWJsZWRdPVwicm93RGF0YS5kYXRhQWxpZ25WZXJ0aWNhbERpc2FibGVkXCIgYWxsb3dFbXB0eT1cImZhbHNlXCI+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiaXRlbVwiIGxldC1pdGVtPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxpIFtjbGFzc109XCJpdGVtLmljb25cIiBzdHlsZT1cIm1hcmdpbjogLTIwcHg7XCIgW3BUb29sdGlwXT1cIihpdGVtLm5hbWUpIHwgZWNzVHJhbnNsYXRlXCIgW3Nob3dEZWxheV09XCI0MDBcIiB0b29sdGlwUG9zaXRpb249XCJ0b3BcIj48L2k+XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxyXG4gICAgICAgICAgICAgICAgICAgICAgICA8L3Atc2VsZWN0QnV0dG9uPlxyXG4gICAgICAgICAgICAgICAgICAgIDwvdGQ+XHJcbiAgICAgICAgICAgICAgICA8L3RyPlxyXG4gICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxyXG4gICAgICAgICAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiZW1wdHltZXNzYWdlXCI+XHJcbiAgICAgICAgICAgICAgICA8dHI+XHJcbiAgICAgICAgICAgICAgICAgICAgPHRkIGNvbHNwYW49XCI5OTlcIj57eyAnVGhlcmUgYXJlIG5vIGNvbHVtbnMnIHwgZWNzVHJhbnNsYXRlIH19PC90ZD5cclxuICAgICAgICAgICAgICAgIDwvdHI+XHJcbiAgICAgICAgICAgIDwvbmctdGVtcGxhdGU+XHJcbiAgICAgICAgPC9wLXRhYmxlPlxyXG4gICAgICAgIDxkaXYgc3R5bGU9XCJkaXNwbGF5OiBmbGV4OyBmbGV4LWRpcmVjdGlvbjogcm93OyBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47IGFsaWduLWl0ZW1zOiBjZW50ZXI7IG1hcmdpbi10b3A6IDEwcHg7XCI+XHJcbiAgICAgICAgICAgIHt7ICdTaG93aW5nIHt7Y291bnR9fSBjb2x1bW5zIG9mIHt7dG90YWx9fSBhdmFpbGFibGUgY29sdW1ucycgfCBlY3NUcmFuc2xhdGU6IHsgY291bnQ6IGZpbHRlcmVkQ29sdW1uRGF0YSA/IGZpbHRlcmVkQ29sdW1uRGF0YS5sZW5ndGggOiAwLCB0b3RhbDogY29sdW1uTW9kYWxEYXRhID8gY29sdW1uTW9kYWxEYXRhLmxlbmd0aCA6IDAgfSB9fVxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcbiAgICA8bmctdGVtcGxhdGUgcFRlbXBsYXRlPVwiZm9vdGVyXCIgc3R5bGU9XCJkaXNwbGF5OiBmbGV4OyBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47IGFsaWduLWl0ZW1zOiBjZW50ZXI7XCI+XHJcbiAgICAgICAgPHAtYnV0dG9uIChjbGljayk9XCJjbG9zZU1vZGFsKClcIiBbbGFiZWxdPVwiJ0NhbmNlbCBjaGFuZ2VzJyB8IGVjc1RyYW5zbGF0ZVwiIG91dGxpbmVkPVwidHJ1ZVwiIFtzdHlsZV09XCJ7J21hcmdpbi10b3AnOiAnMTBweCd9XCI+PC9wLWJ1dHRvbj5cclxuICAgICAgICA8cC1idXR0b24gKGNsaWNrKT1cImFwcGx5Q29sdW1uTW9kYWxDaGFuZ2VzKClcIiBbbGFiZWxdPVwiJ1NhdmUgY2hhbmdlcycgfCBlY3NUcmFuc2xhdGVcIiBbc3R5bGVdPVwieydtYXJnaW4tdG9wJzogJzEwcHgnfVwiPjwvcC1idXR0b24+XHJcbiAgICA8L25nLXRlbXBsYXRlPlxyXG48L3AtZGlhbG9nPiJdfQ==
|