@c8y/ngx-components 1022.21.3 → 1022.26.1
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/asset-properties/asset-properties.model.d.ts +117 -0
- package/asset-properties/asset-properties.model.d.ts.map +1 -0
- package/asset-properties/asset-properties.service.d.ts +72 -0
- package/asset-properties/asset-properties.service.d.ts.map +1 -0
- package/asset-properties/asset-property-list/asset-property-action.directive.d.ts +11 -0
- package/asset-properties/asset-property-list/asset-property-action.directive.d.ts.map +1 -0
- package/asset-properties/asset-property-list/asset-property-icon.pipe.d.ts +11 -0
- package/asset-properties/asset-property-list/asset-property-icon.pipe.d.ts.map +1 -0
- package/asset-properties/asset-property-list/asset-property-list.component.d.ts +195 -0
- package/asset-properties/asset-property-list/asset-property-list.component.d.ts.map +1 -0
- package/asset-properties/asset-property-list/asset-property-value.pipe.d.ts +17 -0
- package/asset-properties/asset-property-list/asset-property-value.pipe.d.ts.map +1 -0
- package/asset-properties/asset-property-list/tree-data-source.d.ts +19 -0
- package/asset-properties/asset-property-list/tree-data-source.d.ts.map +1 -0
- package/asset-properties/asset-property-selector-drawer/asset-property-selector-drawer.component.d.ts +75 -0
- package/asset-properties/asset-property-selector-drawer/asset-property-selector-drawer.component.d.ts.map +1 -0
- package/asset-properties/c8y-ngx-components-asset-properties.d.ts.map +1 -0
- package/asset-properties/index.d.ts +6 -0
- package/asset-properties/index.d.ts.map +1 -0
- package/core/user/user-edit-modal.component.d.ts.map +1 -1
- package/datapoint-explorer/view/datapoint-explorer.component.d.ts +2 -0
- package/datapoint-explorer/view/datapoint-explorer.component.d.ts.map +1 -1
- package/device-provisioned-certificates/device-tab-provisioned-certificates.component.d.ts +8 -2
- package/device-provisioned-certificates/device-tab-provisioned-certificates.component.d.ts.map +1 -1
- package/echart/charts.component.d.ts +1 -1
- package/echart/charts.component.d.ts.map +1 -1
- package/echart/index.d.ts +1 -0
- package/echart/index.d.ts.map +1 -1
- package/echart/models/datapoints-graph-widget.model.d.ts +13 -0
- package/echart/models/datapoints-graph-widget.model.d.ts.map +1 -1
- package/echart/services/chart-helpers.service.d.ts +23 -0
- package/echart/services/chart-helpers.service.d.ts.map +1 -0
- package/echart/services/echarts-options.service.d.ts +1 -1
- package/echart/services/echarts-options.service.d.ts.map +1 -1
- package/fesm2022/c8y-ngx-components-alarms.mjs +2 -2
- package/fesm2022/c8y-ngx-components-alarms.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-asset-properties.mjs +1573 -0
- package/fesm2022/c8y-ngx-components-asset-properties.mjs.map +1 -0
- package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs +22 -7
- package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-device-list.mjs +2 -2
- package/fesm2022/c8y-ngx-components-device-list.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-device-provisioned-certificates.mjs +32 -18
- package/fesm2022/c8y-ngx-components-device-provisioned-certificates.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-echart-models.mjs +14 -1
- package/fesm2022/c8y-ngx-components-echart-models.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-echart.mjs +88 -29
- package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-protocol-opcua.mjs +3 -3
- package/fesm2022/c8y-ngx-components-protocol-opcua.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget.mjs +6 -0
- package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs +12 -4
- package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components-widgets-implementations-html-widget.mjs +51 -10
- package/fesm2022/c8y-ngx-components-widgets-implementations-html-widget.mjs.map +1 -1
- package/fesm2022/c8y-ngx-components.mjs +1 -1
- package/fesm2022/c8y-ngx-components.mjs.map +1 -1
- package/locales/de.po +38 -24
- package/locales/es.po +38 -24
- package/locales/fr.po +38 -24
- package/locales/ja_JP.po +37 -24
- package/locales/ko.po +37 -24
- package/locales/locales.pot +43 -12
- package/locales/nl.po +38 -24
- package/locales/pl.po +38 -24
- package/locales/pt_BR.po +38 -24
- package/locales/zh_CN.po +38 -24
- package/locales/zh_TW.po +38 -24
- package/package.json +1 -1
- package/widgets/definitions/html-widget/html-widget-config.factory.d.ts.map +1 -1
- package/widgets/implementations/datapoints-graph/datapoints-graph-config/datapoints-graph-widget-config.component.d.ts +2 -0
- package/widgets/implementations/datapoints-graph/datapoints-graph-config/datapoints-graph-widget-config.component.d.ts.map +1 -1
- package/widgets/implementations/html-widget/html-widget-properties-selector/html-widget-properties-selector.component.d.ts +17 -0
- package/widgets/implementations/html-widget/html-widget-properties-selector/html-widget-properties-selector.component.d.ts.map +1 -0
- package/widgets/implementations/html-widget/html-widget.model.d.ts +2 -2
- package/widgets/implementations/html-widget/html-widget.model.d.ts.map +1 -1
- package/widgets/implementations/html-widget/index.d.ts +1 -0
- package/widgets/implementations/html-widget/index.d.ts.map +1 -1
|
@@ -0,0 +1,1573 @@
|
|
|
1
|
+
import * as i2 from '@c8y/ngx-components';
|
|
2
|
+
import { gettext, AssetTypesRealtimeService, GroupService, ListGroupModule, C8yTranslatePipe, IconDirective, EmptyStateComponent, BottomDrawerRef, FormsModule as FormsModule$1 } from '@c8y/ngx-components';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { inject, Injectable, Directive, Pipe, viewChild, EventEmitter, effect, ContentChild, Output, Input, Component } from '@angular/core';
|
|
5
|
+
import { InventoryService } from '@c8y/client';
|
|
6
|
+
import { isArray, isObjectLike, isEmpty, find, forOwn, get, cloneDeep } from 'lodash-es';
|
|
7
|
+
import { firstValueFrom, BehaviorSubject, Subject, takeUntil, debounceTime } from 'rxjs';
|
|
8
|
+
import { NgIf, NgClass, NgTemplateOutlet } from '@angular/common';
|
|
9
|
+
import * as i1 from '@angular/forms';
|
|
10
|
+
import { FormsModule } from '@angular/forms';
|
|
11
|
+
import * as i3 from 'ngx-bootstrap/tooltip';
|
|
12
|
+
import { TooltipModule } from 'ngx-bootstrap/tooltip';
|
|
13
|
+
import * as i4 from '@angular/cdk/tree';
|
|
14
|
+
import { CdkTreeModule } from '@angular/cdk/tree';
|
|
15
|
+
import { DataSource } from '@angular/cdk/collections';
|
|
16
|
+
|
|
17
|
+
const defaultAssetPropertyListConfig = {
|
|
18
|
+
searchable: true,
|
|
19
|
+
selectMode: 'none',
|
|
20
|
+
expansionMode: 'expandedByDefault',
|
|
21
|
+
showHeader: true,
|
|
22
|
+
showValue: true,
|
|
23
|
+
showKey: true,
|
|
24
|
+
emptyStateContent: 'empty',
|
|
25
|
+
inputPropertiesHandle: 'merge'
|
|
26
|
+
};
|
|
27
|
+
const defaultAssetProperties = [
|
|
28
|
+
{
|
|
29
|
+
c8y_JsonSchema: { properties: { name: { type: 'string', label: 'Name' } } },
|
|
30
|
+
name: 'name',
|
|
31
|
+
label: 'Name',
|
|
32
|
+
type: 'string',
|
|
33
|
+
active: true,
|
|
34
|
+
isEditable: true,
|
|
35
|
+
isStandardProperty: true
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
c8y_JsonSchema: { properties: { id: { type: 'string', label: 'ID' } } },
|
|
39
|
+
name: 'id',
|
|
40
|
+
label: 'ID',
|
|
41
|
+
type: 'string',
|
|
42
|
+
active: true,
|
|
43
|
+
isEditable: false,
|
|
44
|
+
isStandardProperty: true
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
c8y_JsonSchema: {
|
|
48
|
+
properties: { type: { type: 'string', label: 'Type' } }
|
|
49
|
+
},
|
|
50
|
+
name: 'type',
|
|
51
|
+
label: 'Type',
|
|
52
|
+
type: 'string',
|
|
53
|
+
active: true,
|
|
54
|
+
isEditable: false,
|
|
55
|
+
isStandardProperty: true
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
c8y_JsonSchema: {
|
|
59
|
+
properties: { owner: { type: 'string', label: 'Owner' } }
|
|
60
|
+
},
|
|
61
|
+
name: 'owner',
|
|
62
|
+
label: 'Owner',
|
|
63
|
+
type: 'string',
|
|
64
|
+
isEditable: false,
|
|
65
|
+
isStandardProperty: true
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
c8y_JsonSchema: {
|
|
69
|
+
properties: { lastUpdated: { type: 'string', label: 'Last updated' } }
|
|
70
|
+
},
|
|
71
|
+
name: 'lastUpdated',
|
|
72
|
+
label: 'Last updated',
|
|
73
|
+
type: 'string',
|
|
74
|
+
isEditable: false,
|
|
75
|
+
isStandardProperty: true
|
|
76
|
+
}
|
|
77
|
+
];
|
|
78
|
+
const deviceAssetProperties = [
|
|
79
|
+
{
|
|
80
|
+
label: 'Active alarms status',
|
|
81
|
+
type: 'object',
|
|
82
|
+
isEditable: false,
|
|
83
|
+
isStandardProperty: true,
|
|
84
|
+
name: 'c8y_ActiveAlarmsStatus',
|
|
85
|
+
c8y_JsonSchema: {
|
|
86
|
+
properties: {
|
|
87
|
+
c8y_ActiveAlarmsStatus: {
|
|
88
|
+
key: 'c8y_ActiveAlarmsStatus',
|
|
89
|
+
type: 'object',
|
|
90
|
+
label: 'Active alarms status',
|
|
91
|
+
properties: {
|
|
92
|
+
critical: {
|
|
93
|
+
title: 'Critical',
|
|
94
|
+
type: 'number'
|
|
95
|
+
},
|
|
96
|
+
major: {
|
|
97
|
+
title: 'Major',
|
|
98
|
+
type: 'number'
|
|
99
|
+
},
|
|
100
|
+
minor: {
|
|
101
|
+
title: 'Minor',
|
|
102
|
+
type: 'number'
|
|
103
|
+
},
|
|
104
|
+
warning: {
|
|
105
|
+
title: 'Warning',
|
|
106
|
+
type: 'number'
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
label: 'Address',
|
|
115
|
+
type: 'object',
|
|
116
|
+
isEditable: true,
|
|
117
|
+
isStandardProperty: true,
|
|
118
|
+
name: 'c8y_Address',
|
|
119
|
+
c8y_JsonSchema: {
|
|
120
|
+
properties: {
|
|
121
|
+
c8y_Address: {
|
|
122
|
+
key: 'c8y_Address',
|
|
123
|
+
type: 'object',
|
|
124
|
+
label: 'Address',
|
|
125
|
+
properties: {
|
|
126
|
+
street: {
|
|
127
|
+
title: 'Street',
|
|
128
|
+
type: 'string'
|
|
129
|
+
},
|
|
130
|
+
city: {
|
|
131
|
+
title: 'City',
|
|
132
|
+
type: 'string'
|
|
133
|
+
},
|
|
134
|
+
cityCode: {
|
|
135
|
+
title: 'City code',
|
|
136
|
+
type: 'string'
|
|
137
|
+
},
|
|
138
|
+
territory: {
|
|
139
|
+
title: 'Territory',
|
|
140
|
+
type: 'string'
|
|
141
|
+
},
|
|
142
|
+
region: {
|
|
143
|
+
title: 'Region',
|
|
144
|
+
type: 'string'
|
|
145
|
+
},
|
|
146
|
+
country: {
|
|
147
|
+
title: 'Country',
|
|
148
|
+
type: 'string'
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
label: 'Agent',
|
|
157
|
+
type: 'object',
|
|
158
|
+
isEditable: true,
|
|
159
|
+
isStandardProperty: true,
|
|
160
|
+
name: 'c8y_Agent',
|
|
161
|
+
c8y_JsonSchema: {
|
|
162
|
+
properties: {
|
|
163
|
+
c8y_Agent: {
|
|
164
|
+
key: 'c8y_Agent',
|
|
165
|
+
type: 'object',
|
|
166
|
+
label: 'Agent',
|
|
167
|
+
properties: {
|
|
168
|
+
name: {
|
|
169
|
+
title: 'Name',
|
|
170
|
+
type: 'string'
|
|
171
|
+
},
|
|
172
|
+
version: {
|
|
173
|
+
title: 'Version',
|
|
174
|
+
type: 'string'
|
|
175
|
+
},
|
|
176
|
+
url: {
|
|
177
|
+
title: 'URL',
|
|
178
|
+
type: 'string'
|
|
179
|
+
},
|
|
180
|
+
maintainer: {
|
|
181
|
+
title: 'Maintainer',
|
|
182
|
+
type: 'string'
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
label: 'Availability',
|
|
191
|
+
type: 'object',
|
|
192
|
+
isEditable: false,
|
|
193
|
+
isStandardProperty: true,
|
|
194
|
+
name: 'c8y_Availability',
|
|
195
|
+
c8y_JsonSchema: {
|
|
196
|
+
properties: {
|
|
197
|
+
c8y_Availability: {
|
|
198
|
+
key: 'c8y_Availability',
|
|
199
|
+
type: 'object',
|
|
200
|
+
label: 'Availability',
|
|
201
|
+
properties: {
|
|
202
|
+
status: {
|
|
203
|
+
title: 'Status',
|
|
204
|
+
type: 'string'
|
|
205
|
+
},
|
|
206
|
+
lastMessage: {
|
|
207
|
+
title: 'Last message',
|
|
208
|
+
type: 'string',
|
|
209
|
+
printFormat: 'datetime'
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
label: 'Connection',
|
|
218
|
+
type: 'object',
|
|
219
|
+
isEditable: false,
|
|
220
|
+
isStandardProperty: true,
|
|
221
|
+
name: 'c8y_Connection',
|
|
222
|
+
c8y_JsonSchema: {
|
|
223
|
+
properties: {
|
|
224
|
+
c8y_Connection: {
|
|
225
|
+
key: 'c8y_Connection',
|
|
226
|
+
type: 'object',
|
|
227
|
+
label: 'Connection',
|
|
228
|
+
properties: {
|
|
229
|
+
status: {
|
|
230
|
+
title: 'Status',
|
|
231
|
+
type: 'string'
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
label: 'Communication mode',
|
|
240
|
+
type: 'object',
|
|
241
|
+
isEditable: true,
|
|
242
|
+
isStandardProperty: true,
|
|
243
|
+
name: 'c8y_CommunicationMode',
|
|
244
|
+
c8y_JsonSchema: {
|
|
245
|
+
properties: {
|
|
246
|
+
c8y_CommunicationMode: {
|
|
247
|
+
key: 'c8y_CommunicationMode',
|
|
248
|
+
type: 'object',
|
|
249
|
+
label: 'Communication mode',
|
|
250
|
+
properties: {
|
|
251
|
+
mode: {
|
|
252
|
+
title: 'Mode',
|
|
253
|
+
type: 'string'
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
label: 'Firmware',
|
|
262
|
+
type: 'object',
|
|
263
|
+
isEditable: false,
|
|
264
|
+
isStandardProperty: true,
|
|
265
|
+
name: 'c8y_Firmware',
|
|
266
|
+
c8y_JsonSchema: {
|
|
267
|
+
properties: {
|
|
268
|
+
c8y_Firmware: {
|
|
269
|
+
key: 'c8y_Firmware',
|
|
270
|
+
type: 'object',
|
|
271
|
+
label: 'Firmware',
|
|
272
|
+
properties: {
|
|
273
|
+
moduleVersion: {
|
|
274
|
+
title: 'Module version',
|
|
275
|
+
type: 'string'
|
|
276
|
+
},
|
|
277
|
+
name: {
|
|
278
|
+
title: 'Name',
|
|
279
|
+
type: 'string'
|
|
280
|
+
},
|
|
281
|
+
version: {
|
|
282
|
+
title: 'Version',
|
|
283
|
+
type: 'string'
|
|
284
|
+
},
|
|
285
|
+
url: {
|
|
286
|
+
title: 'URL',
|
|
287
|
+
type: ['string', 'null']
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
label: 'Hardware',
|
|
296
|
+
type: 'object',
|
|
297
|
+
isEditable: true,
|
|
298
|
+
isStandardProperty: true,
|
|
299
|
+
name: 'c8y_Hardware',
|
|
300
|
+
c8y_JsonSchema: {
|
|
301
|
+
properties: {
|
|
302
|
+
c8y_Hardware: {
|
|
303
|
+
key: 'c8y_Hardware',
|
|
304
|
+
type: 'object',
|
|
305
|
+
label: 'Hardware',
|
|
306
|
+
properties: {
|
|
307
|
+
model: {
|
|
308
|
+
title: 'Model',
|
|
309
|
+
type: 'string'
|
|
310
|
+
},
|
|
311
|
+
serialNumber: {
|
|
312
|
+
title: 'Serial number',
|
|
313
|
+
type: 'string'
|
|
314
|
+
},
|
|
315
|
+
revision: {
|
|
316
|
+
title: 'Revision',
|
|
317
|
+
type: 'string'
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
label: 'LPWAN device',
|
|
326
|
+
type: 'object',
|
|
327
|
+
isEditable: false,
|
|
328
|
+
isStandardProperty: true,
|
|
329
|
+
name: 'c8y_LpwanDevice',
|
|
330
|
+
c8y_JsonSchema: {
|
|
331
|
+
properties: {
|
|
332
|
+
c8y_LpwanDevice: {
|
|
333
|
+
key: 'c8y_LpwanDevice',
|
|
334
|
+
type: 'object',
|
|
335
|
+
label: 'LPWAN device',
|
|
336
|
+
properties: {
|
|
337
|
+
provisioned: {
|
|
338
|
+
title: 'Provisioned',
|
|
339
|
+
type: 'boolean'
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
label: 'Mobile',
|
|
348
|
+
type: 'object',
|
|
349
|
+
isEditable: true,
|
|
350
|
+
isStandardProperty: true,
|
|
351
|
+
name: 'c8y_Mobile',
|
|
352
|
+
c8y_JsonSchema: {
|
|
353
|
+
properties: {
|
|
354
|
+
c8y_Mobile: {
|
|
355
|
+
key: 'c8y_Mobile',
|
|
356
|
+
type: 'object',
|
|
357
|
+
label: 'Mobile',
|
|
358
|
+
properties: {
|
|
359
|
+
cellId: {
|
|
360
|
+
title: 'Cell ID',
|
|
361
|
+
type: ['string', 'null']
|
|
362
|
+
},
|
|
363
|
+
connType: {
|
|
364
|
+
title: 'Connection type',
|
|
365
|
+
type: 'string',
|
|
366
|
+
readOnly: true
|
|
367
|
+
},
|
|
368
|
+
currentOperator: {
|
|
369
|
+
title: 'Current operator',
|
|
370
|
+
type: 'string',
|
|
371
|
+
readOnly: true
|
|
372
|
+
},
|
|
373
|
+
currentBand: {
|
|
374
|
+
title: 'Current band',
|
|
375
|
+
type: 'string',
|
|
376
|
+
readOnly: true
|
|
377
|
+
},
|
|
378
|
+
ecn0: {
|
|
379
|
+
title: 'ECN0',
|
|
380
|
+
type: 'string',
|
|
381
|
+
readOnly: true
|
|
382
|
+
},
|
|
383
|
+
iccid: {
|
|
384
|
+
title: 'ICCID',
|
|
385
|
+
type: ['string', 'null']
|
|
386
|
+
},
|
|
387
|
+
imei: {
|
|
388
|
+
title: 'IMEI',
|
|
389
|
+
type: ['string', 'null']
|
|
390
|
+
},
|
|
391
|
+
imsi: {
|
|
392
|
+
title: 'IMSI',
|
|
393
|
+
type: ['string', 'null']
|
|
394
|
+
},
|
|
395
|
+
lac: {
|
|
396
|
+
title: 'LAC',
|
|
397
|
+
type: ['string', 'null']
|
|
398
|
+
},
|
|
399
|
+
mcc: {
|
|
400
|
+
title: 'MCC',
|
|
401
|
+
type: ['string', 'null']
|
|
402
|
+
},
|
|
403
|
+
mnc: {
|
|
404
|
+
title: 'MNC',
|
|
405
|
+
type: ['string', 'null']
|
|
406
|
+
},
|
|
407
|
+
msisdn: {
|
|
408
|
+
title: 'MSISDN',
|
|
409
|
+
type: 'string'
|
|
410
|
+
},
|
|
411
|
+
rcsp: {
|
|
412
|
+
title: 'RCSP',
|
|
413
|
+
type: 'string',
|
|
414
|
+
readOnly: true
|
|
415
|
+
},
|
|
416
|
+
rscp: {
|
|
417
|
+
title: 'RSCP',
|
|
418
|
+
type: 'string',
|
|
419
|
+
readOnly: true
|
|
420
|
+
},
|
|
421
|
+
rsrp: {
|
|
422
|
+
title: 'RSRP',
|
|
423
|
+
type: 'string',
|
|
424
|
+
readOnly: true
|
|
425
|
+
},
|
|
426
|
+
rsrq: {
|
|
427
|
+
title: 'RSRQ',
|
|
428
|
+
type: 'string',
|
|
429
|
+
readOnly: true
|
|
430
|
+
},
|
|
431
|
+
rssi: {
|
|
432
|
+
title: 'RSSI',
|
|
433
|
+
type: 'string',
|
|
434
|
+
readOnly: true
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
name: 'c8y_Notes',
|
|
443
|
+
label: 'Notes',
|
|
444
|
+
type: 'string',
|
|
445
|
+
isEditable: true,
|
|
446
|
+
isStandardProperty: true,
|
|
447
|
+
c8y_JsonSchema: {
|
|
448
|
+
properties: {
|
|
449
|
+
c8y_Notes: {
|
|
450
|
+
type: 'string',
|
|
451
|
+
label: 'Notes',
|
|
452
|
+
'x-schema-form': {
|
|
453
|
+
type: 'textarea'
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
label: 'Position',
|
|
461
|
+
type: 'object',
|
|
462
|
+
isEditable: true,
|
|
463
|
+
isStandardProperty: true,
|
|
464
|
+
name: 'c8y_Position',
|
|
465
|
+
c8y_JsonSchema: {
|
|
466
|
+
properties: {
|
|
467
|
+
c8y_Position: {
|
|
468
|
+
key: 'c8y_Position',
|
|
469
|
+
type: 'object',
|
|
470
|
+
label: 'Position',
|
|
471
|
+
properties: {
|
|
472
|
+
lat: {
|
|
473
|
+
title: 'Latitude',
|
|
474
|
+
type: 'number'
|
|
475
|
+
},
|
|
476
|
+
lng: {
|
|
477
|
+
title: 'Longitude',
|
|
478
|
+
type: 'number'
|
|
479
|
+
},
|
|
480
|
+
alt: {
|
|
481
|
+
title: 'Altitude',
|
|
482
|
+
type: 'number'
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
},
|
|
489
|
+
{
|
|
490
|
+
label: 'Required availability',
|
|
491
|
+
type: 'object',
|
|
492
|
+
isEditable: true,
|
|
493
|
+
isStandardProperty: true,
|
|
494
|
+
name: 'c8y_RequiredAvailability',
|
|
495
|
+
c8y_JsonSchema: {
|
|
496
|
+
properties: {
|
|
497
|
+
c8y_RequiredAvailability: {
|
|
498
|
+
key: 'c8y_RequiredAvailability',
|
|
499
|
+
type: 'object',
|
|
500
|
+
label: 'Required availability',
|
|
501
|
+
properties: {
|
|
502
|
+
responseInterval: {
|
|
503
|
+
title: 'Response interval',
|
|
504
|
+
description: 'Takes a value between -32768 and 32767 minutes (a negative value indicates that the device is under maintenance).',
|
|
505
|
+
type: 'integer',
|
|
506
|
+
minimum: -32768,
|
|
507
|
+
maximum: 32767
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
label: 'Software',
|
|
516
|
+
type: 'object',
|
|
517
|
+
isEditable: false,
|
|
518
|
+
isStandardProperty: true,
|
|
519
|
+
name: 'c8y_Software',
|
|
520
|
+
c8y_JsonSchema: {
|
|
521
|
+
properties: {
|
|
522
|
+
c8y_Software: {
|
|
523
|
+
key: 'c8y_Software',
|
|
524
|
+
type: 'object',
|
|
525
|
+
label: 'Software',
|
|
526
|
+
properties: {
|
|
527
|
+
name: {
|
|
528
|
+
title: 'Name',
|
|
529
|
+
type: 'string'
|
|
530
|
+
},
|
|
531
|
+
version: {
|
|
532
|
+
title: 'Version',
|
|
533
|
+
type: 'string'
|
|
534
|
+
},
|
|
535
|
+
url: {
|
|
536
|
+
title: 'URL',
|
|
537
|
+
type: ['string', 'null']
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
},
|
|
544
|
+
{
|
|
545
|
+
label: 'Network',
|
|
546
|
+
type: 'object',
|
|
547
|
+
isEditable: true,
|
|
548
|
+
isStandardProperty: true,
|
|
549
|
+
name: 'c8y_Network',
|
|
550
|
+
c8y_JsonSchema: {
|
|
551
|
+
properties: {
|
|
552
|
+
c8y_Network: {
|
|
553
|
+
key: 'c8y_Network',
|
|
554
|
+
type: 'object',
|
|
555
|
+
label: 'Network',
|
|
556
|
+
properties: {
|
|
557
|
+
c8y_DHCP: {
|
|
558
|
+
title: 'DHCP',
|
|
559
|
+
type: 'object',
|
|
560
|
+
printFormat: 'hidden',
|
|
561
|
+
name: 'c8y_DHCP',
|
|
562
|
+
properties: {
|
|
563
|
+
addressRange: {
|
|
564
|
+
title: 'Address range',
|
|
565
|
+
type: 'object',
|
|
566
|
+
name: 'addressRange',
|
|
567
|
+
printFormat: 'hidden',
|
|
568
|
+
properties: {
|
|
569
|
+
start: {
|
|
570
|
+
title: 'Start',
|
|
571
|
+
type: 'string'
|
|
572
|
+
},
|
|
573
|
+
end: {
|
|
574
|
+
title: 'End',
|
|
575
|
+
type: 'string'
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
},
|
|
579
|
+
dns1: {
|
|
580
|
+
title: 'DNS 1',
|
|
581
|
+
type: 'string'
|
|
582
|
+
},
|
|
583
|
+
dns2: {
|
|
584
|
+
title: 'DNS 2',
|
|
585
|
+
type: 'string'
|
|
586
|
+
},
|
|
587
|
+
enabled: {
|
|
588
|
+
title: 'Enabled',
|
|
589
|
+
type: 'integer'
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
c8y_LAN: {
|
|
594
|
+
title: 'LAN',
|
|
595
|
+
type: 'object',
|
|
596
|
+
name: 'c8y_LAN',
|
|
597
|
+
printFormat: 'hidden',
|
|
598
|
+
properties: {
|
|
599
|
+
enabled: {
|
|
600
|
+
title: 'Enabled',
|
|
601
|
+
type: 'integer'
|
|
602
|
+
},
|
|
603
|
+
ip: {
|
|
604
|
+
title: 'IP',
|
|
605
|
+
type: 'string'
|
|
606
|
+
},
|
|
607
|
+
mac: {
|
|
608
|
+
title: 'MAC',
|
|
609
|
+
type: 'string'
|
|
610
|
+
},
|
|
611
|
+
name: {
|
|
612
|
+
title: 'Name',
|
|
613
|
+
type: 'string'
|
|
614
|
+
},
|
|
615
|
+
netmask: {
|
|
616
|
+
title: 'Netmask',
|
|
617
|
+
type: 'string'
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
},
|
|
621
|
+
c8y_WAN: {
|
|
622
|
+
title: 'WAN',
|
|
623
|
+
type: 'object',
|
|
624
|
+
name: 'c8y_WAN',
|
|
625
|
+
printFormat: 'hidden',
|
|
626
|
+
properties: {
|
|
627
|
+
apn: {
|
|
628
|
+
title: 'APN',
|
|
629
|
+
type: 'string'
|
|
630
|
+
},
|
|
631
|
+
authType: {
|
|
632
|
+
title: 'Auth type',
|
|
633
|
+
type: 'string'
|
|
634
|
+
},
|
|
635
|
+
ip: {
|
|
636
|
+
title: 'IP',
|
|
637
|
+
type: 'string'
|
|
638
|
+
},
|
|
639
|
+
password: {
|
|
640
|
+
title: 'Password',
|
|
641
|
+
type: 'string'
|
|
642
|
+
},
|
|
643
|
+
simStatus: {
|
|
644
|
+
title: 'SIM status',
|
|
645
|
+
type: 'string'
|
|
646
|
+
},
|
|
647
|
+
username: {
|
|
648
|
+
title: 'Username',
|
|
649
|
+
type: 'string'
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
];
|
|
659
|
+
const RESULT_TYPES = {
|
|
660
|
+
VALUE: { name: 'VALUE', value: 1, label: gettext('Only value') },
|
|
661
|
+
VALUE_UNIT: { name: 'VALUE_UNIT', value: 2, label: gettext('Value and unit') },
|
|
662
|
+
VALUE_UNIT_TIME: { name: 'VALUE_UNIT_TIME', value: 3, label: gettext('Value, unit and time') }
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Service for managing asset properties.
|
|
667
|
+
*/
|
|
668
|
+
class AssetPropertiesService {
|
|
669
|
+
constructor() {
|
|
670
|
+
this.FRAGMENTS_TO_OMIT = [
|
|
671
|
+
'additionParents',
|
|
672
|
+
'assetParents',
|
|
673
|
+
'deviceParents',
|
|
674
|
+
'childAdditions',
|
|
675
|
+
'childAssets',
|
|
676
|
+
'childDevices',
|
|
677
|
+
'c8y_IsDevice',
|
|
678
|
+
'__children',
|
|
679
|
+
'c8y_ui',
|
|
680
|
+
'self',
|
|
681
|
+
'parent',
|
|
682
|
+
'c8y_DataPoint',
|
|
683
|
+
'c8y_Kpi_Migrated',
|
|
684
|
+
/^c8y_Dashboard!\d+/
|
|
685
|
+
];
|
|
686
|
+
this.inventoryService = inject(InventoryService);
|
|
687
|
+
this.assetTypesRealtimeService = inject(AssetTypesRealtimeService);
|
|
688
|
+
this.groupService = inject(GroupService);
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Retrieves custom properties for an asset from asset library.
|
|
692
|
+
* @param asset The asset for which to retrieve custom properties.
|
|
693
|
+
* @returns A promise resolving to the list of custom properties.
|
|
694
|
+
*/
|
|
695
|
+
async getCustomProperties(asset) {
|
|
696
|
+
if (asset && asset.type) {
|
|
697
|
+
const assetType = await firstValueFrom(this.assetTypesRealtimeService.getAssetTypeByName$(asset.type));
|
|
698
|
+
if (assetType) {
|
|
699
|
+
const { data } = await this.inventoryService.childAdditionsList(assetType, {
|
|
700
|
+
pageSize: 2000,
|
|
701
|
+
query: "$filter=(has('c8y_IsAssetProperty'))"
|
|
702
|
+
});
|
|
703
|
+
return data;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
return [];
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Retrieves the initial set of properties for an asset, based on its type.
|
|
710
|
+
* @param asset The asset for which to retrieve properties.
|
|
711
|
+
* @returns A promise resolving to the list of initial properties.
|
|
712
|
+
*/
|
|
713
|
+
async getInitialProperties(asset) {
|
|
714
|
+
if (!asset) {
|
|
715
|
+
return [];
|
|
716
|
+
}
|
|
717
|
+
else if (this.groupService.isDevice(asset)) {
|
|
718
|
+
return await this.getDeviceProperties(asset);
|
|
719
|
+
}
|
|
720
|
+
else if (this.groupService.isGroup(asset) && !this.groupService.isAsset(asset)) {
|
|
721
|
+
return await this.getGroupProperties(asset);
|
|
722
|
+
}
|
|
723
|
+
else if (this.groupService.isAsset(asset)) {
|
|
724
|
+
return await this.getAssetProperties(asset);
|
|
725
|
+
}
|
|
726
|
+
return [];
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Retrieves properties for a device asset.
|
|
730
|
+
* @param asset The device asset for which to retrieve properties.
|
|
731
|
+
* @returns A promise resolving to the list of device properties.
|
|
732
|
+
*/
|
|
733
|
+
async getDeviceProperties(asset) {
|
|
734
|
+
return this.getManagedObjectProperties(asset);
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Retrieves properties for a group asset.
|
|
738
|
+
* @param asset The group asset for which to retrieve properties.
|
|
739
|
+
* @returns A promise resolving to the list of group properties.
|
|
740
|
+
*/
|
|
741
|
+
async getGroupProperties(asset) {
|
|
742
|
+
return this.getManagedObjectProperties(asset);
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Retrieves properties for a regular asset.
|
|
746
|
+
* @param asset The asset for which to retrieve properties.
|
|
747
|
+
* @returns A promise resolving to the list of asset properties.
|
|
748
|
+
*/
|
|
749
|
+
async getAssetProperties(asset) {
|
|
750
|
+
const customProperties = this.categorizeCustomProperties(await this.getCustomProperties(asset)) || [];
|
|
751
|
+
return customProperties;
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Categorizes custom properties into simple and complex types.
|
|
755
|
+
* @param properties The custom properties to categorize.
|
|
756
|
+
* @returns The categorized custom properties.
|
|
757
|
+
*/
|
|
758
|
+
categorizeCustomProperties(properties) {
|
|
759
|
+
const { simple, complex } = properties.reduce((acc, property) => {
|
|
760
|
+
const schema = property.c8y_JsonSchema.properties[property.name];
|
|
761
|
+
if (schema.type === 'object') {
|
|
762
|
+
acc.complex.push(property);
|
|
763
|
+
}
|
|
764
|
+
else {
|
|
765
|
+
acc.simple.push(property);
|
|
766
|
+
}
|
|
767
|
+
return acc;
|
|
768
|
+
}, { simple: [], complex: [] });
|
|
769
|
+
return [...simple, ...complex];
|
|
770
|
+
}
|
|
771
|
+
/**
|
|
772
|
+
* Categorizes and flattens hierarchical properties into simple and complex types.
|
|
773
|
+
* @param properties The hierarchical properties to categorize and flatten.
|
|
774
|
+
* @returns The categorized and flattened properties.
|
|
775
|
+
*/
|
|
776
|
+
categorizeAndFlattenHierarchicalProperties(properties) {
|
|
777
|
+
const sortedProperties = [...properties].sort((a, b) => {
|
|
778
|
+
const aLabel = (a.label || a.name || '').toLowerCase();
|
|
779
|
+
const bLabel = (b.label || b.name || '').toLowerCase();
|
|
780
|
+
return aLabel.localeCompare(bLabel);
|
|
781
|
+
});
|
|
782
|
+
const result = sortedProperties.reduce((acc, property) => {
|
|
783
|
+
property.active = false;
|
|
784
|
+
if (this.isComplexProperty(property)) {
|
|
785
|
+
acc.complex.push(property);
|
|
786
|
+
this.addNestedProperties(property, acc.complex, true);
|
|
787
|
+
}
|
|
788
|
+
else {
|
|
789
|
+
acc.simple.push(property);
|
|
790
|
+
}
|
|
791
|
+
return acc;
|
|
792
|
+
}, { simple: [], complex: [] });
|
|
793
|
+
return result;
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Checks if a property is complex (i.e., has nested properties).
|
|
797
|
+
* @param property The property to check.
|
|
798
|
+
* @returns True if the property is complex, false otherwise.
|
|
799
|
+
*/
|
|
800
|
+
isComplexProperty(property) {
|
|
801
|
+
return (property.c8y_JsonSchema?.properties[property.name]?.type === 'object' ||
|
|
802
|
+
property.properties !== undefined);
|
|
803
|
+
}
|
|
804
|
+
addNestedProperties(parentProperty, complexProperties, sortChildren = false) {
|
|
805
|
+
const schema = parentProperty.c8y_JsonSchema?.properties[parentProperty.name];
|
|
806
|
+
if (!schema?.properties) {
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
this.flattenProperties(schema, complexProperties, parentProperty.name, [], sortChildren);
|
|
810
|
+
}
|
|
811
|
+
flattenProperties(schema, result, parentName, parentPath = [], sortChildren = false) {
|
|
812
|
+
const properties = schema.properties?.[parentName]?.properties || schema.properties;
|
|
813
|
+
let entries = Object.entries(properties);
|
|
814
|
+
if (sortChildren) {
|
|
815
|
+
entries = entries.sort((a, b) => {
|
|
816
|
+
const aLabel = (a[1].title || a[1].label || a[1].name || a[0] || '').toLowerCase();
|
|
817
|
+
const bLabel = (b[1].title || b[1].label || b[1].name || b[0] || '').toLowerCase();
|
|
818
|
+
return aLabel.localeCompare(bLabel);
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
entries.forEach(([key, property]) => {
|
|
822
|
+
const path = parentPath.includes(parentName) ? parentPath : [...parentPath, parentName];
|
|
823
|
+
result.push({ ...property, keyPath: [...path, key] });
|
|
824
|
+
if (property.properties) {
|
|
825
|
+
this.flattenProperties({ properties: { [key]: property } }, result, key, [...path, key], sortChildren);
|
|
826
|
+
}
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
getManagedObjectProperties(asset) {
|
|
830
|
+
return this.extractFragments(asset);
|
|
831
|
+
}
|
|
832
|
+
extractFragments(object) {
|
|
833
|
+
const properties = [];
|
|
834
|
+
for (const [key, value] of Object.entries(object)) {
|
|
835
|
+
if (this.shouldSkipFragment(key) ||
|
|
836
|
+
isArray(value) ||
|
|
837
|
+
(isObjectLike(value) && isEmpty(value))) {
|
|
838
|
+
continue;
|
|
839
|
+
}
|
|
840
|
+
const newProp = {
|
|
841
|
+
label: key,
|
|
842
|
+
name: key,
|
|
843
|
+
type: isObjectLike(value) ? 'object' : 'string',
|
|
844
|
+
isEditable: true,
|
|
845
|
+
c8y_JsonSchema: {
|
|
846
|
+
properties: {
|
|
847
|
+
[key]: {
|
|
848
|
+
key: key,
|
|
849
|
+
type: isObjectLike(value) ? 'object' : 'string',
|
|
850
|
+
label: key,
|
|
851
|
+
properties: {}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
if (isObjectLike(value)) {
|
|
857
|
+
this.addPropertyItem(newProp.c8y_JsonSchema.properties[key].properties, value);
|
|
858
|
+
}
|
|
859
|
+
properties.push(newProp);
|
|
860
|
+
}
|
|
861
|
+
return properties;
|
|
862
|
+
}
|
|
863
|
+
shouldSkipFragment(key) {
|
|
864
|
+
return !!find(this.FRAGMENTS_TO_OMIT, (fragmentToOmit) => {
|
|
865
|
+
if (fragmentToOmit instanceof RegExp) {
|
|
866
|
+
return fragmentToOmit.test(key);
|
|
867
|
+
}
|
|
868
|
+
return fragmentToOmit === key;
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
addPropertyItem(properties, object) {
|
|
872
|
+
if (!properties) {
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
forOwn(object, (value, key) => {
|
|
876
|
+
properties[key] = { title: key, type: value ? typeof value : 'string' };
|
|
877
|
+
if (isObjectLike(value)) {
|
|
878
|
+
properties[key].type = 'object';
|
|
879
|
+
this.addPropertyItem(properties[key]['properties'], value);
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertiesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
884
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertiesService, providedIn: 'root' }); }
|
|
885
|
+
}
|
|
886
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertiesService, decorators: [{
|
|
887
|
+
type: Injectable,
|
|
888
|
+
args: [{
|
|
889
|
+
providedIn: 'root'
|
|
890
|
+
}]
|
|
891
|
+
}] });
|
|
892
|
+
|
|
893
|
+
class FlatTreeDataSource extends DataSource {
|
|
894
|
+
constructor() {
|
|
895
|
+
super();
|
|
896
|
+
this._dataChange = new BehaviorSubject([]);
|
|
897
|
+
}
|
|
898
|
+
get data() {
|
|
899
|
+
return this._dataChange.value;
|
|
900
|
+
}
|
|
901
|
+
set data(value) {
|
|
902
|
+
this._dataChange.next(value);
|
|
903
|
+
}
|
|
904
|
+
connect() {
|
|
905
|
+
return this._dataChange.asObservable();
|
|
906
|
+
}
|
|
907
|
+
disconnect() {
|
|
908
|
+
// No need to unsubscribe from the _dataChange subject since it's a BehaviorSubject
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
class AssetPropertyActionDirective {
|
|
913
|
+
constructor(template, elementRef, viewContainer) {
|
|
914
|
+
this.template = template;
|
|
915
|
+
this.elementRef = elementRef;
|
|
916
|
+
this.viewContainer = viewContainer;
|
|
917
|
+
}
|
|
918
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertyActionDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ElementRef }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
919
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: AssetPropertyActionDirective, isStandalone: true, selector: "[c8yAssetPropertyAction]", ngImport: i0 }); }
|
|
920
|
+
}
|
|
921
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertyActionDirective, decorators: [{
|
|
922
|
+
type: Directive,
|
|
923
|
+
args: [{
|
|
924
|
+
selector: '[c8yAssetPropertyAction]',
|
|
925
|
+
standalone: true
|
|
926
|
+
}]
|
|
927
|
+
}], ctorParameters: () => [{ type: i0.TemplateRef }, { type: i0.ElementRef }, { type: i0.ViewContainerRef }] });
|
|
928
|
+
|
|
929
|
+
/**
|
|
930
|
+
* Formats the value of an asset property.
|
|
931
|
+
* If the property is complex, it will be stringified.
|
|
932
|
+
* If the property has a keyPath, it will be used to retrieve the value from the asset.
|
|
933
|
+
* Otherwise, the value will be taken directly from the asset.
|
|
934
|
+
* If the value is null or undefined, a dash ('-') will be returned.
|
|
935
|
+
*/
|
|
936
|
+
class AssetPropertyValuePipe {
|
|
937
|
+
constructor() {
|
|
938
|
+
this.assetPropertiesService = inject(AssetPropertiesService);
|
|
939
|
+
}
|
|
940
|
+
transform(property, asset) {
|
|
941
|
+
if (!property) {
|
|
942
|
+
return '-';
|
|
943
|
+
}
|
|
944
|
+
let value;
|
|
945
|
+
if (this.assetPropertiesService.isComplexProperty(property)) {
|
|
946
|
+
value = JSON.stringify(asset[property.name]);
|
|
947
|
+
}
|
|
948
|
+
else if ('keyPath' in property) {
|
|
949
|
+
value = get(asset, property.keyPath);
|
|
950
|
+
}
|
|
951
|
+
else {
|
|
952
|
+
value = asset[property.name];
|
|
953
|
+
}
|
|
954
|
+
return value ?? '-';
|
|
955
|
+
}
|
|
956
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertyValuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
957
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertyValuePipe, isStandalone: true, name: "c8yAssetPropertyValue" }); }
|
|
958
|
+
}
|
|
959
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertyValuePipe, decorators: [{
|
|
960
|
+
type: Pipe,
|
|
961
|
+
args: [{
|
|
962
|
+
name: 'c8yAssetPropertyValue',
|
|
963
|
+
standalone: true
|
|
964
|
+
}]
|
|
965
|
+
}] });
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* Pipe to transform asset property types into icon names.
|
|
969
|
+
* Maps various property types to corresponding icon names.
|
|
970
|
+
*/
|
|
971
|
+
class AssetPropertyIconPipe {
|
|
972
|
+
transform(type) {
|
|
973
|
+
switch (type) {
|
|
974
|
+
case 'string':
|
|
975
|
+
return 'paragraph';
|
|
976
|
+
case 'number':
|
|
977
|
+
return 'hashtag';
|
|
978
|
+
case 'boolean':
|
|
979
|
+
return 'true-false';
|
|
980
|
+
case 'date':
|
|
981
|
+
return 'calendar';
|
|
982
|
+
case 'object':
|
|
983
|
+
case 'c8y_JsonSchema':
|
|
984
|
+
return 'open-parcel';
|
|
985
|
+
case 'enum':
|
|
986
|
+
return 'content';
|
|
987
|
+
case 'file':
|
|
988
|
+
return 'file';
|
|
989
|
+
default:
|
|
990
|
+
return 'window-minimize';
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertyIconPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
994
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertyIconPipe, isStandalone: true, name: "c8yAssetPropertyIcon" }); }
|
|
995
|
+
}
|
|
996
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertyIconPipe, decorators: [{
|
|
997
|
+
type: Pipe,
|
|
998
|
+
args: [{
|
|
999
|
+
name: 'c8yAssetPropertyIcon',
|
|
1000
|
+
standalone: true
|
|
1001
|
+
}]
|
|
1002
|
+
}] });
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* Represents a list of asset properties with hierarchical tree structure.
|
|
1006
|
+
*/
|
|
1007
|
+
class AssetPropertyListComponent {
|
|
1008
|
+
/**
|
|
1009
|
+
* Constructor initializes reactive effects for expansion modes.
|
|
1010
|
+
*/
|
|
1011
|
+
constructor() {
|
|
1012
|
+
/**
|
|
1013
|
+
* Reference to the CDdk tree component.
|
|
1014
|
+
*/
|
|
1015
|
+
this.tree = viewChild('tree');
|
|
1016
|
+
/**
|
|
1017
|
+
* Configuration for the asset property list.
|
|
1018
|
+
*/
|
|
1019
|
+
this.config = {};
|
|
1020
|
+
/**
|
|
1021
|
+
* Custom properties to be displayed in the list.
|
|
1022
|
+
*/
|
|
1023
|
+
this.customProperties = [];
|
|
1024
|
+
/**
|
|
1025
|
+
* Emits the selected properties.
|
|
1026
|
+
*/
|
|
1027
|
+
this.selectedProperties = new EventEmitter();
|
|
1028
|
+
/**
|
|
1029
|
+
* List of all properties.
|
|
1030
|
+
*/
|
|
1031
|
+
this.properties = [];
|
|
1032
|
+
/**
|
|
1033
|
+
* Text input for searching properties.
|
|
1034
|
+
*/
|
|
1035
|
+
this.inputText = '';
|
|
1036
|
+
/**
|
|
1037
|
+
* Data source for the tree structure.
|
|
1038
|
+
*/
|
|
1039
|
+
this.dataSource = new FlatTreeDataSource();
|
|
1040
|
+
/**
|
|
1041
|
+
* Map of flat nodes for quick lookup.
|
|
1042
|
+
*/
|
|
1043
|
+
this.flatNodeMap = new Map();
|
|
1044
|
+
/**
|
|
1045
|
+
* Indicates if all nodes are selected.
|
|
1046
|
+
*/
|
|
1047
|
+
this.allSelected = false;
|
|
1048
|
+
/**
|
|
1049
|
+
* Indicates if the selection state is indeterminate.
|
|
1050
|
+
*/
|
|
1051
|
+
this.indeterminate = false;
|
|
1052
|
+
/**
|
|
1053
|
+
* Subject for handling search input.
|
|
1054
|
+
*/
|
|
1055
|
+
this.searchSubject$ = new BehaviorSubject('');
|
|
1056
|
+
/**
|
|
1057
|
+
* Subject for handling component destruction.
|
|
1058
|
+
*/
|
|
1059
|
+
this.destroy$ = new Subject();
|
|
1060
|
+
/**
|
|
1061
|
+
* Service for managing asset properties.
|
|
1062
|
+
*/
|
|
1063
|
+
this.assetPropertiesService = inject(AssetPropertiesService);
|
|
1064
|
+
effect(() => {
|
|
1065
|
+
if ((this.config.expansionMode === 'nonCollapsible' ||
|
|
1066
|
+
this.config.expansionMode === 'expandedByDefault') &&
|
|
1067
|
+
this.tree()) {
|
|
1068
|
+
queueMicrotask(() => {
|
|
1069
|
+
this.expandAllNodes();
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
ngOnInit() {
|
|
1075
|
+
this.config = {
|
|
1076
|
+
...defaultAssetPropertyListConfig,
|
|
1077
|
+
...this.config
|
|
1078
|
+
};
|
|
1079
|
+
this.searchSubject$
|
|
1080
|
+
.pipe(takeUntil(this.destroy$), debounceTime(200))
|
|
1081
|
+
.subscribe(() => this.filterTree());
|
|
1082
|
+
}
|
|
1083
|
+
async ngOnChanges() {
|
|
1084
|
+
await this.updateProperties();
|
|
1085
|
+
}
|
|
1086
|
+
ngAfterViewInit() {
|
|
1087
|
+
if (this.config.selectMode === 'single') {
|
|
1088
|
+
this.selectedProperties.next([]);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
ngOnDestroy() {
|
|
1092
|
+
this.destroy$.next();
|
|
1093
|
+
this.destroy$.complete();
|
|
1094
|
+
}
|
|
1095
|
+
/**
|
|
1096
|
+
* Fetches and categorizes properties.
|
|
1097
|
+
* @returns A promise resolving to the list of asset properties.
|
|
1098
|
+
*/
|
|
1099
|
+
async getProperties() {
|
|
1100
|
+
if (this.asset) {
|
|
1101
|
+
return this.categorizeAndFlattenHierarchicalProperties(await this.assetPropertiesService.getInitialProperties(this.asset));
|
|
1102
|
+
}
|
|
1103
|
+
else {
|
|
1104
|
+
if (this.config?.emptyStateContent === 'default-properties') {
|
|
1105
|
+
return this.categorizeAndFlattenHierarchicalProperties(defaultAssetProperties);
|
|
1106
|
+
}
|
|
1107
|
+
else if (Array.isArray(this.config?.emptyStateContent)) {
|
|
1108
|
+
return this.config.emptyStateContent;
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
return [];
|
|
1112
|
+
}
|
|
1113
|
+
/**
|
|
1114
|
+
* Checks if a node has children.
|
|
1115
|
+
* @param node The node to check.
|
|
1116
|
+
* @returns True if the node has children.
|
|
1117
|
+
*/
|
|
1118
|
+
hasChild(node) {
|
|
1119
|
+
return node.expandable;
|
|
1120
|
+
}
|
|
1121
|
+
/**
|
|
1122
|
+
* Gets the level of a node.
|
|
1123
|
+
* @param node The node to check.
|
|
1124
|
+
* @returns The level of the node.
|
|
1125
|
+
*/
|
|
1126
|
+
getLevel(node) {
|
|
1127
|
+
return node.level;
|
|
1128
|
+
}
|
|
1129
|
+
/**
|
|
1130
|
+
* Gets the parent node of a given node.
|
|
1131
|
+
* @param node The node to check.
|
|
1132
|
+
* @returns The parent node or null if none exists.
|
|
1133
|
+
*/
|
|
1134
|
+
getParentNode(node) {
|
|
1135
|
+
const keyPath = node.property.keyPath;
|
|
1136
|
+
if (!keyPath || keyPath.length <= 1) {
|
|
1137
|
+
return null;
|
|
1138
|
+
}
|
|
1139
|
+
const parentPath = keyPath.slice(0, -1).join('.');
|
|
1140
|
+
return this.flatNodeMap.get(parentPath) || null;
|
|
1141
|
+
}
|
|
1142
|
+
/**
|
|
1143
|
+
* Determines if a node should be rendered.
|
|
1144
|
+
* @param node The node to check.
|
|
1145
|
+
* @returns True if the node should be rendered.
|
|
1146
|
+
*/
|
|
1147
|
+
shouldRender(node) {
|
|
1148
|
+
// Always render root nodes
|
|
1149
|
+
if (node.level === 0) {
|
|
1150
|
+
return true;
|
|
1151
|
+
}
|
|
1152
|
+
// For non-root nodes, check if parent is expanded
|
|
1153
|
+
let parent = this.getParentNode(node);
|
|
1154
|
+
while (parent) {
|
|
1155
|
+
if (!this.tree()?.isExpanded(parent)) {
|
|
1156
|
+
return false;
|
|
1157
|
+
}
|
|
1158
|
+
parent = this.getParentNode(parent);
|
|
1159
|
+
}
|
|
1160
|
+
return true;
|
|
1161
|
+
}
|
|
1162
|
+
/**
|
|
1163
|
+
* Selects or deselects all nodes.
|
|
1164
|
+
* @param selected True to select all, false to deselect.
|
|
1165
|
+
*/
|
|
1166
|
+
selectAll(selected) {
|
|
1167
|
+
this.allSelected = selected;
|
|
1168
|
+
this.indeterminate = false;
|
|
1169
|
+
const visibleNodes = this.dataSource.data.filter(node => node.isVisible);
|
|
1170
|
+
visibleNodes.forEach(node => {
|
|
1171
|
+
node.property.active = selected;
|
|
1172
|
+
});
|
|
1173
|
+
const selectedProperties = this.dataSource.data
|
|
1174
|
+
.filter(n => n.property.active)
|
|
1175
|
+
.map(n => n.property);
|
|
1176
|
+
this.selectedProperties.next(selectedProperties);
|
|
1177
|
+
}
|
|
1178
|
+
/**
|
|
1179
|
+
* Handles single selection mode.
|
|
1180
|
+
* @param selected True if the node is selected.
|
|
1181
|
+
* @param node The node to select.
|
|
1182
|
+
*/
|
|
1183
|
+
onSelectSingle(selected, node) {
|
|
1184
|
+
this.dataSource.data.forEach(n => {
|
|
1185
|
+
n.property.active = false;
|
|
1186
|
+
});
|
|
1187
|
+
node.property.active = selected;
|
|
1188
|
+
if (selected && node.expandable && this.tree() && !this.tree().isExpanded(node)) {
|
|
1189
|
+
this.tree().expand(node);
|
|
1190
|
+
}
|
|
1191
|
+
this.selectedProperties.next([node.property]);
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Handles multi-selection mode.
|
|
1195
|
+
* @param selected True if the node is selected.
|
|
1196
|
+
* @param node The node to select.
|
|
1197
|
+
*/
|
|
1198
|
+
onSelectMulti(selected, node) {
|
|
1199
|
+
node.property.active = selected;
|
|
1200
|
+
if (selected && node.expandable && this.tree() && !this.tree().isExpanded(node)) {
|
|
1201
|
+
this.tree().expand(node);
|
|
1202
|
+
}
|
|
1203
|
+
if (node.expandable) {
|
|
1204
|
+
this.updateChildSelectionStatus(node, selected);
|
|
1205
|
+
}
|
|
1206
|
+
this.updateSelectAllState();
|
|
1207
|
+
const selectedProperties = this.dataSource.data
|
|
1208
|
+
.filter(n => n.property.active)
|
|
1209
|
+
.map(n => n.property);
|
|
1210
|
+
this.selectedProperties.next(selectedProperties);
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Initiates a search operation.
|
|
1214
|
+
*/
|
|
1215
|
+
onSearch() {
|
|
1216
|
+
this.searchSubject$.next(this.inputText);
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Clears the search input.
|
|
1220
|
+
*/
|
|
1221
|
+
clearSearch() {
|
|
1222
|
+
this.inputText = '';
|
|
1223
|
+
this.onSearch();
|
|
1224
|
+
}
|
|
1225
|
+
collapseButtonTitle(node) {
|
|
1226
|
+
const expanded = this.tree().isExpanded(node);
|
|
1227
|
+
return expanded
|
|
1228
|
+
? gettext('Collapse {{ assetPropertyLabel }}')
|
|
1229
|
+
: gettext('Expand {{ assetPropertyLabel }}');
|
|
1230
|
+
}
|
|
1231
|
+
/**
|
|
1232
|
+
* Updates the list of properties based on the configuration.
|
|
1233
|
+
*/
|
|
1234
|
+
async updateProperties() {
|
|
1235
|
+
if (this.config.inputPropertiesHandle === 'merge' || !this.config.inputPropertiesHandle) {
|
|
1236
|
+
this.properties = [...this.customProperties, ...(await this.getProperties())];
|
|
1237
|
+
}
|
|
1238
|
+
else if (this.config.inputPropertiesHandle === 'override') {
|
|
1239
|
+
this.properties = [...this.customProperties];
|
|
1240
|
+
}
|
|
1241
|
+
this.buildTreeNodes();
|
|
1242
|
+
}
|
|
1243
|
+
/**
|
|
1244
|
+
* Updates the selection status of child nodes.
|
|
1245
|
+
* @param parent The parent node.
|
|
1246
|
+
* @param selected True if the parent is selected.
|
|
1247
|
+
*/
|
|
1248
|
+
updateChildSelectionStatus(parent, selected) {
|
|
1249
|
+
if (!parent.expandable)
|
|
1250
|
+
return;
|
|
1251
|
+
const parentKey = parent.property.keyPath?.join('.') || parent.property.name;
|
|
1252
|
+
this.dataSource.data.forEach(node => {
|
|
1253
|
+
const nodePath = node.property.keyPath;
|
|
1254
|
+
if (nodePath && nodePath.join('.').startsWith(parentKey) && node !== parent) {
|
|
1255
|
+
node.property.active = selected;
|
|
1256
|
+
}
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
/**
|
|
1260
|
+
* Checks if a property matches the search criteria.
|
|
1261
|
+
* @param property The property to check.
|
|
1262
|
+
* @param search The search text.
|
|
1263
|
+
* @returns True if the property matches.
|
|
1264
|
+
*/
|
|
1265
|
+
matchesSearch(property, search) {
|
|
1266
|
+
const searchableFields = [
|
|
1267
|
+
property.label,
|
|
1268
|
+
property.name,
|
|
1269
|
+
property.keyPath?.join('.'),
|
|
1270
|
+
property.title
|
|
1271
|
+
].filter(Boolean);
|
|
1272
|
+
return searchableFields.some(field => field?.toLowerCase().includes(search));
|
|
1273
|
+
}
|
|
1274
|
+
/**
|
|
1275
|
+
* Updates the selection state for all nodes.
|
|
1276
|
+
*/
|
|
1277
|
+
updateSelectAllState() {
|
|
1278
|
+
if (this.config.selectMode !== 'multi')
|
|
1279
|
+
return;
|
|
1280
|
+
const visibleNodes = this.dataSource.data.filter(node => node.isVisible);
|
|
1281
|
+
const totalCount = visibleNodes.length;
|
|
1282
|
+
const selectedCount = visibleNodes.filter(node => node.property.active).length;
|
|
1283
|
+
this.allSelected = totalCount > 0 && selectedCount === totalCount;
|
|
1284
|
+
this.indeterminate = selectedCount > 0 && selectedCount < totalCount;
|
|
1285
|
+
// Update indeterminate state for each complex node
|
|
1286
|
+
this.updateIndeterminateStates();
|
|
1287
|
+
}
|
|
1288
|
+
/**
|
|
1289
|
+
* Builds the tree nodes from the properties.
|
|
1290
|
+
*/
|
|
1291
|
+
buildTreeNodes() {
|
|
1292
|
+
const treeData = [];
|
|
1293
|
+
this.flatNodeMap.clear();
|
|
1294
|
+
this.properties.forEach(property => {
|
|
1295
|
+
const isComplex = this.assetPropertiesService.isComplexProperty(property);
|
|
1296
|
+
const hasKeyPath = !!property.keyPath;
|
|
1297
|
+
const level = hasKeyPath ? property.keyPath.length - 1 : 0;
|
|
1298
|
+
const key = hasKeyPath ? property.keyPath.join('.') : property.name;
|
|
1299
|
+
const node = {
|
|
1300
|
+
expandable: isComplex,
|
|
1301
|
+
level,
|
|
1302
|
+
property,
|
|
1303
|
+
isVisible: true,
|
|
1304
|
+
indeterminate: false // add indeterminate property
|
|
1305
|
+
};
|
|
1306
|
+
this.flatNodeMap.set(key, node);
|
|
1307
|
+
treeData.push(node);
|
|
1308
|
+
});
|
|
1309
|
+
this.dataSource.data = treeData;
|
|
1310
|
+
this.filterTree();
|
|
1311
|
+
this.updateSelectAllState();
|
|
1312
|
+
if (this.config.expansionMode === 'nonCollapsible' ||
|
|
1313
|
+
this.config.expansionMode === 'expandedByDefault') {
|
|
1314
|
+
queueMicrotask(() => {
|
|
1315
|
+
this.expandAllNodes();
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
/**
|
|
1320
|
+
* Update indeterminate state for all complex nodes
|
|
1321
|
+
*/
|
|
1322
|
+
updateIndeterminateStates() {
|
|
1323
|
+
// Only for multi-select mode
|
|
1324
|
+
if (this.config.selectMode !== 'multi')
|
|
1325
|
+
return;
|
|
1326
|
+
// For each complex node, check its children
|
|
1327
|
+
this.dataSource.data.forEach(node => {
|
|
1328
|
+
if (node.expandable) {
|
|
1329
|
+
const parentKey = node.property.keyPath?.join('.') || node.property.name;
|
|
1330
|
+
// Find direct children (level = parent.level + 1, keyPath starts with parentKey)
|
|
1331
|
+
const children = this.dataSource.data.filter(child => {
|
|
1332
|
+
if (child === node)
|
|
1333
|
+
return false;
|
|
1334
|
+
const childKeyPath = child.property.keyPath;
|
|
1335
|
+
if (!childKeyPath)
|
|
1336
|
+
return false;
|
|
1337
|
+
// Direct child: one level deeper, and keyPath starts with parentKey
|
|
1338
|
+
return (childKeyPath.length === node.level + 2 &&
|
|
1339
|
+
childKeyPath.slice(0, node.level + 1).join('.') === parentKey);
|
|
1340
|
+
});
|
|
1341
|
+
if (children.length > 0) {
|
|
1342
|
+
const selectedCount = children.filter(child => child.property.active).length;
|
|
1343
|
+
node.indeterminate = selectedCount > 0 && selectedCount < children.length;
|
|
1344
|
+
}
|
|
1345
|
+
else {
|
|
1346
|
+
node.indeterminate = false;
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
else {
|
|
1350
|
+
node.indeterminate = false;
|
|
1351
|
+
}
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
/**
|
|
1355
|
+
* Expands all nodes in the tree.
|
|
1356
|
+
*/
|
|
1357
|
+
expandAllNodes() {
|
|
1358
|
+
if (!this.tree())
|
|
1359
|
+
return;
|
|
1360
|
+
const parentNodes = this.dataSource.data.filter(node => node.expandable);
|
|
1361
|
+
parentNodes.forEach(node => {
|
|
1362
|
+
if (!this.tree().isExpanded(node)) {
|
|
1363
|
+
this.tree().expand(node);
|
|
1364
|
+
}
|
|
1365
|
+
});
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* Filters the tree nodes based on the search input.
|
|
1369
|
+
*/
|
|
1370
|
+
filterTree() {
|
|
1371
|
+
const searchText = this.inputText?.toLowerCase() || '';
|
|
1372
|
+
const allNodes = [...this.dataSource.data];
|
|
1373
|
+
if (!searchText) {
|
|
1374
|
+
allNodes.forEach(node => (node.isVisible = true));
|
|
1375
|
+
this.dataSource.data = Array.from(this.flatNodeMap.values());
|
|
1376
|
+
this.updateSelectAllState();
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
// First pass: Mark nodes that match the search criteria
|
|
1380
|
+
allNodes.forEach(node => {
|
|
1381
|
+
node.isVisible = this.matchesSearch(node.property, searchText);
|
|
1382
|
+
});
|
|
1383
|
+
// Second pass: Make parent nodes of visible nodes also visible
|
|
1384
|
+
allNodes.forEach(node => {
|
|
1385
|
+
if (node.isVisible && node.level > 0) {
|
|
1386
|
+
// Find and mark parent nodes as visible
|
|
1387
|
+
this.makeParentsVisible(node);
|
|
1388
|
+
}
|
|
1389
|
+
});
|
|
1390
|
+
// Final filtered list
|
|
1391
|
+
const filteredNodes = allNodes.filter(node => node.isVisible);
|
|
1392
|
+
// Update the data source with filtered nodes
|
|
1393
|
+
this.dataSource.data = filteredNodes;
|
|
1394
|
+
this.updateSelectAllState();
|
|
1395
|
+
// After data is updated, expand all parent nodes
|
|
1396
|
+
queueMicrotask(() => {
|
|
1397
|
+
this.expandNodesForSearch();
|
|
1398
|
+
});
|
|
1399
|
+
}
|
|
1400
|
+
/**
|
|
1401
|
+
* Expand parent nodes when filtering
|
|
1402
|
+
* This method expands all nodes with children when a search is active
|
|
1403
|
+
*/
|
|
1404
|
+
expandNodesForSearch() {
|
|
1405
|
+
if (!this.inputText || !this.tree()) {
|
|
1406
|
+
return;
|
|
1407
|
+
}
|
|
1408
|
+
const parentNodes = this.dataSource.data.filter(node => node.expandable);
|
|
1409
|
+
// Expand all parent nodes when searching
|
|
1410
|
+
parentNodes.forEach(node => {
|
|
1411
|
+
if (!this.tree().isExpanded(node)) {
|
|
1412
|
+
this.tree().expand(node);
|
|
1413
|
+
}
|
|
1414
|
+
});
|
|
1415
|
+
}
|
|
1416
|
+
/**
|
|
1417
|
+
* Makes all parent nodes visible.
|
|
1418
|
+
* @param node The node whose parents should be made visible.
|
|
1419
|
+
*/
|
|
1420
|
+
makeParentsVisible(node) {
|
|
1421
|
+
if (!node || node.level === 0)
|
|
1422
|
+
return;
|
|
1423
|
+
const keyPath = node.property.keyPath;
|
|
1424
|
+
if (!keyPath)
|
|
1425
|
+
return;
|
|
1426
|
+
// Navigate up the path
|
|
1427
|
+
for (let i = 1; i < keyPath.length; i++) {
|
|
1428
|
+
const parentPath = keyPath.slice(0, i).join('.');
|
|
1429
|
+
const parent = this.flatNodeMap.get(parentPath);
|
|
1430
|
+
if (parent) {
|
|
1431
|
+
parent.isVisible = true;
|
|
1432
|
+
}
|
|
1433
|
+
else {
|
|
1434
|
+
break;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
/**
|
|
1439
|
+
* Categorizes and flattens hierarchical properties.
|
|
1440
|
+
* @param properties The properties to categorize.
|
|
1441
|
+
* @returns The flattened list of properties.
|
|
1442
|
+
*/
|
|
1443
|
+
categorizeAndFlattenHierarchicalProperties(properties) {
|
|
1444
|
+
const { simple, complex } = this.assetPropertiesService.categorizeAndFlattenHierarchicalProperties(properties);
|
|
1445
|
+
return [...simple, ...complex];
|
|
1446
|
+
}
|
|
1447
|
+
/**
|
|
1448
|
+
* Fix syntax error in the file.
|
|
1449
|
+
*/
|
|
1450
|
+
fixSyntaxError() {
|
|
1451
|
+
if (true) {
|
|
1452
|
+
// Correct syntax
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertyListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1456
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: AssetPropertyListComponent, isStandalone: true, selector: "c8y-asset-property-list", inputs: { config: "config", asset: "asset", customProperties: "customProperties" }, outputs: { selectedProperties: "selectedProperties" }, queries: [{ propertyName: "assetPropertyAction", first: true, predicate: AssetPropertyActionDirective, descendants: true }], viewQueries: [{ propertyName: "tree", first: true, predicate: ["tree"], descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<div\n class=\"tree-container bg-inherit\"\n [attr.aria-label]=\"'Asset property list' | translate\"\n role=\"tree\"\n>\n <div\n class=\"select-all-container bg-inherit sticky-top separator-bottom\"\n *ngIf=\"config.showHeader || config.searchable\"\n >\n <div\n class=\"form-group m-b-0 p-16\"\n *ngIf=\"config.searchable\"\n [ngClass]=\"{ 'separator-bottom': config.showHeader }\"\n >\n <div class=\"input-group input-group-search\">\n <input\n class=\"form-control\"\n [attr.aria-label]=\"'Filter properties' | translate\"\n placeholder=\"{{ 'Filter properties' | translate }}\"\n role=\"searchbox\"\n type=\"search\"\n autocomplete=\"off\"\n [(ngModel)]=\"inputText\"\n (input)=\"onSearch()\"\n [disabled]=\"!dataSource.data.length\"\n #filter\n />\n <span\n class=\"input-group-addon\"\n [attr.aria-hidden]=\"true\"\n *ngIf=\"filter.value.length === 0\"\n >\n <i\n class=\"dlt-c8y-icon-search\"\n [c8yIcon]=\"'search'\"\n ></i>\n </span>\n <span\n class=\"input-group-addon\"\n [attr.aria-hidden]=\"true\"\n *ngIf=\"filter.value.length > 0\"\n >\n <i\n class=\"text-muted dlt-c8y-icon-times\"\n [c8yIcon]=\"'times'\"\n [attr.aria-label]=\"'Clear search' | translate\"\n tabindex=\"0\"\n role=\"button\"\n (click)=\"clearSearch()\"\n ></i>\n </span>\n </div>\n </div>\n <div\n class=\"d-flex a-i-center overflow-hidden\"\n *ngIf=\"config.showHeader && dataSource.data.length\"\n >\n <div\n class=\"flex-no-shrink\"\n [ngClass]=\"{\n 'p-r-40': config.selectMode !== 'none' && config.expansionMode !== 'nonCollapsible',\n 'p-r-16': config.selectMode === 'none',\n 'p-r-8': config.selectMode !== 'none' && config.expansionMode === 'nonCollapsible'\n }\"\n ></div>\n <c8y-list-item-checkbox\n class=\"p-l-4 p-r-4\"\n *ngIf=\"config.selectMode === 'multi'\"\n [ngModel]=\"allSelected\"\n [indeterminate]=\"indeterminate\"\n (onSelect)=\"selectAll($event)\"\n ></c8y-list-item-checkbox>\n <div\n class=\"p-l-24 p-t-40\"\n *ngIf=\"config.selectMode !== 'multi'\"\n ></div>\n <div class=\"content-flex-30 fit-w m-t-4 m-b-4\">\n <div class=\"col-6 d-flex a-i-center m-l-0 m-r-0\">\n <span class=\"p-r-4 p-l-16 flex-no-shrink\">\n <div class=\"c8y-icon\"></div>\n </span>\n <span class=\"text-medium m-l-8\">\n {{ 'Property' | translate }}\n </span>\n </div>\n <div\n [ngClass]=\"{ 'col-3': config.showValue, 'col-6': !config.showValue }\"\n *ngIf=\"config.showKey\"\n >\n <span class=\"text-medium\">{{ 'Key' | translate }}</span>\n </div>\n <div\n [ngClass]=\"{ 'col-3': config.showKey, 'col-6': !config.showKey }\"\n *ngIf=\"config.showValue\"\n >\n <span class=\"text-medium\">{{ 'Value' | translate }}</span>\n </div>\n </div>\n <div\n class=\"m-l-8 p-l-24\"\n *ngIf=\"assetPropertyAction\"\n ></div>\n </div>\n </div>\n\n <cdk-tree\n role=\"presentation\"\n *ngIf=\"dataSource.data.length; else emptyState\"\n #tree\n [dataSource]=\"dataSource\"\n [levelAccessor]=\"getLevel\"\n >\n <!-- Tree Node Definition -->\n <cdk-tree-node\n [style.display]=\"shouldRender(node) ? 'flex' : 'none'\"\n [attr.tabindex]=\"0\"\n [attr.aria-level]=\"getLevel(node) + 1\"\n [attr.aria-expanded]=\"hasChild(node) ? tree.isExpanded(node) : null\"\n [attr.aria-selected]=\"config.selectMode !== 'none' ? node.property.active : null\"\n role=\"treeitem\"\n *cdkTreeNodeDef=\"let node\"\n cdkTreeNodePadding\n [cdkTreeNodePaddingIndent]=\"24\"\n [ngClass]=\"{\n nonCollapsible: config.expansionMode === 'nonCollapsible',\n nonSelectable: config.selectMode === 'none'\n }\"\n >\n <div class=\"d-flex p-relative overflow-visible bg-inherit fit-h\">\n <!-- Toggle Button for expandable nodes -->\n <button\n class=\"collapse-btn btn-dot flex-no-shrink\"\n [attr.aria-label]=\"\n collapseButtonTitle(node)\n | translate\n : {\n assetPropertyLabel:\n node.property.label || node.property.title || node.property.name\n }\n \"\n [attr.aria-expanded]=\"tree.isExpanded(node)\"\n *ngIf=\"config.expansionMode !== 'nonCollapsible' && hasChild(node)\"\n cdkTreeNodeToggle\n >\n <i [c8yIcon]=\"'chevron-right'\"></i>\n </button>\n <!-- Placeholder for non-expandable nodes to maintain alignment -->\n <div\n class=\"flex-no-shrink\"\n [ngClass]=\"{\n 'p-r-40': config.expansionMode !== 'nonCollapsible',\n 'p-r-8': config.expansionMode === 'nonCollapsible'\n }\"\n *ngIf=\"!hasChild(node) || config.expansionMode === 'nonCollapsible'\"\n ></div>\n\n <!-- Selection Controls -->\n <div\n class=\"d-contents\"\n *ngIf=\"config.selectMode !== 'none'\"\n >\n @if (config.selectMode === 'single') {\n <c8y-list-item-radio\n class=\"p-l-4\"\n type=\"radio\"\n [ngModel]=\"node.property.active\"\n (onSelect)=\"onSelectSingle($event, node)\"\n ></c8y-list-item-radio>\n } @else if (config.selectMode === 'multi') {\n <c8y-list-item-checkbox\n class=\"p-l-4\"\n [ngModel]=\"node.property.active\"\n [indeterminate]=\"node.indeterminate\"\n (onSelect)=\"onSelectMulti($event, node)\"\n ></c8y-list-item-checkbox>\n }\n </div>\n\n <div class=\"content-flex-30 fit-w bg-inherit\">\n <div\n class=\"d-flex a-i-center bg-inherit m-0\"\n [ngClass]=\"{\n 'col-6': config.showKey || config.showValue,\n 'col-12': !config.showKey && !config.showValue\n }\"\n >\n <c8y-li-icon\n class=\"p-r-4\"\n [icon]=\"node.property.type | c8yAssetPropertyIcon\"\n tooltip=\"{{ node.property.type }}\"\n [delay]=\"500\"\n [ngClass]=\"{\n 'p-l-4': config.selectMode !== 'none',\n 'p-r-16': config.selectMode === 'none'\n }\"\n ></c8y-li-icon>\n\n <span class=\"p-r-8\">\n <div\n class=\"text-truncate\"\n title=\"{{\n node.property.label || node.property.title || node.property.name | translate\n }}\"\n >\n {{ node.property.label || node.property.title || node.property.name | translate }}\n </div>\n </span>\n </div>\n <div\n class=\"d-flex a-i-center\"\n *ngIf=\"config.showKey\"\n [ngClass]=\"{ 'col-3': config.showValue, 'col-6': !config.showValue }\"\n >\n <span\n class=\"d-inline-block tag tag--default a-s-center text-truncate\"\n title=\"{{ node.property.keyPath?.join('.') || (node.property?.name | translate) }}\"\n >\n {{ node.property.keyPath?.join('.') || (node.property?.name | translate) }}\n </span>\n </div>\n <div\n class=\"d-flex a-i-center\"\n [ngClass]=\"{ 'col-3': config.showKey, 'col-6': !config.showKey }\"\n *ngIf=\"asset && config.showValue\"\n >\n <span\n class=\"tag tag--info d-inline-block a-s-center text-truncate\"\n title=\"{{ node.property | c8yAssetPropertyValue: asset }}\"\n >\n {{ node.property | c8yAssetPropertyValue: asset }}\n </span>\n </div>\n </div>\n <div\n class=\"m-l-8 showOnHover d-flex a-i-center\"\n *ngIf=\"assetPropertyAction\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n assetPropertyAction?.template;\n context: {\n $implicit: node.property\n }\n \"\n ></ng-container>\n </div>\n </div>\n </cdk-tree-node>\n </cdk-tree>\n</div>\n\n<ng-template #emptyState>\n <c8y-ui-empty-state\n icon=\"list\"\n title=\"{{ 'No properties to display' | translate }}\"\n subtitle=\"{{ 'Select an asset to see the available properties.' | translate }}\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: ListGroupModule }, { kind: "component", type: i2.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i2.ListItemCheckboxComponent, selector: "c8y-list-item-checkbox, c8y-li-checkbox", inputs: ["selected", "indeterminate", "disabled", "displayAsSwitch"], outputs: ["onSelect"] }, { kind: "component", type: i2.ListItemRadioComponent, selector: "c8y-list-item-radio, c8y-li-radio", inputs: ["selected", "name", "disabled", "value"], outputs: ["onSelect"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i3.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: CdkTreeModule }, { kind: "directive", type: i4.CdkTreeNodeDef, selector: "[cdkTreeNodeDef]", inputs: ["cdkTreeNodeDefWhen"] }, { kind: "directive", type: i4.CdkTreeNodePadding, selector: "[cdkTreeNodePadding]", inputs: ["cdkTreeNodePadding", "cdkTreeNodePaddingIndent"] }, { kind: "directive", type: i4.CdkTreeNodeToggle, selector: "[cdkTreeNodeToggle]", inputs: ["cdkTreeNodeToggleRecursive"] }, { kind: "component", type: i4.CdkTree, selector: "cdk-tree", inputs: ["dataSource", "treeControl", "levelAccessor", "childrenAccessor", "trackBy", "expansionKey"], exportAs: ["cdkTree"] }, { kind: "directive", type: i4.CdkTreeNode, selector: "cdk-tree-node", inputs: ["role", "isExpandable", "isExpanded", "isDisabled", "cdkTreeNodeTypeaheadLabel"], outputs: ["activation", "expandedChange"], exportAs: ["cdkTreeNode"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: AssetPropertyValuePipe, name: "c8yAssetPropertyValue" }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: AssetPropertyIconPipe, name: "c8yAssetPropertyIcon" }] }); }
|
|
1457
|
+
}
|
|
1458
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertyListComponent, decorators: [{
|
|
1459
|
+
type: Component,
|
|
1460
|
+
args: [{ selector: 'c8y-asset-property-list', standalone: true, imports: [
|
|
1461
|
+
NgIf,
|
|
1462
|
+
NgClass,
|
|
1463
|
+
FormsModule,
|
|
1464
|
+
ListGroupModule,
|
|
1465
|
+
C8yTranslatePipe,
|
|
1466
|
+
TooltipModule,
|
|
1467
|
+
IconDirective,
|
|
1468
|
+
CdkTreeModule,
|
|
1469
|
+
NgTemplateOutlet,
|
|
1470
|
+
AssetPropertyValuePipe,
|
|
1471
|
+
EmptyStateComponent,
|
|
1472
|
+
AssetPropertyIconPipe
|
|
1473
|
+
], template: "<div\n class=\"tree-container bg-inherit\"\n [attr.aria-label]=\"'Asset property list' | translate\"\n role=\"tree\"\n>\n <div\n class=\"select-all-container bg-inherit sticky-top separator-bottom\"\n *ngIf=\"config.showHeader || config.searchable\"\n >\n <div\n class=\"form-group m-b-0 p-16\"\n *ngIf=\"config.searchable\"\n [ngClass]=\"{ 'separator-bottom': config.showHeader }\"\n >\n <div class=\"input-group input-group-search\">\n <input\n class=\"form-control\"\n [attr.aria-label]=\"'Filter properties' | translate\"\n placeholder=\"{{ 'Filter properties' | translate }}\"\n role=\"searchbox\"\n type=\"search\"\n autocomplete=\"off\"\n [(ngModel)]=\"inputText\"\n (input)=\"onSearch()\"\n [disabled]=\"!dataSource.data.length\"\n #filter\n />\n <span\n class=\"input-group-addon\"\n [attr.aria-hidden]=\"true\"\n *ngIf=\"filter.value.length === 0\"\n >\n <i\n class=\"dlt-c8y-icon-search\"\n [c8yIcon]=\"'search'\"\n ></i>\n </span>\n <span\n class=\"input-group-addon\"\n [attr.aria-hidden]=\"true\"\n *ngIf=\"filter.value.length > 0\"\n >\n <i\n class=\"text-muted dlt-c8y-icon-times\"\n [c8yIcon]=\"'times'\"\n [attr.aria-label]=\"'Clear search' | translate\"\n tabindex=\"0\"\n role=\"button\"\n (click)=\"clearSearch()\"\n ></i>\n </span>\n </div>\n </div>\n <div\n class=\"d-flex a-i-center overflow-hidden\"\n *ngIf=\"config.showHeader && dataSource.data.length\"\n >\n <div\n class=\"flex-no-shrink\"\n [ngClass]=\"{\n 'p-r-40': config.selectMode !== 'none' && config.expansionMode !== 'nonCollapsible',\n 'p-r-16': config.selectMode === 'none',\n 'p-r-8': config.selectMode !== 'none' && config.expansionMode === 'nonCollapsible'\n }\"\n ></div>\n <c8y-list-item-checkbox\n class=\"p-l-4 p-r-4\"\n *ngIf=\"config.selectMode === 'multi'\"\n [ngModel]=\"allSelected\"\n [indeterminate]=\"indeterminate\"\n (onSelect)=\"selectAll($event)\"\n ></c8y-list-item-checkbox>\n <div\n class=\"p-l-24 p-t-40\"\n *ngIf=\"config.selectMode !== 'multi'\"\n ></div>\n <div class=\"content-flex-30 fit-w m-t-4 m-b-4\">\n <div class=\"col-6 d-flex a-i-center m-l-0 m-r-0\">\n <span class=\"p-r-4 p-l-16 flex-no-shrink\">\n <div class=\"c8y-icon\"></div>\n </span>\n <span class=\"text-medium m-l-8\">\n {{ 'Property' | translate }}\n </span>\n </div>\n <div\n [ngClass]=\"{ 'col-3': config.showValue, 'col-6': !config.showValue }\"\n *ngIf=\"config.showKey\"\n >\n <span class=\"text-medium\">{{ 'Key' | translate }}</span>\n </div>\n <div\n [ngClass]=\"{ 'col-3': config.showKey, 'col-6': !config.showKey }\"\n *ngIf=\"config.showValue\"\n >\n <span class=\"text-medium\">{{ 'Value' | translate }}</span>\n </div>\n </div>\n <div\n class=\"m-l-8 p-l-24\"\n *ngIf=\"assetPropertyAction\"\n ></div>\n </div>\n </div>\n\n <cdk-tree\n role=\"presentation\"\n *ngIf=\"dataSource.data.length; else emptyState\"\n #tree\n [dataSource]=\"dataSource\"\n [levelAccessor]=\"getLevel\"\n >\n <!-- Tree Node Definition -->\n <cdk-tree-node\n [style.display]=\"shouldRender(node) ? 'flex' : 'none'\"\n [attr.tabindex]=\"0\"\n [attr.aria-level]=\"getLevel(node) + 1\"\n [attr.aria-expanded]=\"hasChild(node) ? tree.isExpanded(node) : null\"\n [attr.aria-selected]=\"config.selectMode !== 'none' ? node.property.active : null\"\n role=\"treeitem\"\n *cdkTreeNodeDef=\"let node\"\n cdkTreeNodePadding\n [cdkTreeNodePaddingIndent]=\"24\"\n [ngClass]=\"{\n nonCollapsible: config.expansionMode === 'nonCollapsible',\n nonSelectable: config.selectMode === 'none'\n }\"\n >\n <div class=\"d-flex p-relative overflow-visible bg-inherit fit-h\">\n <!-- Toggle Button for expandable nodes -->\n <button\n class=\"collapse-btn btn-dot flex-no-shrink\"\n [attr.aria-label]=\"\n collapseButtonTitle(node)\n | translate\n : {\n assetPropertyLabel:\n node.property.label || node.property.title || node.property.name\n }\n \"\n [attr.aria-expanded]=\"tree.isExpanded(node)\"\n *ngIf=\"config.expansionMode !== 'nonCollapsible' && hasChild(node)\"\n cdkTreeNodeToggle\n >\n <i [c8yIcon]=\"'chevron-right'\"></i>\n </button>\n <!-- Placeholder for non-expandable nodes to maintain alignment -->\n <div\n class=\"flex-no-shrink\"\n [ngClass]=\"{\n 'p-r-40': config.expansionMode !== 'nonCollapsible',\n 'p-r-8': config.expansionMode === 'nonCollapsible'\n }\"\n *ngIf=\"!hasChild(node) || config.expansionMode === 'nonCollapsible'\"\n ></div>\n\n <!-- Selection Controls -->\n <div\n class=\"d-contents\"\n *ngIf=\"config.selectMode !== 'none'\"\n >\n @if (config.selectMode === 'single') {\n <c8y-list-item-radio\n class=\"p-l-4\"\n type=\"radio\"\n [ngModel]=\"node.property.active\"\n (onSelect)=\"onSelectSingle($event, node)\"\n ></c8y-list-item-radio>\n } @else if (config.selectMode === 'multi') {\n <c8y-list-item-checkbox\n class=\"p-l-4\"\n [ngModel]=\"node.property.active\"\n [indeterminate]=\"node.indeterminate\"\n (onSelect)=\"onSelectMulti($event, node)\"\n ></c8y-list-item-checkbox>\n }\n </div>\n\n <div class=\"content-flex-30 fit-w bg-inherit\">\n <div\n class=\"d-flex a-i-center bg-inherit m-0\"\n [ngClass]=\"{\n 'col-6': config.showKey || config.showValue,\n 'col-12': !config.showKey && !config.showValue\n }\"\n >\n <c8y-li-icon\n class=\"p-r-4\"\n [icon]=\"node.property.type | c8yAssetPropertyIcon\"\n tooltip=\"{{ node.property.type }}\"\n [delay]=\"500\"\n [ngClass]=\"{\n 'p-l-4': config.selectMode !== 'none',\n 'p-r-16': config.selectMode === 'none'\n }\"\n ></c8y-li-icon>\n\n <span class=\"p-r-8\">\n <div\n class=\"text-truncate\"\n title=\"{{\n node.property.label || node.property.title || node.property.name | translate\n }}\"\n >\n {{ node.property.label || node.property.title || node.property.name | translate }}\n </div>\n </span>\n </div>\n <div\n class=\"d-flex a-i-center\"\n *ngIf=\"config.showKey\"\n [ngClass]=\"{ 'col-3': config.showValue, 'col-6': !config.showValue }\"\n >\n <span\n class=\"d-inline-block tag tag--default a-s-center text-truncate\"\n title=\"{{ node.property.keyPath?.join('.') || (node.property?.name | translate) }}\"\n >\n {{ node.property.keyPath?.join('.') || (node.property?.name | translate) }}\n </span>\n </div>\n <div\n class=\"d-flex a-i-center\"\n [ngClass]=\"{ 'col-3': config.showKey, 'col-6': !config.showKey }\"\n *ngIf=\"asset && config.showValue\"\n >\n <span\n class=\"tag tag--info d-inline-block a-s-center text-truncate\"\n title=\"{{ node.property | c8yAssetPropertyValue: asset }}\"\n >\n {{ node.property | c8yAssetPropertyValue: asset }}\n </span>\n </div>\n </div>\n <div\n class=\"m-l-8 showOnHover d-flex a-i-center\"\n *ngIf=\"assetPropertyAction\"\n >\n <ng-container\n *ngTemplateOutlet=\"\n assetPropertyAction?.template;\n context: {\n $implicit: node.property\n }\n \"\n ></ng-container>\n </div>\n </div>\n </cdk-tree-node>\n </cdk-tree>\n</div>\n\n<ng-template #emptyState>\n <c8y-ui-empty-state\n icon=\"list\"\n title=\"{{ 'No properties to display' | translate }}\"\n subtitle=\"{{ 'Select an asset to see the available properties.' | translate }}\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n</ng-template>\n" }]
|
|
1474
|
+
}], ctorParameters: () => [], propDecorators: { config: [{
|
|
1475
|
+
type: Input
|
|
1476
|
+
}], asset: [{
|
|
1477
|
+
type: Input
|
|
1478
|
+
}], customProperties: [{
|
|
1479
|
+
type: Input
|
|
1480
|
+
}], selectedProperties: [{
|
|
1481
|
+
type: Output
|
|
1482
|
+
}], assetPropertyAction: [{
|
|
1483
|
+
type: ContentChild,
|
|
1484
|
+
args: [AssetPropertyActionDirective]
|
|
1485
|
+
}] } });
|
|
1486
|
+
|
|
1487
|
+
/**
|
|
1488
|
+
* Represents a drawer component for selecting asset properties.
|
|
1489
|
+
*/
|
|
1490
|
+
class AssetPropertySelectorDrawerComponent {
|
|
1491
|
+
constructor() {
|
|
1492
|
+
/**
|
|
1493
|
+
* Title of the drawer.
|
|
1494
|
+
*/
|
|
1495
|
+
this.title = gettext('Select property');
|
|
1496
|
+
/**
|
|
1497
|
+
* Custom properties to be displayed in the list.
|
|
1498
|
+
*/
|
|
1499
|
+
this.customProperties = [];
|
|
1500
|
+
/**
|
|
1501
|
+
* Emits the selected properties when saved.
|
|
1502
|
+
*/
|
|
1503
|
+
this.savePropertySelection = new EventEmitter();
|
|
1504
|
+
/**
|
|
1505
|
+
* Emits an event when the selection is canceled.
|
|
1506
|
+
*/
|
|
1507
|
+
this.cancelPropertySelection = new EventEmitter();
|
|
1508
|
+
/**
|
|
1509
|
+
* List of selected properties.
|
|
1510
|
+
*/
|
|
1511
|
+
this.selectedProperties = [];
|
|
1512
|
+
/**
|
|
1513
|
+
* Reference to the bottom drawer.
|
|
1514
|
+
*/
|
|
1515
|
+
this.bottomDrawerRef = inject(BottomDrawerRef);
|
|
1516
|
+
/**
|
|
1517
|
+
* Promise resolving to the selected properties.
|
|
1518
|
+
*/
|
|
1519
|
+
this.result = new Promise((resolve, reject) => {
|
|
1520
|
+
this._save = resolve;
|
|
1521
|
+
this._cancel = reject;
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
/**
|
|
1525
|
+
* Updates the selected properties.
|
|
1526
|
+
* @param properties The selected properties.
|
|
1527
|
+
*/
|
|
1528
|
+
onSelectedProperties(properties) {
|
|
1529
|
+
this.selectedProperties = cloneDeep(properties);
|
|
1530
|
+
}
|
|
1531
|
+
/**
|
|
1532
|
+
* Saves the selected properties and closes the drawer.
|
|
1533
|
+
*/
|
|
1534
|
+
onSave() {
|
|
1535
|
+
this._save(this.selectedProperties);
|
|
1536
|
+
this.bottomDrawerRef.close();
|
|
1537
|
+
}
|
|
1538
|
+
/**
|
|
1539
|
+
* Cancels the selection and closes the drawer.
|
|
1540
|
+
*/
|
|
1541
|
+
onCancel() {
|
|
1542
|
+
this._cancel();
|
|
1543
|
+
this.bottomDrawerRef.close();
|
|
1544
|
+
}
|
|
1545
|
+
/**
|
|
1546
|
+
* Checks if the select button should be disabled.
|
|
1547
|
+
* @returns True if all selected properties are inactive.
|
|
1548
|
+
*/
|
|
1549
|
+
selectIsDisabled() {
|
|
1550
|
+
return this.selectedProperties?.every(({ active }) => !active);
|
|
1551
|
+
}
|
|
1552
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertySelectorDrawerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1553
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: AssetPropertySelectorDrawerComponent, isStandalone: true, selector: "c8y-asset-property-selector-drawer-component", inputs: { title: "title" }, outputs: { savePropertySelection: "savePropertySelection", cancelPropertySelection: "cancelPropertySelection" }, host: { classAttribute: "d-contents" }, ngImport: i0, template: "<div class=\"card-header separator\">\n <span class=\"h4 card-title\">{{ title | translate }}</span>\n</div>\n\n<div class=\"inner-scroll flex-grow\">\n <c8y-asset-property-list\n class=\"bg-component\"\n [asset]=\"asset\"\n [config]=\"config\"\n [customProperties]=\"customProperties\"\n (selectedProperties)=\"onSelectedProperties($event)\"\n ></c8y-asset-property-list>\n</div>\n\n<div class=\"card-footer text-center p-24 separator flex-no-shrink\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"onCancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Select' | translate }}\"\n type=\"button\"\n [disabled]=\"selectIsDisabled()\"\n (click)=\"onSave()\"\n >\n {{ 'Select' | translate }}\n </button>\n</div>\n", dependencies: [{ kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "ngmodule", type: FormsModule$1 }, { kind: "component", type: AssetPropertyListComponent, selector: "c8y-asset-property-list", inputs: ["config", "asset", "customProperties"], outputs: ["selectedProperties"] }] }); }
|
|
1554
|
+
}
|
|
1555
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AssetPropertySelectorDrawerComponent, decorators: [{
|
|
1556
|
+
type: Component,
|
|
1557
|
+
args: [{ selector: 'c8y-asset-property-selector-drawer-component', host: {
|
|
1558
|
+
class: 'd-contents'
|
|
1559
|
+
}, standalone: true, imports: [C8yTranslatePipe, FormsModule$1, AssetPropertyListComponent], template: "<div class=\"card-header separator\">\n <span class=\"h4 card-title\">{{ title | translate }}</span>\n</div>\n\n<div class=\"inner-scroll flex-grow\">\n <c8y-asset-property-list\n class=\"bg-component\"\n [asset]=\"asset\"\n [config]=\"config\"\n [customProperties]=\"customProperties\"\n (selectedProperties)=\"onSelectedProperties($event)\"\n ></c8y-asset-property-list>\n</div>\n\n<div class=\"card-footer text-center p-24 separator flex-no-shrink\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"onCancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Select' | translate }}\"\n type=\"button\"\n [disabled]=\"selectIsDisabled()\"\n (click)=\"onSave()\"\n >\n {{ 'Select' | translate }}\n </button>\n</div>\n" }]
|
|
1560
|
+
}], propDecorators: { title: [{
|
|
1561
|
+
type: Input
|
|
1562
|
+
}], savePropertySelection: [{
|
|
1563
|
+
type: Output
|
|
1564
|
+
}], cancelPropertySelection: [{
|
|
1565
|
+
type: Output
|
|
1566
|
+
}] } });
|
|
1567
|
+
|
|
1568
|
+
/**
|
|
1569
|
+
* Generated bundle index. Do not edit.
|
|
1570
|
+
*/
|
|
1571
|
+
|
|
1572
|
+
export { AssetPropertiesService, AssetPropertyActionDirective, AssetPropertyListComponent, AssetPropertySelectorDrawerComponent, RESULT_TYPES, defaultAssetProperties, defaultAssetPropertyListConfig, deviceAssetProperties };
|
|
1573
|
+
//# sourceMappingURL=c8y-ngx-components-asset-properties.mjs.map
|