@c8y/ngx-components 1023.48.2 → 1023.50.2

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 (56) hide show
  1. package/asset-properties/index.d.ts +1 -2
  2. package/asset-properties/index.d.ts.map +1 -1
  3. package/context-dashboard/index.d.ts +2 -1
  4. package/context-dashboard/index.d.ts.map +1 -1
  5. package/echart/index.d.ts +5 -2
  6. package/echart/index.d.ts.map +1 -1
  7. package/fesm2022/c8y-ngx-components-asset-properties.mjs +3 -4
  8. package/fesm2022/c8y-ngx-components-asset-properties.mjs.map +1 -1
  9. package/fesm2022/c8y-ngx-components-context-dashboard.mjs +12 -9
  10. package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
  11. package/fesm2022/c8y-ngx-components-device-grid.mjs +1 -1
  12. package/fesm2022/c8y-ngx-components-device-grid.mjs.map +1 -1
  13. package/fesm2022/c8y-ngx-components-echart.mjs +96 -42
  14. package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
  15. package/fesm2022/c8y-ngx-components-widgets-definitions-asset-table.mjs +127 -0
  16. package/fesm2022/c8y-ngx-components-widgets-definitions-asset-table.mjs.map +1 -0
  17. package/fesm2022/c8y-ngx-components-widgets-definitions-datapoints-graph.mjs +3 -3
  18. package/fesm2022/c8y-ngx-components-widgets-definitions-datapoints-graph.mjs.map +1 -1
  19. package/fesm2022/c8y-ngx-components-widgets-definitions.mjs +1 -0
  20. package/fesm2022/c8y-ngx-components-widgets-definitions.mjs.map +1 -1
  21. package/fesm2022/c8y-ngx-components-widgets-exports.mjs +8 -1
  22. package/fesm2022/c8y-ngx-components-widgets-exports.mjs.map +1 -1
  23. package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs +1959 -0
  24. package/fesm2022/c8y-ngx-components-widgets-implementations-asset-table.mjs.map +1 -0
  25. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs +55 -51
  26. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs.map +1 -1
  27. package/fesm2022/c8y-ngx-components.mjs +323 -164
  28. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  29. package/index.d.ts +150 -8
  30. package/index.d.ts.map +1 -1
  31. package/locales/de.po +204 -0
  32. package/locales/es.po +204 -0
  33. package/locales/fr.po +204 -0
  34. package/locales/ja_JP.po +204 -0
  35. package/locales/ko.po +204 -0
  36. package/locales/locales.pot +204 -0
  37. package/locales/nl.po +204 -0
  38. package/locales/pl.po +204 -0
  39. package/locales/pt_BR.po +204 -0
  40. package/locales/zh_CN.po +204 -0
  41. package/locales/zh_TW.po +204 -0
  42. package/package.json +1 -1
  43. package/widgets/cockpit-exports/index.d.ts +6 -0
  44. package/widgets/cockpit-exports/index.d.ts.map +1 -1
  45. package/widgets/definitions/asset-table/index.d.ts +6 -0
  46. package/widgets/definitions/asset-table/index.d.ts.map +1 -0
  47. package/widgets/definitions/index.d.ts +1 -0
  48. package/widgets/definitions/index.d.ts.map +1 -1
  49. package/widgets/device-management-exports/index.d.ts +6 -0
  50. package/widgets/device-management-exports/index.d.ts.map +1 -1
  51. package/widgets/exports/index.d.ts +8 -1
  52. package/widgets/exports/index.d.ts.map +1 -1
  53. package/widgets/implementations/asset-table/index.d.ts +229 -0
  54. package/widgets/implementations/asset-table/index.d.ts.map +1 -0
  55. package/widgets/implementations/datapoints-graph/index.d.ts +6 -3
  56. package/widgets/implementations/datapoints-graph/index.d.ts.map +1 -1
@@ -737,8 +737,8 @@ class EchartsOptionsService {
737
737
  }, []);
738
738
  // Construct series with markPoint
