@c8y/ngx-components 1023.96.0 → 1023.97.4

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 (43) hide show
  1. package/alarms/index.d.ts.map +1 -1
  2. package/context-dashboard/device/view/index.d.ts +24 -1
  3. package/context-dashboard/device/view/index.d.ts.map +1 -1
  4. package/context-dashboard/index.d.ts +9 -3
  5. package/context-dashboard/index.d.ts.map +1 -1
  6. package/echart/index.d.ts.map +1 -1
  7. package/fesm2022/c8y-ngx-components-alarms.mjs +12 -5
  8. package/fesm2022/c8y-ngx-components-alarms.mjs.map +1 -1
  9. package/fesm2022/c8y-ngx-components-context-dashboard-device-view.mjs +21 -3
  10. package/fesm2022/c8y-ngx-components-context-dashboard-device-view.mjs.map +1 -1
  11. package/fesm2022/c8y-ngx-components-context-dashboard-devicemanagement.mjs +2 -2
  12. package/fesm2022/c8y-ngx-components-context-dashboard-devicemanagement.mjs.map +1 -1
  13. package/fesm2022/c8y-ngx-components-context-dashboard.mjs +25 -15
  14. package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
  15. package/fesm2022/c8y-ngx-components-echart.mjs +52 -36
  16. package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
  17. package/fesm2022/c8y-ngx-components-map.mjs +15 -0
  18. package/fesm2022/c8y-ngx-components-map.mjs.map +1 -1
  19. package/fesm2022/c8y-ngx-components-upgrade.mjs +12 -1
  20. package/fesm2022/c8y-ngx-components-upgrade.mjs.map +1 -1
  21. package/fesm2022/c8y-ngx-components-widgets-implementations-quick-links.mjs +33 -9
  22. package/fesm2022/c8y-ngx-components-widgets-implementations-quick-links.mjs.map +1 -1
  23. package/fesm2022/c8y-ngx-components.mjs +30 -5
  24. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  25. package/index.d.ts +5 -0
  26. package/index.d.ts.map +1 -1
  27. package/locales/de.po +57 -3
  28. package/locales/es.po +57 -3
  29. package/locales/fr.po +57 -3
  30. package/locales/ja_JP.po +57 -3
  31. package/locales/ko.po +57 -3
  32. package/locales/locales.pot +9 -0
  33. package/locales/nl.po +57 -3
  34. package/locales/pl.po +57 -3
  35. package/locales/pt_BR.po +57 -3
  36. package/locales/zh_CN.po +57 -3
  37. package/locales/zh_TW.po +57 -3
  38. package/map/index.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/upgrade/index.d.ts +1 -0
  41. package/upgrade/index.d.ts.map +1 -1
  42. package/widgets/implementations/quick-links/index.d.ts +3 -1
  43. package/widgets/implementations/quick-links/index.d.ts.map +1 -1
