@c8y/ngx-components 1021.50.0 → 1021.51.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 (92) hide show
  1. package/core/aggregation/aggregation.model.d.ts.map +1 -0
  2. package/core/aggregation/aggregation.service.d.ts +44 -0
  3. package/core/aggregation/aggregation.service.d.ts.map +1 -0
  4. package/core/aggregation/index.d.ts +3 -0
  5. package/core/aggregation/index.d.ts.map +1 -0
  6. package/core/common/index.d.ts +0 -2
  7. package/core/common/index.d.ts.map +1 -1
  8. package/core/dashboard/wiget-time-context/aggregation-picker/aggregation-picker.component.d.ts +2 -2
  9. package/core/dashboard/wiget-time-context/aggregation-picker/aggregation-picker.component.d.ts.map +1 -1
  10. package/core/dashboard/wiget-time-context/widget-time-context-icon-bar/widget-time-context-icon-bar.component.d.ts +1 -1
  11. package/core/dashboard/wiget-time-context/widget-time-context-icon-bar/widget-time-context-icon-bar.component.d.ts.map +1 -1
  12. package/core/dashboard/wiget-time-context/widget-time-context.component.d.ts +1 -1
  13. package/core/dashboard/wiget-time-context/widget-time-context.component.d.ts.map +1 -1
  14. package/core/index.d.ts +1 -0
  15. package/core/index.d.ts.map +1 -1
  16. package/datapoints-export-selector/datapoints-export-selector-modal/datapoints-export-selector-file-exporter/data-fetching.service.d.ts +54 -42
  17. package/datapoints-export-selector/datapoints-export-selector-modal/datapoints-export-selector-file-exporter/data-fetching.service.d.ts.map +1 -1
  18. package/datapoints-export-selector/datapoints-export-selector-modal/datapoints-export-selector-file-exporter/datapoints-export-selector-file-exporter.component.d.ts +28 -8
  19. package/datapoints-export-selector/datapoints-export-selector-modal/datapoints-export-selector-file-exporter/datapoints-export-selector-file-exporter.component.d.ts.map +1 -1
  20. package/datapoints-export-selector/datapoints-export-selector-modal/datapoints-export-selector-file-exporter/datapoints-export-selector-file-exporter.service.d.ts +3 -52
  21. package/datapoints-export-selector/datapoints-export-selector-modal/datapoints-export-selector-file-exporter/datapoints-export-selector-file-exporter.service.d.ts.map +1 -1
  22. package/datapoints-export-selector/datapoints-export-selector.model.d.ts +5 -14
  23. package/datapoints-export-selector/datapoints-export-selector.model.d.ts.map +1 -1
  24. package/device-grid/device-grid.component.d.ts.map +1 -1
  25. package/device-grid/device-grid.service.d.ts +2 -0
  26. package/device-grid/device-grid.service.d.ts.map +1 -1
  27. package/esm2022/core/aggregation/aggregation.model.mjs +46 -0
  28. package/esm2022/core/aggregation/aggregation.service.mjs +76 -0
  29. package/esm2022/core/aggregation/index.mjs +3 -0
  30. package/esm2022/core/common/index.mjs +1 -3
  31. package/esm2022/core/dashboard/wiget-time-context/aggregation-picker/aggregation-picker.component.mjs +2 -2
  32. package/esm2022/core/dashboard/wiget-time-context/widget-time-context-icon-bar/widget-time-context-icon-bar.component.mjs +2 -2
  33. package/esm2022/core/dashboard/wiget-time-context/widget-time-context.component.mjs +4 -4
  34. package/esm2022/core/index.mjs +2 -1
  35. package/esm2022/datapoints-export-selector/datapoints-export-selector-modal/datapoints-export-selector-file-exporter/data-fetching.service.mjs +165 -163
  36. package/esm2022/datapoints-export-selector/datapoints-export-selector-modal/datapoints-export-selector-file-exporter/datapoints-export-selector-file-exporter.component.mjs +82 -48
  37. package/esm2022/datapoints-export-selector/datapoints-export-selector-modal/datapoints-export-selector-file-exporter/datapoints-export-selector-file-exporter.service.mjs +5 -95
  38. package/esm2022/datapoints-export-selector/datapoints-export-selector-modal/datapoints-export-selector-file-exporter/datapoints-exports-selector-data-scope/datapoints-exports-selector-data-scope.component.mjs +3 -3
  39. package/esm2022/datapoints-export-selector/datapoints-export-selector.component.mjs +3 -3
  40. package/esm2022/datapoints-export-selector/datapoints-export-selector.model.mjs +1 -9
  41. package/esm2022/device-grid/device-grid.component.mjs +3 -3
  42. package/esm2022/device-grid/device-grid.service.mjs +16 -1
  43. package/esm2022/interval-picker/interval-picker.model.mjs +5 -1
  44. package/esm2022/widgets/implementations/datapoints-table/datapoints-table-config/datapoints-table-config.component.mjs +25 -41
  45. package/esm2022/widgets/implementations/datapoints-table/datapoints-table-view/datapoints-reload/datapoints-reload.component.mjs +3 -3
  46. package/esm2022/widgets/implementations/datapoints-table/datapoints-table-view/datapoints-table-view.component.mjs +55 -49
  47. package/esm2022/widgets/implementations/datapoints-table/datapoints-table-view/datapoints-table-view.service.mjs +25 -73
  48. package/esm2022/widgets/implementations/datapoints-table/datapoints-table-widget.model.mjs +20 -20
  49. package/esm2022/widgets/implementations/datapoints-table/datapoints-table.service.mjs +19 -19
  50. package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs +247 -307
  51. package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs.map +1 -1
  52. package/fesm2022/c8y-ngx-components-device-grid.mjs +17 -2
  53. package/fesm2022/c8y-ngx-components-device-grid.mjs.map +1 -1
  54. package/fesm2022/c8y-ngx-components-interval-picker.mjs +5 -1
  55. package/fesm2022/c8y-ngx-components-interval-picker.mjs.map +1 -1
  56. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-table.mjs +1075 -1253
  57. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-table.mjs.map +1 -1
  58. package/fesm2022/c8y-ngx-components.mjs +118 -76
  59. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  60. package/interval-picker/interval-picker.model.d.ts +6 -0
  61. package/interval-picker/interval-picker.model.d.ts.map +1 -1
  62. package/locales/de.po +40 -27
  63. package/locales/es.po +40 -27
  64. package/locales/fr.po +40 -27
  65. package/locales/ja_JP.po +40 -26
  66. package/locales/ko.po +38 -24
  67. package/locales/locales.pot +23 -25
  68. package/locales/nl.po +40 -27
  69. package/locales/pl.po +40 -26
  70. package/locales/pt_BR.po +40 -27
  71. package/locales/zh_CN.po +38 -24
  72. package/locales/zh_TW.po +38 -24
  73. package/package.json +1 -1
  74. package/widgets/implementations/datapoints-table/datapoints-table-config/datapoints-table-config.component.d.ts +3 -5
  75. package/widgets/implementations/datapoints-table/datapoints-table-config/datapoints-table-config.component.d.ts.map +1 -1
  76. package/widgets/implementations/datapoints-table/datapoints-table-view/datapoints-table-view.component.d.ts +7 -2
  77. package/widgets/implementations/datapoints-table/datapoints-table-view/datapoints-table-view.component.d.ts.map +1 -1
  78. package/widgets/implementations/datapoints-table/datapoints-table-view/datapoints-table-view.service.d.ts +7 -27
  79. package/widgets/implementations/datapoints-table/datapoints-table-view/datapoints-table-view.service.d.ts.map +1 -1
  80. package/widgets/implementations/datapoints-table/datapoints-table-widget.model.d.ts +4 -3
  81. package/widgets/implementations/datapoints-table/datapoints-table-widget.model.d.ts.map +1 -1
  82. package/widgets/implementations/datapoints-table/datapoints-table.service.d.ts +5 -5
  83. package/widgets/implementations/datapoints-table/datapoints-table.service.d.ts.map +1 -1
  84. package/core/common/aggregation/aggregation.model.d.ts.map +0 -1
  85. package/core/common/aggregation/aggregation.service.d.ts +0 -17
  86. package/core/common/aggregation/aggregation.service.d.ts.map +0 -1
  87. package/esm2022/core/common/aggregation/aggregation.model.mjs +0 -46
  88. package/esm2022/core/common/aggregation/aggregation.service.mjs +0 -34
  89. package/esm2022/widgets/implementations/datapoints-table/datapoints-table-config/datapoints-table-config.service.mjs +0 -124
  90. package/widgets/implementations/datapoints-table/datapoints-table-config/datapoints-table-config.service.d.ts +0 -56
  91. package/widgets/implementations/datapoints-table/datapoints-table-config/datapoints-table-config.service.d.ts.map +0 -1
  92. /package/core/{common/aggregation → aggregation}/aggregation.model.d.ts +0 -0
@@ -1,22 +1,19 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Injectable, Component, Input, EventEmitter, Output, InjectionToken, Inject, ViewChild, HostListener } from '@angular/core';
3
- import * as i3 from '@angular/platform-browser';
4
3
  import * as i2 from '@c8y/client';
5
4
  import * as i1 from '@c8y/ngx-components';
6
5
  import { gettext, AGGREGATION_VALUES, CoreModule, AGGREGATION_LABELS, AGGREGATION_VALUES_ARR, CommonModule, ModalModule } from '@c8y/ngx-components';
7
- import * as i4 from '@ngx-translate/core';
6
+ import * as i3 from '@ngx-translate/core';
8
7
  import JSZip from 'jszip';
9
- import * as i2$1 from '@angular/common';
10
- import { KeyValuePipe } from '@angular/common';
11
8
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
12
9
  import * as i3$2 from '@angular/forms';
13
10
  import { FormsModule, FormControl, ReactiveFormsModule } from '@angular/forms';
14
11
  import saveAs from 'file-saver';
15
12
  import { Subject, debounceTime, merge, takeUntil } from 'rxjs';
16
- import { TimeSpanInMs } from '@c8y/ngx-components/interval-picker';
17
13
  import { A11yModule } from '@angular/cdk/a11y';
18
14
  import * as i3$1 from 'ngx-bootstrap/popover';
19
15
  import { PopoverModule } from 'ngx-bootstrap/popover';
16
+ import * as i2$1 from '@angular/common';
20
17
  import { isNil, isEmpty, isNumber } from 'lodash-es';
21
18
  import * as i1$1 from 'ngx-bootstrap/modal';
22
19
  import * as i3$3 from 'ngx-bootstrap/tooltip';
@@ -55,14 +52,6 @@ const FILE_COMPRESSION_TYPES_VALUES = {
55
52
  store: 'STORE',
56
53
  deflate: 'DEFLATE'
57
54
  };
58
- const TIME_RANGE_INTERVAL_UNITS_VALUES = {
59
- minutes: 'minutes',
60
- hours: 'hours',
61
- days: 'days',
62
- weeks: 'weeks',
63
- months: 'months',
64
- custom: 'custom'
65
- };
66
55
  const PRODUCT_EXPERIENCE_DATAPOINTS_EXPORT_SELECTOR = {
67
56
  EVENTS: {
68
57
  EXPORT_SELECTOR: 'exportSelector'
@@ -156,10 +145,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImpor
156
145
  }] });
