@c8y/ngx-components 1023.57.0 → 1023.59.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.
Files changed (41) hide show
  1. package/ai/agents/html/index.d.ts +6 -0
  2. package/ai/agents/html/index.d.ts.map +1 -0
  3. package/assets-navigator/index.d.ts.map +1 -1
  4. package/computed-asset-properties/index.d.ts.map +1 -1
  5. package/context-dashboard/index.d.ts +7 -3
  6. package/context-dashboard/index.d.ts.map +1 -1
  7. package/fesm2022/c8y-ngx-components-ai-agents-html.mjs +1672 -0
  8. package/fesm2022/c8y-ngx-components-ai-agents-html.mjs.map +1 -0
  9. package/fesm2022/c8y-ngx-components-assets-navigator.mjs +4 -2
  10. package/fesm2022/c8y-ngx-components-assets-navigator.mjs.map +1 -1
  11. package/fesm2022/c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-C5oS4Be-.mjs +790 -0
  12. package/fesm2022/c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-C5oS4Be-.mjs.map +1 -0
  13. package/fesm2022/c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-Bg9mbBkF.mjs +120 -0
  14. package/fesm2022/c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-Bg9mbBkF.mjs.map +1 -0
  15. package/fesm2022/c8y-ngx-components-computed-asset-properties.mjs +1 -642
  16. package/fesm2022/c8y-ngx-components-computed-asset-properties.mjs.map +1 -1
  17. package/fesm2022/c8y-ngx-components-context-dashboard.mjs +19 -5
  18. package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
  19. package/fesm2022/c8y-ngx-components-map.mjs +241 -24
  20. package/fesm2022/c8y-ngx-components-map.mjs.map +1 -1
  21. package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget-ai-config.mjs +2 -1667
  22. package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget-ai-config.mjs.map +1 -1
  23. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs +32 -0
  24. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs.map +1 -1
  25. package/fesm2022/c8y-ngx-components-widgets-implementations-map.mjs +13 -13
  26. package/fesm2022/c8y-ngx-components-widgets-implementations-map.mjs.map +1 -1
  27. package/locales/de.po +15 -6
  28. package/locales/es.po +15 -6
  29. package/locales/fr.po +15 -6
  30. package/locales/ja_JP.po +15 -6
  31. package/locales/ko.po +15 -6
  32. package/locales/locales.pot +21 -3
  33. package/locales/nl.po +15 -6
  34. package/locales/pl.po +15 -6
  35. package/locales/pt_BR.po +15 -6
  36. package/locales/zh_CN.po +15 -6
  37. package/locales/zh_TW.po +15 -6
  38. package/map/index.d.ts +66 -8
  39. package/map/index.d.ts.map +1 -1
  40. package/package.json +1 -1
  41. package/widgets/implementations/datapoints-graph/index.d.ts.map +1 -1
