@c8y/ngx-components 1023.14.102 → 1023.14.103

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/echart/index.d.ts CHANGED
@@ -293,14 +293,17 @@ declare class ChartsComponent implements OnChanges, OnInit, OnDestroy {
293
293
  debounce<T extends (...args: any[]) => void>(func: T, wait: number): (...args: Parameters<T>) => void;
294
294
  /**
295
295
  * Toggles the visibility of a series in the chart based on the provided datapoint.
296
+ * Uses explicit legendSelect/legendUnSelect based on __active state.
296
297
  * @param datapoint - The datapoint to toggle visibility for.
297
298
  */
298
299
  toggleDatapointSeriesVisibility(datapoint: DatapointsGraphKPIDetails): void;
299
300
  /**
300
- * Toggles the visibility of a series in the chart based on the provided alarm or event.
301
+ * Toggles the visibility of alarm/event series in the chart.
302
+ * Uses explicit legendSelect/legendUnSelect based on __hidden state.
303
+ * Targets specific device's series using type + deviceId.
301
304
  * @param alarmOrEvent - The alarm or event to toggle visibility for.
302
305
  */
303
- toggleAlarmEventSeriesVisibility(alarmOrEvent: AlarmDetailsExtended | EventDetailsExtended): void;
306
+ toggleAlarmEventSeriesVisibility(alarmOrEvent: AlarmOrEventExtended): void;
304
307
  private getDefaultChartOptions;
305
308
  private getMarkedAreaData;
306
309
  private getMarkedLineData;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sources":["../../echart/models/datapoints-graph-widget.model.ts","../../echart/models/chart.model.ts","../../echart/models/svg-icons.model.ts","../../echart/charts.component.ts","../../echart/services/chart-alarms.service.ts","../../echart/services/chart-events.service.ts","../../echart/services/chart-helpers.service.ts","../../echart/select-aggregated-datapoint/select-aggregated-datapoint.component.ts"],"sourcesContent":[null,null,null,null,null,null,null,null],"names":[],"mappings":";;;;;;;;;;;;;;AAmBM;;;;AAKA;AACJ;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;;;;;;AAOA;;AAEA;AACA;AACA;AACA;;;AAGA;;;;;;;;;AAUI;;;;;;;;;;AAUJ;;AAGI;;AAEJ;AACA;;AAGI;;;AAIN;;AAEG;;AAGG;AAIN;AACE;AACA;AACD;AAED;AACM;;AAEL;AAED;;;;AAIM;;;;;;;AAQL;AAED;;;;;AAUE;;;;;AAGD;;AAGC;;AAEA;;AAEE;;AAEF;;;AACD;;;;;;;AAQC;AACA;AACD;AAEK;AACA;AAEA;AAEA;AAEN;;;;AAKA;;;;;;;;;;;;;AAcM;AACA;AAEA;;;;AAKA;;;;;;;;;;;AAYL;AAED;;;;;;;;AAUE;AACA;AACD;;AC9MD;;;;;;AAMG;AACH;AACE;;;;AAIA;;;AACD;;;AAIA;;;AAIA;AAEK;AACA;AACJ;AACE;AACD;AACF;;AAGC;AACA;AACD;AAED;AACE;AACA;AACA;AACD;;AC3CD;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACD;AAED;;;;;;;;;;;ACwDA;AA4BE;;AAEA;;;;;;;;AAQA;;;;;;AAMK;AACK;AAGA;AACA;AACA;AACA;AACA;AACA;;AAEV;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAgDA;;;;;AA2IuB;;;AAA4B;AAiDnD;AAOA;AAIA;AAwBA;AA6BA;AAWA;;;AAGG;AACH;AAcA;;;AAGG;AACH;AAmBA;AAeA;AA0BA;;AA8DA;;;AA8MA;AA0DA;AA0CA;AAkBA;AAWA;AAYA;;;AA6BD;;AC97BD;AAEc;AAAQ;AAEpB;;;;;AAKG;AACG;;;AAqCP;;AC/CD;AAEc;AAAQ;AAEpB;;;;;AAKG;AACG;;;AAuBP;;AChCD;AAEE;;;;AAIG;;;;;;;;;;;AAcH;AAcA;;;AAGD;;ACtBD;;AAqBW;AACC;AAEV;;AAGA;;;AAiBA;;;AAgBD;;;"}
1
+ {"version":3,"file":"index.d.ts","sources":["../../echart/models/datapoints-graph-widget.model.ts","../../echart/models/chart.model.ts","../../echart/models/svg-icons.model.ts","../../echart/charts.component.ts","../../echart/services/chart-alarms.service.ts","../../echart/services/chart-events.service.ts","../../echart/services/chart-helpers.service.ts","../../echart/select-aggregated-datapoint/select-aggregated-datapoint.component.ts"],"sourcesContent":[null,null,null,null,null,null,null,null],"names":[],"mappings":";;;;;;;;;;;;;;AAmBM;;;;AAKA;AACJ;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;;;;;;AAOA;;AAEA;AACA;AACA;AACA;;;AAGA;;;;;;;;;AAUI;;;;;;;;;;AAUJ;;AAGI;;AAEJ;AACA;;AAGI;;;AAIN;;AAEG;;AAGG;AAIN;AACE;AACA;AACD;AAED;AACM;;AAEL;AAED;;;;AAIM;;;;;;;AAQL;AAED;;;;;AAUE;;;;;AAGD;;AAGC;;AAEA;;AAEE;;AAEF;;;AACD;;;;;;;AAQC;AACA;AACD;AAEK;AACA;AAEA;AAEA;AAEN;;;;AAKA;;;;;;;;;;;;;AAcM;AACA;AAEA;;;;AAKA;;;;;;;;;;;AAYL;AAED;;;;;;;;AAUE;AACA;AACD;;AC9MD;;;;;;AAMG;AACH;AACE;;;;AAIA;;;AACD;;;AAIA;;;AAIA;AAEK;AACA;AACJ;AACE;AACD;AACF;;AAGC;AACA;AACD;AAED;AACE;AACA;AACA;AACD;;AC3CD;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACD;AAED;;;;;;;;;;;ACwDA;AA4BE;;AAEA;;;;;;;;AAQA;;;;;;AAMK;AACK;AAGA;AACA;AACA;AACA;AACA;AACA;;AAEV;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;AAgDA;;;;;AA2IuB;;;AAA4B;AAiDnD;AAOA;AAIA;AAwBA;AA6BA;AAWA;;;;AAIG;AACH;AAcA;;;;;AAKG;AACH;AAgCA;AAeA;AA0BA;;AA8DA;;;AA8MA;AA0DA;AA0CA;AAkBA;AAWA;AAYA;;;AA6BD;;AC98BD;AAEc;AAAQ;AAEpB;;;;;AAKG;AACG;;;AAqCP;;AC/CD;AAEc;AAAQ;AAEpB;;;;;AAKG;AACG;;;AAuBP;;AChCD;AAEE;;;;AAIG;;;;;;;;;;;AAcH;AAcA;;;AAGD;;ACtBD;;AAqBW;AACC;AAEV;;AAGA;;;AAiBA;;;AAgBD;;;"}
@@ -736,8 +736,8 @@ class EchartsOptionsService {
736
736
  }, []);