@@ -748,12 +748,15 @@ class EchartsOptionsService {
748
748
  let isDpTemplateSelected = false;
749
749
  // MarkPoint data
750
750
  const markPointData = itemsOfType.reduce((acc, item) => {
751
- isDpTemplateSelected =
752
- item['selectedDatapoint'] &&
753
- dp['__target'] &&
754
- item['selectedDatapoint']['fragment'] === dp['fragment'] &&
755
- item['selectedDatapoint']['series'] === dp['series'] &&
756
- item['selectedDatapoint']['target'] === dp['__target']['id'];
751
+ // Mark the series as bound to the selected datapoint if ANY item of this type matches
752
+ // the current datapoint. Accumulating (instead of overwriting per item) keeps the flag
753
+ // correct when multiple alarms/events of the same type exist.
754
+ const itemMatchesSelectedDp = !!(item['selectedDatapoint'] &&
755
+ dp['__target'] &&
756
+ item['selectedDatapoint']['fragment'] === dp['fragment'] &&
757
+ item['selectedDatapoint']['series'] === dp['series'] &&
758
+ item['selectedDatapoint']['target'] === dp['__target']['id']);
759
+ isDpTemplateSelected = isDpTemplateSelected || itemMatchesSelectedDp;
757
760
  if (dp.__target?.id === item.source.id) {
758
761
  const isCleared = isAlarm && item.status === AlarmStatus.CLEARED;
759
762
  const isEvent = !isAlarm;
@@ -787,7 +790,7 @@ class EchartsOptionsService {
787
790
  symbolKeepAspect: true,
788
791
  data: markPointData
789
792
  },
790
- yAxisIndex: idx,
793
+ ...(displayOptions.forceMergeDatapoints ? {} : { yAxisIndex: idx }),
791
794
  ...this.chartTypesService.getSeriesOptions(dp, isMinMaxChart, renderType)
792
795
  };
793
796
  const markLineData = this.createMarkLine(itemsOfType, itemType);
@@ -847,7 +850,7 @@ class EchartsOptionsService {
847
850
  allAlarms.find(a => a.type === params.data.itemType && params.data.value === a.creationTime); // fallback to creationTime for cleared alarms.
848
851
  let value = '';
849
852
  if (event) {
850
- value = this.processEvent(event, XAxisValue);
853
+ value = this.processEvent(event);
851
854
  }
852
855
  if (alarm) {
853
856
  this.processAlarm(alarm).then(alarmVal => {
@@ -1050,7 +1053,7 @@ class EchartsOptionsService {
1050
1053
  value = this.processRegularSeries(series, XAxisValue, displayOptions);
1051
1054
  }
1052
1055
  if (value) {
1053
- const color = echarts.format.encodeHTML(series.itemStyle.color);
1056
+ const color = echarts.format.encodeHTML(series.itemStyle?.color);
1054
1057
  const label = echarts.format.encodeHTML(series.datapointLabel);
1055
1058
  if (displayOptions.showCompactTooltip) {
1056
1059
  YAxisReadings.push(this.buildCompactTooltipRow(color, label, value));
@@ -1118,11 +1121,11 @@ class EchartsOptionsService {
1118
1121
  * @param event - The event object.
1119
1122
  * @returns The processed value.
1120
1123
  */
1121
- processEvent(event, XAxisValue) {
1124
+ processEvent(event) {
1122
1125
  let value = `<ul class="list-unstyled small separator-top text-default">`;
1123
1126
  value += `<li class="p-t-4 p-b-4 d-flex separator-bottom text-truncate"><label class="text-label-small m-b-0 m-r-8">${echarts.format.encodeHTML(this.translate.instant(gettext('Event type')))}</label><span class="small m-l-auto"><code title="${echarts.format.encodeHTML(event.type)}">${echarts.format.encodeHTML(event.type)}</code></span></li>`;
1124
1127
  value += `<li class="p-t-4 p-b-4 d-flex separator-bottom text-truncate"><label class="text-label-small m-b-0 m-r-8">${echarts.format.encodeHTML(this.translate.instant(gettext('Event text')))}</label><span class="small m-l-auto" style="display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis; word-break: break-word; white-space: normal; max-width: 200px; -webkit-line-clamp: 5;" title="${echarts.format.encodeHTML(event.text)}">${echarts.format.encodeHTML(event.text)}</span></li>`;
1125
- value += `<li class="p-t-4 p-b-4 d-flex separator-bottom text-truncate"><label class="text-label-small m-b-0 m-r-8">${echarts.format.encodeHTML(this.translate.instant(gettext('Event time')))}</label><span class="small m-l-auto">${echarts.format.encodeHTML(this.datePipe.transform(XAxisValue))}<span></li>`;
1128
+ value += `<li class="p-t-4 p-b-4 d-flex separator-bottom text-truncate"><label class="text-label-small m-b-0 m-r-8">${echarts.format.encodeHTML(this.translate.instant(gettext('Event time')))}</label><span class="small m-l-auto">${echarts.format.encodeHTML(this.datePipe.transform(event.time))}<span></li>`;
1126
1129
  value += `</ul>`;
1127
1130
  return value;
1128
1131
  }
@@ -1192,22 +1195,27 @@ class EchartsOptionsService {
1192
1195
  };
1193
1196
  alarmSeries = deduplicateMarkLines(alarmSeries);
1194
1197
  eventSeries = deduplicateMarkLines(eventSeries);
1195
- const deduplicateFilterCallback = (obj1, i, arr) => {
1196
- const duplicates = arr.filter(obj2 => obj1['id'] === obj2['id'] && i !== arr.indexOf(obj2));
1197
- if (duplicates.length > 0) {
1198
- return obj1['isDpTemplateSelected'];
1199
- }
1200
- return true;
1198
+ // markPoint series for multiple datapoints on the same target and alarm/event type collide by
1199
+ // id. Resolve each id independently: keep the series bound to the selected datapoint when a
1200
+ // selection exists, otherwise keep the first. Grouping by id (rather than filtering against the
1201
+ // whole list with a global emptiness fallback) guarantees every id resolves to exactly one
1202
+ // surviving series, so a paired markLine can never suppress its markPoint and the event/alarm
1203
+ // icons persist across datapoint selection changes and data refreshes.
1204
+ const deduplicateById = (seriesList) => {
1205
+ const groupsById = new Map();
1206
+ seriesList.forEach(series => {
1207
+ const id = series.id;
1208
+ const group = groupsById.get(id) ?? [];
1209
+ group.push(series);
1210
+ groupsById.set(id, group);
1211
+ });
1212
+ return Array.from(groupsById.values(), group => {
1213
+ const selected = group.find(series => series['isDpTemplateSelected']);
1214
+ return selected ?? group[0];
1215
+ });
1201
1216
  };
1202
- const deduplicateFilterCallbackFallback = (obj1, i, arr) => arr.findIndex(obj2 => obj2['id'] === obj1['id']) === i;
1203
- let deduplicatedEvents = eventSeries.filter(deduplicateFilterCallback);
1204
- let deduplicatedAlarms = alarmSeries.filter(deduplicateFilterCallback);
1205
- if (deduplicatedAlarms.length === 0) {
1206
- deduplicatedAlarms = alarmSeries.filter(deduplicateFilterCallbackFallback);
1207
- }
1208
- if (deduplicatedEvents.length === 0) {
1209
- deduplicatedEvents = eventSeries.filter(deduplicateFilterCallbackFallback);
1210
- }
1217
+ const deduplicatedEvents = deduplicateById(eventSeries);
1218
+ const deduplicatedAlarms = deduplicateById(alarmSeries);
1211
1219
  return [...series, ...deduplicatedEvents, ...deduplicatedAlarms];
1212
1220
  }
1213
1221
  groupByType(items, typeField) {
@@ -1296,12 +1304,16 @@ class EchartsOptionsService {
1296
1304
  }));
1297
1305
  const creationTime = new Date(item.creationTime).getTime();
1298
1306
  const lastUpdatedTime = new Date(item['lastUpdated']).getTime();
1307
+ // Events are positioned on the chart by their `time` (when the event occurred), while alarms
1308
+ // use their creation time.
1309
+ const anchorTime = isEvent ? new Date(item['time']).getTime() : creationTime;
1310
+ const anchorTimeValue = isEvent ? item['time'] : item.creationTime;
1299
1311
  let coordCreationTime;
1300
1312
  let coordLastUpdatedTime;
1301
1313
  if (realtime) {
1302
1314
  const lastValue = dpValuesArray[dpValuesArray.length - 1];
1303
1315
  coordCreationTime = [
1304
- item.creationTime,
1316
+ anchorTimeValue,
1305
1317
  lastValue?.values[0]?.min ?? lastValue?.values[1] ?? null
1306
1318
  ];
1307
1319
  coordLastUpdatedTime = [
@@ -1310,12 +1322,12 @@ class EchartsOptionsService {
1310
1322
  ];
1311
1323
  }
1312
1324
  else {
1313
- const closestDpValue = this.interpolateBetweenTwoDps(dpValuesArray, creationTime);
1314
- const dpValuesForNewAlarms = this.getClosestDpValueToTargetTime(dpValuesArray, creationTime);
1325
+ const closestDpValue = this.interpolateBetweenTwoDps(dpValuesArray, anchorTime);
1326
+ const dpValuesForNewAlarms = this.getClosestDpValueToTargetTime(dpValuesArray, anchorTime);
1315
1327
  const closestDpValueLastUpdated = this.interpolateBetweenTwoDps(dpValuesArray, lastUpdatedTime);
1316
1328
  const dpValuesForNewAlarmsLastUpdated = this.getClosestDpValueToTargetTime(dpValuesArray, lastUpdatedTime);
1317
1329
  coordCreationTime = [
1318
- item.creationTime,
1330
+ anchorTimeValue,
1319
1331
  closestDpValue?.values[0]?.min ??
1320
1332
  closestDpValue?.values[1] ??
1321
1333
  dpValuesForNewAlarms?.values[0]?.min ??
@@ -2708,18 +2720,22 @@ class ChartsComponent {
2708
2720
  }
2709
2721
  async loadAlarmsAndEvents(customTimeRange) {
2710
2722
  const timeRange = this.getTimeRange();
2711
- const updatedTimeRange = {
2712
- lastUpdatedFrom: customTimeRange ? customTimeRange.dateFrom : timeRange.dateFrom,
2713
- createdTo: customTimeRange ? customTimeRange.dateTo : timeRange.dateTo
2714
- };
2723
+ const dateFrom = customTimeRange ? customTimeRange.dateFrom : timeRange.dateFrom;
2724
+ const dateTo = customTimeRange ? customTimeRange.dateTo : timeRange.dateTo;
2725
+ // Events are positioned on the chart by their `time` property, so they must be retrieved by
2726
+ // the same property (`dateFrom`/`dateTo` filter the events API on `time`). Filtering by the
2727
+ // update/creation window instead dropped events whose `time` fell inside the visible range.
2728
+ const eventsTimeRange = { dateFrom, dateTo };
2729
+ // Alarms keep the update window: an alarm active within the range may have been created earlier.
2730
+ const alarmsTimeRange = { lastUpdatedFrom: dateFrom, createdTo: dateTo };
2715
2731
  if (!this.config.alarmsEventsConfigs)
2716
2732
  return;
2717
2733
  const visibleAlarmsOrEvents = this.config.alarmsEventsConfigs?.filter(alarmOrEvent => !alarmOrEvent.__hidden && alarmOrEvent.__active);
2718
2734
  const alarms = visibleAlarmsOrEvents?.filter(alarmOrEvent => alarmOrEvent.timelineType === 'ALARM');
2719
2735
  const events = visibleAlarmsOrEvents?.filter(alarmOrEvent => alarmOrEvent.timelineType === 'EVENT');
2720
2736
  const [listedEvents, listedAlarms] = await Promise.all([
2721
- this.chartEventsService.listEvents(updatedTimeRange, events),
2722
- this.chartAlarmsService.listAlarms(updatedTimeRange, alarms)
2737
+ this.chartEventsService.listEvents(eventsTimeRange, events),
2738
+ this.chartAlarmsService.listAlarms(alarmsTimeRange, alarms)
2723
2739
  ]);
2724
2740
  this.events = listedEvents;
2725
2741
  this.alarms = listedAlarms;