157
146
 
158
147
  class DataFetchingService {
159
- constructor(alertService, measurementService, sanitizer, translateService, utilsService) {
148
+ constructor(alertService, measurementService, translateService, utilsService) {
160
149
  this.alertService = alertService;
161
150
  this.measurementService = measurementService;
162
- this.sanitizer = sanitizer;
163
151
  this.translateService = translateService;
164
152
  this.utilsService = utilsService;
165
153
  }
@@ -202,6 +190,7 @@ class DataFetchingService {
202
190
  }
203
191
  catch (error) {
204
192
  this.alertService.addServerFailure(error);
193
+ return null;
205
194
  }
206
195
  });
207
196
  const results = await Promise.all(promises);
@@ -244,6 +233,33 @@ class DataFetchingService {
244
233
  ]);
245
234
  return trimmedMessage;
246
235
  }
236
+ /**
237
+ * Trims the given HTML message by removing list items that correspond to zero counts.
238
+ *
239
+ * @param message - The HTML string containing the message with list items.
240
+ * @param counts - An array of number values corresponding to each list item.
241
+ * @param countToTrim - A count that will be trimmed with corresponding list item.
242
+ * @returns A trimmed HTML string with list items removed where the corresponding count is zero.
243
+ *
244
+ * Example:
245
+ * ```typescript
246
+ * const message = '<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>';
247
+ * const counts = [1, 0, 2];
248
+ * const trimmedMessage = this.removeZeroCountListItems(message, counts);
249
+ * // Result: '<ul><li>Item 1</li><li>Item 3</li></ul>'
250
+ * ```
251
+ */
252
+ removeZeroCountListItems(message, counts, countToTrim = 0) {
253
+ const parser = new DOMParser();
254
+ const doc = parser.parseFromString(message, 'text/html');
255
+ const listItems = doc.querySelectorAll('ul li');
256
+ listItems.forEach((item, index) => {
257
+ if (counts[index] === countToTrim) {
258
+ item.remove();
259
+ }
260
+ });
261
+ return doc.body.innerHTML;
262
+ }
247
263
  /**
248
264
  * Displays an information alert about sending data via email.
249
265
  *
@@ -267,8 +283,8 @@ class DataFetchingService {
267
283
  const filePromises = exportConfig.datapointDetails.map(details => this.fetchAndProcessMeasurementFile(details, measurementFileConfig));
268
284
  return Promise.all(filePromises);
269
285
  }
270
- async fetchAndProcessMeasurementFile(details, measurementFileConfig) {
271
- const filter = this.prepareMeasurementsFilter(details, measurementFileConfig.exportConfig);
286
+ async fetchAndProcessMeasurementFile(details, measurementFileConfig, roundSeconds = false) {
287
+ const filter = this.prepareMeasurementsFilter(details, measurementFileConfig.exportConfig, roundSeconds);
272
288
  const header = { accept: measurementFileConfig.acceptFileType };
273
289
  try {
274
290
  const measurementFileResponse = await this.measurementService.getMeasurementsFile(filter, header);
@@ -295,6 +311,77 @@ class DataFetchingService {
295
311
  ? await this.fetchAndPrepareMeasurementDataToExportForPreview(exportConfig)
296
312
  : await this.fetchAndPrepareSeriesDataToExport(exportConfig);
297
313
  }
314
+ prepareMeasurementsFilter(details, exportConfig, roundSeconds, pageSize) {
315
+ const filter = {
316
+ dateFrom: this.adjustDate(exportConfig.dateFrom, 0, roundSeconds),
317
+ dateTo: this.adjustDate(exportConfig.dateTo, 0, roundSeconds),
318
+ source: details.source,
319
+ valueFragmentSeries: details.valueFragmentSeries,
320
+ valueFragmentType: details.valueFragmentType
321
+ };
322
+ if (pageSize) {
323
+ filter.pageSize = pageSize;
324
+ }
325
+ return filter;
326
+ }
327
+ processMeasurementDataForPreview(details, data) {
328
+ const unit = data[0][details.valueFragmentType][details.valueFragmentSeries]?.unit || '';
329
+ const values = {};
330
+ data.forEach(measurement => {
331
+ values[measurement.time] =
332
+ measurement[details.valueFragmentType][details.valueFragmentSeries].value;
333
+ });
334
+ return { ...details, unit, timeValueMap: values };
335
+ }
336
+ /**
337
+ * Returns a map of active data points device IDs with their corresponding series.
338
+ *
339
+ * Example output:
340
+ * ```typescript
341
+ * new Map([
342
+ * ['844657202', ['c8y_Temperature.T']],
343
+ * ['32666427', ['c8y_Battery.Battery']]
344
+ * ]);
345
+ * ```
346
+ * @param datapointDetails - An array of data points details.
347
+ * @returns A map where the key is the data point ID and the value is an array of data point series.
348
+ */
349
+ groupSeriesByDeviceId(datapointDetails) {
350
+ return datapointDetails.reduce((map, { valueFragmentType, valueFragmentSeries, source }) => {
351
+ const value = `${valueFragmentType}.${valueFragmentSeries}`;
352
+ const existingValue = map.get(source) ?? [];
353
+ map.set(source, [...existingValue, value]);
354
+ return map;
355
+ }, new Map());
356
+ }
357
+ /**
358
+ * Processes the fetched series data and prepares it for export.
359
+ *
360
+ * @param datapointDetails - An array of data point details.
361
+ * @param fetchedDataMap - A map of fetched series data grouped by source.
362
+ * @returns An array of DataToExport objects.
363
+ */
364
+ processSeriesData(datapointDetails, fetchedDataMap) {
365
+ const valuesGroupedBySource = this.utilsService.transformDataStructure(fetchedDataMap);
366
+ return datapointDetails.map((details) => {
367
+ let unit;
368
+ let data;
369
+ /**
370
+ * Unique key to distinguish between different series from same source,
371
+ * e.g.: c8y_Acceleration.accelerationX, c8y_Acceleration.accelerationY, c8y_Acceleration.accelerationZ
372
+ */
373
+ const seriesKey = `${details.valueFragmentType}.${details.valueFragmentSeries}`;
374
+ if (valuesGroupedBySource[details.source][seriesKey]) {
375
+ unit = valuesGroupedBySource[details.source][seriesKey].seriesDetails.unit;
376
+ data = valuesGroupedBySource[details.source][seriesKey].values;
377
+ }
378
+ return {
379
+ ...details,
380
+ unit,
381
+ timeValueMap: data
382
+ };
383
+ });
384
+ }
298
385
  async getSourcesWithPermissionsToRead(datapointDetails) {
299
386
  const dateFrom = new Date();
300
387
  const dateTo = new Date(dateFrom);
@@ -319,6 +406,56 @@ class DataFetchingService {
319
406
  const fetchedSources = await Promise.all(fetchedDataPromises);
320
407
  return fetchedSources.filter((source) => source !== null);
321
408
  }
409
+ /**
410
+ * Adjusts the given date by adding the specified number of minutes and setting seconds to 0.
411
+ *
412
+ * @param date - The date to be adjusted in string format.
413
+ * @param minutes - The number of minutes to add to the date.
414
+ * @param roundSeconds - Whether to round the seconds or not.
415
+ * If true, the seconds will be rounded to 0.
416
+ * If false, the seconds will be displayed as they are.
417
+ * @returns The adjusted date in ISO string format.
418
+ */
419
+ adjustDate(date, minutes, roundSeconds = true) {
420
+ const dateTime = new Date(date);
421
+ if (isNaN(dateTime.getTime())) {
422
+ throw new Error('Invalid date');
423
+ }
424
+ dateTime.setUTCMinutes(dateTime.getUTCMinutes() + minutes);
425
+ if (roundSeconds) {
426
+ dateTime.setUTCSeconds(0, 0);
427
+ }
428
+ return dateTime.toISOString();
429
+ }
430
+ /**
431
+ * Asynchronously loads series data based on the provided parameters.
432
+ *
433
+ * This method constructs a filter for retrieving series data within a specified date range,
434
+ * from a specific source, and optionally applying an aggregation type.
435
+ *
436
+ * @param rawFilter - The parameters for loading series data, including date range, source, series names, and aggregation type.
437
+ * @param roundSeconds - Indicates whether to round the seconds in the date range to the nearest whole number.
438
+ * @returns A promise that resolves to series data wrapped in result object.
439
+ */
440
+ async fetchSeriesData(rawFilter, roundSeconds = false) {
441
+ let seriesData;
442
+ const filter = this.prepareSeriesFilter({
443
+ dateFrom: rawFilter.dateFrom,
444
+ dateTo: rawFilter.dateTo,
445
+ source: rawFilter.source,
446
+ series: rawFilter.series,
447
+ aggregationType: rawFilter.aggregationType
448
+ }, roundSeconds);
449
+ try {
450
+ // TODO: consider adding a cache mechanism -> MTM-60289, MTM-59233
451
+ // When user switches between report types, and rest of the settings are the same, then the data should not be fetched again?
452
+ seriesData = await this.measurementService.listSeries(filter);
453
+ }
454
+ catch (error) {
455
+ this.alertService.addServerFailure(error);
456
+ }
457
+ return seriesData;
458
+ }
322
459
  /**
323
460
  * Fetches and prepares measurement data for preview.
324
461
  *
@@ -327,11 +464,12 @@ class DataFetchingService {
327
464
  * CSV/Excel files are generated by the backend for measurements.
328
465
  *
329
466
  * @param exportConfig - The export configuration.
467
+ * @param roundSeconds - Indicates whether to round the seconds in the date range to the nearest whole number.
330
468
  * @returns A promise that resolves to an array of DataToExport objects or null when no data is fetched.
331
469
  */
332
- async fetchAndPrepareMeasurementDataToExportForPreview(exportConfig) {
470
+ async fetchAndPrepareMeasurementDataToExportForPreview(exportConfig, roundSeconds = false) {
333
471
  const dataToExportPromises = exportConfig.datapointDetails.map(async (details) => {
334
- const fetchedMeasurementData = await this.fetchMeasurementDataForPreview(details, exportConfig);
472
+ const fetchedMeasurementData = await this.fetchMeasurementDataForPreview(details, exportConfig, roundSeconds);
335
473
  if (fetchedMeasurementData?.data?.length) {
336
474
  return this.processMeasurementDataForPreview(details, fetchedMeasurementData.data);
337
475
  }
@@ -339,9 +477,9 @@ class DataFetchingService {
339
477
  });
340
478
  return await Promise.all(dataToExportPromises);
341
479
  }
342
- async fetchMeasurementDataForPreview(details, exportConfig) {
480
+ async fetchMeasurementDataForPreview(details, exportConfig, roundSeconds) {
343
481
  let measurements;
344
- const filter = this.prepareMeasurementsFilter(details, exportConfig, MEASUREMENTS_PREVIEW_ITEMS_LIMIT);
482
+ const filter = this.prepareMeasurementsFilter(details, exportConfig, roundSeconds, MEASUREMENTS_PREVIEW_ITEMS_LIMIT);
345
483
  try {
346
484
  // TODO: consider adding a cache mechanism -> MTM-60289
347
485
  // When user switches between report types, and rest of the settings are the same, then the data should not be fetched again?
@@ -352,30 +490,6 @@ class DataFetchingService {
352
490
  }
353
491
  return measurements;
354
492
  }
355
- prepareMeasurementsFilter(details, exportConfig, pageSize) {
356
- const filter = {
357
- // Round the 'from' time to the previous full minute.
358
- dateFrom: this.adjustDate(exportConfig.dateFrom, -1),
359
- // Round the 'to' time to the nearest full minute.
360
- dateTo: this.adjustDate(exportConfig.dateTo, 1),
361
- source: details.source,
362
- valueFragmentSeries: details.valueFragmentSeries,
363
- valueFragmentType: details.valueFragmentType
364
- };
365
- if (pageSize) {
366
- filter.pageSize = pageSize;
367
- }
368
- return filter;
369
- }
370
- processMeasurementDataForPreview(details, data) {
371
- const unit = data[0][details.valueFragmentType][details.valueFragmentSeries]?.unit || '';
372
- const values = {};
373
- data.forEach(measurement => {
374
- values[measurement.time] =
375
- measurement[details.valueFragmentType][details.valueFragmentSeries].value;
376
- });
377
- return { ...details, unit, timeValueMap: values };
378
- }
379
493
  async fetchAndPrepareSeriesDataToExport(exportConfig) {
380
494
  const datapointsValuesDataMap = this.groupSeriesByDeviceId(exportConfig.datapointDetails);
381
495
  const fetchedDataPromises = Array.from(datapointsValuesDataMap).map(async ([source, series]) => {
@@ -393,52 +507,10 @@ class DataFetchingService {
393
507
  const fetchedDataGroupedBySource = await Promise.all(fetchedDataPromises);
394
508
  return this.processSeriesData(exportConfig.datapointDetails, fetchedDataGroupedBySource);
395
509
  }
396
- /**
397
- * Returns a map of active data points device IDs with their corresponding series.
398
- *
399
- * Example output:
400
- * ```typescript
401
- * new Map([
402
- * ['844657202', ['c8y_Temperature.T']],
403
- * ['32666427', ['c8y_Battery.Battery']]
404
- * ]);
405
- * ```
406
- * @param datapointDetails - An array of data points details.
407
- * @returns A map where the key is the data point ID and the value is an array of data point series.
408
- */
409
- groupSeriesByDeviceId(datapointDetails) {
410
- return datapointDetails.reduce((map, { valueFragmentType, valueFragmentSeries, source }) => {
411
- const value = `${valueFragmentType}.${valueFragmentSeries}`;
412
- const existingValue = map.get(source) ?? [];
413
- map.set(source, [...existingValue, value]);
414
- return map;
415
- }, new Map());
416
- }
417
- async fetchSeriesData(rawFilter) {
418
- let seriesData;
419
- const filter = this.prepareSeriesFilter({
420
- dateFrom: rawFilter.dateFrom,
421
- dateTo: rawFilter.dateTo,
422
- source: rawFilter.source,
423
- series: rawFilter.series,
424
- aggregationType: rawFilter.aggregationType
425
- });
426
- try {
427
- // TODO: consider adding a cache mechanism -> MTM-60289
428
- // When user switches between report types, and rest of the settings are the same, then the data should not be fetched again?
429
- seriesData = await this.measurementService.listSeries(filter);
430
- }
431
- catch (error) {
432
- this.alertService.addServerFailure(error);
433
- }
434
- return seriesData;
435
- }
436
- prepareSeriesFilter(filters) {
510
+ prepareSeriesFilter(filters, roundSeconds) {
437
511
  const { dateFrom, dateTo, source, series, aggregationType } = filters;
438
- // Round the 'from' time to the previous full minute.
439
- const from = this.adjustDate(dateFrom, -1);
440
- // Round the 'to' time to the nearest full minute.
441
- const to = this.adjustDate(dateTo, 1);
512
+ const from = this.adjustDate(dateFrom, 0, roundSeconds);
513
+ const to = this.adjustDate(dateTo, 0, roundSeconds);
442
514
  const filter = {
443
515
  dateFrom: from,
444
516
  dateTo: to,
@@ -460,86 +532,7 @@ class DataFetchingService {
460
532
  }
461
533
  return filter;
462
534
  }
463
- /**
464
- * Processes the fetched series data and prepares it for export.
465
- *
466
- * @param datapointDetails - An array of data point details.
467
- * @param fetchedDataMap - A map of fetched series data grouped by source.
468
- * @returns An array of DataToExport objects.
469
- */
470
- processSeriesData(datapointDetails, fetchedDataMap) {
471
- const valuesGroupedBySource = this.utilsService.transformDataStructure(fetchedDataMap);
472
- return datapointDetails.map((details) => {
473
- let unit;
474
- let data;
475
- /**
476
- * Unique key to distinguish between different series from same source,
477
- * e.g.: c8y_Acceleration.accelerationX, c8y_Acceleration.accelerationY, c8y_Acceleration.accelerationZ
478
- */
479
- const seriesKey = `${details.valueFragmentType}.${details.valueFragmentSeries}`;
480
- if (valuesGroupedBySource[details.source][seriesKey]) {
481
- unit = valuesGroupedBySource[details.source][seriesKey].seriesDetails.unit;
482
- data = valuesGroupedBySource[details.source][seriesKey].values;
483
- }
484
- return {
485
- ...details,
486
- unit,
487
- timeValueMap: data
488
- };
489
- });
490
- }
491
- /**
492
- * Adjusts the given date by adding the specified number of minutes and setting seconds to 0.
493
- *
494
- * @param date - The date to be adjusted in string format.
495
- * @param minutes - The number of minutes to add to the date.
496
- * @returns The adjusted date in the format 'YYYY-MM-DDTHH:mm:ss+HH:MM'.
497
- */
498
- adjustDate(date, minutes) {
499
- const dateTime = new Date(date);
500
- dateTime.setMinutes(dateTime.getMinutes() + minutes);
501
- dateTime.setSeconds(0);
502
- const offset = -dateTime.getTimezoneOffset();
503
- const offsetSign = offset >= 0 ? '+' : '-';
504
- const pad = (num) => (num < 10 ? '0' + num : num.toString());
505
- const offsetHours = pad(Math.floor(Math.abs(offset) / 60));
506
- const offsetMinutes = pad(Math.abs(offset) % 60);
507
- const year = dateTime.getFullYear();
508
- const month = pad(dateTime.getMonth() + 1);
509
- const day = pad(dateTime.getDate());
510
- const hours = pad(dateTime.getHours());
511
- const minutesString = pad(dateTime.getMinutes());
512
- const seconds = '00';
513
- return `${year}-${month}-${day}T${hours}:${minutesString}:${seconds}${offsetSign}${offsetHours}:${offsetMinutes}`;
514
- }
515
- /**
516
- * Trims the given HTML message by removing list items that correspond to zero counts.
517
- *
518
- * @param message - The HTML string containing the message with list items.
519
- * @param counts - An array of number values corresponding to each list item.
520
- * @param countToTrim - A count that will be trimmed with corresponding list item.
521
- * @returns A trimmed HTML string with list items removed where the corresponding count is zero.
522
- *
523
- * Example:
524
- * ```typescript
525
- * const message = '<ul><li>Item 1</li><li>Item 2</li><li>Item 3</li></ul>';
526
- * const counts = [1, 0, 2];
527
- * const trimmedMessage = this.removeZeroCountListItems(message, counts);
528
- * // Result: '<ul><li>Item 1</li><li>Item 3</li></ul>'
529
- * ```
530
- */
531
- removeZeroCountListItems(message, counts, countToTrim = 0) {
532
- const parser = new DOMParser();
533
- const doc = parser.parseFromString(message, 'text/html');
534
- const listItems = doc.querySelectorAll('ul li');
535
- listItems.forEach((item, index) => {
536
- if (counts[index] === countToTrim) {
537
- item.remove();
538
- }
539
- });
540
- return doc.body.innerHTML;
541
- }
542
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DataFetchingService, deps: [{ token: i1.AlertService }, { token: i2.MeasurementService }, { token: i3.DomSanitizer }, { token: i4.TranslateService }, { token: UtilsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
535
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DataFetchingService, deps: [{ token: i1.AlertService }, { token: i2.MeasurementService }, { token: i3.TranslateService }, { token: UtilsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
543
536
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DataFetchingService, providedIn: 'root' }); }
544
537
  }
545
538
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DataFetchingService, decorators: [{
@@ -547,102 +540,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImpor
547
540
  args: [{
548
541
  providedIn: 'root'
549
542
  }]
550
- }], ctorParameters: () => [{ type: i1.AlertService }, { type: i2.MeasurementService }, { type: i3.DomSanitizer }, { type: i4.TranslateService }, { type: UtilsService }] });
543
+ }], ctorParameters: () => [{ type: i1.AlertService }, { type: i2.MeasurementService }, { type: i3.TranslateService }, { type: UtilsService }] });
551
544
 
552
545
  class DatapointsExportSelectorFileExporterService {
553
- constructor(aggregationService, alertService, datapointsExportSelectorDataProcessingService, translateService) {
554
- this.aggregationService = aggregationService;
546
+ constructor(alertService, datapointsExportSelectorDataProcessingService, translateService) {
555
547
  this.alertService = alertService;
556
548
  this.datapointsExportSelectorDataProcessingService = datapointsExportSelectorDataProcessingService;
557
549
  this.translateService = translateService;
558
550
  }
559
- /**
560
- * Determines the interval between two dates.
561
- *
562
- * @param dateFrom - The starting date in ISO 8601 string format.
563
- * @param dateTo - The ending date in ISO 8601 string format.
564
- * @returns The time range interval unit.
565
- */
566
- determineInterval(dateFrom, dateTo) {
567
- const from = new Date(dateFrom);
568
- const to = new Date(dateTo);
569
- const differenceInMilliseconds = to.getTime() - from.getTime();
570
- const intervals = [
571
- { value: TimeSpanInMs.MINUTE, label: TIME_RANGE_INTERVAL_UNITS_VALUES.minutes }, // milliseconds in one minute
572
- { value: TimeSpanInMs.HOUR, label: TIME_RANGE_INTERVAL_UNITS_VALUES.hours }, // milliseconds in one hour
573
- { value: TimeSpanInMs.DAY, label: TIME_RANGE_INTERVAL_UNITS_VALUES.days }, // milliseconds in one day
574
- { value: TimeSpanInMs.WEEK, label: TIME_RANGE_INTERVAL_UNITS_VALUES.weeks }, // milliseconds in one week
575
- { value: TimeSpanInMs.MONTH, label: TIME_RANGE_INTERVAL_UNITS_VALUES.months } // approximation for milliseconds in one month
576
- ];
577
- for (let i = 0; i < intervals.length; i++) {
578
- if (differenceInMilliseconds <= intervals[i].value) {
579
- return intervals[i].label;
580
- }
581
- }
582
- return TIME_RANGE_INTERVAL_UNITS_VALUES.custom;
583
- }
584
- /**
585
- * Updates the disabled state of aggregation options based on the current value of the time interval form control.
586
- *
587
- * This method:
588
- * - Retrieves the current date range from the form controls.
589
- * - Determines the current time interval based on the date range.
590
- * - Sets the disabled state for each aggregation option based on predefined conditions.
591
- *
592
- * The disabled state is stored in the `disabledAggregationOptions` object,
593
- * where the key is the aggregation value and the value is a boolean indicating whether the option should be disabled.
594
- *
595
- * The `disabledConditions` object defines the conditions under which each aggregation option should be disabled.
596
- *
597
- * @param dateFrom - The value of the "date from" input.
598
- * @param dateTo - The value of the "date to" input.
599
- * @param disabledAggregationOptions - The object containing the disabled state of aggregation options.
600
- * @returns The updated object with the disabled state of aggregation options.
601
- */
602
- updateDisabledStateOfAggregationOptionEntries(dateFrom, dateTo, disabledAggregationOptions) {
603
- disabledAggregationOptions = this.aggregationService.getDisabledAggregationOptions(dateFrom, dateTo);
604
- return disabledAggregationOptions;
605
- }
606
- /**
607
- * Sets the aggregation control to the first available (non-disabled) option if the current option is disabled.
608
- *
609
- * This method:
610
- * - Retrieves the current value of the aggregation control.
611
- * - Checks if the current aggregation option is disabled.
612
- * - If the current option is disabled, sets the control to the first available (non-disabled) option based on the following order:
613
- * - If the current value is `DAILY`, it switches to `HOURLY` if it's not disabled, otherwise to `MINUTELY` if `HOURLY` is also disabled.
614
- * - If the current value is `HOURLY`, it switches to `MINUTELY` if it's not disabled.
615
- * - If all options are disabled, it sets the value to `NONE`.
616
- *
617
- * The disabled state is stored in the `disabledAggregationOptions` object,
618
- * where the key is the aggregation value and the value is a boolean indicating whether the option is disabled.
619
- *
620
- * The `AGGREGATION_VALUES` object defines the possible aggregation values.
621
- *
622
- * @param aggregationValue - The value of the current aggregation option.
623
- * @param disabledAggregationOptions - An object containing disabled aggregation options.
624
- * @returns The new aggregation option to be set.
625
- */
626
- setToFirstAvailableAggregationOptionIfCurrentIsDisabled(aggregationValue, disabledAggregationOptions) {
627
- const currentValue = aggregationValue;
628
- const disabledOptions = disabledAggregationOptions;
629
- if (disabledOptions[currentValue]) {
630
- const { daily, hourly, minutely, none } = AGGREGATION_VALUES;
631
- let newAggregationValue = none;
632
- if (currentValue === daily) {
633
- if (!disabledOptions[hourly]) {
634
- newAggregationValue = hourly;
635
- }
636
- else if (!disabledOptions[minutely]) {
637
- newAggregationValue = minutely;
638
- }
639
- }
640
- else if (currentValue === hourly && !disabledOptions[minutely]) {
641
- newAggregationValue = minutely;
642
- }
643
- return newAggregationValue;
644
- }
645
- }
646
551
  async getMeasurementExportedDataBlob(extension, dataToExport) {
647
552
  try {
648
553
  return await this.getMeasurementDataZipBlob(extension, dataToExport);
@@ -716,7 +621,7 @@ class DatapointsExportSelectorFileExporterService {
716
621
  });
717
622
  }
718
623
  }
719
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DatapointsExportSelectorFileExporterService, deps: [{ token: i1.AggregationService }, { token: i1.AlertService }, { token: DataProcessingService }, { token: i4.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
624
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DatapointsExportSelectorFileExporterService, deps: [{ token: i1.AlertService }, { token: DataProcessingService }, { token: i3.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
720
625
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DatapointsExportSelectorFileExporterService, providedIn: 'root' }); }
721
626
  }
722
627
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DatapointsExportSelectorFileExporterService, decorators: [{
@@ -724,7 +629,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImpor
724
629
  args: [{
725
630
  providedIn: 'root'
726
631
  }]
727
- }], ctorParameters: () => [{ type: i1.AggregationService }, { type: i1.AlertService }, { type: DataProcessingService }, { type: i4.TranslateService }] });
632
+ }], ctorParameters: () => [{ type: i1.AlertService }, { type: DataProcessingService }, { type: i3.TranslateService }] });
728
633
 