737
737
  // Construct series with markPoint
738
738
  const seriesWithMarkPoint = {
739
- id: `${type}/${dp.__target?.id}+${id ? id : ''}-markPoint`,
740
- name: `${type}-markPoint`,
739
+ id: `${type}/${dp.__target?.id}${id ? '+' + id : ''}-markPoint`,
740
+ name: `${type}/${dp.__target?.id}-markPoint`,
741
741
  typeOfSeries: itemType,
742
742
  data: mainData,
743
743
  isDpTemplateSelected,
@@ -754,8 +754,8 @@ class EchartsOptionsService {
754
754
  const markLineData = this.createMarkLine(itemsOfType, itemType);
755
755
  // Construct series with markLine
756
756
  const seriesWithMarkLine = {
757
- id: `${type}/${dp.__target?.id}+${id ? id : ''}-markLine`,
758
- name: `${type}-markLine`,
757
+ id: `${type}/${dp.__target?.id}${id ? '+' + id : ''}-markLine`,
758
+ name: `${type}/${dp.__target?.id}-markLine`,
759
759
  typeOfSeries: itemType,
760
760
  isDpTemplateSelected,
761
761
  data: mainData,
@@ -1511,9 +1511,11 @@ class ChartRealtimeService {
1511
1511
  this.pendingAlarmsOrEvents = new Map();
1512
1512
  this.currentAlarms = [];
1513
1513
  this.currentEvents = [];
1514
+ this.activeDatapoints = [];
1514
1515
  }
1515
1516
  startRealtime(echartsInstance, datapoints, timeRange, datapointOutOfSyncCallback, timeRangeChangedCallback, alarmOrEventConfig = [], displayOptions, alarms, events) {
1516
1517
  this.echartsInstance = echartsInstance;
1518
+ this.activeDatapoints = datapoints;
1517
1519
  this.currentTimeRange = {
1518
1520
  dateFrom: new Date(timeRange.dateFrom),
1519
1521
  dateTo: new Date(timeRange.dateTo)
@@ -1602,7 +1604,9 @@ class ChartRealtimeService {
1602
1604
  });
1603
1605
  this.realtimeSubscriptionAlarmsEvents = allAlarmsAndEvents$
1604
1606
  .pipe(map(alarmOrEvent => {
1605
- const foundAlarmOrEvent = activeAlarmsOrEvents.find(aOrE => aOrE.filters.type === alarmOrEvent.type);
1607
+ // Match by both type AND device source
1608
+ const foundAlarmOrEvent = activeAlarmsOrEvents.find(aOrE => aOrE.filters.type === alarmOrEvent.type &&
1609
+ aOrE.__target?.id === alarmOrEvent.source?.id);
1606
1610
  if (foundAlarmOrEvent) {
1607
1611
  alarmOrEvent['color'] = foundAlarmOrEvent.color;
1608
1612
  alarmOrEvent['selectedDatapoint'] = foundAlarmOrEvent.selectedDatapoint;
@@ -1670,6 +1674,7 @@ class ChartRealtimeService {
1670
1674
  seriesDataToUpdate.get(datapoint)?.push(measurement);
1671
1675
  });
1672
1676
  let allDataSeries = this.echartsInstance?.getOption()['series'];
1677
+ // Process measurements for each datapoint
1673
1678
  seriesDataToUpdate.forEach((measurements, datapoint) => {
1674
1679
  const newValues = measurements.map(m => [
1675
1680
  m.time,
@@ -1683,46 +1688,80 @@ class ChartRealtimeService {
1683
1688
  const seriesDataToUpdate = seriesMatchingDatapoint['data'];
1684
1689
  seriesDataToUpdate.push(...newValues);
1685
1690
  seriesMatchingDatapoint['data'] = this.removeValuesBeforeTimeRange(seriesMatchingDatapoint);
1686
- if (alarmOrEvent) {
1691
+ this.checkForValuesAfterTimeRange(seriesMatchingDatapoint['data'], datapoint, datapointOutOfSyncCallback);
1692
+ });
1693
+ // Process alarm/event OUTSIDE the measurement loop.
1694
+ // Previously this was inside seriesDataToUpdate.forEach(), which meant alarms/events
1695
+ // were only processed when measurements existed for that datapoint. This caused
1696
+ // alarms/events to not appear on the chart when no measurements arrived in the interval.
1697
+ if (alarmOrEvent) {
1698
+ // The alarm config's selectedDatapoint is a partial object { target, fragment, series },
1699
+ // not a full DatapointsGraphKPIDetails. We need to find the matching full datapoint.
1700
+ const selectedDp = alarmOrEvent['selectedDatapoint'];
1701
+ // Find the correct datapoint to position this alarm/event on the chart:
1702
+ // 1. Use selectedDatapoint from alarm config (user-configured)
1703
+ // 2. Match by alarm's source device ID
1704
+ // 3. Fall back to first datapoint
1705
+ let datapoint = selectedDp
1706
+ ? this.activeDatapoints.find(dp => dp.__target?.id === selectedDp.target &&
1707
+ dp.fragment === selectedDp.fragment &&
1708
+ dp.series === selectedDp.series)
1709
+ : undefined;
1710
+ if (!datapoint && alarmOrEvent['source']?.id) {
1711
+ datapoint = this.activeDatapoints.find(dp => dp.__target?.id === alarmOrEvent['source'].id);
1712
+ }
1713
+ if (!datapoint) {
1714
+ datapoint = this.activeDatapoints[0];
1715
+ }
1716
+ if (datapoint) {
1717
+ const datapointId = datapoint.__target?.id + datapoint.fragment + datapoint.series;
1718
+ const matchingSeries = allDataSeries.find(s => s['datapointId'] === datapointId);
1719
+ const seriesData = matchingSeries ? matchingSeries['data'] : [];
1720
+ // Convert ECharts series data format to the format expected by getAlarmOrEventSeries.
1721
+ // ECharts: [[timestamp, value], ...] → Expected: { [timestamp]: [{min, max}] }
1722
+ const values = {};
1723
+ seriesData.forEach(([timestamp, value]) => {
1724
+ values[timestamp] = [{ min: value, max: value }];
1725
+ });
1687
1726
  const renderType = datapoint.renderType || 'min';
1688
1727
  const dp = {
1689
1728
  ...datapoint,
1690
- values: seriesMatchingDatapoint['data']
1729
+ values
1691
1730
  };
1692
1731
  if (isEvent(alarmOrEvent)) {
1693
- // if event series with the same id already exists, return
1694
- const eventExists = allDataSeries.some(series => series['data'].some(data => data[0] === alarmOrEvent.creationTime));
1732
+ // Check if event already exists on chart to avoid duplicates
1733
+ const eventExists = allDataSeries.some(series => series['data']?.some(data => data[0] === alarmOrEvent.creationTime));
1695
1734
  if (eventExists) {
1696
1735
  return;
1697
1736
  }
1737
+ // For events, pass creationTime as unique id to create unique series per event.
1738
+ // This allows multiple events of the same type/device to coexist on the chart.
1739
+ // Series ID will be: eventType/deviceId+creationTime-markPoint
1698
1740
  const newEventSeries = this.echartsOptionsService.getAlarmOrEventSeries(dp, renderType, false, [alarmOrEvent], 'event', displayOptions, alarmOrEvent.creationTime, null, true);
1699
1741
  allDataSeries.push(...newEventSeries);
1700
1742
  }
1701
1743
  else if (isAlarm(alarmOrEvent)) {
1702
- const alarmExists = allDataSeries.some((series) => {
1703
- const seriesData = series['data'];
1704
- return seriesData.some((data) => data[0] === alarmOrEvent.creationTime);
1744
+ // For alarms, remove existing series for this alarm type + device before adding.
1745
+ // This ensures alarm status changes (e.g., ACTIVE → CLEARED) are reflected.
1746
+ // Series ID format: ${alarmType}/${deviceId}-markPoint/markLine
1747
+ const alarm = alarmOrEvent;
1748
+ const alarmType = alarm.type;
1749
+ const datapointTargetId = datapoint.__target?.id;
1750
+ allDataSeries = allDataSeries.filter((series) => {
1751
+ const seriesId = series['id'];
1752
+ return !seriesId?.startsWith(`${alarmType}/${datapointTargetId}`);
1705
1753
  });
1706
- if (alarmExists) {
1707
- const alarmSeries = allDataSeries.filter((series) => {
1708
- const seriesData = series['data'];
1709
- return seriesData.some((data) => data[0] === alarmOrEvent.creationTime);
1710
- });
1711
- // remove all matching alarm series which are in the array
1712
- alarmSeries.forEach(series => {
1713
- allDataSeries = allDataSeries.filter(s => s['id'] !== series['id']);
1714
- });
1715
- const newAlarmSeries = this.echartsOptionsService.getAlarmOrEventSeries(dp, renderType, false, [alarmOrEvent], 'alarm', displayOptions, alarmOrEvent.creationTime, null, true);
1716
- allDataSeries.push(...newAlarmSeries);
1717
- }
1718
- else {
1719
- const newAlarmSeries = this.echartsOptionsService.getAlarmOrEventSeries(dp, renderType, false, [alarmOrEvent], 'alarm', displayOptions, alarmOrEvent.id, null, true);
1720
- allDataSeries.push(...newAlarmSeries);
1721
- }
1754
+ // For alarms, pass null as id - we want one series per alarm type/device.
1755
+ // Series ID will be: alarmType/deviceId-markPoint (no unique suffix).
1756
+ // We already removed the old series above, so this replaces it.
1757
+ const newAlarmSeries = this.echartsOptionsService.getAlarmOrEventSeries(dp, renderType, false, [alarm], 'alarm', displayOptions, null, null, true);
1758
+ allDataSeries.push(...newAlarmSeries);
1722
1759
  }
1723
1760
  }
1724
- this.checkForValuesAfterTimeRange(seriesMatchingDatapoint['data'], datapoint, datapointOutOfSyncCallback);
1725
- });
1761
+ }
1762
+ // Use replaceMerge for series to ensure removed alarm series don't persist.
1763
+ // Without this, ECharts merges the new series array with existing ones,
1764
+ // which can leave stale alarm/event series on the chart.
1726
1765
  this.echartsInstance?.setOption({
1727
1766
  dataZoom: [
1728
1767
  {
@@ -1735,7 +1774,7 @@ class ChartRealtimeService {
1735
1774
  max: this.currentTimeRange?.dateTo
1736
1775
  },
1737
1776
  series: allDataSeries
1738
- });
1777
+ }, { replaceMerge: ['series'] });
1739
1778
  }
1740
1779
  /**
1741
1780
  * Detects if a datapoint has measurements with future timestamps (out-of-sync).
@@ -2247,6 +2286,7 @@ class ChartsComponent {
2247
2286
  }
2248
2287
  /**
2249
2288
  * Toggles the visibility of a series in the chart based on the provided datapoint.
2289
+ * Uses explicit legendSelect/legendUnSelect based on __active state.
2250
2290
  * @param datapoint - The datapoint to toggle visibility for.
2251
2291
  */
2252
2292
  toggleDatapointSeriesVisibility(datapoint) {
@@ -2254,26 +2294,40 @@ class ChartsComponent {
2254
2294
  const seriesToUpdate = series.find(s => s.datapointId === `${datapoint.__target?.id}${datapoint.fragment}${datapoint.series}`);
2255
2295
  if (seriesToUpdate) {
2256
2296
  this.echartsInstance.dispatchAction({
2257
- type: 'legendToggleSelect',
2297
+ type: datapoint.__active ? 'legendSelect' : 'legendUnSelect',
2258
2298
  name: seriesToUpdate.name
2259
2299
  });
2260
2300
  }
2261
2301
  }
2262
2302
  /**
2263
- * Toggles the visibility of a series in the chart based on the provided alarm or event.
2303
+ * Toggles the visibility of alarm/event series in the chart.
2304
+ * Uses explicit legendSelect/legendUnSelect based on __hidden state.
2305
+ * Targets specific device's series using type + deviceId.
2264
2306
  * @param alarmOrEvent - The alarm or event to toggle visibility for.
2265
2307
  */
2266
2308
  toggleAlarmEventSeriesVisibility(alarmOrEvent) {
2267
- const series = this.echartsInstance.getOption().series;
2268
- const seriesToUpdate = series.filter(s => s.name === `${alarmOrEvent.label}-markPoint` || s.name === `${alarmOrEvent.label}-markLine`);
2269
- if (seriesToUpdate) {
2270
- seriesToUpdate.forEach(s => {
2271
- this.echartsInstance.dispatchAction({
2272
- type: 'legendToggleSelect',
2273
- name: s.name
2274
- });
2275
- });
2309
+ if (!this.echartsInstance) {
2310
+ return;
2276
2311
  }
2312
+ const options = this.echartsInstance.getOption();
2313
+ const allSeries = options.series;
2314
+ if (!allSeries || allSeries.length === 0) {
2315
+ return;
2316
+ }
2317
+ const type = alarmOrEvent.filters.type;
2318
+ const deviceId = alarmOrEvent.__target?.id;
2319
+ const actionType = alarmOrEvent.__hidden ? 'legendUnSelect' : 'legendSelect';
2320
+ // Series names are: ${type}/${deviceId}-markPoint and ${type}/${deviceId}-markLine
2321
+ const markPointName = `${type}/${deviceId}-markPoint`;
2322
+ const markLineName = `${type}/${deviceId}-markLine`;
2323
+ // Find series matching this specific alarm type + device
2324
+ const matchingSeries = allSeries.filter(s => s.name === markPointName || s.name === markLineName);
2325
+ matchingSeries.forEach(series => {
2326
+ this.echartsInstance.dispatchAction({
2327
+ type: actionType,
2328
+ name: series.name
2329
+ });
2330
+ });
2277
2331
  }
2278
2332
  getDefaultChartOptions() {
2279
2333
  return {