@@ -0,0 +1,790 @@
1
+ import { ComputedPropertiesService, hookComputedProperty } from '@c8y/ngx-components/asset-properties';
2
+ import * as i0 from '@angular/core';
3
+ import { inject, Injector, Injectable } from '@angular/core';
4
+ import { MeasurementService, InventoryService, AlarmService, EventService, OperationService } from '@c8y/client';
5
+ import { MeasurementRealtimeService, DatePipe, ManagedObjectRealtimeService, AlarmRealtimeService, EventRealtimeService, OperationRealtimeService } from '@c8y/ngx-components';
6
+ import { from, map, filter, startWith, take, switchMap, distinctUntilChanged, pairwise, share, NEVER, scan, tap, of, catchError, combineLatest, merge } from 'rxjs';
7
+ import { gettext } from '@c8y/ngx-components/gettext';
8
+ import { get } from 'lodash-es';
9
+
10
+ class LastMeasurementStrategy {
11
+ constructor(config, injector) {
12
+ this.config = config;
13
+ this.measurementService = injector.get(MeasurementService);
14
+ this.measurementRealtime = injector.get(MeasurementRealtimeService);
15
+ this.datePipe = injector.get(DatePipe);
16
+ this.datapoint = config.dp.filter(dp => dp.__active)[0];
17
+ }
18
+ fetchCurrentValue() {
19
+ const measurementFilter = {
20
+ valueFragmentSeries: this.datapoint.series,
21
+ valueFragmentType: this.datapoint.fragment,
22
+ pageSize: 1,
23
+ revert: true,
24
+ dateFrom: '1970-01-01',
25
+ source: this.datapoint.__target.id
26
+ };
27
+ return from(this.measurementService.list(measurementFilter)).pipe(map(({ data }) => data[0]), filter(measurement => !!measurement), map(measurement => this.formatMeasurement(measurement)));
28
+ }
29
+ createRealtimeStream(initialValue) {
30
+ return this.measurementRealtime
31
+ .onCreateOfSpecificMeasurement$(this.datapoint.fragment, this.datapoint.series, this.datapoint.__target)
32
+ .pipe(map(measurement => this.formatMeasurement(measurement)), startWith(initialValue));
33
+ }
34
+ formatMeasurement(measurement) {
35
+ const resultType = this.config?.resultType;
36
+ const fragment = this.datapoint.fragment;
37
+ const series = this.datapoint.series;
38
+ if (resultType === 1) {
39
+ return measurement[fragment][series].value;
40
+ }
41
+ else if (resultType === 2) {
42
+ return measurement[fragment][series].value + ' ' + measurement[fragment][series].unit;
43
+ }
44
+ else if (resultType === 3) {
45
+ const date = this.datePipe.transform(new Date(measurement.time), 'short');
46
+ return `${date} | ${measurement[fragment][series].value} ${measurement[fragment][series].unit}`;
47
+ }
48
+ else if (resultType === 4) {
49
+ return measurement[fragment][series];
50
+ }
51
+ return '';
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Generic handler for realtime values following the three modes pattern
57
+ * Closed for modification but open for extension through strategies
58
+ */
59
+ class RealtimeValueHandler {
60
+ constructor(strategy, config) {
61
+ this.strategy = strategy;
62
+ this.config = {
63
+ refetchOnResume: true,
64
+ preserveValueOnPause: true
65
+ };
66
+ if (config) {
67
+ this.config = { ...this.config, ...config };
68
+ }
69
+ }
70
+ /**
71
+ * Creates an Observable based on the metadata mode
72
+ */
73
+ getValue(metadata = { mode: 'realtime' }) {
74
+ if (metadata.mode === 'singleValue') {
75
+ return this.strategy.fetchCurrentValue().pipe(take(1));
76
+ }
77
+ if (metadata.mode === 'realtime' && !metadata.realtimeControl$) {
78
+ return this.handleUncontrolledRealtime();
79
+ }
80
+ if (metadata.mode === 'realtime' && metadata.realtimeControl$) {
81
+ return this.handleControlledRealtime(metadata.realtimeControl$);
82
+ }
83
+ }
84
+ handleUncontrolledRealtime() {
85
+ return this.strategy
86
+ .fetchCurrentValue()
87
+ .pipe(switchMap(initialValue => this.strategy.createRealtimeStream(initialValue)));
88
+ }
89
+ handleControlledRealtime(control$) {
90
+ const controlWithPrevious$ = control$.pipe(distinctUntilChanged(), startWith(null), pairwise(), share());
91
+ return controlWithPrevious$.pipe(switchMap(([previous, current]) => {
92
+ if (!current) {
93
+ // Realtime is disabled
94
+ if (previous === null) {
95
+ // Initial emission while disabled
96
+ return this.strategy.fetchCurrentValue().pipe(take(1));
97
+ }
98
+ else if (this.config.preserveValueOnPause) {
99
+ // Was previously enabled - preserve last value
100
+ return NEVER;
101
+ }
102
+ else {
103
+ // Don't preserve value - fetch current
104
+ return this.strategy.fetchCurrentValue().pipe(take(1));
105
+ }
106
+ }
107
+ else {
108
+ // Realtime is enabled
109
+ if (this.config.refetchOnResume || previous === null) {
110
+ // Re-fetch current value and start streaming
111
+ return this.strategy
112
+ .fetchCurrentValue()
113
+ .pipe(switchMap(currentValue => this.strategy.createRealtimeStream(currentValue)));
114
+ }
115
+ else {
116
+ // Continue with realtime stream without re-fetching
117
+ return this.strategy.createRealtimeStream(null);
118
+ }
119
+ }
120
+ }));
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Creates an Observable that tracks the latest measurement value for a specific datapoint.
126
+ * Combines initial server fetch with real-time measurement updates.
127
+ *
128
+ * @param config - Measurement configuration (datapoint, result type, etc.)
129
+ * @param metadata - Configuration controlling the behavior of the function
130
+ * @returns Observable<string> - Stream of measurement string values
131
+ */
132
+ function lastMeasurementValue(config, metadata = { mode: 'realtime' }) {
133
+ const injector = inject(Injector);
134
+ const strategy = new LastMeasurementStrategy(config, injector);
135
+ const handler = new RealtimeValueHandler(strategy);
136
+ return handler.getValue(metadata);
137
+ }
138
+
139
+ const lastMeasurement = {
140
+ name: 'lastMeasurement',
141
+ contextType: ['device', 'asset', 'group'],
142
+ prop: {
143
+ c8y_JsonSchema: {
144
+ properties: {
145
+ lastMeasurement: {
146
+ label: 'Last measurement',
147
+ type: 'string'
148
+ }
149
+ }
150
+ },
151
+ name: 'lastMeasurement',
152
+ label: gettext('Last measurement'),
153
+ type: 'string',
154
+ config: { dp: [], resultType: 1 },
155
+ computed: true,
156
+ isEditable: false,
157
+ isStandardProperty: true
158
+ },
159
+ loadConfigComponent: () => import('./c8y-ngx-components-computed-asset-properties-last-measurement-config.component-DkrSvf9F.mjs').then(m => m.ComputedPropertyLastMeasurementConfigComponent),
160
+ value: ({ config }) => {
161
+ return lastMeasurementValue(config);
162
+ }
163
+ };
164
+
165
+ class ChildCountStrategy {
166
+ constructor(asset, childType, injector) {
167
+ this.asset = asset;
168
+ this.childType = childType;
169
+ this.inventoryService = injector.get(InventoryService);
170
+ this.moRealtimeService = injector.get(ManagedObjectRealtimeService);
171
+ }
172
+ fetchCurrentValue() {
173
+ return from(this.inventoryService.detail(this.asset.id, { withChildren: true })).pipe(map(resp => resp?.data?.[this.childType]?.references?.length || 0));
174
+ }
175
+ createRealtimeStream(initialValue) {
176
+ return this.moRealtimeService.onAll$(this.asset.id).pipe(map(resp => resp?.data?.[this.childType]?.references?.length || 0), startWith(initialValue));
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Shared function that tracks the count of child items (devices or assets) for a specific managed object.
182
+ * Supports real-time updates when child items are added or removed.
183
+ *
184
+ * @param asset - The managed object to track child items for
185
+ * @param childType - Type of child items ('childDevices' or 'childAssets')
186
+ * @param metadata - Configuration controlling the behavior of the function
187
+ * @returns Observable<number> - Stream of child items count values
188
+ */
189
+ function childCountValue(asset, metadata = { mode: 'realtime' }, childType) {
190
+ const injector = inject(Injector);
191
+ const strategy = new ChildCountStrategy(asset, childType, injector);
192
+ const handler = new RealtimeValueHandler(strategy);
193
+ return handler.getValue(metadata);
194
+ }
195
+
196
+ const childAssetsCount = {
197
+ name: 'childAssetsCount',
198
+ contextType: ['group', 'asset'],
199
+ prop: {
200
+ c8y_JsonSchema: {
201
+ properties: {
202
+ childAssetsCount: {
203
+ label: 'Number of child assets',
204
+ type: 'number'
205
+ }
206
+ }
207
+ },
208
+ name: 'childAssetsCount',
209
+ label: gettext('Number of child assets'),
210
+ type: 'number',
211
+ computed: true,
212
+ isEditable: false,
213
+ isStandardProperty: true
214
+ },
215
+ value: ({ context, metadata }) => childAssetsCountValue(context, metadata)
216
+ };
217
+ /**
218
+ * Creates an Observable that tracks the count of child assets for a specific asset.
219
+ * Supports real-time updates when child assets are added or removed.
220
+ *
221
+ * @param asset - The managed object (asset) to track child assets for
222
+ * @param metadata - Configuration controlling the behavior of the function
223
+ * @returns Observable<number> - Stream of child assets count values
224
+ */
225
+ function childAssetsCountValue(asset, metadata = { mode: 'realtime' }) {
226
+ return childCountValue(asset, metadata, 'childAssets');
227
+ }
228
+
229
+ /**
230
+ * Base class for count-based strategies
231
+ * Provides common accumulation logic
232
+ */
233
+ class CountStrategyBase {
234
+ createRealtimeStream(initialValue) {
235
+ return this.getRealtimeIncrement$().pipe(scan((count, increment) => count + increment, initialValue), startWith(initialValue));
236
+ }
237
+ }
238
+
239
+ class AlarmCountStrategy extends CountStrategyBase {
240
+ constructor(config, asset, dateFrom, injector) {
241
+ super();
242
+ this.config = config;
243
+ this.asset = asset;
244
+ this.dateFrom = dateFrom;
245
+ this.alarmService = injector.get(AlarmService);
246
+ this.alarmRealtimeService = injector.get(AlarmRealtimeService);
247
+ this.startTime = new Date();
248
+ }
249
+ fetchCurrentValue() {
250
+ const severities = Object.keys(this.config.severities || {}).filter(key => this.config.severities[key]);
251
+ const filters = {
252
+ source: this.asset.id,
253
+ dateFrom: this.dateFrom.toISOString(),
254
+ type: this.config.type,
255
+ pageSize: 1,
256
+ withTotalElements: true,
257
+ ...(severities.length && { severity: severities.join(',') })
258
+ };
259
+ return from(this.alarmService.list(filters)).pipe(map(resp => resp?.paging?.totalElements || 0), tap(() => (this.startTime = new Date())) // Update start time after fetch
260
+ );
261
+ }
262
+ getRealtimeIncrement$() {
263
+ return this.alarmRealtimeService.onAll$(this.asset.id).pipe(map(({ data }) => data), filter(alarm => alarm.type === this.config.type &&
264
+ this.config.severities[alarm.severity] &&
265
+ new Date(alarm.creationTime) > this.startTime), tap(() => (this.startTime = new Date())), map(() => 1) // Each matching alarm increments by 1
266
+ );
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Creates an Observable that tracks alarm count for a specific asset.
272
+ * When real-time is paused and resumed, it re-fetches the current count from server
273
+ * to account for alarms that occurred during the pause.
274
+ *
275
+ * @param config - Alarm filtering configuration (type, severities, etc.)
276
+ * @param asset - The managed object (device/asset) to track alarms for
277
+ * @param dateFrom - Start date for counting alarms
278
+ * @param metadata - Configuration controlling the behavior of the function
279
+ * @returns Observable<number> - Stream of alarm count values
280
+ */
281
+ function alarmCountValue(config, asset, dateFrom, metadata = { mode: 'realtime' }) {
282
+ const injector = inject(Injector);
283
+ const strategy = new AlarmCountStrategy(config, asset, dateFrom, injector);
284
+ const handler = new RealtimeValueHandler(strategy);
285
+ return handler.getValue(metadata);
286
+ }
287
+
288
+ const alarmCount3Months = {
289
+ name: 'alarmCount3Months',
290
+ contextType: ['device', 'group', 'asset'],
291
+ prop: {
292
+ c8y_JsonSchema: {
293
+ properties: {
294
+ alarmCount3Months: {
295
+ label: 'Alarm count 3 months',
296
+ type: 'number'
297
+ }
298
+ }
299
+ },
300
+ name: 'alarmCount3Months',
301
+ label: gettext('Alarm count 3 months'),
302
+ type: 'number',
303
+ config: { type: '' },
304
+ computed: true,
305
+ isEditable: false,
306
+ isStandardProperty: true
307
+ },
308
+ loadConfigComponent: () => import('./c8y-ngx-components-computed-asset-properties-alarm-count-config.component-SA0syLy7.mjs').then(m => m.ComputedPropertyAlarmCountConfigComponent),
309
+ value: ({ config, context, metadata }) => alarmCount3MonthsValue(config, context, metadata)
310
+ };
311
+ function alarmCount3MonthsValue(config, asset, metadata) {
312
+ const threeMonthsAgo = new Date();
313
+ threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3);
314
+ return alarmCountValue(config, asset, threeMonthsAgo, metadata);
315
+ }
316
+
317
+ const alarmCountToday = {
318
+ name: 'alarmCountToday',
319
+ contextType: ['device', 'group', 'asset'],
320
+ prop: {
321
+ c8y_JsonSchema: {
322
+ properties: {
323
+ alarmCountToday: {
324
+ label: 'Alarm count today',
325
+ type: 'number'
326
+ }
327
+ }
328
+ },
329
+ name: 'alarmCountToday',
330
+ label: gettext('Alarm count today'),
331
+ type: 'number',
332
+ config: { type: '' },
333
+ computed: true,
334
+ isEditable: false,
335
+ isStandardProperty: true
336
+ },
337
+ loadConfigComponent: () => import('./c8y-ngx-components-computed-asset-properties-alarm-count-config.component-SA0syLy7.mjs').then(m => m.ComputedPropertyAlarmCountConfigComponent),
338
+ value: ({ config, context, metadata }) => alarmCountTodayValue(config, context, metadata)
339
+ };
340
+ function alarmCountTodayValue(config, asset, metadata) {
341
+ const oneDayAgo = new Date();
342
+ oneDayAgo.setDate(oneDayAgo.getDate() - 1);
343
+ return alarmCountValue(config, asset, oneDayAgo, metadata);
344
+ }
345
+
346
+ class EventCountStrategy extends CountStrategyBase {
347
+ constructor(config, asset, dateFrom, injector) {
348
+ super();
349
+ this.config = config;
350
+ this.asset = asset;
351
+ this.dateFrom = dateFrom;
352
+ this.eventService = injector.get(EventService);
353
+ this.eventRealtimeService = injector.get(EventRealtimeService);
354
+ }
355
+ fetchCurrentValue() {
356
+ const filters = {
357
+ source: this.asset.id,
358
+ dateFrom: this.dateFrom.toISOString(),
359
+ type: this.config.type,
360
+ pageSize: 1,
361
+ withTotalElements: true
362
+ };
363
+ return from(this.eventService.list(filters)).pipe(map(resp => resp?.paging?.totalElements || 0));
364
+ }
365
+ getRealtimeIncrement$() {
366
+ return this.eventRealtimeService.onAll$(this.asset.id).pipe(map(({ data }) => data), filter(event => event.type === this.config.type && new Date(event.time) >= this.dateFrom), map(() => 1));
367
+ }
368
+ }
369
+
370
+ /**
371
+ * Creates an Observable that tracks event count for a specific asset.
372
+ * When real-time is paused and resumed, it re-fetches the current count from server
373
+ * to account for events that occurred during the pause.
374
+ *
375
+ * @param config - Event filtering configuration (type, etc.)
376
+ * @param asset - The managed object (device/asset) to track events for
377
+ * @param dateFrom - Start date for counting events
378
+ * @param metadata - Configuration controlling the behavior of the function
379
+ * @returns Observable<number> - Stream of event count values
380
+ */
381
+ function eventCountValue(config, asset, dateFrom, metadata = { mode: 'realtime' }) {
382
+ const injector = inject(Injector);
383
+ const strategy = new EventCountStrategy(config, asset, dateFrom, injector);
384
+ const handler = new RealtimeValueHandler(strategy);
385
+ return handler.getValue(metadata);
386
+ }
387
+
388
+ const eventCountToday = {
389
+ name: 'eventCountToday',
390
+ contextType: ['device', 'group', 'asset'],
391
+ prop: {
392
+ c8y_JsonSchema: {
393
+ properties: {
394
+ eventCountToday: {
395
+ label: 'Event count today',
396
+ type: 'number'
397
+ }
398
+ }
399
+ },
400
+ name: 'eventCountToday',
401
+ label: gettext('Event count today'),
402
+ type: 'number',
403
+ config: { type: '' },
404
+ computed: true,
405
+ isEditable: false,
406
+ isStandardProperty: true
407
+ },
408
+ loadConfigComponent: () => import('./c8y-ngx-components-computed-asset-properties-event-count-config.component-CaTb9cph.mjs').then(m => m.ComputedPropertyEventCountConfigComponent),
409
+ value: ({ config, context, metadata }) => eventCountTodayValue(config, context, metadata)
410
+ };
411
+ function eventCountTodayValue(config, asset, metadata) {
412
+ const today = new Date();
413
+ today.setHours(0, 0, 0, 0);
414
+ return eventCountValue(config, asset, today, metadata);
415
+ }
416
+
417
+ const eventCount3Months = {
418
+ name: 'eventCount3Months',
419
+ contextType: ['device', 'group', 'asset'],
420
+ prop: {
421
+ c8y_JsonSchema: {
422
+ properties: {
423
+ eventCount3Months: {
424
+ label: 'Event count 3 months',
425
+ type: 'number'
426
+ }
427
+ }
428
+ },
429
+ name: 'eventCount3Months',
430
+ label: gettext('Event count 3 months'),
431
+ type: 'number',
432
+ config: { type: '' },
433
+ computed: true,
434
+ isEditable: false,
435
+ isStandardProperty: true
436
+ },
437
+ loadConfigComponent: () => import('./c8y-ngx-components-computed-asset-properties-event-count-config.component-CaTb9cph.mjs').then(m => m.ComputedPropertyEventCountConfigComponent),
438
+ value: ({ config, context, metadata }) => eventCount3MonthsValue(config, context, metadata)
439
+ };
440
+ function eventCount3MonthsValue(config, asset, metadata) {
441
+ const threeMonthsAgo = new Date();
442
+ threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3);
443
+ return eventCountValue(config, asset, threeMonthsAgo, metadata);
444
+ }
445
+
446
+ const configurationSnapshot = {
447
+ name: 'configurationSnapshot',
448
+ contextType: ['device', 'asset'],
449
+ prop: {
450
+ c8y_JsonSchema: {
451
+ properties: {
452
+ configurationSnapshot: {
453
+ label: 'Configuration snapshot',
454
+ type: 'string'
455
+ }
456
+ }
457
+ },
458
+ contextType: ['device', 'asset'],
459
+ name: 'configurationSnapshot',
460
+ label: gettext('Configuration snapshot'),
461
+ type: 'string',
462
+ config: { legacy: true },
463
+ computed: true,
464
+ isEditable: false,
465
+ isStandardProperty: true
466
+ },
467
+ loadConfigComponent: () => import('./c8y-ngx-components-computed-asset-properties-configuration-snapshot-config.component-BOmgJI14.mjs').then(m => m.ConfigurationSnapshotConfigComponent),
468
+ value: ({ config, context }) => configurationSnapshotValue(config, context)
469
+ };
470
+ function configurationSnapshotValue(config, asset) {
471
+ if (config.legacy) {
472
+ const configId = asset.c8y_ConfigurationDump?.id;
473
+ if (!configId) {
474
+ return of(null);
475
+ }
476
+ const injector = inject(Injector);
477
+ const inventoryService = injector.get(InventoryService);
478
+ return from(inventoryService.detail(configId)).pipe(switchMap(({ data }) => {
479
+ return of(data?.name);
480
+ }));
481
+ }
482
+ else {
483
+ const fragment = `c8y_Configuration_${config.type}`;
484
+ return of(asset[fragment]?.name);
485
+ }
486
+ }
487
+
488
+ const childDevicesCount = {
489
+ name: 'childDevicesCount',
490
+ contextType: ['group', 'device', 'asset'],
491
+ prop: {
492
+ c8y_JsonSchema: {
493
+ properties: {
494
+ childDevicesCount: {
495
+ label: 'Number of child devices',
496
+ type: 'number'
497
+ }
498
+ }
499
+ },
500
+ name: 'childDevicesCount',
501
+ label: gettext('Number of child devices'),
502
+ type: 'number',
503
+ computed: true,
504
+ isEditable: false,
505
+ isStandardProperty: true
506
+ },
507
+ value: ({ context, metadata }) => childDevicesCountValue(context, metadata)
508
+ };
509
+ /**
510
+ * Creates an Observable that tracks the count of child devices for a specific asset.
511
+ * Supports real-time updates when child devices are added or removed.
512
+ *
513
+ * @param asset - The managed object (asset) to track child devices for
514
+ * @param metadata - Configuration controlling the behavior of the function
515
+ * @returns Observable<number> - Stream of child devices count values
516
+ */
517
+ function childDevicesCountValue(asset, metadata = { mode: 'realtime' }) {
518
+ return childCountValue(asset, metadata, 'childDevices');
519
+ }
520
+
521
+ class LastDeviceMessageStrategy {
522
+ constructor(asset, injector) {
523
+ this.asset = asset;
524
+ this.measurementService = injector.get(MeasurementService);
525
+ this.measurementRealtime = injector.get(MeasurementRealtimeService);
526
+ this.eventService = injector.get(EventService);
527
+ this.eventRealtimeService = injector.get(EventRealtimeService);
528
+ this.alarmService = injector.get(AlarmService);
529
+ this.alarmRealtimeService = injector.get(AlarmRealtimeService);
530
+ this.operationService = injector.get(OperationService);
531
+ this.operationRealtimeService = injector.get(OperationRealtimeService);
532
+ this.startTime = new Date();
533
+ }
534
+ fetchCurrentValue() {
535
+ const fetchFilter = {
536
+ source: this.asset.id,
537
+ pageSize: 1,
538
+ revert: true
539
+ };
540
+ const fetchLatestMeasurement = () => {
541
+ return from(this.measurementService.list(fetchFilter)).pipe(map(resp => resp.data?.[0]?.time || null), catchError(() => of(null)));
542
+ };
543
+ const fetchLatestEvent = () => {
544
+ return from(this.eventService.list(fetchFilter)).pipe(map(resp => resp.data?.[0]?.time || null), catchError(() => of(null)));
545
+ };
546
+ const fetchLatestAlarm = () => {
547
+ return from(this.alarmService.list(fetchFilter)).pipe(map(resp => resp.data?.[0]?.time || null), catchError(() => of(null)));
548
+ };
549
+ const fetchLatestOperation = () => {
550
+ return from(this.operationService.list(fetchFilter)).pipe(map(resp => resp.data?.[0]?.creationTime || null), catchError(() => of(null)));
551
+ };
552
+ return combineLatest([
553
+ fetchLatestMeasurement(),
554
+ fetchLatestEvent(),
555
+ fetchLatestAlarm(),
556
+ fetchLatestOperation()
557
+ ]).pipe(map(timestamps => {
558
+ const validTimestamps = timestamps.filter(Boolean);
559
+ if (validTimestamps.length === 0) {
560
+ return null;
561
+ }
562
+ const latest = validTimestamps.reduce((latest, current) => {
563
+ return new Date(current) > new Date(latest) ? current : latest;
564
+ });
565
+ // Update start time for realtime filtering
566
+ this.startTime = new Date();
567
+ return latest;
568
+ }));
569
+ }
570
+ createRealtimeStream(initialValue) {
571
+ const measurementStream$ = this.measurementRealtime.onAll$(this.asset.id).pipe(map(({ data }) => data.time), filter(time => new Date(time) > this.startTime));
572
+ const eventStream$ = this.eventRealtimeService.onAll$(this.asset.id).pipe(map(({ data }) => data.time), filter(time => new Date(time) > this.startTime));
573
+ const alarmStream$ = this.alarmRealtimeService.onAll$(this.asset.id).pipe(map(({ data }) => data.time), filter(time => time && new Date(time) > this.startTime));
574
+ const operationStream$ = this.operationRealtimeService.onAll$(this.asset.id).pipe(map(({ data }) => data.creationTime), filter(time => time && new Date(time) > this.startTime));
575
+ return merge(measurementStream$, eventStream$, alarmStream$, operationStream$).pipe(scan((latestTimestamp, newTimestamp) => {
576
+ return new Date(newTimestamp) > new Date(latestTimestamp) ? newTimestamp : latestTimestamp;
577
+ }, initialValue), startWith(initialValue));
578
+ }
579
+ }
580
+
581
+ /**
582
+ * Gets the latest timestamp from events, alarms, measurements, and operations for a device.
583
+ * Returns the most recent timestamp across all these sources.
584
+ *
585
+ * @param asset - The managed object (device/asset) to track
586
+ * @param metadata - Configuration controlling the behavior of the function
587
+ * @returns Observable<string> - Stream of latest timestamp values
588
+ */
589
+ function getLastDeviceMessage(asset, metadata = { mode: 'realtime' }) {
590
+ const injector = inject(Injector);
591
+ const strategy = new LastDeviceMessageStrategy(asset, injector);
592
+ const handler = new RealtimeValueHandler(strategy);
593
+ return handler.getValue(metadata);
594
+ }
595
+
596
+ const lastDeviceMessage = {
597
+ name: 'lastDeviceMessage',
598
+ contextType: ['device'],
599
+ prop: {
600
+ c8y_JsonSchema: {
601
+ properties: {
602
+ lastDeviceMessage: {
603
+ label: 'Last device message',
604
+ type: 'string'
605
+ }
606
+ }
607
+ },
608
+ name: 'lastDeviceMessage',
609
+ label: gettext('Last device message'),
610
+ printFormat: 'datetime',
611
+ type: 'string',
612
+ computed: true,
613
+ isEditable: false,
614
+ isStandardProperty: true
615
+ },
616
+ value: ({ context }) => {
617
+ return getLastDeviceMessage(context);
618
+ }
619
+ };
620
+
621
+ const RESULT_TYPES = {
622
+ RAW_VALUE: { name: 'RAW_VALUE', value: 'RAW_VALUE', label: gettext('Raw value') },
623
+ ENUM_VALUE: { name: 'ENUM_VALUE', value: 'ENUM_VALUE', label: gettext('Enum value') }
624
+ };
625
+
626
+ class FieldbusService {
627
+ constructor() {
628
+ this.inventory = inject(InventoryService);
629
+ this.computedProperties = inject(ComputedPropertiesService);
630
+ }
631
+ async getDeviceTypeOf(fieldbusDevice) {
632
+ const typeRef = fieldbusDevice?.c8y_ModbusDevice?.type;
633
+ if (!typeRef) {
634
+ throw new Error('Provided device is missing c8y_ModbusDevice.type.');
635
+ }
636
+ const match = /^\/inventory\/managedObjects\/(\d+)$/.exec(typeRef);
637
+ if (!match) {
638
+ throw new Error(`Provided Fieldbus type reference ${typeRef} has invalid format, expected: /inventory/managedObjects/{id}`);
639
+ }
640
+ const deviceTypeId = match[1];
641
+ try {
642
+ const { data } = await this.inventory.detail(deviceTypeId);
643
+ return data;
644
+ }
645
+ catch (ex) {
646
+ const errorMessage = ex instanceof Error ? ex.message : String(ex);
647
+ throw new Error(`Could not fetch Fieldbus device type with ID ${deviceTypeId}: ${errorMessage}.`);
648
+ }
649
+ }
650
+ async migrateFieldbusProperty(legacyProperty, fieldbusDevice) {
651
+ if (!legacyProperty.fieldbus) {
652
+ throw new Error('Provided property is not a legacy Fieldbus property.');
653
+ }
654
+ const computedPropertyName = 'fieldbusItemStatus';
655
+ const computedProperty = await this.computedProperties.getByName(computedPropertyName);
656
+ const [statusPropertyName, itemName] = legacyProperty.keyPath;
657
+ const itemType = statusPropertyName === 'c8y_CoilStatus' ? 'c8y_Coil' : 'c8y_Register';
658
+ const deviceType = await this.getDeviceTypeOf(fieldbusDevice);
659
+ const itemListPropertyName = `${itemType}s`;
660
+ const itemList = deviceType[itemListPropertyName] || [];
661
+ const item = itemList.find(i => i.name === itemName);
662
+ const resultType = item.enumValues ? 'ENUM_VALUE' : 'RAW_VALUE';
663
+ return {
664
+ ...computedProperty.prop,
665
+ active: true,
666
+ temporary: true,
667
+ asset: {
668
+ id: fieldbusDevice.id,
669
+ name: fieldbusDevice.name
670
+ },
671
+ config: {
672
+ itemName,
673
+ itemType,
674
+ resultType
675
+ }
676
+ };
677
+ }
678
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FieldbusService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
679
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FieldbusService, providedIn: 'root' }); }
680
+ }
681
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FieldbusService, decorators: [{
682
+ type: Injectable,
683
+ args: [{ providedIn: 'root' }]
684
+ }] });
685
+
686
+ class FieldbusItemStatusStrategy {
687
+ constructor(asset, config, injector) {
688
+ this.asset = asset;
689
+ this.config = config;
690
+ this.inventoryService = injector.get(InventoryService);
691
+ this.moRealtimeService = injector.get(ManagedObjectRealtimeService);
692
+ this.fieldbusService = injector.get(FieldbusService);
693
+ }
694
+ fetchCurrentValue() {
695
+ return from(this.inventoryService.detail(this.asset.id)).pipe(switchMap(({ data }) => this.getStatus(data)));
696
+ }
697
+ createRealtimeStream(initialValue) {
698
+ return this.moRealtimeService.onAll$(this.asset.id).pipe(switchMap(({ data }) => this.getStatus(data)), startWith(initialValue));
699
+ }
700
+ async getStatus(fieldbusDevice) {
701
+ const fieldbusDeviceType = await this.getFieldbusDeviceType(fieldbusDevice);
702
+ if (!fieldbusDeviceType) {
703
+ return null;
704
+ }
705
+ const itemListPropertyName = `${this.config.itemType}s`;
706
+ const statusPropertyName = `${this.config.itemType}Status`;
707
+ const items = fieldbusDeviceType[itemListPropertyName] ?? [];
708
+ const item = items.find(i => i.name === this.config.itemName);
709
+ const statusProperty = get(fieldbusDevice, statusPropertyName);
710
+ const rawValue = get(statusProperty, this.config.itemName);
711
+ if (this.config.resultType === RESULT_TYPES.ENUM_VALUE.value && item?.enumValues) {
712
+ return item.enumValues[rawValue] ?? rawValue;
713
+ }
714
+ else {
715
+ return rawValue;
716
+ }
717
+ }
718
+ async getFieldbusDeviceType(fieldbusDevice) {
719
+ if (this._fieldbusDeviceType === undefined) {
720
+ try {
721
+ this._fieldbusDeviceType = await this.fieldbusService.getDeviceTypeOf(fieldbusDevice);
722
+ }
723
+ catch (ex) {
724
+ this._fieldbusDeviceType = null;
725
+ }
726
+ }
727
+ return this._fieldbusDeviceType;
728
+ }
729
+ }
730
+
731
+ const fieldbusItemStatus = {
732
+ name: 'fieldbusItemStatus',
733
+ contextType: ['device'],
734
+ prop: {
735
+ c8y_JsonSchema: {
736
+ properties: {
737
+ fieldbusItemStatus: {
738
+ label: gettext('Fieldbus item status'),
739
+ type: ['number', 'string']
740
+ }
741
+ }
742
+ },
743
+ name: 'fieldbusItemStatus',
744
+ label: gettext('Fieldbus item status'),
745
+ type: ['number', 'string'],
746
+ config: {
747
+ itemName: null,
748
+ itemType: null,
749
+ resultType: 'RAW_VALUE'
750
+ },
751
+ computed: true,
752
+ isEditable: false,
753
+ isStandardProperty: true
754
+ },
755
+ loadConfigComponent: () => import('./c8y-ngx-components-computed-asset-properties-fieldbus-item-status-config.component-Bg9mbBkF.mjs').then(m => m.FieldbusItemStatusConfigComponent),
756
+ value: ({ config, context }) => fieldbusItemStatusValue(context, config)
757
+ };
758
+ function fieldbusItemStatusValue(asset, config, metadata = { mode: 'realtime' }) {
759
+ const injector = inject(Injector);
760
+ const strategy = new FieldbusItemStatusStrategy(asset, config, injector);
761
+ const handler = new RealtimeValueHandler(strategy);
762
+ return handler.getValue(metadata);
763
+ }
764
+
765
+ const computedAssetPropertiesProviders = [
766
+ AlarmRealtimeService,
767
+ EventRealtimeService,
768
+ MeasurementRealtimeService,
769
+ OperationRealtimeService,
770
+ ManagedObjectRealtimeService,
771
+ hookComputedProperty([
772
+ lastMeasurement,
773
+ lastDeviceMessage,
774
+ childAssetsCount,
775
+ childDevicesCount,
776
+ alarmCount3Months,
777
+ alarmCountToday,
778
+ eventCountToday,
779
+ eventCount3Months,
780
+ configurationSnapshot,
781
+ fieldbusItemStatus
782
+ ])
783
+ ];
784
+
785
+ /**
786
+ * Generated bundle index. Do not edit.
787
+ */
788
+
789
+ export { FieldbusService as F, RESULT_TYPES as R, computedAssetPropertiesProviders as c };
790
+ //# sourceMappingURL=c8y-ngx-components-computed-asset-properties-c8y-ngx-components-computed-asset-properties-C5oS4Be-.mjs.map