739
739
  const seriesWithMarkPoint = {
740
- id: `${type}/${dp.__target?.id}+${id ? id : ''}-markPoint`,
741
- name: `${type}-markPoint`,
740
+ id: `${type}/${dp.__target?.id}${id ? '+' + id : ''}-markPoint`,
741
+ name: `${type}/${dp.__target?.id}-markPoint`,
742
742
  typeOfSeries: itemType,
743
743
  data: mainData,
744
744
  isDpTemplateSelected,
@@ -755,8 +755,8 @@ class EchartsOptionsService {
755
755
  const markLineData = this.createMarkLine(itemsOfType, itemType);
756
756
  // Construct series with markLine
757
757
  const seriesWithMarkLine = {
758
- id: `${type}/${dp.__target?.id}+${id ? id : ''}-markLine`,
759
- name: `${type}-markLine`,
758
+ id: `${type}/${dp.__target?.id}${id ? '+' + id : ''}-markLine`,
759
+ name: `${type}/${dp.__target?.id}-markLine`,
760
760
  typeOfSeries: itemType,
761
761
  isDpTemplateSelected,
762
762
  data: mainData,
@@ -1518,9 +1518,11 @@ class ChartRealtimeService {
1518
1518
  this.pendingAlarmsOrEvents = new Map();
1519
1519
  this.currentAlarms = [];
1520
1520
  this.currentEvents = [];
1521
+ this.activeDatapoints = [];
1521
1522
  }
1522
1523
  startRealtime(echartsInstance, datapoints, timeRange, datapointOutOfSyncCallback, timeRangeChangedCallback, alarmOrEventConfig = [], displayOptions, alarms, events) {
1523
1524
  this.echartsInstance = echartsInstance;
1525
+ this.activeDatapoints = datapoints;
1524
1526
  this.currentTimeRange = {
1525
1527
  dateFrom: new Date(timeRange.dateFrom),
1526
1528
  dateTo: new Date(timeRange.dateTo)
@@ -1609,7 +1611,9 @@ class ChartRealtimeService {
1609
1611
  });
1610
1612
  this.realtimeSubscriptionAlarmsEvents = allAlarmsAndEvents$
1611
1613
  .pipe(map(alarmOrEvent => {
1612
- const foundAlarmOrEvent = activeAlarmsOrEvents.find(aOrE => aOrE.filters.type === alarmOrEvent.type);
1614
+ // Match by both type AND device source
1615
+ const foundAlarmOrEvent = activeAlarmsOrEvents.find(aOrE => aOrE.filters.type === alarmOrEvent.type &&
1616
+ aOrE.__target?.id === alarmOrEvent.source?.id);
1613
1617
  if (foundAlarmOrEvent) {
1614
1618
  alarmOrEvent['color'] = foundAlarmOrEvent.color;
1615
1619
  alarmOrEvent['selectedDatapoint'] = foundAlarmOrEvent.selectedDatapoint;
@@ -1677,6 +1681,7 @@ class ChartRealtimeService {
1677
1681
  seriesDataToUpdate.get(datapoint)?.push(measurement);
1678
1682
  });
1679
1683
  let allDataSeries = this.echartsInstance?.getOption()['series'];
1684
+ // Process measurements for each datapoint
1680
1685
  seriesDataToUpdate.forEach((measurements, datapoint) => {
1681
1686
  const newValues = measurements.map(m => [
1682
1687
  m.time,
@@ -1690,46 +1695,80 @@ class ChartRealtimeService {
1690
1695
  const seriesDataToUpdate = seriesMatchingDatapoint['data'];
1691
1696
  seriesDataToUpdate.push(...newValues);
1692
1697
  seriesMatchingDatapoint['data'] = this.removeValuesBeforeTimeRange(seriesMatchingDatapoint);
1693
- if (alarmOrEvent) {
1698
+ this.checkForValuesAfterTimeRange(seriesMatchingDatapoint['data'], datapoint, datapointOutOfSyncCallback);
1699
+ });
1700
+ // Process alarm/event OUTSIDE the measurement loop.
1701
+ // Previously this was inside seriesDataToUpdate.forEach(), which meant alarms/events
1702
+ // were only processed when measurements existed for that datapoint. This caused
1703
+ // alarms/events to not appear on the chart when no measurements arrived in the interval.
1704
+ if (alarmOrEvent) {
1705
+ // The alarm config's selectedDatapoint is a partial object { target, fragment, series },
1706
+ // not a full DatapointsGraphKPIDetails. We need to find the matching full datapoint.
1707
+ const selectedDp = alarmOrEvent['selectedDatapoint'];
1708
+ // Find the correct datapoint to position this alarm/event on the chart:
1709
+ // 1. Use selectedDatapoint from alarm config (user-configured)
1710
+ // 2. Match by alarm's source device ID
1711
+ // 3. Fall back to first datapoint
1712
+ let datapoint = selectedDp
1713
+ ? this.activeDatapoints.find(dp => dp.__target?.id === selectedDp.target &&
1714
+ dp.fragment === selectedDp.fragment &&
1715
+ dp.series === selectedDp.series)
1716
+ : undefined;
1717
+ if (!datapoint && alarmOrEvent['source']?.id) {
1718
+ datapoint = this.activeDatapoints.find(dp => dp.__target?.id === alarmOrEvent['source'].id);
1719
+ }
1720
+ if (!datapoint) {
1721
+ datapoint = this.activeDatapoints[0];
1722
+ }
1723
+ if (datapoint) {
1724
+ const datapointId = datapoint.__target?.id + datapoint.fragment + datapoint.series;
1725
+ const matchingSeries = allDataSeries.find(s => s['datapointId'] === datapointId);
1726
+ const seriesData = matchingSeries ? matchingSeries['data'] : [];
1727
+ // Convert ECharts series data format to the format expected by getAlarmOrEventSeries.
1728
+ // ECharts: [[timestamp, value], ...] → Expected: { [timestamp]: [{min, max}] }
1729
+ const values = {};
1730
+ seriesData.forEach(([timestamp, value]) => {
1731
+ values[timestamp] = [{ min: value, max: value }];
1732
+ });
1694
1733
  const renderType = datapoint.renderType || 'min';
1695
1734
  const dp = {
1696
1735
  ...datapoint,
1697
- values: seriesMatchingDatapoint['data']
1736
+ values
1698
1737
  };
1699
1738
  if (isEvent(alarmOrEvent)) {
1700
- // if event series with the same id already exists, return
1701
- const eventExists = allDataSeries.some(series => series['data'].some(data => data[0] === alarmOrEvent.creationTime));
1739
+ // Check if event already exists on chart to avoid duplicates
1740
+ const eventExists = allDataSeries.some(series => series['data']?.some(data => data[0] === alarmOrEvent.creationTime));
1702
1741
  if (eventExists) {
1703
1742
  return;
1704
1743
  }
1744
+ // For events, pass creationTime as unique id to create unique series per event.
1745
+ // This allows multiple events of the same type/device to coexist on the chart.
1746
+ // Series ID will be: eventType/deviceId+creationTime-markPoint
1705
1747
  const newEventSeries = this.echartsOptionsService.getAlarmOrEventSeries(dp, renderType, false, [alarmOrEvent], 'event', displayOptions, alarmOrEvent.creationTime, null, true);
1706
1748
  allDataSeries.push(...newEventSeries);
1707
1749
  }
1708
1750
  else if (isAlarm(alarmOrEvent)) {
1709
- const alarmExists = allDataSeries.some((series) => {
1710
- const seriesData = series['data'];
1711
- return seriesData.some((data) => data[0] === alarmOrEvent.creationTime);
1751
+ // For alarms, remove existing series for this alarm type + device before adding.
1752
+ // This ensures alarm status changes (e.g., ACTIVE → CLEARED) are reflected.
1753
+ // Series ID format: ${alarmType}/${deviceId}-markPoint/markLine
1754
+ const alarm = alarmOrEvent;
1755
+ const alarmType = alarm.type;
1756
+ const datapointTargetId = datapoint.__target?.id;
1757
+ allDataSeries = allDataSeries.filter((series) => {
1758
+ const seriesId = series['id'];
1759
+ return !seriesId?.startsWith(`${alarmType}/${datapointTargetId}`);
1712
1760
  });
1713
- if (alarmExists) {
1714
- const alarmSeries = allDataSeries.filter((series) => {
1715
- const seriesData = series['data'];
1716
- return seriesData.some((data) => data[0] === alarmOrEvent.creationTime);
1717
- });
1718
- // remove all matching alarm series which are in the array
1719
- alarmSeries.forEach(series => {
1720
- allDataSeries = allDataSeries.filter(s => s['id'] !== series['id']);
1721
- });
1722
- const newAlarmSeries = this.echartsOptionsService.getAlarmOrEventSeries(dp, renderType, false, [alarmOrEvent], 'alarm', displayOptions, alarmOrEvent.creationTime, null, true);
1723
- allDataSeries.push(...newAlarmSeries);
1724
- }
1725
- else {
1726
- const newAlarmSeries = this.echartsOptionsService.getAlarmOrEventSeries(dp, renderType, false, [alarmOrEvent], 'alarm', displayOptions, alarmOrEvent.id, null, true);
1727
- allDataSeries.push(...newAlarmSeries);
1728
- }
1761
+ // For alarms, pass null as id - we want one series per alarm type/device.
1762
+ // Series ID will be: alarmType/deviceId-markPoint (no unique suffix).
1763
+ // We already removed the old series above, so this replaces it.
1764
+ const newAlarmSeries = this.echartsOptionsService.getAlarmOrEventSeries(dp, renderType, false, [alarm], 'alarm', displayOptions, null, null, true);
1765
+ allDataSeries.push(...newAlarmSeries);
1729
1766
  }
1730
1767
  }
1731
- this.checkForValuesAfterTimeRange(seriesMatchingDatapoint['data'], datapoint, datapointOutOfSyncCallback);
1732
- });
1768
+ }
1769
+ // Use replaceMerge for series to ensure removed alarm series don't persist.
1770
+ // Without this, ECharts merges the new series array with existing ones,
1771
+ // which can leave stale alarm/event series on the chart.
1733
1772
  this.echartsInstance?.setOption({
1734
1773
  dataZoom: [
1735
1774
  {
@@ -1742,7 +1781,7 @@ class ChartRealtimeService {
1742
1781
  max: this.currentTimeRange?.dateTo
1743
1782
  },
1744
1783
  series: allDataSeries
1745
- });
1784
+ }, { replaceMerge: ['series'] });
1746
1785
  }
1747
1786
  /**
1748
1787
  * Detects if a datapoint has measurements with future timestamps (out-of-sync).
@@ -2254,6 +2293,7 @@ class ChartsComponent {
2254
2293
  }
2255
2294
  /**
2256
2295
  * Toggles the visibility of a series in the chart based on the provided datapoint.
2296
+ * Uses explicit legendSelect/legendUnSelect based on __active state.
2257
2297
  * @param datapoint - The datapoint to toggle visibility for.
2258
2298
  */
2259
2299
  toggleDatapointSeriesVisibility(datapoint) {
@@ -2261,26 +2301,40 @@ class ChartsComponent {
2261
2301
  const seriesToUpdate = series.find(s => s.datapointId === `${datapoint.__target?.id}${datapoint.fragment}${datapoint.series}`);
2262
2302
  if (seriesToUpdate) {
2263
2303
  this.echartsInstance.dispatchAction({
2264
- type: 'legendToggleSelect',
2304
+ type: datapoint.__active ? 'legendSelect' : 'legendUnSelect',
2265
2305
  name: seriesToUpdate.name
2266
2306
  });
2267
2307
  }
2268
2308
  }
2269
2309
  /**
2270
- * Toggles the visibility of a series in the chart based on the provided alarm or event.
2310
+ * Toggles the visibility of alarm/event series in the chart.
2311
+ * Uses explicit legendSelect/legendUnSelect based on __hidden state.
2312
+ * Targets specific device's series using type + deviceId.
2271
2313
  * @param alarmOrEvent - The alarm or event to toggle visibility for.
2272
2314
  */
2273
2315
  toggleAlarmEventSeriesVisibility(alarmOrEvent) {
2274
- const series = this.echartsInstance.getOption().series;
2275
- const seriesToUpdate = series.filter(s => s.name === `${alarmOrEvent.label}-markPoint` || s.name === `${alarmOrEvent.label}-markLine`);
2276
- if (seriesToUpdate) {
2277
- seriesToUpdate.forEach(s => {
2278
- this.echartsInstance.dispatchAction({
2279
- type: 'legendToggleSelect',
2280
- name: s.name
2281
- });
2282
- });
2316
+ if (!this.echartsInstance) {
2317
+ return;
2283
2318
  }
2319
+ const options = this.echartsInstance.getOption();
2320
+ const allSeries = options.series;
2321
+ if (!allSeries || allSeries.length === 0) {
2322
+ return;
2323
+ }
2324
+ const type = alarmOrEvent.filters.type;
2325
+ const deviceId = alarmOrEvent.__target?.id;
2326
+ const actionType = alarmOrEvent.__hidden ? 'legendUnSelect' : 'legendSelect';
2327
+ // Series names are: ${type}/${deviceId}-markPoint and ${type}/${deviceId}-markLine
2328
+ const markPointName = `${type}/${deviceId}-markPoint`;
2329
+ const markLineName = `${type}/${deviceId}-markLine`;
2330
+ // Find series matching this specific alarm type + device
2331
+ const matchingSeries = allSeries.filter(s => s.name === markPointName || s.name === markLineName);
2332
+ matchingSeries.forEach(series => {
2333
+ this.echartsInstance.dispatchAction({
2334
+ type: actionType,
2335
+ name: series.name
2336
+ });
2337
+ });
2284
2338
  }
2285
2339
  getDefaultChartOptions() {
2286
2340
  return {