729
634
  class DataPointsExportSelectorPreviewComponent {
730
635
  constructor() {
@@ -760,11 +665,11 @@ class DataPointsExportSelectorDataScopeComponent {
760
665
  this.onExportTypeChange.emit(exportType);
761
666
  }
762
667
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DataPointsExportSelectorDataScopeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
763
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: DataPointsExportSelectorDataScopeComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-data-scope", inputs: { disabledAggregationOptions: "disabledAggregationOptions", formGroup: "formGroup" }, outputs: { onAggregationChange: "onAggregationChange", onExportTypeChange: "onExportTypeChange" }, ngImport: i0, template: "<fieldset class=\"c8y-fieldset\">\n <legend class=\"d-flex a-i-center\">\n {{ 'Data scope' | translate }}\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"popoverDataScopeTemplate\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n <ng-template #popoverDataScopeTemplate>\n <p\n class=\"m-b-8\"\n translate\n >\n Choose type of an export to generate, the available options are:\n </p>\n <p><strong translate>Compact</strong></p>\n <ul class=\"p-l-16\">\n <li translate>\n Up to 5,000 records per data point, or up to the data retention limit\n </li>\n <li translate>Creates a single merged file containing all the data</li>\n <li translate>Preview is not available</li>\n <li translate>Supports data aggregation (optional)</li>\n </ul>\n <p><strong translate>Full</strong></p>\n <ul class=\"p-l-16\">\n <li translate>\n Up to 1,000,000 records per data point, or up to the data retention limit\n </li>\n <li translate>\n If the export exceeds 50,000 records, the data will be sent via email\n </li>\n <li translate>\n Creates a compressed ZIP file that contains separate data files for each of your\n selected points\n </li>\n <li translate>Preview is available</li>\n <li translate>No data aggregation</li>\n </ul>\n </ng-template>\n </legend>\n <c8y-form-group class=\"m-b-8\">\n <label>\n {{ 'Export mode' | translate }}\n </label>\n <div\n class=\"c8y-select-wrapper\"\n [formGroup]=\"formGroup\"\n >\n <select\n class=\"form-control text-12\"\n [title]=\"'Export mode' | translate\"\n id=\"exportMode\"\n formControlName=\"exportMode\"\n (ngModelChange)=\"emitExportTypeChange($event)\"\n >\n <option\n *ngFor=\"let exportModeValue of EXPORT_MODE_VALUES_ARR\"\n [ngValue]=\"exportModeValue\"\n >\n {{ EXPORT_MODE_LABELS[exportModeValue] | translate }}\n </option>\n </select>\n </div>\n </c8y-form-group>\n <c8y-form-group class=\"m-b-8\">\n <label>\n {{ 'Aggregation' | translate }}\n </label>\n <div\n class=\"c8y-select-wrapper\"\n [formGroup]=\"formGroup\"\n >\n <select\n class=\"form-control text-12\"\n [title]=\"'Aggregation' | translate\"\n id=\"aggregation\"\n formControlName=\"aggregation\"\n (ngModelChange)=\"emitAggregationChange($event)\"\n >\n <option\n *ngFor=\"let aggregationValue of AGGREGATION_VALUES_ARR\"\n [ngValue]=\"aggregationValue\"\n [disabled]=\"disabledAggregationOptions[aggregationValue]\"\n >\n {{ AGGREGATION_LABELS[aggregationValue] | translate }}\n </option>\n </select>\n </div>\n </c8y-form-group>\n </fieldset>", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3$2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: i1.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i3$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i3$1.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }] }); }
668
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: DataPointsExportSelectorDataScopeComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-data-scope", inputs: { disabledAggregationOptions: "disabledAggregationOptions", formGroup: "formGroup" }, outputs: { onAggregationChange: "onAggregationChange", onExportTypeChange: "onExportTypeChange" }, ngImport: i0, template: "<fieldset class=\"c8y-fieldset\">\n <legend class=\"d-flex a-i-center\">\n {{ 'Data scope' | translate }}\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"popoverDataScopeTemplate\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n <ng-template #popoverDataScopeTemplate>\n <p\n class=\"m-b-8\"\n translate\n >\n Choose export type from available options:\n </p>\n <p><strong translate>Compact</strong></p>\n <ul class=\"p-l-16\">\n <li translate>Up to 5,000 records per data point or data retention limit</li>\n <li translate>Single merged file for all data</li>\n <li translate>No preview available</li>\n <li translate>Optional data aggregation supported</li>\n </ul>\n <p><strong translate>Full</strong></p>\n <ul class=\"p-l-16\">\n <li translate>Up to 1,000,000 records per data point or data retention limit</li>\n <li translate>Email delivery if exceeds 50,000 records</li>\n <li translate>Separate files for each data point in ZIP format</li>\n <li translate>Preview available</li>\n <li translate>No data aggregation</li>\n </ul>\n </ng-template>\n </legend>\n <c8y-form-group class=\"m-b-8\">\n <label>\n {{ 'Export mode' | translate }}\n </label>\n <div\n class=\"c8y-select-wrapper\"\n [formGroup]=\"formGroup\"\n >\n <select\n class=\"form-control text-12\"\n [title]=\"'Export mode' | translate\"\n id=\"exportMode\"\n formControlName=\"exportMode\"\n (ngModelChange)=\"emitExportTypeChange($event)\"\n >\n <option\n *ngFor=\"let exportModeValue of EXPORT_MODE_VALUES_ARR\"\n [ngValue]=\"exportModeValue\"\n >\n {{ EXPORT_MODE_LABELS[exportModeValue] | translate }}\n </option>\n </select>\n </div>\n </c8y-form-group>\n <c8y-form-group class=\"m-b-8\">\n <label>\n {{ 'Aggregation' | translate }}\n </label>\n <div\n class=\"c8y-select-wrapper\"\n [formGroup]=\"formGroup\"\n >\n <select\n class=\"form-control text-12\"\n [title]=\"'Aggregation' | translate\"\n id=\"aggregation\"\n formControlName=\"aggregation\"\n (ngModelChange)=\"emitAggregationChange($event)\"\n >\n <option\n *ngFor=\"let aggregationValue of AGGREGATION_VALUES_ARR\"\n [ngValue]=\"aggregationValue\"\n [disabled]=\"disabledAggregationOptions[aggregationValue]\"\n >\n {{ AGGREGATION_LABELS[aggregationValue] | translate }}\n </option>\n </select>\n </div>\n </c8y-form-group>\n</fieldset>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3$2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: i1.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i3$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i3$1.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }] }); }
764
669
  }
765
670
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DataPointsExportSelectorDataScopeComponent, decorators: [{
766
671
  type: Component,
767
- args: [{ selector: 'c8y-datapoints-export-selector-data-scope', standalone: true, imports: [CoreModule, FormsModule, PopoverModule], template: "<fieldset class=\"c8y-fieldset\">\n <legend class=\"d-flex a-i-center\">\n {{ 'Data scope' | translate }}\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"popoverDataScopeTemplate\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n <ng-template #popoverDataScopeTemplate>\n <p\n class=\"m-b-8\"\n translate\n >\n Choose type of an export to generate, the available options are:\n </p>\n <p><strong translate>Compact</strong></p>\n <ul class=\"p-l-16\">\n <li translate>\n Up to 5,000 records per data point, or up to the data retention limit\n </li>\n <li translate>Creates a single merged file containing all the data</li>\n <li translate>Preview is not available</li>\n <li translate>Supports data aggregation (optional)</li>\n </ul>\n <p><strong translate>Full</strong></p>\n <ul class=\"p-l-16\">\n <li translate>\n Up to 1,000,000 records per data point, or up to the data retention limit\n </li>\n <li translate>\n If the export exceeds 50,000 records, the data will be sent via email\n </li>\n <li translate>\n Creates a compressed ZIP file that contains separate data files for each of your\n selected points\n </li>\n <li translate>Preview is available</li>\n <li translate>No data aggregation</li>\n </ul>\n </ng-template>\n </legend>\n <c8y-form-group class=\"m-b-8\">\n <label>\n {{ 'Export mode' | translate }}\n </label>\n <div\n class=\"c8y-select-wrapper\"\n [formGroup]=\"formGroup\"\n >\n <select\n class=\"form-control text-12\"\n [title]=\"'Export mode' | translate\"\n id=\"exportMode\"\n formControlName=\"exportMode\"\n (ngModelChange)=\"emitExportTypeChange($event)\"\n >\n <option\n *ngFor=\"let exportModeValue of EXPORT_MODE_VALUES_ARR\"\n [ngValue]=\"exportModeValue\"\n >\n {{ EXPORT_MODE_LABELS[exportModeValue] | translate }}\n </option>\n </select>\n </div>\n </c8y-form-group>\n <c8y-form-group class=\"m-b-8\">\n <label>\n {{ 'Aggregation' | translate }}\n </label>\n <div\n class=\"c8y-select-wrapper\"\n [formGroup]=\"formGroup\"\n >\n <select\n class=\"form-control text-12\"\n [title]=\"'Aggregation' | translate\"\n id=\"aggregation\"\n formControlName=\"aggregation\"\n (ngModelChange)=\"emitAggregationChange($event)\"\n >\n <option\n *ngFor=\"let aggregationValue of AGGREGATION_VALUES_ARR\"\n [ngValue]=\"aggregationValue\"\n [disabled]=\"disabledAggregationOptions[aggregationValue]\"\n >\n {{ AGGREGATION_LABELS[aggregationValue] | translate }}\n </option>\n </select>\n </div>\n </c8y-form-group>\n </fieldset>" }]
672
+ args: [{ selector: 'c8y-datapoints-export-selector-data-scope', standalone: true, imports: [CoreModule, FormsModule, PopoverModule], template: "<fieldset class=\"c8y-fieldset\">\n <legend class=\"d-flex a-i-center\">\n {{ 'Data scope' | translate }}\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"popoverDataScopeTemplate\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n <ng-template #popoverDataScopeTemplate>\n <p\n class=\"m-b-8\"\n translate\n >\n Choose export type from available options:\n </p>\n <p><strong translate>Compact</strong></p>\n <ul class=\"p-l-16\">\n <li translate>Up to 5,000 records per data point or data retention limit</li>\n <li translate>Single merged file for all data</li>\n <li translate>No preview available</li>\n <li translate>Optional data aggregation supported</li>\n </ul>\n <p><strong translate>Full</strong></p>\n <ul class=\"p-l-16\">\n <li translate>Up to 1,000,000 records per data point or data retention limit</li>\n <li translate>Email delivery if exceeds 50,000 records</li>\n <li translate>Separate files for each data point in ZIP format</li>\n <li translate>Preview available</li>\n <li translate>No data aggregation</li>\n </ul>\n </ng-template>\n </legend>\n <c8y-form-group class=\"m-b-8\">\n <label>\n {{ 'Export mode' | translate }}\n </label>\n <div\n class=\"c8y-select-wrapper\"\n [formGroup]=\"formGroup\"\n >\n <select\n class=\"form-control text-12\"\n [title]=\"'Export mode' | translate\"\n id=\"exportMode\"\n formControlName=\"exportMode\"\n (ngModelChange)=\"emitExportTypeChange($event)\"\n >\n <option\n *ngFor=\"let exportModeValue of EXPORT_MODE_VALUES_ARR\"\n [ngValue]=\"exportModeValue\"\n >\n {{ EXPORT_MODE_LABELS[exportModeValue] | translate }}\n </option>\n </select>\n </div>\n </c8y-form-group>\n <c8y-form-group class=\"m-b-8\">\n <label>\n {{ 'Aggregation' | translate }}\n </label>\n <div\n class=\"c8y-select-wrapper\"\n [formGroup]=\"formGroup\"\n >\n <select\n class=\"form-control text-12\"\n [title]=\"'Aggregation' | translate\"\n id=\"aggregation\"\n formControlName=\"aggregation\"\n (ngModelChange)=\"emitAggregationChange($event)\"\n >\n <option\n *ngFor=\"let aggregationValue of AGGREGATION_VALUES_ARR\"\n [ngValue]=\"aggregationValue\"\n [disabled]=\"disabledAggregationOptions[aggregationValue]\"\n >\n {{ AGGREGATION_LABELS[aggregationValue] | translate }}\n </option>\n </select>\n </div>\n </c8y-form-group>\n</fieldset>\n" }]
768
673
  }], propDecorators: { disabledAggregationOptions: [{
769
674
  type: Input
770
675
  }], formGroup: [{
@@ -1247,10 +1152,11 @@ const dateRangeValidator = (control) => {
1247
1152
  return null;
1248
1153
  };
1249
1154
  class DatapointsExportSelectorFileExporterComponent {
1250
- constructor(datapointsExportModalService, datapointsExportSelectorService, datapointsExportSelectorFileExporterService, formBuilder, generators, gainsightService) {
1155
+ constructor(aggregationService, datapointsExportModalService, datapointsExportSelectorFileExporterService, dataFetchingService, formBuilder, generators, gainsightService) {
1156
+ this.aggregationService = aggregationService;
1251
1157
  this.datapointsExportModalService = datapointsExportModalService;
1252
- this.datapointsExportSelectorService = datapointsExportSelectorService;
1253
1158
  this.datapointsExportSelectorFileExporterService = datapointsExportSelectorFileExporterService;
1159
+ this.dataFetchingService = dataFetchingService;
1254
1160
  this.formBuilder = formBuilder;
1255
1161
  this.generators = generators;
1256
1162
  this.gainsightService = gainsightService;
@@ -1295,13 +1201,13 @@ class DatapointsExportSelectorFileExporterComponent {
1295
1201
  this.setFilesType(this.generators);
1296
1202
  this.dateFromSubject
1297
1203
  .pipe(debounceTime(300), takeUntilDestroyed())
1298
- .subscribe(async (updatedDate) => {
1299
- await this.updateDateAndFetchData('dateFrom', updatedDate);
1204
+ .subscribe(async (dateInfo) => {
1205
+ await this.updateDateAndFetchData('dateFrom', dateInfo);
1300
1206
  });
1301
1207
  this.dateToSubject
1302
1208
  .pipe(debounceTime(300), takeUntilDestroyed())
1303
- .subscribe(async (updatedDate) => {
1304
- await this.updateDateAndFetchData('dateTo', updatedDate);
1209
+ .subscribe(async (dateInfo) => {
1210
+ await this.updateDateAndFetchData('dateTo', dateInfo);
1305
1211
  });
1306
1212
  }
1307
1213
  setFilesType(generators) {
@@ -1317,7 +1223,7 @@ class DatapointsExportSelectorFileExporterComponent {
1317
1223
  });
1318
1224
  }
1319
1225
  async ngOnInit() {
1320
- const sourcesPermittedToRead = await this.datapointsExportSelectorService.getSourcesWithPermissionsToRead(this.exportConfig.datapointDetails);
1226
+ const sourcesPermittedToRead = await this.dataFetchingService.getSourcesWithPermissionsToRead(this.exportConfig.datapointDetails);
1321
1227
  if (sourcesPermittedToRead.length === 0) {
1322
1228
  return;
1323
1229
  }
@@ -1328,14 +1234,14 @@ class DatapointsExportSelectorFileExporterComponent {
1328
1234
  this.storeInitialChangeableConfig();
1329
1235
  this.fileTypeSelectionState = this.getInitialSelection(this.dynamicFilesTypeMetadata, [0]);
1330
1236
  this.formGroup = this.createForm();
1331
- this.dataToExport = await this.datapointsExportSelectorService.fetchAndPrepareDataToExport(this.exportConfig, this.isFullTypeOfExport);
1237
+ this.dataToExport = await this.dataFetchingService.fetchAndPrepareDataToExport(this.exportConfig, this.isFullTypeOfExport);
1332
1238
  this.handleDateSelectorChanges();
1333
1239
  this.determineShowingPreviewOrEmptyState();
1334
1240
  this.handleExportModeChanges();
1335
1241
  this.handleFileTypeSelectionChanges();
1336
1242
  this.handleFormValidationChanges();
1337
1243
  this.updateFileTypeControl();
1338
- this.updateDisabledAggregationOptionsState();
1244
+ this.updateDisabledAggregationOptions();
1339
1245
  }
1340
1246
  ngOnDestroy() {
1341
1247
  this.destroy$.next();
@@ -1369,13 +1275,13 @@ class DatapointsExportSelectorFileExporterComponent {
1369
1275
  const shouldShowAlert = this.datapointsExceedingBrowserDownloadLimit.length > 0;
1370
1276
  // Handles a case where all files are sent by email.
1371
1277
  if (!blob && shouldShowAlert) {
1372
- this.datapointsExportSelectorService.showSendViaEmailInfoAlert(fileType, this.datapointsExceedingBrowserDownloadLimit);
1278
+ this.dataFetchingService.showSendViaEmailInfoAlert(fileType, this.datapointsExceedingBrowserDownloadLimit);
1373
1279
  return;
1374
1280
  }
1375
1281
  if (blob) {
1376
1282
  // Handles the case where some of the files are sent by email.
1377
1283
  if (shouldShowAlert) {
1378
- this.datapointsExportSelectorService.showSendViaEmailInfoAlert(fileType, this.datapointsExceedingBrowserDownloadLimit);
1284
+ this.dataFetchingService.showSendViaEmailInfoAlert(fileType, this.datapointsExceedingBrowserDownloadLimit);
1379
1285
  }
1380
1286
  this.isFullTypeOfExport
1381
1287
  ? saveAs(blob, measurementsZipFileName)
@@ -1397,7 +1303,7 @@ class DatapointsExportSelectorFileExporterComponent {
1397
1303
  async exportMeasurementFile(fileType) {
1398
1304
  const { acceptType, extension } = this.datapointsExportModalService.fileTypesConfigs[fileType];
1399
1305
  const updatedExportConfig = this.excludeDatapointsThatExceedsApiLimit(this.exportConfig);
1400
- const dataToExport = await this.datapointsExportSelectorService.fetchMeasurementDataFilesAndPairWithSourceDetails(acceptType, updatedExportConfig);
1306
+ const dataToExport = await this.dataFetchingService.fetchMeasurementDataFilesAndPairWithSourceDetails(acceptType, updatedExportConfig);
1401
1307
  const isAllUndefined = dataToExport.every(data => data === undefined);
1402
1308
  if (isAllUndefined) {
1403
1309
  return null;
@@ -1429,22 +1335,30 @@ class DatapointsExportSelectorFileExporterComponent {
1429
1335
  };
1430
1336
  return this.datapointsExportSelectorFileExporterService.getSeriesExportedDataBlob(fileType, this.dataToExport, mergedExportDetails);
1431
1337
  }
1432
- async onAggregationChange(aggregation) {
1433
- this.exportConfig.aggregation = aggregation;
1434
- if (!this.isAggregationChangedProgrammatically) {
1435
- await this.updateExportConfigAndFetchData();
1436
- this.updateDownloadButtonState();
1338
+ async onAggregationChange(newAggregation) {
1339
+ const currentAggregation = this.exportConfig.aggregation ?? AGGREGATION_VALUES.none;
1340
+ if (currentAggregation === newAggregation) {
1341
+ return;
1437
1342
  }
1343
+ this.exportConfig.aggregation = newAggregation;
1344
+ if (this.isAggregationChangedProgrammatically) {
1345
+ return;
1346
+ }
1347
+ await this.loadExportData();
1348
+ this.updateDownloadButtonState();
1438
1349
  }
1439
1350
  onDateFromChange(updatedDate) {
1440
- this.dateFromSubject.next(updatedDate);
1351
+ this.update(updatedDate, this.exportConfig.dateTo);
1441
1352
  }
1442
1353
  onDateToChange(updatedDate) {
1443
- this.dateToSubject.next(updatedDate);
1354
+ this.update(this.exportConfig.dateFrom, updatedDate);
1444
1355
  }
1445
- async updateDateAndFetchData(dateType, updatedDate) {
1446
- this.exportConfig[dateType] = updatedDate;
1447
- await this.updateExportConfigAndFetchData();
1356
+ async updateDateAndFetchData(dateType, dateInfo) {
1357
+ this.exportConfig[dateType] = dateInfo.date;
1358
+ if (!dateInfo.shouldFetchData) {
1359
+ return;
1360
+ }
1361
+ await this.loadExportData();
1448
1362
  if (this.isFullTypeOfExport) {
1449
1363
  await this.determineIfMeasurementResponseWillBeProcessedByBackend();
1450
1364
  }
@@ -1458,19 +1372,18 @@ class DatapointsExportSelectorFileExporterComponent {
1458
1372
  this.formGroup.controls.aggregation.setValue(AGGREGATION_VALUES.none);
1459
1373
  this.isAggregationChangedProgrammatically = false;
1460
1374
  this.isFullTypeOfExport = true;
1461
- await this.updateExportConfigAndFetchData();
1375
+ await this.loadExportData();
1462
1376
  await this.determineIfMeasurementResponseWillBeProcessedByBackend();
1463
1377
  return;
1464
1378
  }
1465
1379
  this.resetFullExportRelatedProperties();
1466
1380
  this.isFullTypeOfExport = false;
1467
- await this.updateExportConfigAndFetchData();
1468
- this.updateDisabledAggregationOptionsState();
1381
+ await this.loadExportData();
1382
+ this.updateDisabledAggregationOptions();
1469
1383
  this.updateDownloadButtonState();
1470
1384
  }
1471
- updateDisabledAggregationOptionsState() {
1472
- this.disabledAggregationOptions =
1473
- this.datapointsExportSelectorFileExporterService.updateDisabledStateOfAggregationOptionEntries(this.formGroup.controls.dateFrom.value, this.formGroup.controls.dateTo.value, this.disabledAggregationOptions);
1385
+ updateDisabledAggregationOptions() {
1386
+ this.disabledAggregationOptions = this.aggregationService.getDisabledAggregationOptions(this.formGroup.controls.dateFrom.value, this.formGroup.controls.dateTo.value);
1474
1387
  }
1475
1388
  createForm() {
1476
1389
  return this.formBuilder.group({
@@ -1498,8 +1411,8 @@ class DatapointsExportSelectorFileExporterComponent {
1498
1411
  const dateToSelector = this.formGroup.controls.dateTo;
1499
1412
  const updateAggregationOptions = () => {
1500
1413
  if (!this.isFullTypeOfExport) {
1501
- this.updateDisabledAggregationOptionsState();
1502
- const firstAvailableAggregationValue = this.datapointsExportSelectorFileExporterService.setToFirstAvailableAggregationOptionIfCurrentIsDisabled(aggregationControl.value, this.disabledAggregationOptions);
1414
+ this.updateDisabledAggregationOptions();
1415
+ const firstAvailableAggregationValue = this.aggregationService.determineFirstNewAvailableAggregationValue(aggregationControl.value, this.disabledAggregationOptions);
1503
1416
  if (firstAvailableAggregationValue) {
1504
1417
  aggregationControl.setValue(firstAvailableAggregationValue);
1505
1418
  }
@@ -1567,15 +1480,15 @@ class DatapointsExportSelectorFileExporterComponent {
1567
1480
  async determineIfMeasurementResponseWillBeProcessedByBackend() {
1568
1481
  this.isPreviewLoading = true;
1569
1482
  this.datapointsExceedingBrowserDownloadLimit =
1570
- await this.datapointsExportSelectorService.getDatapointsExceedingLimit(this.exportConfig);
1483
+ await this.dataFetchingService.getDatapointsExceedingLimit(this.exportConfig);
1571
1484
  const { browserDownloadableCount, emailDeliverableCount, nonRetrievableCount } = this.calculateDatapointCounts();
1572
1485
  this.hasNoExportableData =
1573
1486
  browserDownloadableCount === 0 && emailDeliverableCount === 0 && nonRetrievableCount > 0;
1574
1487
  if (this.datapointsExceedingBrowserDownloadLimit.length > 0 && !this.hasNoExportableData) {
1575
- this.limitExceededMessage = this.datapointsExportSelectorService.getLimitExceededMessage(this.hasNoExportableData, emailDeliverableCount, browserDownloadableCount, nonRetrievableCount, this.exportConfig.datapointDetails.length);
1488
+ this.limitExceededMessage = this.dataFetchingService.getLimitExceededMessage(this.hasNoExportableData, emailDeliverableCount, browserDownloadableCount, nonRetrievableCount, this.exportConfig.datapointDetails.length);
1576
1489
  }
1577
1490
  if (this.datapointsExceedingBrowserDownloadLimit.length > 0 && this.hasNoExportableData) {
1578
- this.limitExceededMessage = this.datapointsExportSelectorService.getLimitExceededMessage(this.hasNoExportableData);
1491
+ this.limitExceededMessage = this.dataFetchingService.getLimitExceededMessage(this.hasNoExportableData);
1579
1492
  }
1580
1493
  this.updateDownloadButtonState();
1581
1494
  this.isPreviewLoading = false;
@@ -1608,13 +1521,13 @@ class DatapointsExportSelectorFileExporterComponent {
1608
1521
  this.exportConfig.aggregation = this.initialAggregation;
1609
1522
  }
1610
1523
  }
1611
- async updateExportConfigAndFetchData() {
1524
+ async loadExportData() {
1612
1525
  if (this.formGroup.invalid) {
1613
1526
  return;
1614
1527
  }
1615
1528
  this.isPreviewLoading = true;
1616
1529
  this.onDownloadButtonStateChange.emit(false);
1617
- this.dataToExport = await this.datapointsExportSelectorService.fetchAndPrepareDataToExport(this.exportConfig, this.isFullTypeOfExport);
1530
+ this.dataToExport = await this.dataFetchingService.fetchAndPrepareDataToExport(this.exportConfig, this.isFullTypeOfExport);
1618
1531
  this.determineShowingPreviewOrEmptyState();
1619
1532
  }
1620
1533
  updateDownloadButtonState() {
@@ -1644,6 +1557,34 @@ class DatapointsExportSelectorFileExporterComponent {
1644
1557
  });
1645
1558
  return initialSelection;
1646
1559
  }
1560
+ /**
1561
+ * Adjusts both "from" and "to" dates when either is updated:
1562
+ * - Resets seconds to 00 even when only one date changes
1563
+ * - Prevents persisting hidden seconds ≠ 00 from initial load
1564
+ * - Triggers data fetch
1565
+ *
1566
+ * Example:
1567
+ * When user changes "from" date:
1568
+ * Input: startDate = "2024-03-26 13:30:45", endDate = "2024-03-27 15:20:45"
1569
+ * Result: startDate -> "2024-03-26 14:30:00", endDate -> "2024-03-27 15:20:00"
1570
+ *
1571
+ * When user changes "to" date:
1572
+ * Input: startDate = "2024-03-26 14:30:45", endDate = "2024-03-27 15:20:45"
1573
+ * Result: startDate -> "2024-03-26 14:30:00", endDate -> "2024-03-27 16:20:00"
1574
+ *
1575
+ * @param startDate - The "start" date to be adjusted.
1576
+ * @param endDate - The "end" date to be adjusted.
1577
+ */
1578
+ update(startDate, endDate) {
1579
+ this.dateFromSubject.next({
1580
+ date: this.dataFetchingService.adjustDate(startDate, 0),
1581
+ shouldFetchData: false
1582
+ });
1583
+ this.dateToSubject.next({
1584
+ date: this.dataFetchingService.adjustDate(endDate, 0),
1585
+ shouldFetchData: true
1586
+ });
1587
+ }
1647
1588
  triggerGainsightDownloadEvent(selectedFileExports) {
1648
1589
  const commonEventData = {
1649
1590
  action: PRODUCT_EXPERIENCE_DATAPOINTS_EXPORT_SELECTOR.ACTIONS.DOWNLOAD_STARTED,
@@ -1665,8 +1606,8 @@ class DatapointsExportSelectorFileExporterComponent {
1665
1606
  });
1666
1607
  }
1667
1608
  }
1668
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DatapointsExportSelectorFileExporterComponent, deps: [{ token: DataProcessingService }, { token: DataFetchingService }, { token: DatapointsExportSelectorFileExporterService }, { token: i3$2.FormBuilder }, { token: FILE_GENERATORS }, { token: i1.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
1669
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: DatapointsExportSelectorFileExporterComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-file-exporter", inputs: { exportConfig: "exportConfig" }, outputs: { onDownloadButtonStateChange: "onDownloadButtonStateChange" }, ngImport: i0, template: "<div class=\"p-b-16\">\n <ng-container *ngIf=\"hasPermissionToReadAnyMeasurements; else hasNoRoleToReadAnyMeasurements\">\n <div class=\"p-16 text-center separator-bottom sticky-top bg-component\">\n <p class=\"text-medium text-16\">\n {{ 'Configure export' | translate }}\n </p>\n </div>\n <div\n class=\"p-t-24 p-r-16 p-l-16 gap-8 p-b-16 flex-wrap\"\n [ngClass]=\"{ 'separator-bottom': isFullTypeOfExport }\"\n >\n <div class=\"row\">\n <div class=\"col-md-4\">\n <c8y-datapoints-export-selector-time-range\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [formGroup]=\"formGroup\"\n (onDateFromChange)=\"onDateFromChange($event)\"\n (onDateToChange)=\"onDateToChange($event)\"\n ></c8y-datapoints-export-selector-time-range>\n </div>\n <div class=\"col-md-4\">\n <c8y-datapoints-export-selector-data-scope\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [disabledAggregationOptions]=\"disabledAggregationOptions\"\n [formGroup]=\"formGroup\"\n (onAggregationChange)=\"onAggregationChange($event)\"\n (onExportTypeChange)=\"onExportTypeChange($event)\"\n ></c8y-datapoints-export-selector-data-scope>\n </div>\n <div class=\"col-md-4\">\n <c8y-datapoints-export-selector-file-types\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [dynamicFilesTypeMetadata]=\"dynamicFilesTypeMetadata\"\n [formGroup]=\"formGroup\"\n ></c8y-datapoints-export-selector-file-types>\n </div>\n </div>\n </div>\n <ng-container\n *ngIf=\"!isFullTypeOfExport && !hasFetchedDataAnyValuesToExport && !isPreviewLoading\"\n >\n <div class=\"p-t-24 p-r-16 p-l-16 p-b-16 separator-bottom d-flex\">\n <div\n class=\"alert alert-warning center-block\"\n role=\"alert\"\n data-cy=\"file-exporter--no-data-available\"\n translate\n >\n No data available.\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"datapointsExceedingBrowserDownloadLimit.length > 0\">\n <div class=\"p-t-24 p-r-16 p-l-16 p-b-16 separator-bottom d-flex\">\n <div\n [class]=\"\n hasNoExportableData\n ? 'alert alert-warning center-block'\n : 'alert alert-info center-block'\n \"\n role=\"alert\"\n [innerHTML]=\"limitExceededMessage\"\n ></div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"isFullTypeOfExport\">\n <c8y-datapoints-export-selector-preview\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [hasFetchedDataAnyValuesToExport]=\"hasFetchedDataAnyValuesToExport\"\n [isPreviewLoading]=\"isPreviewLoading\"\n [previewTableData]=\"previewTableData\"\n ></c8y-datapoints-export-selector-preview>\n </ng-container>\n </ng-container>\n <ng-template #hasNoRoleToReadAnyMeasurements>\n <div class=\"p-t-24 p-r-16 p-l-16 p-b-16 d-flex\">\n <div\n class=\"alert alert-info center-block\"\n role=\"alert\"\n translate\n >\n <p>To export data, you must meet at least one of these criteria:</p>\n <ul>\n <li>\n Have\n <b>READ permission for \"Measurements\" permission type</b>\n (either as a global role or for the specific source)\n </li>\n <li>\n Be the\n <b>owner of the source</b>\n you want to export data from\n </li>\n </ul>\n <p>Don't meet these requirements? Contact your system administrator for assistance.</p>\n </div>\n </div>\n </ng-template>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: DataPointsExportSelectorDataScopeComponent, selector: "c8y-datapoints-export-selector-data-scope", inputs: ["disabledAggregationOptions", "formGroup"], outputs: ["onAggregationChange", "onExportTypeChange"] }, { kind: "component", type: DataPointsExportSelectorFileTypesComponent, selector: "c8y-datapoints-export-selector-file-types", inputs: ["dynamicFilesTypeMetadata", "formGroup"] }, { kind: "component", type: DataPointsExportSelectorPreviewComponent, selector: "c8y-datapoints-export-selector-preview", inputs: ["hasFetchedDataAnyValuesToExport", "isPreviewLoading", "previewTableData"] }, { kind: "component", type: DataPointsExportSelectorTimeRangeComponent, selector: "c8y-datapoints-export-selector-time-range", inputs: ["formGroup"], outputs: ["onDateFromChange", "onDateToChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }] }); }
1609
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DatapointsExportSelectorFileExporterComponent, deps: [{ token: i1.AggregationService }, { token: DataProcessingService }, { token: DatapointsExportSelectorFileExporterService }, { token: DataFetchingService }, { token: i3$2.FormBuilder }, { token: FILE_GENERATORS }, { token: i1.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
1610
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: DatapointsExportSelectorFileExporterComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-file-exporter", inputs: { exportConfig: "exportConfig" }, outputs: { onDownloadButtonStateChange: "onDownloadButtonStateChange" }, ngImport: i0, template: "<div class=\"p-b-16\">\n <ng-container *ngIf=\"hasPermissionToReadAnyMeasurements; else hasNoRoleToReadAnyMeasurements\">\n <div class=\"p-16 text-center separator-bottom sticky-top bg-component\">\n <p class=\"text-medium text-16\">\n {{ 'Configure export' | translate }}\n </p>\n </div>\n <div\n class=\"p-t-24 p-r-16 p-l-16 gap-8 p-b-16 flex-wrap\"\n [ngClass]=\"{ 'separator-bottom': isFullTypeOfExport }\"\n >\n <div class=\"row\">\n <div class=\"col-md-4\">\n <c8y-datapoints-export-selector-time-range\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [formGroup]=\"formGroup\"\n (onDateFromChange)=\"onDateFromChange($event)\"\n (onDateToChange)=\"onDateToChange($event)\"\n ></c8y-datapoints-export-selector-time-range>\n </div>\n <div class=\"col-md-4\">\n <c8y-datapoints-export-selector-data-scope\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [disabledAggregationOptions]=\"disabledAggregationOptions\"\n [formGroup]=\"formGroup\"\n (onAggregationChange)=\"onAggregationChange($event)\"\n (onExportTypeChange)=\"onExportTypeChange($event)\"\n ></c8y-datapoints-export-selector-data-scope>\n </div>\n <div class=\"col-md-4\">\n <c8y-datapoints-export-selector-file-types\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [dynamicFilesTypeMetadata]=\"dynamicFilesTypeMetadata\"\n [formGroup]=\"formGroup\"\n ></c8y-datapoints-export-selector-file-types>\n </div>\n </div>\n </div>\n <ng-container\n *ngIf=\"!isFullTypeOfExport && !hasFetchedDataAnyValuesToExport && !isPreviewLoading\"\n >\n <div class=\"p-t-24 p-r-16 p-l-16 p-b-16 d-flex\">\n <div\n class=\"alert alert-warning center-block\"\n role=\"alert\"\n data-cy=\"file-exporter--no-data-available\"\n translate\n >\n No data available.\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"datapointsExceedingBrowserDownloadLimit.length > 0\">\n <div class=\"p-t-24 p-r-16 p-l-16 p-b-16 separator-bottom d-flex\">\n <div\n [class]=\"\n hasNoExportableData\n ? 'alert alert-warning center-block'\n : 'alert alert-info center-block'\n \"\n role=\"alert\"\n [innerHTML]=\"limitExceededMessage\"\n ></div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"isFullTypeOfExport\">\n <c8y-datapoints-export-selector-preview\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [hasFetchedDataAnyValuesToExport]=\"hasFetchedDataAnyValuesToExport\"\n [isPreviewLoading]=\"isPreviewLoading\"\n [previewTableData]=\"previewTableData\"\n ></c8y-datapoints-export-selector-preview>\n </ng-container>\n </ng-container>\n <ng-template #hasNoRoleToReadAnyMeasurements>\n <div class=\"p-t-24 p-r-16 p-l-16 p-b-16 d-flex\">\n <div\n class=\"alert alert-info center-block\"\n role=\"alert\"\n translate\n >\n <p>To export data, you must meet at least one of these criteria:</p>\n <ul>\n <li>\n Have\n <b>READ permission for \"Measurements\" permission type</b>\n (either as a global role or for the specific source)\n </li>\n <li>\n Be the\n <b>owner of the source</b>\n you want to export data from\n </li>\n </ul>\n <p>Don't meet these requirements? Contact your system administrator for assistance.</p>\n </div>\n </div>\n </ng-template>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: DataPointsExportSelectorDataScopeComponent, selector: "c8y-datapoints-export-selector-data-scope", inputs: ["disabledAggregationOptions", "formGroup"], outputs: ["onAggregationChange", "onExportTypeChange"] }, { kind: "component", type: DataPointsExportSelectorFileTypesComponent, selector: "c8y-datapoints-export-selector-file-types", inputs: ["dynamicFilesTypeMetadata", "formGroup"] }, { kind: "component", type: DataPointsExportSelectorPreviewComponent, selector: "c8y-datapoints-export-selector-preview", inputs: ["hasFetchedDataAnyValuesToExport", "isPreviewLoading", "previewTableData"] }, { kind: "component", type: DataPointsExportSelectorTimeRangeComponent, selector: "c8y-datapoints-export-selector-time-range", inputs: ["formGroup"], outputs: ["onDateFromChange", "onDateToChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }] }); }
1670
1611
  }
1671
1612
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DatapointsExportSelectorFileExporterComponent, decorators: [{
1672
1613
  type: Component,
@@ -1676,10 +1617,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImpor
1676
1617
  DataPointsExportSelectorFileTypesComponent,
1677
1618
  DataPointsExportSelectorPreviewComponent,
1678
1619
  DataPointsExportSelectorTimeRangeComponent,
1679
- KeyValuePipe,
1680
1620
  ReactiveFormsModule
1681
- ], template: "<div class=\"p-b-16\">\n <ng-container *ngIf=\"hasPermissionToReadAnyMeasurements; else hasNoRoleToReadAnyMeasurements\">\n <div class=\"p-16 text-center separator-bottom sticky-top bg-component\">\n <p class=\"text-medium text-16\">\n {{ 'Configure export' | translate }}\n </p>\n </div>\n <div\n class=\"p-t-24 p-r-16 p-l-16 gap-8 p-b-16 flex-wrap\"\n [ngClass]=\"{ 'separator-bottom': isFullTypeOfExport }\"\n >\n <div class=\"row\">\n <div class=\"col-md-4\">\n <c8y-datapoints-export-selector-time-range\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [formGroup]=\"formGroup\"\n (onDateFromChange)=\"onDateFromChange($event)\"\n (onDateToChange)=\"onDateToChange($event)\"\n ></c8y-datapoints-export-selector-time-range>\n </div>\n <div class=\"col-md-4\">\n <c8y-datapoints-export-selector-data-scope\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [disabledAggregationOptions]=\"disabledAggregationOptions\"\n [formGroup]=\"formGroup\"\n (onAggregationChange)=\"onAggregationChange($event)\"\n (onExportTypeChange)=\"onExportTypeChange($event)\"\n ></c8y-datapoints-export-selector-data-scope>\n </div>\n <div class=\"col-md-4\">\n <c8y-datapoints-export-selector-file-types\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [dynamicFilesTypeMetadata]=\"dynamicFilesTypeMetadata\"\n [formGroup]=\"formGroup\"\n ></c8y-datapoints-export-selector-file-types>\n </div>\n </div>\n </div>\n <ng-container\n *ngIf=\"!isFullTypeOfExport && !hasFetchedDataAnyValuesToExport && !isPreviewLoading\"\n >\n <div class=\"p-t-24 p-r-16 p-l-16 p-b-16 separator-bottom d-flex\">\n <div\n class=\"alert alert-warning center-block\"\n role=\"alert\"\n data-cy=\"file-exporter--no-data-available\"\n translate\n >\n No data available.\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"datapointsExceedingBrowserDownloadLimit.length > 0\">\n <div class=\"p-t-24 p-r-16 p-l-16 p-b-16 separator-bottom d-flex\">\n <div\n [class]=\"\n hasNoExportableData\n ? 'alert alert-warning center-block'\n : 'alert alert-info center-block'\n \"\n role=\"alert\"\n [innerHTML]=\"limitExceededMessage\"\n ></div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"isFullTypeOfExport\">\n <c8y-datapoints-export-selector-preview\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [hasFetchedDataAnyValuesToExport]=\"hasFetchedDataAnyValuesToExport\"\n [isPreviewLoading]=\"isPreviewLoading\"\n [previewTableData]=\"previewTableData\"\n ></c8y-datapoints-export-selector-preview>\n </ng-container>\n </ng-container>\n <ng-template #hasNoRoleToReadAnyMeasurements>\n <div class=\"p-t-24 p-r-16 p-l-16 p-b-16 d-flex\">\n <div\n class=\"alert alert-info center-block\"\n role=\"alert\"\n translate\n >\n <p>To export data, you must meet at least one of these criteria:</p>\n <ul>\n <li>\n Have\n <b>READ permission for \"Measurements\" permission type</b>\n (either as a global role or for the specific source)\n </li>\n <li>\n Be the\n <b>owner of the source</b>\n you want to export data from\n </li>\n </ul>\n <p>Don't meet these requirements? Contact your system administrator for assistance.</p>\n </div>\n </div>\n </ng-template>\n</div>\n" }]
1682
- }], ctorParameters: () => [{ type: DataProcessingService }, { type: DataFetchingService }, { type: DatapointsExportSelectorFileExporterService }, { type: i3$2.FormBuilder }, { type: undefined, decorators: [{
1621
+ ], template: "<div class=\"p-b-16\">\n <ng-container *ngIf=\"hasPermissionToReadAnyMeasurements; else hasNoRoleToReadAnyMeasurements\">\n <div class=\"p-16 text-center separator-bottom sticky-top bg-component\">\n <p class=\"text-medium text-16\">\n {{ 'Configure export' | translate }}\n </p>\n </div>\n <div\n class=\"p-t-24 p-r-16 p-l-16 gap-8 p-b-16 flex-wrap\"\n [ngClass]=\"{ 'separator-bottom': isFullTypeOfExport }\"\n >\n <div class=\"row\">\n <div class=\"col-md-4\">\n <c8y-datapoints-export-selector-time-range\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [formGroup]=\"formGroup\"\n (onDateFromChange)=\"onDateFromChange($event)\"\n (onDateToChange)=\"onDateToChange($event)\"\n ></c8y-datapoints-export-selector-time-range>\n </div>\n <div class=\"col-md-4\">\n <c8y-datapoints-export-selector-data-scope\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [disabledAggregationOptions]=\"disabledAggregationOptions\"\n [formGroup]=\"formGroup\"\n (onAggregationChange)=\"onAggregationChange($event)\"\n (onExportTypeChange)=\"onExportTypeChange($event)\"\n ></c8y-datapoints-export-selector-data-scope>\n </div>\n <div class=\"col-md-4\">\n <c8y-datapoints-export-selector-file-types\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [dynamicFilesTypeMetadata]=\"dynamicFilesTypeMetadata\"\n [formGroup]=\"formGroup\"\n ></c8y-datapoints-export-selector-file-types>\n </div>\n </div>\n </div>\n <ng-container\n *ngIf=\"!isFullTypeOfExport && !hasFetchedDataAnyValuesToExport && !isPreviewLoading\"\n >\n <div class=\"p-t-24 p-r-16 p-l-16 p-b-16 d-flex\">\n <div\n class=\"alert alert-warning center-block\"\n role=\"alert\"\n data-cy=\"file-exporter--no-data-available\"\n translate\n >\n No data available.\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"datapointsExceedingBrowserDownloadLimit.length > 0\">\n <div class=\"p-t-24 p-r-16 p-l-16 p-b-16 separator-bottom d-flex\">\n <div\n [class]=\"\n hasNoExportableData\n ? 'alert alert-warning center-block'\n : 'alert alert-info center-block'\n \"\n role=\"alert\"\n [innerHTML]=\"limitExceededMessage\"\n ></div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"isFullTypeOfExport\">\n <c8y-datapoints-export-selector-preview\n *ngIf=\"this.hasPermissionToReadAnyMeasurements\"\n [hasFetchedDataAnyValuesToExport]=\"hasFetchedDataAnyValuesToExport\"\n [isPreviewLoading]=\"isPreviewLoading\"\n [previewTableData]=\"previewTableData\"\n ></c8y-datapoints-export-selector-preview>\n </ng-container>\n </ng-container>\n <ng-template #hasNoRoleToReadAnyMeasurements>\n <div class=\"p-t-24 p-r-16 p-l-16 p-b-16 d-flex\">\n <div\n class=\"alert alert-info center-block\"\n role=\"alert\"\n translate\n >\n <p>To export data, you must meet at least one of these criteria:</p>\n <ul>\n <li>\n Have\n <b>READ permission for \"Measurements\" permission type</b>\n (either as a global role or for the specific source)\n </li>\n <li>\n Be the\n <b>owner of the source</b>\n you want to export data from\n </li>\n </ul>\n <p>Don't meet these requirements? Contact your system administrator for assistance.</p>\n </div>\n </div>\n </ng-template>\n</div>\n" }]
1622
+ }], ctorParameters: () => [{ type: i1.AggregationService }, { type: DataProcessingService }, { type: DatapointsExportSelectorFileExporterService }, { type: DataFetchingService }, { type: i3$2.FormBuilder }, { type: undefined, decorators: [{
1683
1623
  type: Inject,
1684
1624
  args: [FILE_GENERATORS]
1685
1625
  }] }, { type: i1.GainsightService }], propDecorators: { exportConfig: [{
@@ -1954,11 +1894,11 @@ class DatapointsExportSelectorComponent {
1954
1894
  this.isOpen.emit(await modalRef.result);
1955
1895
  }
1956
1896
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DatapointsExportSelectorComponent, deps: [{ token: i1$1.BsModalService }, { token: i1.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
1957
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: DatapointsExportSelectorComponent, isStandalone: true, selector: "c8y-datapoints-export-selector", inputs: { exportConfig: "exportConfig" }, outputs: { isOpen: "isOpen" }, ngImport: i0, template: "<div class=\"input-group p-t-4 p-b-4 max-width-fit m-l-auto\">\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Generate export' | translate\"\n tooltip=\"{{ 'Generate export' | translate }}\"\n container=\"body\"\n type=\"button\"\n (click)=\"openExportModal()\"\n [adaptivePosition]=\"false\"\n [disabled]=\"!exportConfig\"\n [delay]=\"500\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"data-export\"\n ></i>\n </button>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i3$3.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"] }] }); }
1897
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.9", type: DatapointsExportSelectorComponent, isStandalone: true, selector: "c8y-datapoints-export-selector", inputs: { exportConfig: "exportConfig" }, outputs: { isOpen: "isOpen" }, ngImport: i0, template: "<div class=\"d-flex p-t-4 p-b-4\">\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Generate export' | translate\"\n tooltip=\"{{ 'Generate export' | translate }}\"\n container=\"body\"\n type=\"button\"\n (click)=\"openExportModal()\"\n [adaptivePosition]=\"false\"\n [disabled]=\"!exportConfig\"\n [delay]=\"500\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"data-export\"\n ></i>\n </button>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i3$3.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"] }] }); }
1958
1898
  }
1959
1899
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImport: i0, type: DatapointsExportSelectorComponent, decorators: [{
1960
1900
  type: Component,
1961
- args: [{ selector: 'c8y-datapoints-export-selector', standalone: true, imports: [CommonModule, TooltipModule], template: "<div class=\"input-group p-t-4 p-b-4 max-width-fit m-l-auto\">\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Generate export' | translate\"\n tooltip=\"{{ 'Generate export' | translate }}\"\n container=\"body\"\n type=\"button\"\n (click)=\"openExportModal()\"\n [adaptivePosition]=\"false\"\n [disabled]=\"!exportConfig\"\n [delay]=\"500\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"data-export\"\n ></i>\n </button>\n </div>\n</div>\n" }]
1901
+ args: [{ selector: 'c8y-datapoints-export-selector', standalone: true, imports: [CommonModule, TooltipModule], template: "<div class=\"d-flex p-t-4 p-b-4\">\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Generate export' | translate\"\n tooltip=\"{{ 'Generate export' | translate }}\"\n container=\"body\"\n type=\"button\"\n (click)=\"openExportModal()\"\n [adaptivePosition]=\"false\"\n [disabled]=\"!exportConfig\"\n [delay]=\"500\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"data-export\"\n ></i>\n </button>\n </div>\n</div>\n" }]
1962
1902
  }], ctorParameters: () => [{ type: i1$1.BsModalService }, { type: i1.GainsightService }], propDecorators: { exportConfig: [{
1963
1903
  type: Input
1964
1904
  }], isOpen: [{
@@ -1969,5 +1909,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.9", ngImpor
1969
1909
  * Generated bundle index. Do not edit.
1970
1910
  */
1971
1911
 
1972
- export { CSVGeneratorAdapter, DataFetchingService, DataPointsExportSelectorDataScopeComponent, DataPointsExportSelectorFileTypesComponent, DataPointsExportSelectorPreviewComponent, DataPointsExportSelectorTimeRangeComponent, DataProcessingService, DatapointsExportSelectorComponent, DatapointsExportSelectorFileExporterComponent, DatapointsExportSelectorFileExporterService, DatapointsExportSelectorModalComponent, EXPORT_MODE_LABELS, EXPORT_MODE_VALUES, ExcelDataTransformer, ExcelGeneratorAdapter, FILE_COMPRESSION_TYPES_VALUES, FILE_GENERATORS, HAS_ERROR, MEASUREMENTS_PREVIEW_ITEMS_LIMIT, PRODUCT_EXPERIENCE_DATAPOINTS_EXPORT_SELECTOR, SERIES_DATA_MERGED_FILE_NAME, TIME_RANGE_INTERVAL_UNITS_VALUES, UtilsService, dateRangeValidator };
1912
+ export { CSVGeneratorAdapter, DataFetchingService, DataPointsExportSelectorDataScopeComponent, DataPointsExportSelectorFileTypesComponent, DataPointsExportSelectorPreviewComponent, DataPointsExportSelectorTimeRangeComponent, DataProcessingService, DatapointsExportSelectorComponent, DatapointsExportSelectorFileExporterComponent, DatapointsExportSelectorFileExporterService, DatapointsExportSelectorModalComponent, EXPORT_MODE_LABELS, EXPORT_MODE_VALUES, ExcelDataTransformer, ExcelGeneratorAdapter, FILE_COMPRESSION_TYPES_VALUES, FILE_GENERATORS, HAS_ERROR, MEASUREMENTS_PREVIEW_ITEMS_LIMIT, PRODUCT_EXPERIENCE_DATAPOINTS_EXPORT_SELECTOR, SERIES_DATA_MERGED_FILE_NAME, UtilsService, dateRangeValidator };
1973
1913
  //# sourceMappingURL=c8y-ngx-components-datapoints-export-selector.mjs.map