@c8y/ngx-components 1023.63.1 → 1023.64.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/datapoints-export-selector/index.d.ts +213 -48
  2. package/datapoints-export-selector/index.d.ts.map +1 -1
  3. package/echart/index.d.ts +1 -0
  4. package/echart/index.d.ts.map +1 -1
  5. package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs +568 -138
  6. package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs.map +1 -1
  7. package/fesm2022/c8y-ngx-components-echart.mjs +6 -3
  8. package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
  9. package/fesm2022/c8y-ngx-components-global-context.mjs +36 -1
  10. package/fesm2022/c8y-ngx-components-global-context.mjs.map +1 -1
  11. package/fesm2022/c8y-ngx-components-widgets-definitions-datapoints-list.mjs +80 -0
  12. package/fesm2022/c8y-ngx-components-widgets-definitions-datapoints-list.mjs.map +1 -0
  13. package/fesm2022/c8y-ngx-components-widgets-definitions.mjs +1 -0
  14. package/fesm2022/c8y-ngx-components-widgets-definitions.mjs.map +1 -1
  15. package/fesm2022/c8y-ngx-components-widgets-exports.mjs +8 -1
  16. package/fesm2022/c8y-ngx-components-widgets-exports.mjs.map +1 -1
  17. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-list.mjs +702 -0
  18. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-list.mjs.map +1 -0
  19. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-table.mjs +3 -110
  20. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-table.mjs.map +1 -1
  21. package/fesm2022/c8y-ngx-components.mjs +116 -6
  22. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  23. package/global-context/index.d.ts +2 -0
  24. package/global-context/index.d.ts.map +1 -1
  25. package/index.d.ts +59 -2
  26. package/index.d.ts.map +1 -1
  27. package/locales/de.po +94 -23
  28. package/locales/es.po +96 -23
  29. package/locales/fr.po +95 -23
  30. package/locales/ja_JP.po +82 -23
  31. package/locales/ko.po +97 -23
  32. package/locales/locales.pot +62 -11
  33. package/locales/nl.po +94 -23
  34. package/locales/pl.po +98 -23
  35. package/locales/pt_BR.po +97 -23
  36. package/locales/zh_CN.po +98 -23
  37. package/locales/zh_TW.po +98 -23
  38. package/package.json +1 -1
  39. package/widgets/cockpit-exports/index.d.ts +6 -0
  40. package/widgets/cockpit-exports/index.d.ts.map +1 -1
  41. package/widgets/definitions/datapoints-list/index.d.ts +51 -0
  42. package/widgets/definitions/datapoints-list/index.d.ts.map +1 -0
  43. package/widgets/definitions/index.d.ts +1 -0
  44. package/widgets/definitions/index.d.ts.map +1 -1
  45. package/widgets/device-management-exports/index.d.ts +6 -0
  46. package/widgets/device-management-exports/index.d.ts.map +1 -1
  47. package/widgets/exports/index.d.ts +8 -1
  48. package/widgets/exports/index.d.ts.map +1 -1
  49. package/widgets/implementations/alarms/index.d.ts +2 -0
  50. package/widgets/implementations/alarms/index.d.ts.map +1 -1
  51. package/widgets/implementations/datapoints-list/index.d.ts +286 -0
  52. package/widgets/implementations/datapoints-list/index.d.ts.map +1 -0
  53. package/widgets/implementations/datapoints-table/index.d.ts +5 -66
  54. package/widgets/implementations/datapoints-table/index.d.ts.map +1 -1
@@ -1,25 +1,25 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, Input, Component, EventEmitter, Output, InjectionToken, Inject, HostListener, ViewChild } from '@angular/core';
2
+ import { Injectable, input, output, ChangeDetectionStrategy, Component, InjectionToken, Inject, computed, viewChild } from '@angular/core';
3
3
  import * as i2 from '@c8y/client';
4
- import { gettext } from '@c8y/ngx-components/gettext';
5
4
  import * as i1 from '@c8y/ngx-components';
6
- import { AGGREGATION_VALUES, CoreModule, CommonModule, ModalModule } from '@c8y/ngx-components';
5
+ import { AGGREGATION_VALUES, CoreModule, ModalModule, IconDirective, C8yTranslatePipe, CommonModule } from '@c8y/ngx-components';
6
+ import { gettext } from '@c8y/ngx-components/gettext';
7
7
  import * as i3 from '@ngx-translate/core';
8
8
  import JSZip from 'jszip';
9
9
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
10
- import * as i3$2 from '@angular/forms';
10
+ import * as i2$1 from '@angular/forms';
11
11
  import { FormsModule, FormControl, ReactiveFormsModule } from '@angular/forms';
12
12
  import saveAs from 'file-saver';
13
13
  import { Subject, debounceTime, merge, takeUntil as takeUntil$1 } from 'rxjs';
14
- import { A11yModule } from '@angular/cdk/a11y';
14
+ import { AGGREGATION_LABELS, AGGREGATION_VALUES_ARR } from '@c8y/ngx-components/global-context';
15
15
  import * as i3$1 from 'ngx-bootstrap/popover';
16
16
  import { PopoverModule } from 'ngx-bootstrap/popover';
17
- import * as i2$1 from '@angular/common';
18
- import { AGGREGATION_LABELS, AGGREGATION_VALUES_ARR } from '@c8y/ngx-components/global-context';
17
+ import * as i3$2 from '@angular/common';
19
18
  import { skip, takeUntil } from 'rxjs/operators';
20
19
  import { isNil, isEmpty, isNumber } from 'lodash-es';
20
+ import { A11yModule } from '@angular/cdk/a11y';
21
21
  import * as i1$1 from 'ngx-bootstrap/modal';
22
- import * as i4 from 'ngx-bootstrap/tooltip';
22
+ import * as i3$3 from 'ngx-bootstrap/tooltip';
23
23
  import { TooltipModule } from 'ngx-bootstrap/tooltip';
24
24
 
25
25
  const HAS_ERROR = 'has-error';
@@ -464,6 +464,68 @@ class DataFetchingService {
464
464
  }
465
465
  return seriesData;
466
466
  }
467
+ /**
468
+ * Fetches snapshot data for list-type exports
469
+ * Gets the latest measurement for each datapoint within the date range
470
+ * @param exportConfig - The export configuration with list type
471
+ * @returns Promise with array of ListExportDatapoint objects
472
+ */
473
+ async fetchAndPrepareListExportData(exportConfig) {
474
+ const { datapointDetails, dateFrom, dateTo } = exportConfig;
475
+ const dataPromises = datapointDetails.map(async (detail) => {
476
+ try {
477
+ // Fetch the latest measurement within the date range
478
+ const filter = {
479
+ dateFrom,
480
+ dateTo,
481
+ source: detail.source,
482
+ valueFragmentSeries: detail.valueFragmentSeries,
483
+ valueFragmentType: detail.valueFragmentType,
484
+ pageSize: 1, // Only get the most recent measurement
485
+ revert: true // Sort by newest first
486
+ };
487
+ const { data } = await this.measurementService.list(filter);
488
+ const measurement = data && data.length > 0 ? data[0] : null;
489
+ // Extract value and unit from measurement
490
+ let current = null;
491
+ let unit;
492
+ if (measurement) {
493
+ const fragment = measurement[detail.valueFragmentType];
494
+ if (fragment && fragment[detail.valueFragmentSeries]) {
495
+ const seriesData = fragment[detail.valueFragmentSeries];
496
+ current = seriesData.value != null ? Number(seriesData.value) : null;
497
+ unit = seriesData.unit;
498
+ }
499
+ }
500
+ // Calculate derived values using target from detail
501
+ const target = detail.target;
502
+ const diff = current !== null && current !== undefined && target !== null && target !== undefined
503
+ ? current - target
504
+ : null;
505
+ const diffPercent = target !== null && target !== undefined && diff !== null ? (diff / target) * 100 : null;
506
+ return {
507
+ ...detail,
508
+ label: detail.label || `${detail.valueFragmentType}.${detail.valueFragmentSeries}`,
509
+ target: target ?? null,
510
+ current,
511
+ diff,
512
+ diffPercent,
513
+ unit
514
+ };
515
+ }
516
+ catch (error) {
517
+ return {
518
+ ...detail,
519
+ label: detail.label || `${detail.valueFragmentType}.${detail.valueFragmentSeries}`,
520
+ target: detail.target ?? null,
521
+ current: null,
522
+ diff: null,
523
+ diffPercent: null
524
+ };
525
+ }
526
+ });
527
+ return Promise.all(dataPromises);
528
+ }
467
529
  /**
468
530
  * Fetches and prepares measurement data for preview.
469
531
  *
@@ -570,6 +632,24 @@ class DatapointsExportSelectorFileExporterService {
570
632
  this.cachedRawExportSeriesData = null;
571
633
  this.cachedFlatteredAndSortedSeriesExportData = null;
572
634
  }
635
+ /**
636
+ * Generates a blob for list-type exports (snapshot data)
637
+ * @param fileType - The type of file to generate (csv or excel)
638
+ * @param listData - Array of datapoints with current values
639
+ * @param columns - Column configuration for export
640
+ * @param dateRange - Date range for the export header
641
+ * @returns Promise with Blob or null on error
642
+ */
643
+ async getListExportedDataBlob(fileType, listData, columns, dateRange) {
644
+ try {
645
+ const blob = await this.datapointsExportSelectorDataProcessingService.generateListExport(fileType, listData, columns, dateRange);
646
+ return blob;
647
+ }
648
+ catch (error) {
649
+ this.showZipCreationErrorAlert();
650
+ return null;
651
+ }
652
+ }
573
653
  showZipCreationErrorAlert() {
574
654
  const alertMessage = this.translateService.instant(gettext('Could not create zip file.'));
575
655
  this.alertService.danger(alertMessage);
@@ -631,28 +711,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
631
711
  }]
632
712
  }], ctorParameters: () => [{ type: i1.AlertService }, { type: DataProcessingService }, { type: i3.TranslateService }] });
633
713
 
634
- class DataPointsExportSelectorPreviewComponent {
635
- constructor() {
636
- this.MEASUREMENTS_PREVIEW_ITEMS_LIMIT = MEASUREMENTS_PREVIEW_ITEMS_LIMIT;
637
- }
638
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DataPointsExportSelectorPreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
639
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: DataPointsExportSelectorPreviewComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-preview", inputs: { hasFetchedDataAnyValuesToExport: "hasFetchedDataAnyValuesToExport", isPreviewLoading: "isPreviewLoading", previewTableData: "previewTableData" }, ngImport: i0, template: "<div class=\"p-t-16 p-l-16 p-r-16 m-b-0\">\n <div class=\"d-flex a-i-center\">\n <label\n class=\"m-b-0 d-flex a-i-center gap-4\"\n [title]=\"'Preview`of exported file`' | translate\"\n >\n {{ 'Preview`of exported file`' | translate }}\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"popoverPreviewTemplate\"\n placement=\"right\"\n triggers=\"focus\"\n data-cy=\"preview--help\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n <ng-template #popoverPreviewTemplate>\n <span translate>\n <p>The preview shows the structure of the raw file from a single source.</p>\n <p>If no data is available, only the column headers are visible.</p>\n <p>\n The preview is limited to\n <b>{{ MEASUREMENTS_PREVIEW_ITEMS_LIMIT }}</b>\n records.\n </p>\n </span>\n </ng-template>\n </label>\n </div>\n <div\n class=\"table-responsive\"\n style=\"min-height: 275px\"\n >\n <table class=\"table\">\n <thead>\n <tr>\n <th>{{ 'Time' | translate }}</th>\n <th>{{ 'Source' | translate }}</th>\n <th>{{ 'Device name' | translate }}</th>\n <th>\n {{ 'Fragment and series' | translate }}\n </th>\n <th>{{ 'Value' | translate }}</th>\n <th>{{ 'Unit' | translate }}</th>\n </tr>\n </thead>\n <ng-container *ngIf=\"hasFetchedDataAnyValuesToExport || isPreviewLoading; else emptyState\">\n <ng-container *ngIf=\"!isPreviewLoading; else loading\">\n <tbody>\n <tr *ngFor=\"let row of previewTableData\">\n <td>{{ row.time }}</td>\n <td>{{ row.source }}</td>\n <td>{{ row.device_name }}</td>\n <td>\n {{ row.fragment_series }}\n </td>\n <td>{{ row.value }}</td>\n <td>{{ row.unit }}</td>\n </tr>\n </tbody>\n </ng-container>\n </ng-container>\n <ng-template #emptyState>\n <tbody>\n <tr>\n <td colspan=\"8\">\n <div class=\"d-col a-i-center\">\n <c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No data available.' | translate\"\n [horizontal]=\"true\"\n data-cy=\"datapoints-table-list--empty-state\"\n ></c8y-ui-empty-state>\n </div>\n </td>\n </tr>\n </tbody>\n </ng-template>\n <ng-template #loading>\n <tbody>\n <tr>\n <td colspan=\"8\">\n <c8y-loading></c8y-loading>\n </td>\n </tr>\n </tbody>\n </ng-template>\n </table>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: A11yModule }, { kind: "ngmodule", type: CoreModule }, { kind: "component", type: i1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { 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: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i1.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { 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"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }] }); }
640
- }
641
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DataPointsExportSelectorPreviewComponent, decorators: [{
642
- type: Component,
643
- args: [{ selector: 'c8y-datapoints-export-selector-preview', standalone: true, imports: [A11yModule, CoreModule, PopoverModule], template: "<div class=\"p-t-16 p-l-16 p-r-16 m-b-0\">\n <div class=\"d-flex a-i-center\">\n <label\n class=\"m-b-0 d-flex a-i-center gap-4\"\n [title]=\"'Preview`of exported file`' | translate\"\n >\n {{ 'Preview`of exported file`' | translate }}\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"popoverPreviewTemplate\"\n placement=\"right\"\n triggers=\"focus\"\n data-cy=\"preview--help\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"true\"\n ></button>\n <ng-template #popoverPreviewTemplate>\n <span translate>\n <p>The preview shows the structure of the raw file from a single source.</p>\n <p>If no data is available, only the column headers are visible.</p>\n <p>\n The preview is limited to\n <b>{{ MEASUREMENTS_PREVIEW_ITEMS_LIMIT }}</b>\n records.\n </p>\n </span>\n </ng-template>\n </label>\n </div>\n <div\n class=\"table-responsive\"\n style=\"min-height: 275px\"\n >\n <table class=\"table\">\n <thead>\n <tr>\n <th>{{ 'Time' | translate }}</th>\n <th>{{ 'Source' | translate }}</th>\n <th>{{ 'Device name' | translate }}</th>\n <th>\n {{ 'Fragment and series' | translate }}\n </th>\n <th>{{ 'Value' | translate }}</th>\n <th>{{ 'Unit' | translate }}</th>\n </tr>\n </thead>\n <ng-container *ngIf=\"hasFetchedDataAnyValuesToExport || isPreviewLoading; else emptyState\">\n <ng-container *ngIf=\"!isPreviewLoading; else loading\">\n <tbody>\n <tr *ngFor=\"let row of previewTableData\">\n <td>{{ row.time }}</td>\n <td>{{ row.source }}</td>\n <td>{{ row.device_name }}</td>\n <td>\n {{ row.fragment_series }}\n </td>\n <td>{{ row.value }}</td>\n <td>{{ row.unit }}</td>\n </tr>\n </tbody>\n </ng-container>\n </ng-container>\n <ng-template #emptyState>\n <tbody>\n <tr>\n <td colspan=\"8\">\n <div class=\"d-col a-i-center\">\n <c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No data available.' | translate\"\n [horizontal]=\"true\"\n data-cy=\"datapoints-table-list--empty-state\"\n ></c8y-ui-empty-state>\n </div>\n </td>\n </tr>\n </tbody>\n </ng-template>\n <ng-template #loading>\n <tbody>\n <tr>\n <td colspan=\"8\">\n <c8y-loading></c8y-loading>\n </td>\n </tr>\n </tbody>\n </ng-template>\n </table>\n </div>\n</div>\n" }]
644
- }], propDecorators: { hasFetchedDataAnyValuesToExport: [{
645
- type: Input
646
- }], isPreviewLoading: [{
647
- type: Input
648
- }], previewTableData: [{
649
- type: Input
650
- }] } });
651
-
652
714
  class DataPointsExportSelectorDataScopeComponent {
653
715
  constructor() {
654
- this.onAggregationChange = new EventEmitter();
655
- this.onExportTypeChange = new EventEmitter();
716
+ this.disabledAggregationOptions = input.required(...(ngDevMode ? [{ debugName: "disabledAggregationOptions" }] : []));
717
+ this.formGroup = input.required(...(ngDevMode ? [{ debugName: "formGroup" }] : []));
718
+ this.onAggregationChange = output();
719
+ this.onExportTypeChange = output();
656
720
  this.AGGREGATION_LABELS = AGGREGATION_LABELS;
657
721
  this.AGGREGATION_VALUES_ARR = AGGREGATION_VALUES_ARR;
658
722
  this.EXPORT_MODE_LABELS = EXPORT_MODE_LABELS;
@@ -665,41 +729,31 @@ class DataPointsExportSelectorDataScopeComponent {
665
729
  this.onExportTypeChange.emit(exportType);
666
730
  }
667
731
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DataPointsExportSelectorDataScopeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
668
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", 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 data-cy=\"data-scope--help\"\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 data-cy=\"data-scope--export-selector\"\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 data-cy=\"data-scope--aggregation-selector\"\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: "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"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }] }); }
732
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: DataPointsExportSelectorDataScopeComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-data-scope", inputs: { disabledAggregationOptions: { classPropertyName: "disabledAggregationOptions", publicName: "disabledAggregationOptions", isSignal: true, isRequired: true, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: true, transformFunction: null } }, 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 data-cy=\"data-scope--help\"\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 data-cy=\"data-scope--export-selector\"\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 @for (exportModeValue of EXPORT_MODE_VALUES_ARR; track exportModeValue) {\n <option [ngValue]=\"exportModeValue\">\n {{ EXPORT_MODE_LABELS[exportModeValue] | translate }}\n </option>\n }\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 data-cy=\"data-scope--aggregation-selector\"\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 @for (aggregationValue of AGGREGATION_VALUES_ARR; track aggregationValue) {\n <option\n [ngValue]=\"aggregationValue\"\n [disabled]=\"disabledAggregationOptions()[aggregationValue]\"\n >\n {{ AGGREGATION_LABELS[aggregationValue] | translate }}\n </option>\n }\n </select>\n </div>\n </c8y-form-group>\n</fieldset>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i2$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.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: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.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"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
669
733
  }
670
734
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DataPointsExportSelectorDataScopeComponent, decorators: [{
671
735
  type: Component,
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 data-cy=\"data-scope--help\"\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 data-cy=\"data-scope--export-selector\"\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 data-cy=\"data-scope--aggregation-selector\"\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" }]
673
- }], propDecorators: { disabledAggregationOptions: [{
674
- type: Input
675
- }], formGroup: [{
676
- type: Input
677
- }], onAggregationChange: [{
678
- type: Output
679
- }], onExportTypeChange: [{
680
- type: Output
681
- }] } });
736
+ args: [{ selector: 'c8y-datapoints-export-selector-data-scope', imports: [CoreModule, FormsModule, PopoverModule], changeDetection: ChangeDetectionStrategy.OnPush, 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 data-cy=\"data-scope--help\"\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 data-cy=\"data-scope--export-selector\"\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 @for (exportModeValue of EXPORT_MODE_VALUES_ARR; track exportModeValue) {\n <option [ngValue]=\"exportModeValue\">\n {{ EXPORT_MODE_LABELS[exportModeValue] | translate }}\n </option>\n }\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 data-cy=\"data-scope--aggregation-selector\"\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 @for (aggregationValue of AGGREGATION_VALUES_ARR; track aggregationValue) {\n <option\n [ngValue]=\"aggregationValue\"\n [disabled]=\"disabledAggregationOptions()[aggregationValue]\"\n >\n {{ AGGREGATION_LABELS[aggregationValue] | translate }}\n </option>\n }\n </select>\n </div>\n </c8y-form-group>\n</fieldset>\n" }]
737
+ }], propDecorators: { disabledAggregationOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledAggregationOptions", required: true }] }], formGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "formGroup", required: true }] }], onAggregationChange: [{ type: i0.Output, args: ["onAggregationChange"] }], onExportTypeChange: [{ type: i0.Output, args: ["onExportTypeChange"] }] } });
682
738
 
683
739
  class DataPointsExportSelectorFileTypesComponent {
684
740
  constructor() {
685
- this.dynamicFilesTypeMetadata = {};
741
+ this.dynamicFilesTypeMetadata = input({}, ...(ngDevMode ? [{ debugName: "dynamicFilesTypeMetadata" }] : []));
742
+ this.formGroup = input.required(...(ngDevMode ? [{ debugName: "formGroup" }] : []));
686
743
  }
687
744
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DataPointsExportSelectorFileTypesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
688
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: DataPointsExportSelectorFileTypesComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-file-types", inputs: { dynamicFilesTypeMetadata: "dynamicFilesTypeMetadata", formGroup: "formGroup" }, ngImport: i0, template: "<fieldset class=\"c8y-fieldset\">\n <legend class=\"d-flex a-i-center\">{{ 'File types' | translate }}</legend>\n <div [formGroup]=\"formGroup\">\n <div formGroupName=\"fileTypes\">\n <c8y-form-group\n class=\"m-b-8\"\n *ngFor=\"let item of dynamicFilesTypeMetadata | keyvalue\"\n >\n <label\n class=\"c8y-checkbox m-t-0\"\n title=\"{{ item.value.title }}\"\n >\n <input\n type=\"checkbox\"\n formControlName=\"{{ item.key }}\"\n />\n <span></span>\n <i\n class=\"m-l-8 m-r-4\"\n c8yIcon=\"{{ item.value.icon }}\"\n ></i>\n <span>{{ item.value.label | translate }}</span>\n </label>\n </c8y-form-group>\n </div>\n </div>\n</fieldset>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3$2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { 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: i1.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { 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: "directive", type: i3$2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "ngmodule", type: FormsModule }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i2$1.KeyValuePipe, name: "keyvalue" }] }); }
745
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: DataPointsExportSelectorFileTypesComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-file-types", inputs: { dynamicFilesTypeMetadata: { classPropertyName: "dynamicFilesTypeMetadata", publicName: "dynamicFilesTypeMetadata", isSignal: true, isRequired: false, transformFunction: null }, formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<fieldset class=\"c8y-fieldset\">\n <legend class=\"d-flex a-i-center\">{{ 'File types' | translate }}</legend>\n <div [formGroup]=\"formGroup()\">\n <div formGroupName=\"fileTypes\">\n @for (item of dynamicFilesTypeMetadata() | keyvalue; track item.key) {\n <c8y-form-group class=\"m-b-8\">\n <label\n class=\"c8y-checkbox m-t-0\"\n title=\"{{ item.value.title }}\"\n >\n <input\n type=\"checkbox\"\n formControlName=\"{{ item.key }}\"\n />\n <span></span>\n <i\n class=\"m-l-8 m-r-4\"\n c8yIcon=\"{{ item.value.icon }}\"\n ></i>\n <span>{{ item.value.label | translate }}</span>\n </label>\n </c8y-form-group>\n }\n </div>\n </div>\n</fieldset>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2$1.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: i1.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i2$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i2$1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "ngmodule", type: FormsModule }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i3$2.KeyValuePipe, name: "keyvalue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
689
746
  }
690
747
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DataPointsExportSelectorFileTypesComponent, decorators: [{
691
748
  type: Component,
692
- args: [{ selector: 'c8y-datapoints-export-selector-file-types', standalone: true, imports: [CoreModule, FormsModule], template: "<fieldset class=\"c8y-fieldset\">\n <legend class=\"d-flex a-i-center\">{{ 'File types' | translate }}</legend>\n <div [formGroup]=\"formGroup\">\n <div formGroupName=\"fileTypes\">\n <c8y-form-group\n class=\"m-b-8\"\n *ngFor=\"let item of dynamicFilesTypeMetadata | keyvalue\"\n >\n <label\n class=\"c8y-checkbox m-t-0\"\n title=\"{{ item.value.title }}\"\n >\n <input\n type=\"checkbox\"\n formControlName=\"{{ item.key }}\"\n />\n <span></span>\n <i\n class=\"m-l-8 m-r-4\"\n c8yIcon=\"{{ item.value.icon }}\"\n ></i>\n <span>{{ item.value.label | translate }}</span>\n </label>\n </c8y-form-group>\n </div>\n </div>\n</fieldset>\n" }]
693
- }], propDecorators: { dynamicFilesTypeMetadata: [{
694
- type: Input
695
- }], formGroup: [{
696
- type: Input
697
- }] } });
749
+ args: [{ selector: 'c8y-datapoints-export-selector-file-types', imports: [CoreModule, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<fieldset class=\"c8y-fieldset\">\n <legend class=\"d-flex a-i-center\">{{ 'File types' | translate }}</legend>\n <div [formGroup]=\"formGroup()\">\n <div formGroupName=\"fileTypes\">\n @for (item of dynamicFilesTypeMetadata() | keyvalue; track item.key) {\n <c8y-form-group class=\"m-b-8\">\n <label\n class=\"c8y-checkbox m-t-0\"\n title=\"{{ item.value.title }}\"\n >\n <input\n type=\"checkbox\"\n formControlName=\"{{ item.key }}\"\n />\n <span></span>\n <i\n class=\"m-l-8 m-r-4\"\n c8yIcon=\"{{ item.value.icon }}\"\n ></i>\n <span>{{ item.value.label | translate }}</span>\n </label>\n </c8y-form-group>\n }\n </div>\n </div>\n</fieldset>\n" }]
750
+ }], propDecorators: { dynamicFilesTypeMetadata: [{ type: i0.Input, args: [{ isSignal: true, alias: "dynamicFilesTypeMetadata", required: false }] }], formGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "formGroup", required: true }] }] } });
698
751
 
699
752
  class DataPointsExportSelectorTimeRangeComponent {
700
753
  constructor() {
701
- this.onDateFromChange = new EventEmitter();
702
- this.onDateToChange = new EventEmitter();
754
+ this.formGroup = input.required(...(ngDevMode ? [{ debugName: "formGroup" }] : []));
755
+ this.onDateFromChange = output();
756
+ this.onDateToChange = output();
703
757
  this.destroy$ = new Subject();
704
758
  this.DATE_FROM = 'dateFrom';
705
759
  this.DATE_TO = 'dateTo';
@@ -712,14 +766,15 @@ class DataPointsExportSelectorTimeRangeComponent {
712
766
  this.TO_DATE = gettext('To`date`');
713
767
  }
714
768
  ngOnInit() {
715
- if (this.formGroup?.controls?.dateFrom) {
716
- this.formGroup.controls.dateFrom.valueChanges
769
+ const fg = this.formGroup();
770
+ if (fg?.controls?.dateFrom) {
771
+ fg.controls.dateFrom.valueChanges
717
772
  // Skip the first value emitted by the observable to avoid overriding the initial value while form is being created
718
773
  .pipe(skip(1), takeUntil(this.destroy$))
719
774
  .subscribe((updatedDate) => this.onDateFromChange.emit(updatedDate));
720
775
  }
721
- if (this.formGroup?.controls?.dateTo) {
722
- this.formGroup.controls.dateTo.valueChanges
776
+ if (fg?.controls?.dateTo) {
777
+ fg.controls.dateTo.valueChanges
723
778
  // Skip the first value emitted by the observable to avoid overriding the initial value while form is being created
724
779
  .pipe(skip(1), takeUntil(this.destroy$))
725
780
  .subscribe((updatedDate) => this.onDateToChange.emit(updatedDate));
@@ -730,18 +785,12 @@ class DataPointsExportSelectorTimeRangeComponent {
730
785
  this.destroy$.complete();
731
786
  }
732
787
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DataPointsExportSelectorTimeRangeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
733
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: DataPointsExportSelectorTimeRangeComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-time-range", inputs: { formGroup: "formGroup" }, outputs: { onDateFromChange: "onDateFromChange", onDateToChange: "onDateToChange" }, ngImport: i0, template: "<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Time range' | translate }}</legend>\n <c8y-form-group\n class=\"m-b-8\"\n [ngClass]=\"formGroup.controls.dateFrom.errors ? HAS_ERROR : ''\"\n >\n <label\n [title]=\"FROM_DATE | translate\"\n [for]=\"DATE_FROM\"\n >\n {{ FROM_DATE | translate }}\n </label>\n <div>\n <c8y-date-time-picker\n id=\"DATE_FROM\"\n [maxDate]=\"formGroup.value.dateTo\"\n [placeholder]=\"FROM_DATE | translate\"\n [formControl]=\"formGroup.controls.dateFrom\"\n [ngClass]=\"formGroup.controls.dateFrom.errors ? HAS_ERROR : ''\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"formGroup.controls.dateFrom.errors\">\n <c8y-message\n name=\"dateAfterRangeMax\"\n [text]=\"THIS_DATE_IS_AFTER_THE_LAST_ALLOWED_DATE | translate\"\n ></c8y-message>\n <c8y-message\n name=\"INVALID_DATE_TIME\"\n [text]=\"THIS_DATE_IS_INVALID | translate\"\n ></c8y-message>\n </c8y-messages>\n </div>\n </c8y-form-group>\n <c8y-form-group\n class=\"m-b-8\"\n [ngClass]=\"formGroup.controls.dateTo.errors ? HAS_ERROR : ''\"\n >\n <label\n [title]=\"TO_DATE | translate\"\n [for]=\"DATE_TO\"\n >\n {{ TO_DATE | translate }}\n </label>\n <div>\n <c8y-date-time-picker\n id=\"DATE_TO\"\n [minDate]=\"formGroup.value.dateFrom\"\n [placeholder]=\"TO_DATE | translate\"\n [formControl]=\"formGroup.controls.dateTo\"\n [ngClass]=\"formGroup.controls.dateTo.errors ? HAS_ERROR : ''\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"formGroup.controls.dateTo.errors\">\n <c8y-message\n name=\"dateBeforeRangeMin\"\n [text]=\"THIS_DATE_IS_BEFORE_THE_EARLIEST_ALLOWED_DATE | translate\"\n ></c8y-message>\n <c8y-message\n name=\"INVALID_DATE_TIME\"\n [text]=\"THIS_DATE_IS_INVALID | translate\"\n ></c8y-message>\n </c8y-messages>\n </div>\n </c8y-form-group>\n</fieldset>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: i1.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i1.MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: i1.MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: i3$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: i1.DateTimePickerComponent, selector: "c8y-date-time-picker", inputs: ["minDate", "maxDate", "placeholder", "dateInputFormat", "adaptivePosition", "size", "dateType", "config"], outputs: ["onDateSelected"] }, { kind: "ngmodule", type: FormsModule }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }] }); }
788
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.18", type: DataPointsExportSelectorTimeRangeComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-time-range", inputs: { formGroup: { classPropertyName: "formGroup", publicName: "formGroup", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { onDateFromChange: "onDateFromChange", onDateToChange: "onDateToChange" }, ngImport: i0, template: "<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Time range' | translate }}</legend>\n <c8y-form-group\n class=\"m-b-8 d-flex gap-4 a-i-center\"\n [class]=\"formGroup().controls.dateFrom.errors ? HAS_ERROR : ''\"\n >\n <label\n class=\"m-b-0\"\n style=\"min-width: 120px\"\n [title]=\"FROM_DATE | translate\"\n [for]=\"DATE_FROM\"\n >\n {{ FROM_DATE | translate }}\n </label>\n <div>\n <c8y-date-time-picker\n [class]=\"formGroup().controls.dateFrom.errors ? HAS_ERROR : ''\"\n id=\"DATE_FROM\"\n [maxDate]=\"formGroup().controls.dateTo.value ?? ''\"\n [placeholder]=\"FROM_DATE | translate\"\n [formControl]=\"formGroup().controls.dateFrom\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"formGroup().controls.dateFrom.errors ?? {}\">\n <c8y-message\n name=\"dateAfterRangeMax\"\n [text]=\"THIS_DATE_IS_AFTER_THE_LAST_ALLOWED_DATE | translate\"\n ></c8y-message>\n <c8y-message\n name=\"INVALID_DATE_TIME\"\n [text]=\"THIS_DATE_IS_INVALID | translate\"\n ></c8y-message>\n </c8y-messages>\n </div>\n </c8y-form-group>\n <c8y-form-group\n class=\"m-b-8 d-flex gap-4 a-i-center\"\n [class]=\"formGroup().controls.dateTo.errors ? HAS_ERROR : ''\"\n >\n <label\n class=\"m-b-0\"\n style=\"min-width: 120px\"\n [title]=\"TO_DATE | translate\"\n [for]=\"DATE_TO\"\n >\n {{ TO_DATE | translate }}\n </label>\n <div>\n <c8y-date-time-picker\n [class]=\"formGroup().controls.dateTo.errors ? HAS_ERROR : ''\"\n id=\"DATE_TO\"\n [minDate]=\"formGroup().controls.dateFrom.value ?? ''\"\n [placeholder]=\"TO_DATE | translate\"\n [formControl]=\"formGroup().controls.dateTo\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"formGroup().controls.dateTo.errors ?? {}\">\n <c8y-message\n name=\"dateBeforeRangeMin\"\n [text]=\"THIS_DATE_IS_BEFORE_THE_EARLIEST_ALLOWED_DATE | translate\"\n ></c8y-message>\n <c8y-message\n name=\"INVALID_DATE_TIME\"\n [text]=\"THIS_DATE_IS_INVALID | translate\"\n ></c8y-message>\n </c8y-messages>\n </div>\n </c8y-form-group>\n</fieldset>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i2$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: i1.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i1.MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: i1.MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: i2$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: i1.DateTimePickerComponent, selector: "c8y-date-time-picker", inputs: ["minDate", "maxDate", "placeholder", "dateInputFormat", "adaptivePosition", "size", "dateType", "config"], outputs: ["onDateSelected"] }, { kind: "ngmodule", type: FormsModule }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
734
789
  }
735
790
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DataPointsExportSelectorTimeRangeComponent, decorators: [{
736
791
  type: Component,
737
- args: [{ selector: 'c8y-datapoints-export-selector-time-range', standalone: true, imports: [CoreModule, FormsModule], template: "<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Time range' | translate }}</legend>\n <c8y-form-group\n class=\"m-b-8\"\n [ngClass]=\"formGroup.controls.dateFrom.errors ? HAS_ERROR : ''\"\n >\n <label\n [title]=\"FROM_DATE | translate\"\n [for]=\"DATE_FROM\"\n >\n {{ FROM_DATE | translate }}\n </label>\n <div>\n <c8y-date-time-picker\n id=\"DATE_FROM\"\n [maxDate]=\"formGroup.value.dateTo\"\n [placeholder]=\"FROM_DATE | translate\"\n [formControl]=\"formGroup.controls.dateFrom\"\n [ngClass]=\"formGroup.controls.dateFrom.errors ? HAS_ERROR : ''\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"formGroup.controls.dateFrom.errors\">\n <c8y-message\n name=\"dateAfterRangeMax\"\n [text]=\"THIS_DATE_IS_AFTER_THE_LAST_ALLOWED_DATE | translate\"\n ></c8y-message>\n <c8y-message\n name=\"INVALID_DATE_TIME\"\n [text]=\"THIS_DATE_IS_INVALID | translate\"\n ></c8y-message>\n </c8y-messages>\n </div>\n </c8y-form-group>\n <c8y-form-group\n class=\"m-b-8\"\n [ngClass]=\"formGroup.controls.dateTo.errors ? HAS_ERROR : ''\"\n >\n <label\n [title]=\"TO_DATE | translate\"\n [for]=\"DATE_TO\"\n >\n {{ TO_DATE | translate }}\n </label>\n <div>\n <c8y-date-time-picker\n id=\"DATE_TO\"\n [minDate]=\"formGroup.value.dateFrom\"\n [placeholder]=\"TO_DATE | translate\"\n [formControl]=\"formGroup.controls.dateTo\"\n [ngClass]=\"formGroup.controls.dateTo.errors ? HAS_ERROR : ''\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"formGroup.controls.dateTo.errors\">\n <c8y-message\n name=\"dateBeforeRangeMin\"\n [text]=\"THIS_DATE_IS_BEFORE_THE_EARLIEST_ALLOWED_DATE | translate\"\n ></c8y-message>\n <c8y-message\n name=\"INVALID_DATE_TIME\"\n [text]=\"THIS_DATE_IS_INVALID | translate\"\n ></c8y-message>\n </c8y-messages>\n </div>\n </c8y-form-group>\n</fieldset>\n" }]
738
- }], propDecorators: { formGroup: [{
739
- type: Input
740
- }], onDateFromChange: [{
741
- type: Output
742
- }], onDateToChange: [{
743
- type: Output
744
- }] } });
792
+ args: [{ selector: 'c8y-datapoints-export-selector-time-range', imports: [CoreModule, FormsModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Time range' | translate }}</legend>\n <c8y-form-group\n class=\"m-b-8 d-flex gap-4 a-i-center\"\n [class]=\"formGroup().controls.dateFrom.errors ? HAS_ERROR : ''\"\n >\n <label\n class=\"m-b-0\"\n style=\"min-width: 120px\"\n [title]=\"FROM_DATE | translate\"\n [for]=\"DATE_FROM\"\n >\n {{ FROM_DATE | translate }}\n </label>\n <div>\n <c8y-date-time-picker\n [class]=\"formGroup().controls.dateFrom.errors ? HAS_ERROR : ''\"\n id=\"DATE_FROM\"\n [maxDate]=\"formGroup().controls.dateTo.value ?? ''\"\n [placeholder]=\"FROM_DATE | translate\"\n [formControl]=\"formGroup().controls.dateFrom\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"formGroup().controls.dateFrom.errors ?? {}\">\n <c8y-message\n name=\"dateAfterRangeMax\"\n [text]=\"THIS_DATE_IS_AFTER_THE_LAST_ALLOWED_DATE | translate\"\n ></c8y-message>\n <c8y-message\n name=\"INVALID_DATE_TIME\"\n [text]=\"THIS_DATE_IS_INVALID | translate\"\n ></c8y-message>\n </c8y-messages>\n </div>\n </c8y-form-group>\n <c8y-form-group\n class=\"m-b-8 d-flex gap-4 a-i-center\"\n [class]=\"formGroup().controls.dateTo.errors ? HAS_ERROR : ''\"\n >\n <label\n class=\"m-b-0\"\n style=\"min-width: 120px\"\n [title]=\"TO_DATE | translate\"\n [for]=\"DATE_TO\"\n >\n {{ TO_DATE | translate }}\n </label>\n <div>\n <c8y-date-time-picker\n [class]=\"formGroup().controls.dateTo.errors ? HAS_ERROR : ''\"\n id=\"DATE_TO\"\n [minDate]=\"formGroup().controls.dateFrom.value ?? ''\"\n [placeholder]=\"TO_DATE | translate\"\n [formControl]=\"formGroup().controls.dateTo\"\n ></c8y-date-time-picker>\n <c8y-messages [show]=\"formGroup().controls.dateTo.errors ?? {}\">\n <c8y-message\n name=\"dateBeforeRangeMin\"\n [text]=\"THIS_DATE_IS_BEFORE_THE_EARLIEST_ALLOWED_DATE | translate\"\n ></c8y-message>\n <c8y-message\n name=\"INVALID_DATE_TIME\"\n [text]=\"THIS_DATE_IS_INVALID | translate\"\n ></c8y-message>\n </c8y-messages>\n </div>\n </c8y-form-group>\n</fieldset>\n" }]
793
+ }], propDecorators: { formGroup: [{ type: i0.Input, args: [{ isSignal: true, alias: "formGroup", required: true }] }], onDateFromChange: [{ type: i0.Output, args: ["onDateFromChange"] }], onDateToChange: [{ type: i0.Output, args: ["onDateToChange"] }] } });
745
794
 
746
795
  class CSVDataTransformer {
747
796
  transformToMergedFormat(exportData) {
@@ -819,6 +868,41 @@ class CSVGenerator {
819
868
  const csvContent = rows.map(row => row.join(',')).join('\n');
820
869
  return instance.fileCreator.createFile(csvContent, CSVGenerator.getMimeType());
821
870
  }
871
+ /**
872
+ * Converts list-type datapoints to CSV format
873
+ * @param listData - Array of datapoints with current values
874
+ * @param columns - Column configuration specifying which columns to include and their order
875
+ * @returns Promise with CSV Blob
876
+ */
877
+ static async convertToListCSV(listData, columns) {
878
+ const instance = CSVGenerator.getInstance();
879
+ const sortedColumns = columns.sort((a, b) => a.order - b.order);
880
+ const headers = sortedColumns.map(col => col.label);
881
+ const columnMapping = {
882
+ kpi: 'label',
883
+ target: 'target',
884
+ current: 'current',
885
+ diff: 'diff',
886
+ diffPercentage: 'diffPercent',
887
+ asset: 'deviceName'
888
+ };
889
+ const dataRows = listData.map(datapoint => {
890
+ return sortedColumns.map(col => {
891
+ const propKey = columnMapping[col.id];
892
+ const value = datapoint[propKey];
893
+ if (value === null || value === undefined) {
894
+ return '';
895
+ }
896
+ if (typeof value === 'number') {
897
+ return value.toFixed(2);
898
+ }
899
+ return String(value);
900
+ });
901
+ });
902
+ const allRows = [headers, ...dataRows];
903
+ const csvContent = allRows.map(row => row.join(',')).join('\n');
904
+ return instance.fileCreator.createFile(csvContent, CSVGenerator.getMimeType());
905
+ }
822
906
  static getInstance() {
823
907
  if (!CSVGenerator.instance) {
824
908
  CSVGenerator.instance = new CSVGenerator();
@@ -856,12 +940,18 @@ const CSVGeneratorAdapter = {
856
940
  getFileExtension: CSVGenerator.getFileExtension.bind(CSVGenerator),
857
941
  getMimeType: CSVGenerator.getMimeType.bind(CSVGenerator),
858
942
  generateMerged: CSVGenerator.convertToMergedCSV.bind(CSVGenerator),
943
+ generateList: CSVGenerator.convertToListCSV.bind(CSVGenerator),
859
944
  getType: CSVGenerator.getType.bind(CSVGenerator),
860
945
  getTitle: CSVGenerator.getTitle.bind(CSVGenerator),
861
946
  getZipName: CSVGenerator.getZipName.bind(CSVGenerator),
862
947
  getAcceptType: CSVGenerator.getAcceptType.bind(CSVGenerator)
863
948
  };
864
949
 
950
+ var csvGenerator = /*#__PURE__*/Object.freeze({
951
+ __proto__: null,
952
+ CSVGeneratorAdapter: CSVGeneratorAdapter
953
+ });
954
+
865
955
  // Utility functions
866
956
  class XmlUtils {
867
957
  static escapeXml(unsafe) {
@@ -1080,6 +1170,40 @@ class ExcelGenerator {
1080
1170
  ];
1081
1171
  return instance.createExcelFile(rows, mergedExportDetails);
1082
1172
  }
1173
+ /**
1174
+ * Converts list-type datapoints to Excel format
1175
+ * @param listData - Array of datapoints with current values
1176
+ * @param columns - Column configuration specifying which columns to include and their order
1177
+ * @returns Promise with Excel Blob
1178
+ */
1179
+ static async convertToListExcel(listData, columns) {
1180
+ const instance = ExcelGenerator.getInstance();
1181
+ const sortedColumns = columns.sort((a, b) => a.order - b.order);
1182
+ const headers = sortedColumns.map(col => col.label);
1183
+ const columnMapping = {
1184
+ kpi: 'label',
1185
+ target: 'target',
1186
+ current: 'current',
1187
+ diff: 'diff',
1188
+ diffPercentage: 'diffPercent',
1189
+ asset: 'deviceName'
1190
+ };
1191
+ const dataRows = listData.map(datapoint => {
1192
+ return sortedColumns.map(col => {
1193
+ const propKey = columnMapping[col.id];
1194
+ const value = datapoint[propKey];
1195
+ if (value === null || value === undefined) {
1196
+ return '';
1197
+ }
1198
+ if (typeof value === 'number') {
1199
+ return value.toFixed(2);
1200
+ }
1201
+ return String(value);
1202
+ });
1203
+ });
1204
+ const allRows = [headers, ...dataRows];
1205
+ return instance.createExcelFile(allRows);
1206
+ }
1083
1207
  static getInstance() {
1084
1208
  if (!ExcelGenerator.instance) {
1085
1209
  ExcelGenerator.instance = new ExcelGenerator();
@@ -1134,12 +1258,19 @@ const ExcelGeneratorAdapter = {
1134
1258
  getFileExtension: ExcelGenerator.getFileExtension.bind(ExcelGenerator),
1135
1259
  getMimeType: ExcelGenerator.getMimeType.bind(ExcelGenerator),
1136
1260
  generateMerged: ExcelGenerator.convertToMergedExcel.bind(ExcelGenerator),
1261
+ generateList: ExcelGenerator.convertToListExcel.bind(ExcelGenerator),
1137
1262
  getType: ExcelGenerator.getType.bind(ExcelGenerator),
1138
1263
  getTitle: ExcelGenerator.getTitle.bind(ExcelGenerator),
1139
1264
  getZipName: ExcelGenerator.getZipName.bind(ExcelGenerator),
1140
1265
  getAcceptType: ExcelGenerator.getAcceptType.bind(ExcelGenerator)
1141
1266
  };
1142
1267
 
1268
+ var excelGenerator = /*#__PURE__*/Object.freeze({
1269
+ __proto__: null,
1270
+ ExcelDataTransformer: ExcelDataTransformer,
1271
+ ExcelGeneratorAdapter: ExcelGeneratorAdapter
1272
+ });
1273
+
1143
1274
  const FILE_GENERATORS = new InjectionToken('FILE_GENERATORS', {
1144
1275
  providedIn: 'root',
1145
1276
  factory: () => [ExcelGeneratorAdapter, CSVGeneratorAdapter]
@@ -1165,15 +1296,28 @@ const dateRangeValidator = (control) => {
1165
1296
  return null;
1166
1297
  };
1167
1298
  class DatapointsExportSelectorFileExporterComponent {
1168
- constructor(aggregationService, datapointsExportModalService, datapointsExportSelectorFileExporterService, dataFetchingService, formBuilder, generators, gainsightService) {
1299
+ get isPreviewLoading() {
1300
+ return this._isPreviewLoading;
1301
+ }
1302
+ set isPreviewLoading(value) {
1303
+ if (this._isPreviewLoading !== value) {
1304
+ this._isPreviewLoading = value;
1305
+ this.previewLoadingChange.emit(value);
1306
+ }
1307
+ }
1308
+ constructor(aggregationService, cdr, datapointsExportModalService, datapointsExportSelectorFileExporterService, dataFetchingService, formBuilder, generators, gainsightService) {
1169
1309
  this.aggregationService = aggregationService;
1310
+ this.cdr = cdr;
1170
1311
  this.datapointsExportModalService = datapointsExportModalService;
1171
1312
  this.datapointsExportSelectorFileExporterService = datapointsExportSelectorFileExporterService;
1172
1313
  this.dataFetchingService = dataFetchingService;
1173
1314
  this.formBuilder = formBuilder;
1174
1315
  this.generators = generators;
1175
1316
  this.gainsightService = gainsightService;
1176
- this.onDownloadButtonStateChange = new EventEmitter();
1317
+ this.exportConfig = input.required(...(ngDevMode ? [{ debugName: "exportConfig" }] : []));
1318
+ this.onDownloadButtonStateChange = output();
1319
+ this.previewAvailabilityChange = output();
1320
+ this.previewLoadingChange = output();
1177
1321
  /**
1178
1322
  * Represents aggregation selector options that are disabled.
1179
1323
  * This state is determined based on the current date range.
@@ -1190,13 +1334,24 @@ class DatapointsExportSelectorFileExporterComponent {
1190
1334
  */
1191
1335
  this.hasFetchedDataAnyValuesToExport = false;
1192
1336
  this.hasPermissionToReadAnyMeasurements = false;
1193
- this.isPreviewLoading = true;
1337
+ this.isCheckingPermissions = true;
1338
+ this._isPreviewLoading = true;
1194
1339
  /**
1195
1340
  * Indicates whether the full or compact type of export is selected.
1196
1341
  * Full type of export is based on measurement API data.
1197
1342
  * Compact type of export is based on series API data.
1198
1343
  */
1199
1344
  this.isFullTypeOfExport = false;
1345
+ /**
1346
+ * Indicates whether list-type export is selected.
1347
+ * List type of export is a snapshot of current datapoints values.
1348
+ */
1349
+ this.isListTypeOfExport = false;
1350
+ /**
1351
+ * Indicates whether the Data Scope component should be visible.
1352
+ * Hidden for list-type exports, visible for table-type exports.
1353
+ */
1354
+ this.isDataScopeVisible = true;
1200
1355
  /**
1201
1356
  * Indicates whether the aggregation value was changed programmatically.
1202
1357
  * It prevents a case where fetching may be triggered twice when export type is changed.
@@ -1236,25 +1391,36 @@ class DatapointsExportSelectorFileExporterComponent {
1236
1391
  });
1237
1392
  }
1238
1393
  async ngOnInit() {
1239
- const sourcesPermittedToRead = await this.dataFetchingService.getSourcesWithPermissionsToRead(this.exportConfig.datapointDetails);
1394
+ this.isListTypeOfExport = this.exportConfig().exportType === 'latestWithDetails';
1395
+ this.isDataScopeVisible = !this.isListTypeOfExport;
1396
+ this.emitPreviewAvailability();
1397
+ const sourcesPermittedToRead = await this.dataFetchingService.getSourcesWithPermissionsToRead(this.exportConfig().datapointDetails);
1398
+ this.isCheckingPermissions = false;
1399
+ this.cdr.markForCheck();
1240
1400
  if (sourcesPermittedToRead.length === 0) {
1241
1401
  return;
1242
1402
  }
1243
- if (sourcesPermittedToRead.length !== this.exportConfig.datapointDetails.length) {
1244
- this.exportConfig.datapointDetails = this.exportConfig.datapointDetails.filter(dataPoint => sourcesPermittedToRead.includes(String(dataPoint.source)));
1403
+ if (sourcesPermittedToRead.length !== this.exportConfig().datapointDetails.length) {
1404
+ this.exportConfig().datapointDetails = this.exportConfig().datapointDetails.filter(dataPoint => sourcesPermittedToRead.includes(String(dataPoint.source)));
1245
1405
  }
1246
1406
  this.hasPermissionToReadAnyMeasurements = true;
1247
1407
  this.storeInitialChangeableConfig();
1248
1408
  this.fileTypeSelectionState = this.getInitialSelection(this.dynamicFilesTypeMetadata, [0]);
1249
1409
  this.formGroup = this.createForm();
1250
- this.dataToExport = await this.dataFetchingService.fetchAndPrepareDataToExport(this.exportConfig, this.isFullTypeOfExport);
1410
+ this.isPreviewLoading = true;
1411
+ if (this.isListTypeOfExport) {
1412
+ await this.loadListExportData();
1413
+ }
1414
+ else {
1415
+ await this.loadTableExportData();
1416
+ this.handleExportModeChanges();
1417
+ }
1251
1418
  this.handleDateSelectorChanges();
1252
- this.determineShowingPreviewOrEmptyState();
1253
- this.handleExportModeChanges();
1254
1419
  this.handleFileTypeSelectionChanges();
1255
1420
  this.handleFormValidationChanges();
1256
1421
  this.updateFileTypeControl();
1257
1422
  this.updateDisabledAggregationOptions();
1423
+ this.cdr.markForCheck();
1258
1424
  }
1259
1425
  ngOnDestroy() {
1260
1426
  this.destroy$.next();
@@ -1278,6 +1444,9 @@ class DatapointsExportSelectorFileExporterComponent {
1278
1444
  return fileExports.filter(f => this.fileTypeSelectionState[f.fileType] === true);
1279
1445
  }
1280
1446
  async exportFile(fileType) {
1447
+ if (this.isListTypeOfExport) {
1448
+ return await this.exportListFile(fileType);
1449
+ }
1281
1450
  return this.isFullTypeOfExport
1282
1451
  ? await this.exportMeasurementFile(fileType)
1283
1452
  : await this.exportSeriesFile(fileType);
@@ -1296,9 +1465,13 @@ class DatapointsExportSelectorFileExporterComponent {
1296
1465
  if (shouldShowAlert) {
1297
1466
  this.dataFetchingService.showSendViaEmailInfoAlert(fileType, this.datapointsExceedingBrowserDownloadLimit);
1298
1467
  }
1299
- this.isFullTypeOfExport
1300
- ? saveAs(blob, measurementsZipFileName)
1301
- : saveAs(blob, blob[SERIES_DATA_MERGED_FILE_NAME]);
1468
+ // Full export uses zip filename, compact and list exports use blob's attached filename
1469
+ if (this.isFullTypeOfExport) {
1470
+ saveAs(blob, measurementsZipFileName);
1471
+ }
1472
+ else {
1473
+ saveAs(blob, blob[SERIES_DATA_MERGED_FILE_NAME]);
1474
+ }
1302
1475
  }
1303
1476
  }
1304
1477
  /**
@@ -1315,7 +1488,7 @@ class DatapointsExportSelectorFileExporterComponent {
1315
1488
  */
1316
1489
  async exportMeasurementFile(fileType) {
1317
1490
  const { acceptType, extension } = this.datapointsExportModalService.fileTypesConfigs[fileType];
1318
- const updatedExportConfig = this.excludeDatapointsThatExceedsApiLimit(this.exportConfig);
1491
+ const updatedExportConfig = this.excludeDatapointsThatExceedsApiLimit(this.exportConfig());
1319
1492
  const dataToExport = await this.dataFetchingService.fetchMeasurementDataFilesAndPairWithSourceDetails(acceptType, updatedExportConfig);
1320
1493
  const isAllUndefined = dataToExport.every(data => data === undefined);
1321
1494
  if (isAllUndefined) {
@@ -1342,32 +1515,47 @@ class DatapointsExportSelectorFileExporterComponent {
1342
1515
  */
1343
1516
  async exportSeriesFile(fileType) {
1344
1517
  const mergedExportDetails = {
1345
- aggregation: this.exportConfig.aggregation,
1346
- dateFrom: this.exportConfig.dateFrom,
1347
- dateTo: this.exportConfig.dateTo
1518
+ aggregation: this.exportConfig().aggregation,
1519
+ dateFrom: this.exportConfig().dateFrom,
1520
+ dateTo: this.exportConfig().dateTo
1348
1521
  };
1349
1522
  return this.datapointsExportSelectorFileExporterService.getSeriesExportedDataBlob(fileType, this.dataToExport, mergedExportDetails);
1350
1523
  }
1524
+ /**
1525
+ * Exports list-type data (snapshot of datapoints with current values)
1526
+ * @param fileType - The type of file to export (csv or excel)
1527
+ * @returns Promise resolving to a Blob with the exported file
1528
+ */
1529
+ async exportListFile(fileType) {
1530
+ const listData = await this.dataFetchingService.fetchAndPrepareListExportData(this.exportConfig());
1531
+ const columns = this.exportConfig().columns || [];
1532
+ const dateRange = {
1533
+ dateFrom: this.exportConfig().dateFrom,
1534
+ dateTo: this.exportConfig().dateTo
1535
+ };
1536
+ return this.datapointsExportSelectorFileExporterService.getListExportedDataBlob(fileType, listData, columns, dateRange);
1537
+ }
1351
1538
  async onAggregationChange(newAggregation) {
1352
- const currentAggregation = this.exportConfig.aggregation ?? AGGREGATION_VALUES.none;
1539
+ const currentAggregation = this.exportConfig().aggregation ?? AGGREGATION_VALUES.none;
1353
1540
  if (currentAggregation === newAggregation) {
1354
1541
  return;
1355
1542
  }
1356
- this.exportConfig.aggregation = newAggregation;
1543
+ this.exportConfig().aggregation = newAggregation;
1357
1544
  if (this.isAggregationChangedProgrammatically) {
1358
1545
  return;
1359
1546
  }
1360
1547
  await this.loadExportData();
1361
1548
  this.updateDownloadButtonState();
1549
+ this.cdr.markForCheck();
1362
1550
  }
1363
1551
  onDateFromChange(updatedDate) {
1364
- this.update(updatedDate, this.exportConfig.dateTo);
1552
+ this.update(updatedDate, this.exportConfig().dateTo);
1365
1553
  }
1366
1554
  onDateToChange(updatedDate) {
1367
- this.update(this.exportConfig.dateFrom, updatedDate);
1555
+ this.update(this.exportConfig().dateFrom, updatedDate);
1368
1556
  }
1369
1557
  async updateDateAndFetchData(dateType, dateInfo) {
1370
- this.exportConfig[dateType] = dateInfo.date;
1558
+ this.exportConfig()[dateType] = dateInfo.date;
1371
1559
  if (!dateInfo.shouldFetchData) {
1372
1560
  return;
1373
1561
  }
@@ -1378,6 +1566,7 @@ class DatapointsExportSelectorFileExporterComponent {
1378
1566
  else {
1379
1567
  this.updateDownloadButtonState();
1380
1568
  }
1569
+ this.cdr.markForCheck();
1381
1570
  }
1382
1571
  async onExportTypeChange(exportType) {
1383
1572
  if (exportType === EXPORT_MODE_VALUES.full) {
@@ -1385,24 +1574,39 @@ class DatapointsExportSelectorFileExporterComponent {
1385
1574
  this.formGroup.controls.aggregation.setValue(AGGREGATION_VALUES.none);
1386
1575
  this.isAggregationChangedProgrammatically = false;
1387
1576
  this.isFullTypeOfExport = true;
1577
+ this.emitPreviewAvailability();
1388
1578
  await this.loadExportData();
1389
1579
  await this.determineIfMeasurementResponseWillBeProcessedByBackend();
1580
+ this.cdr.markForCheck();
1390
1581
  return;
1391
1582
  }
1392
1583
  this.resetFullExportRelatedProperties();
1393
1584
  this.isFullTypeOfExport = false;
1585
+ this.emitPreviewAvailability();
1394
1586
  await this.loadExportData();
1395
1587
  this.updateDisabledAggregationOptions();
1396
1588
  this.updateDownloadButtonState();
1589
+ this.cdr.markForCheck();
1590
+ }
1591
+ /**
1592
+ * Prepares preview for list-type exports
1593
+ * @param listData - Array of list datapoints
1594
+ */
1595
+ prepareListPreview(listData) {
1596
+ const columns = this.exportConfig().columns || [];
1597
+ this.previewTableData = this.datapointsExportModalService.transformListDataToPreview(listData, columns);
1598
+ this.isPreviewLoading = false;
1397
1599
  }
1398
1600
  updateDisabledAggregationOptions() {
1399
1601
  this.disabledAggregationOptions = this.aggregationService.getDisabledAggregationOptions(this.formGroup.controls.dateFrom.value, this.formGroup.controls.dateTo.value);
1400
1602
  }
1401
1603
  createForm() {
1402
1604
  return this.formBuilder.group({
1403
- dateFrom: new FormControl(this.exportConfig.dateFrom),
1404
- dateTo: new FormControl(this.exportConfig.dateTo),
1405
- aggregation: new FormControl(this.exportConfig.aggregation ? this.exportConfig.aggregation : AGGREGATION_VALUES.none),
1605
+ dateFrom: new FormControl(this.exportConfig().dateFrom),
1606
+ dateTo: new FormControl(this.exportConfig().dateTo),
1607
+ aggregation: new FormControl(this.exportConfig().aggregation
1608
+ ? this.exportConfig().aggregation
1609
+ : AGGREGATION_VALUES.none),
1406
1610
  exportMode: new FormControl(EXPORT_MODE_VALUES.compact),
1407
1611
  fileTypes: this.formBuilder.group(this.generators.reduce((a, c) => {
1408
1612
  a[c.getType()] = false;
@@ -1493,12 +1697,12 @@ class DatapointsExportSelectorFileExporterComponent {
1493
1697
  async determineIfMeasurementResponseWillBeProcessedByBackend() {
1494
1698
  this.isPreviewLoading = true;
1495
1699
  this.datapointsExceedingBrowserDownloadLimit =
1496
- await this.dataFetchingService.getDatapointsExceedingLimit(this.exportConfig);
1700
+ await this.dataFetchingService.getDatapointsExceedingLimit(this.exportConfig());
1497
1701
  const { browserDownloadableCount, emailDeliverableCount, nonRetrievableCount } = this.calculateDatapointCounts();
1498
1702
  this.hasNoExportableData =
1499
1703
  browserDownloadableCount === 0 && emailDeliverableCount === 0 && nonRetrievableCount > 0;
1500
1704
  if (this.datapointsExceedingBrowserDownloadLimit.length > 0 && !this.hasNoExportableData) {
1501
- this.limitExceededMessage = this.dataFetchingService.getLimitExceededMessage(this.hasNoExportableData, emailDeliverableCount, browserDownloadableCount, nonRetrievableCount, this.exportConfig.datapointDetails.length);
1705
+ this.limitExceededMessage = this.dataFetchingService.getLimitExceededMessage(this.hasNoExportableData, emailDeliverableCount, browserDownloadableCount, nonRetrievableCount, this.exportConfig().datapointDetails.length);
1502
1706
  }
1503
1707
  if (this.datapointsExceedingBrowserDownloadLimit.length > 0 && this.hasNoExportableData) {
1504
1708
  this.limitExceededMessage = this.dataFetchingService.getLimitExceededMessage(this.hasNoExportableData);
@@ -1511,7 +1715,7 @@ class DatapointsExportSelectorFileExporterComponent {
1511
1715
  this.dataPointsExceedingOneMillionLimit = this.datapointsExceedingBrowserDownloadLimit.filter(datapointsExceedingBrowserDownloadLimit => datapointsExceedingBrowserDownloadLimit.totalElements > RECORD_API_LIMIT);
1512
1716
  const nonRetrievableCount = this.dataPointsExceedingOneMillionLimit.length;
1513
1717
  const emailDeliverableCount = this.datapointsExceedingBrowserDownloadLimit.length - nonRetrievableCount;
1514
- const browserDownloadableCount = this.exportConfig.datapointDetails.length - emailDeliverableCount - nonRetrievableCount;
1718
+ const browserDownloadableCount = this.exportConfig().datapointDetails.length - emailDeliverableCount - nonRetrievableCount;
1515
1719
  return {
1516
1720
  browserDownloadableCount,
1517
1721
  emailDeliverableCount,
@@ -1519,19 +1723,19 @@ class DatapointsExportSelectorFileExporterComponent {
1519
1723
  };
1520
1724
  }
1521
1725
  storeInitialChangeableConfig() {
1522
- this.initialDateFrom = this.exportConfig.dateFrom;
1523
- this.initialDateTo = this.exportConfig.dateTo;
1524
- this.initialDatapointDetails = this.exportConfig.datapointDetails;
1726
+ this.initialDateFrom = this.exportConfig().dateFrom;
1727
+ this.initialDateTo = this.exportConfig().dateTo;
1728
+ this.initialDatapointDetails = this.exportConfig().datapointDetails;
1525
1729
  if (!this.isFullTypeOfExport) {
1526
- this.initialAggregation = this.exportConfig.aggregation;
1730
+ this.initialAggregation = this.exportConfig().aggregation;
1527
1731
  }
1528
1732
  }
1529
1733
  loadInitialChangeableConfig() {
1530
- this.exportConfig.dateFrom = this.initialDateFrom;
1531
- this.exportConfig.dateTo = this.initialDateTo;
1532
- this.exportConfig.datapointDetails = this.initialDatapointDetails;
1734
+ this.exportConfig().dateFrom = this.initialDateFrom;
1735
+ this.exportConfig().dateTo = this.initialDateTo;
1736
+ this.exportConfig().datapointDetails = this.initialDatapointDetails;
1533
1737
  if (!this.isFullTypeOfExport) {
1534
- this.exportConfig.aggregation = this.initialAggregation;
1738
+ this.exportConfig().aggregation = this.initialAggregation;
1535
1739
  }
1536
1740
  }
1537
1741
  async loadExportData() {
@@ -1540,7 +1744,25 @@ class DatapointsExportSelectorFileExporterComponent {
1540
1744
  }
1541
1745
  this.isPreviewLoading = true;
1542
1746
  this.onDownloadButtonStateChange.emit(false);
1543
- this.dataToExport = await this.dataFetchingService.fetchAndPrepareDataToExport(this.exportConfig, this.isFullTypeOfExport);
1747
+ if (this.isListTypeOfExport) {
1748
+ await this.loadListExportData();
1749
+ }
1750
+ else {
1751
+ await this.loadTableExportData();
1752
+ }
1753
+ }
1754
+ async loadListExportData() {
1755
+ const listData = await this.dataFetchingService.fetchAndPrepareListExportData(this.exportConfig());
1756
+ this.hasFetchedDataAnyValuesToExport = listData.length > 0;
1757
+ if (this.hasFetchedDataAnyValuesToExport) {
1758
+ this.prepareListPreview(listData);
1759
+ }
1760
+ else {
1761
+ this.isPreviewLoading = false;
1762
+ }
1763
+ }
1764
+ async loadTableExportData() {
1765
+ this.dataToExport = await this.dataFetchingService.fetchAndPrepareDataToExport(this.exportConfig(), this.isFullTypeOfExport);
1544
1766
  this.determineShowingPreviewOrEmptyState();
1545
1767
  }
1546
1768
  updateDownloadButtonState() {
@@ -1550,6 +1772,9 @@ class DatapointsExportSelectorFileExporterComponent {
1550
1772
  !this.hasNoExportableData;
1551
1773
  this.onDownloadButtonStateChange.emit(canEnableDownloadButton);
1552
1774
  }
1775
+ emitPreviewAvailability() {
1776
+ this.previewAvailabilityChange.emit(this.isFullTypeOfExport || this.isListTypeOfExport);
1777
+ }
1553
1778
  resetFullExportRelatedProperties() {
1554
1779
  this.hasNoExportableData = false;
1555
1780
  this.datapointsExceedingBrowserDownloadLimit = [];
@@ -1615,31 +1840,26 @@ class DatapointsExportSelectorFileExporterComponent {
1615
1840
  this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_DATAPOINTS_EXPORT_SELECTOR.EVENTS.EXPORT_SELECTOR, {
1616
1841
  ...commonEventData,
1617
1842
  selectedExportType: PRODUCT_EXPERIENCE_DATAPOINTS_EXPORT_SELECTOR.EXPORT_CONFIG.COMPACT_EXPORT_TYPE,
1618
- selectedAggregation: this.exportConfig.aggregation ?? AGGREGATION_VALUES.none
1843
+ selectedAggregation: this.exportConfig().aggregation ?? AGGREGATION_VALUES.none
1619
1844
  });
1620
1845
  }
1621
1846
  }
1622
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", 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 }); }
1623
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", 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 [attr.data-cy]=\"\n hasNoExportableData\n ? 'file-exporter--over-one-million-message'\n : 'file-exporter--over-50k-message'\n \"\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: "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 }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }] }); }
1847
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DatapointsExportSelectorFileExporterComponent, deps: [{ token: i1.AggregationService }, { token: i0.ChangeDetectorRef }, { token: DataProcessingService }, { token: DatapointsExportSelectorFileExporterService }, { token: DataFetchingService }, { token: i2$1.FormBuilder }, { token: FILE_GENERATORS }, { token: i1.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
1848
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: DatapointsExportSelectorFileExporterComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-file-exporter", inputs: { exportConfig: { classPropertyName: "exportConfig", publicName: "exportConfig", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { onDownloadButtonStateChange: "onDownloadButtonStateChange", previewAvailabilityChange: "previewAvailabilityChange", previewLoadingChange: "previewLoadingChange" }, ngImport: i0, template: "<div class=\"p-b-16\">\n @if (isCheckingPermissions) {\n <div class=\"p-t-24 p-r-16 p-l-16 p-b-16 d-flex j-c-center\">\n <c8y-loading></c8y-loading>\n </div>\n } @else if (hasPermissionToReadAnyMeasurements) {\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-r-24 p-l-24 gap-8 p-b-16\"\n [class.separator-bottom]=\"isFullTypeOfExport\"\n >\n <c8y-datapoints-export-selector-time-range\n [formGroup]=\"formGroup\"\n (onDateFromChange)=\"onDateFromChange($event)\"\n (onDateToChange)=\"onDateToChange($event)\"\n ></c8y-datapoints-export-selector-time-range>\n @if (isDataScopeVisible) {\n <c8y-datapoints-export-selector-data-scope\n [disabledAggregationOptions]=\"disabledAggregationOptions\"\n [formGroup]=\"formGroup\"\n (onAggregationChange)=\"onAggregationChange($event)\"\n (onExportTypeChange)=\"onExportTypeChange($event)\"\n ></c8y-datapoints-export-selector-data-scope>\n }\n <c8y-datapoints-export-selector-file-types\n [dynamicFilesTypeMetadata]=\"dynamicFilesTypeMetadata\"\n [formGroup]=\"formGroup\"\n ></c8y-datapoints-export-selector-file-types>\n </div>\n @if (\n !isFullTypeOfExport &&\n !hasFetchedDataAnyValuesToExport &&\n !isPreviewLoading &&\n !isListTypeOfExport\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 }\n @if (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 [attr.data-cy]=\"\n hasNoExportableData\n ? 'file-exporter--over-one-million-message'\n : 'file-exporter--over-50k-message'\n \"\n [innerHTML]=\"limitExceededMessage\"\n ></div>\n </div>\n }\n } @else {\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 }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: i1.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "directive", type: i2$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2$1.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: DataPointsExportSelectorTimeRangeComponent, selector: "c8y-datapoints-export-selector-time-range", inputs: ["formGroup"], outputs: ["onDateFromChange", "onDateToChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1624
1849
  }
1625
1850
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DatapointsExportSelectorFileExporterComponent, decorators: [{
1626
1851
  type: Component,
1627
- args: [{ selector: 'c8y-datapoints-export-selector-file-exporter', standalone: true, imports: [
1852
+ args: [{ selector: 'c8y-datapoints-export-selector-file-exporter', imports: [
1628
1853
  CoreModule,
1629
1854
  DataPointsExportSelectorDataScopeComponent,
1630
1855
  DataPointsExportSelectorFileTypesComponent,
1631
- DataPointsExportSelectorPreviewComponent,
1632
1856
  DataPointsExportSelectorTimeRangeComponent,
1633
1857
  ReactiveFormsModule
1634
- ], 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 [attr.data-cy]=\"\n hasNoExportableData\n ? 'file-exporter--over-one-million-message'\n : 'file-exporter--over-50k-message'\n \"\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" }]
1635
- }], ctorParameters: () => [{ type: i1.AggregationService }, { type: DataProcessingService }, { type: DatapointsExportSelectorFileExporterService }, { type: DataFetchingService }, { type: i3$2.FormBuilder }, { type: undefined, decorators: [{
1858
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"p-b-16\">\n @if (isCheckingPermissions) {\n <div class=\"p-t-24 p-r-16 p-l-16 p-b-16 d-flex j-c-center\">\n <c8y-loading></c8y-loading>\n </div>\n } @else if (hasPermissionToReadAnyMeasurements) {\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-r-24 p-l-24 gap-8 p-b-16\"\n [class.separator-bottom]=\"isFullTypeOfExport\"\n >\n <c8y-datapoints-export-selector-time-range\n [formGroup]=\"formGroup\"\n (onDateFromChange)=\"onDateFromChange($event)\"\n (onDateToChange)=\"onDateToChange($event)\"\n ></c8y-datapoints-export-selector-time-range>\n @if (isDataScopeVisible) {\n <c8y-datapoints-export-selector-data-scope\n [disabledAggregationOptions]=\"disabledAggregationOptions\"\n [formGroup]=\"formGroup\"\n (onAggregationChange)=\"onAggregationChange($event)\"\n (onExportTypeChange)=\"onExportTypeChange($event)\"\n ></c8y-datapoints-export-selector-data-scope>\n }\n <c8y-datapoints-export-selector-file-types\n [dynamicFilesTypeMetadata]=\"dynamicFilesTypeMetadata\"\n [formGroup]=\"formGroup\"\n ></c8y-datapoints-export-selector-file-types>\n </div>\n @if (\n !isFullTypeOfExport &&\n !hasFetchedDataAnyValuesToExport &&\n !isPreviewLoading &&\n !isListTypeOfExport\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 }\n @if (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 [attr.data-cy]=\"\n hasNoExportableData\n ? 'file-exporter--over-one-million-message'\n : 'file-exporter--over-50k-message'\n \"\n [innerHTML]=\"limitExceededMessage\"\n ></div>\n </div>\n }\n } @else {\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 }\n</div>\n" }]
1859
+ }], ctorParameters: () => [{ type: i1.AggregationService }, { type: i0.ChangeDetectorRef }, { type: DataProcessingService }, { type: DatapointsExportSelectorFileExporterService }, { type: DataFetchingService }, { type: i2$1.FormBuilder }, { type: undefined, decorators: [{
1636
1860
  type: Inject,
1637
1861
  args: [FILE_GENERATORS]
1638
- }] }, { type: i1.GainsightService }], propDecorators: { exportConfig: [{
1639
- type: Input
1640
- }], onDownloadButtonStateChange: [{
1641
- type: Output
1642
- }] } });
1862
+ }] }, { type: i1.GainsightService }], propDecorators: { exportConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportConfig", required: true }] }], onDownloadButtonStateChange: [{ type: i0.Output, args: ["onDownloadButtonStateChange"] }], previewAvailabilityChange: [{ type: i0.Output, args: ["previewAvailabilityChange"] }], previewLoadingChange: [{ type: i0.Output, args: ["previewLoadingChange"] }] } });
1643
1863
 
1644
1864
  class DataProcessingService {
1645
1865
  constructor(fileGenerators, utils) {
@@ -1692,6 +1912,17 @@ class DataProcessingService {
1692
1912
  const exportData = this.processDataToExport(data);
1693
1913
  return exportData.slice(0, MEASUREMENTS_PREVIEW_ITEMS_LIMIT);
1694
1914
  }
1915
+ /**
1916
+ * Transforms list export data into a structured format for preview.
1917
+ *
1918
+ * @param listData - Array of list datapoints with snapshot values
1919
+ * @param columns - Column configuration for ordering
1920
+ * @returns Provides an array of up to 5 ExportData elements for preview
1921
+ */
1922
+ transformListDataToPreview(listData, columns) {
1923
+ const exportData = this.processListDataToExport(listData, columns);
1924
+ return exportData.slice(0, MEASUREMENTS_PREVIEW_ITEMS_LIMIT);
1925
+ }
1695
1926
  /**
1696
1927
  * Processes a single dataToExport and transforms it into an array of ExportData.
1697
1928
  *
@@ -1806,6 +2037,77 @@ class DataProcessingService {
1806
2037
  createFileName(source, fragmentSeries, fileExtension) {
1807
2038
  return `${source}_${fragmentSeries}.${fileExtension}`;
1808
2039
  }
2040
+ /**
2041
+ * Generates list export blob (CSV or Excel) for snapshot data
2042
+ * @param fileType - Type of file (csv or excel)
2043
+ * @param listData - Array of datapoints with current values
2044
+ * @param columns - Column configuration
2045
+ * @param dateRange - Date range for filename generation
2046
+ * @returns Promise with Blob containing the exported file
2047
+ */
2048
+ async generateListExport(fileType, listData, columns, dateRange) {
2049
+ const fileTypeConfig = this.fileTypesConfigs[fileType];
2050
+ let blobContent;
2051
+ if (fileType === 'csv') {
2052
+ const module = await Promise.resolve().then(function () { return csvGenerator; });
2053
+ blobContent = await module.CSVGeneratorAdapter.generateList(listData, columns);
2054
+ }
2055
+ else if (fileType === 'excel') {
2056
+ const module = await Promise.resolve().then(function () { return excelGenerator; });
2057
+ blobContent = await module.ExcelGeneratorAdapter.generateList(listData, columns);
2058
+ }
2059
+ else {
2060
+ throw new Error(`Unsupported file type for list export: ${fileType}`);
2061
+ }
2062
+ const fileName = `${this.utils.getFormattedDateRange(dateRange.dateFrom, dateRange.dateTo)}.${fileTypeConfig.extension}`;
2063
+ const blob = new Blob([blobContent], { type: fileTypeConfig.mimeType });
2064
+ Object.defineProperty(blob, SERIES_DATA_MERGED_FILE_NAME, {
2065
+ value: fileName,
2066
+ writable: false,
2067
+ enumerable: false,
2068
+ configurable: true
2069
+ });
2070
+ return blob;
2071
+ }
2072
+ /**
2073
+ * Processes list datapoints and transforms them into an array of ExportData.
2074
+ *
2075
+ * @param listData - Array of list datapoints with snapshot values
2076
+ * @param columns - Column configuration for ordering
2077
+ * @returns An array of ExportData representing the processed list datapoints
2078
+ */
2079
+ processListDataToExport(listData, columns) {
2080
+ const sortedColumns = columns.sort((a, b) => a.order - b.order);
2081
+ const columnMapping = {
2082
+ kpi: 'label',
2083
+ target: 'target',
2084
+ current: 'current',
2085
+ diff: 'diff',
2086
+ diffPercentage: 'diffPercent',
2087
+ asset: 'deviceName'
2088
+ };
2089
+ return listData.map(datapoint => {
2090
+ const values = sortedColumns.map(col => {
2091
+ const propKey = columnMapping[col.id];
2092
+ const value = datapoint[propKey];
2093
+ if (value === null || value === undefined) {
2094
+ return '';
2095
+ }
2096
+ if (typeof value === 'number') {
2097
+ return value.toFixed(2);
2098
+ }
2099
+ return String(value);
2100
+ });
2101
+ return {
2102
+ device_name: datapoint.deviceName || '',
2103
+ source: datapoint.source,
2104
+ fragment_series: values.join(' | '),
2105
+ value: datapoint.current,
2106
+ unit: datapoint.unit || null,
2107
+ time: null
2108
+ };
2109
+ });
2110
+ }
1809
2111
  /**
1810
2112
  * Generates a zip blob using the provided zip object.
1811
2113
  *
@@ -1841,17 +2143,110 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
1841
2143
  args: [FILE_GENERATORS]
1842
2144
  }] }, { type: UtilsService }] });
1843
2145
 
1844
- class DatapointsExportSelectorModalComponent {
2146
+ class DataPointsExportSelectorPreviewComponent {
2147
+ constructor() {
2148
+ this.columns = input(...(ngDevMode ? [undefined, { debugName: "columns" }] : []));
2149
+ this.hasFetchedDataAnyValuesToExport = input(...(ngDevMode ? [undefined, { debugName: "hasFetchedDataAnyValuesToExport" }] : []));
2150
+ this.isPreviewLoading = input(...(ngDevMode ? [undefined, { debugName: "isPreviewLoading" }] : []));
2151
+ this.previewTableData = input(...(ngDevMode ? [undefined, { debugName: "previewTableData" }] : []));
2152
+ this.MEASUREMENTS_PREVIEW_ITEMS_LIMIT = MEASUREMENTS_PREVIEW_ITEMS_LIMIT;
2153
+ this.isListPreview = computed(() => {
2154
+ const cols = this.columns();
2155
+ return !!cols && cols.length > 0;
2156
+ }, ...(ngDevMode ? [{ debugName: "isListPreview" }] : []));
2157
+ this.listHeaders = computed(() => {
2158
+ if (!this.isListPreview()) {
2159
+ return [];
2160
+ }
2161
+ return [...this.columns()].sort((a, b) => a.order - b.order).map(col => col.label);
2162
+ }, ...(ngDevMode ? [{ debugName: "listHeaders" }] : []));
2163
+ this.previewRows = computed(() => {
2164
+ const data = this.previewTableData();
2165
+ if (!data) {
2166
+ return [];
2167
+ }
2168
+ return data.map(row => ({
2169
+ ...row,
2170
+ rowValues: row.fragment_series ? row.fragment_series.split(' | ') : []
2171
+ }));
2172
+ }, ...(ngDevMode ? [{ debugName: "previewRows" }] : []));
2173
+ }
2174
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DataPointsExportSelectorPreviewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
2175
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: DataPointsExportSelectorPreviewComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-preview", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null }, hasFetchedDataAnyValuesToExport: { classPropertyName: "hasFetchedDataAnyValuesToExport", publicName: "hasFetchedDataAnyValuesToExport", isSignal: true, isRequired: false, transformFunction: null }, isPreviewLoading: { classPropertyName: "isPreviewLoading", publicName: "isPreviewLoading", isSignal: true, isRequired: false, transformFunction: null }, previewTableData: { classPropertyName: "previewTableData", publicName: "previewTableData", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"p-t-16 p-l-16 p-r-16 m-b-0\">\n <div class=\"d-flex a-i-center\">\n <label\n class=\"m-b-0 d-flex a-i-center gap-4\"\n [title]=\"'Preview`of exported file`' | translate\"\n >\n {{ 'Preview`of exported file`' | translate }}\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"isListPreview() ? popoverListPreviewTemplate : popoverTablePreviewTemplate\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n data-cy=\"preview--help\"\n [adaptivePosition]=\"true\"\n ></button>\n <ng-template #popoverTablePreviewTemplate>\n <p translate>The preview shows the structure of the raw file from a single source.</p>\n <p translate>If no data is available, only the column headers are visible.</p>\n <p>\n {{ 'The preview is limited to' | translate }}\n <b>{{ MEASUREMENTS_PREVIEW_ITEMS_LIMIT }}</b>\n {{ 'records.' | translate }}\n </p>\n </ng-template>\n <ng-template #popoverListPreviewTemplate>\n <p translate>The preview shows the structure of the raw file from all sources.</p>\n <p>\n {{ 'The preview is limited to' | translate }}\n <b>{{ MEASUREMENTS_PREVIEW_ITEMS_LIMIT }}</b>\n {{ 'records.' | translate }}\n </p>\n </ng-template>\n </label>\n </div>\n <div\n class=\"table-responsive\"\n style=\"min-height: 275px\"\n >\n @if (isListPreview()) {\n <table class=\"table\">\n <thead>\n <tr>\n @for (header of listHeaders(); track header) {\n <th>{{ header | translate }}</th>\n }\n </tr>\n </thead>\n @if (hasFetchedDataAnyValuesToExport() || isPreviewLoading()) {\n @if (!isPreviewLoading()) {\n <tbody>\n @for (row of previewRows(); track row.source) {\n <tr>\n @for (value of row.rowValues; track $index) {\n <td>{{ value }}</td>\n }\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n <tr>\n <td [attr.colspan]=\"listHeaders().length\">\n <c8y-loading></c8y-loading>\n </td>\n </tr>\n </tbody>\n }\n } @else {\n <tbody>\n <tr>\n <td [attr.colspan]=\"listHeaders().length\">\n <div class=\"d-col a-i-center\">\n <c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No data available.' | translate\"\n [horizontal]=\"true\"\n data-cy=\"datapoints-table-list--empty-state\"\n ></c8y-ui-empty-state>\n </div>\n </td>\n </tr>\n </tbody>\n }\n </table>\n } @else {\n <table class=\"table\">\n <thead>\n <tr>\n <th>{{ 'Time' | translate }}</th>\n <th>{{ 'Source' | translate }}</th>\n <th>{{ 'Device name' | translate }}</th>\n <th>\n {{ 'Fragment and series' | translate }}\n </th>\n <th>{{ 'Value' | translate }}</th>\n <th>{{ 'Unit' | translate }}</th>\n </tr>\n </thead>\n @if (hasFetchedDataAnyValuesToExport() || isPreviewLoading()) {\n @if (!isPreviewLoading()) {\n <tbody>\n @for (row of previewTableData(); track row.source) {\n <tr>\n <td>{{ row.time }}</td>\n <td>{{ row.source }}</td>\n <td>{{ row.device_name }}</td>\n <td>\n {{ row.fragment_series }}\n </td>\n <td>{{ row.value }}</td>\n <td>{{ row.unit }}</td>\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n <tr>\n <td colspan=\"8\">\n <c8y-loading></c8y-loading>\n </td>\n </tr>\n </tbody>\n }\n } @else {\n <tbody>\n <tr>\n <td colspan=\"8\">\n <div class=\"d-col a-i-center\">\n <c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No data available.' | translate\"\n [horizontal]=\"true\"\n data-cy=\"datapoints-table-list--empty-state\"\n ></c8y-ui-empty-state>\n </div>\n </td>\n </tr>\n </tbody>\n }\n </table>\n }\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: A11yModule }, { kind: "ngmodule", type: CoreModule }, { kind: "component", type: i1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: i1.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { 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"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2176
+ }
2177
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DataPointsExportSelectorPreviewComponent, decorators: [{
2178
+ type: Component,
2179
+ args: [{ selector: 'c8y-datapoints-export-selector-preview', imports: [A11yModule, CoreModule, PopoverModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"p-t-16 p-l-16 p-r-16 m-b-0\">\n <div class=\"d-flex a-i-center\">\n <label\n class=\"m-b-0 d-flex a-i-center gap-4\"\n [title]=\"'Preview`of exported file`' | translate\"\n >\n {{ 'Preview`of exported file`' | translate }}\n <button\n class=\"btn-help\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"isListPreview() ? popoverListPreviewTemplate : popoverTablePreviewTemplate\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n type=\"button\"\n data-cy=\"preview--help\"\n [adaptivePosition]=\"true\"\n ></button>\n <ng-template #popoverTablePreviewTemplate>\n <p translate>The preview shows the structure of the raw file from a single source.</p>\n <p translate>If no data is available, only the column headers are visible.</p>\n <p>\n {{ 'The preview is limited to' | translate }}\n <b>{{ MEASUREMENTS_PREVIEW_ITEMS_LIMIT }}</b>\n {{ 'records.' | translate }}\n </p>\n </ng-template>\n <ng-template #popoverListPreviewTemplate>\n <p translate>The preview shows the structure of the raw file from all sources.</p>\n <p>\n {{ 'The preview is limited to' | translate }}\n <b>{{ MEASUREMENTS_PREVIEW_ITEMS_LIMIT }}</b>\n {{ 'records.' | translate }}\n </p>\n </ng-template>\n </label>\n </div>\n <div\n class=\"table-responsive\"\n style=\"min-height: 275px\"\n >\n @if (isListPreview()) {\n <table class=\"table\">\n <thead>\n <tr>\n @for (header of listHeaders(); track header) {\n <th>{{ header | translate }}</th>\n }\n </tr>\n </thead>\n @if (hasFetchedDataAnyValuesToExport() || isPreviewLoading()) {\n @if (!isPreviewLoading()) {\n <tbody>\n @for (row of previewRows(); track row.source) {\n <tr>\n @for (value of row.rowValues; track $index) {\n <td>{{ value }}</td>\n }\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n <tr>\n <td [attr.colspan]=\"listHeaders().length\">\n <c8y-loading></c8y-loading>\n </td>\n </tr>\n </tbody>\n }\n } @else {\n <tbody>\n <tr>\n <td [attr.colspan]=\"listHeaders().length\">\n <div class=\"d-col a-i-center\">\n <c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No data available.' | translate\"\n [horizontal]=\"true\"\n data-cy=\"datapoints-table-list--empty-state\"\n ></c8y-ui-empty-state>\n </div>\n </td>\n </tr>\n </tbody>\n }\n </table>\n } @else {\n <table class=\"table\">\n <thead>\n <tr>\n <th>{{ 'Time' | translate }}</th>\n <th>{{ 'Source' | translate }}</th>\n <th>{{ 'Device name' | translate }}</th>\n <th>\n {{ 'Fragment and series' | translate }}\n </th>\n <th>{{ 'Value' | translate }}</th>\n <th>{{ 'Unit' | translate }}</th>\n </tr>\n </thead>\n @if (hasFetchedDataAnyValuesToExport() || isPreviewLoading()) {\n @if (!isPreviewLoading()) {\n <tbody>\n @for (row of previewTableData(); track row.source) {\n <tr>\n <td>{{ row.time }}</td>\n <td>{{ row.source }}</td>\n <td>{{ row.device_name }}</td>\n <td>\n {{ row.fragment_series }}\n </td>\n <td>{{ row.value }}</td>\n <td>{{ row.unit }}</td>\n </tr>\n }\n </tbody>\n } @else {\n <tbody>\n <tr>\n <td colspan=\"8\">\n <c8y-loading></c8y-loading>\n </td>\n </tr>\n </tbody>\n }\n } @else {\n <tbody>\n <tr>\n <td colspan=\"8\">\n <div class=\"d-col a-i-center\">\n <c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No data available.' | translate\"\n [horizontal]=\"true\"\n data-cy=\"datapoints-table-list--empty-state\"\n ></c8y-ui-empty-state>\n </div>\n </td>\n </tr>\n </tbody>\n }\n </table>\n }\n </div>\n</div>\n" }]
2180
+ }], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], hasFetchedDataAnyValuesToExport: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasFetchedDataAnyValuesToExport", required: false }] }], isPreviewLoading: [{ type: i0.Input, args: [{ isSignal: true, alias: "isPreviewLoading", required: false }] }], previewTableData: [{ type: i0.Input, args: [{ isSignal: true, alias: "previewTableData", required: false }] }] } });
2181
+
2182
+ class DatapointsExportSelectorPreviewModalComponent {
1845
2183
  constructor(bsModalRef) {
1846
2184
  this.bsModalRef = bsModalRef;
2185
+ this.labels = { cancel: gettext('Close') };
2186
+ }
2187
+ close() {
2188
+ this.bsModalRef.hide();
2189
+ }
2190
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DatapointsExportSelectorPreviewModalComponent, deps: [{ token: i1$1.BsModalRef }], target: i0.ɵɵFactoryTarget.Component }); }
2191
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: DatapointsExportSelectorPreviewModalComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-preview-modal", host: { listeners: { "document:keydown.escape": "close()" } }, ngImport: i0, template: `
2192
+ <c8y-modal
2193
+ [title]="'Export preview' | translate"
2194
+ [labels]="labels"
2195
+ [headerClasses]="'dialog-header'"
2196
+ (onDismiss)="close()"
2197
+ >
2198
+ <c8y-datapoints-export-selector-preview
2199
+ [hasFetchedDataAnyValuesToExport]="hasFetchedDataAnyValuesToExport"
2200
+ [isPreviewLoading]="isPreviewLoading"
2201
+ [previewTableData]="previewTableData"
2202
+ [columns]="columns"
2203
+ ></c8y-datapoints-export-selector-preview>
2204
+ </c8y-modal>
2205
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "component", type: i1.ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "component", type: DataPointsExportSelectorPreviewComponent, selector: "c8y-datapoints-export-selector-preview", inputs: ["columns", "hasFetchedDataAnyValuesToExport", "isPreviewLoading", "previewTableData"] }, { kind: "ngmodule", type: ModalModule }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
2206
+ }
2207
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DatapointsExportSelectorPreviewModalComponent, decorators: [{
2208
+ type: Component,
2209
+ args: [{
2210
+ selector: 'c8y-datapoints-export-selector-preview-modal',
2211
+ template: `
2212
+ <c8y-modal
2213
+ [title]="'Export preview' | translate"
2214
+ [labels]="labels"
2215
+ [headerClasses]="'dialog-header'"
2216
+ (onDismiss)="close()"
2217
+ >
2218
+ <c8y-datapoints-export-selector-preview
2219
+ [hasFetchedDataAnyValuesToExport]="hasFetchedDataAnyValuesToExport"
2220
+ [isPreviewLoading]="isPreviewLoading"
2221
+ [previewTableData]="previewTableData"
2222
+ [columns]="columns"
2223
+ ></c8y-datapoints-export-selector-preview>
2224
+ </c8y-modal>
2225
+ `,
2226
+ imports: [CoreModule, DataPointsExportSelectorPreviewComponent, ModalModule],
2227
+ changeDetection: ChangeDetectionStrategy.OnPush,
2228
+ host: {
2229
+ '(document:keydown.escape)': 'close()'
2230
+ }
2231
+ }]
2232
+ }], ctorParameters: () => [{ type: i1$1.BsModalRef }] });
2233
+
2234
+ class DatapointsExportSelectorModalComponent {
2235
+ constructor(bsModalRef, bsModalService) {
2236
+ this.bsModalRef = bsModalRef;
2237
+ this.bsModalService = bsModalService;
2238
+ this.fileExporter = viewChild(DatapointsExportSelectorFileExporterComponent, ...(ngDevMode ? [{ debugName: "fileExporter" }] : []));
1847
2239
  this.isDownloadEnabled = false;
2240
+ this.isPreviewAvailable = false;
2241
+ this.isPreviewLoading = true;
1848
2242
  this.labels = { ok: gettext('Download'), cancel: gettext('Cancel') };
1849
2243
  this.result = new Promise(resolve => {
1850
2244
  this._close = resolve;
1851
2245
  });
2246
+ this.isPreviewModalOpen = false;
1852
2247
  }
1853
2248
  handleKeyboardEvent(event) {
1854
- if (event.key === 'Escape') {
2249
+ if (event.key === 'Escape' && !this.isPreviewModalOpen) {
1855
2250
  this.dismiss();
1856
2251
  }
1857
2252
  }
@@ -1860,46 +2255,89 @@ class DatapointsExportSelectorModalComponent {
1860
2255
  this.bsModalRef.hide();
1861
2256
  }
1862
2257
  async exportAndDownload() {
1863
- await this.datapointsExportSelectorFileExporterComponent.exportAndDownload();
2258
+ await this.fileExporter().exportAndDownload();
1864
2259
  this.dismiss();
1865
2260
  }
2261
+ openPreviewModal() {
2262
+ const exporter = this.fileExporter();
2263
+ const initialState = {
2264
+ columns: this.exportConfig.columns,
2265
+ hasFetchedDataAnyValuesToExport: exporter.hasFetchedDataAnyValuesToExport,
2266
+ isPreviewLoading: exporter.isPreviewLoading,
2267
+ previewTableData: exporter.previewTableData
2268
+ };
2269
+ const previewModalRef = this.bsModalService.show(DatapointsExportSelectorPreviewModalComponent, {
2270
+ class: 'modal-lg',
2271
+ ariaDescribedby: 'modal-body',
2272
+ ariaLabelledBy: 'modal-title',
2273
+ initialState
2274
+ });
2275
+ this.isPreviewModalOpen = true;
2276
+ previewModalRef.onHidden.subscribe(() => {
2277
+ this.isPreviewModalOpen = false;
2278
+ });
2279
+ }
1866
2280
  changeDownloadButtonState(isEnabled) {
1867
2281
  this.isDownloadEnabled = isEnabled;
1868
2282
  }
1869
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DatapointsExportSelectorModalComponent, deps: [{ token: i1$1.BsModalRef }], target: i0.ɵɵFactoryTarget.Component }); }
1870
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: DatapointsExportSelectorModalComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-modal", host: { listeners: { "document:keydown": "handleKeyboardEvent($event)" } }, viewQueries: [{ propertyName: "datapointsExportSelectorFileExporterComponent", first: true, predicate: DatapointsExportSelectorFileExporterComponent, descendants: true }], ngImport: i0, template: "<c8y-modal\n [title]=\"'Generate export' | translate\"\n [labels]=\"labels\"\n [disabled]=\"!isDownloadEnabled\"\n [headerClasses]=\"'dialog-header'\"\n (onDismiss)=\"dismiss()\"\n (onClose)=\"exportAndDownload()\"\n>\n <ng-container c8y-modal-title>\n <span [c8yIcon]=\"'data-export'\"></span>\n </ng-container>\n <c8y-datapoints-export-selector-file-exporter\n [exportConfig]=\"exportConfig\"\n (onDownloadButtonStateChange)=\"changeDownloadButtonState($event)\"\n ></c8y-datapoints-export-selector-file-exporter>\n</c8y-modal>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: DatapointsExportSelectorFileExporterComponent, selector: "c8y-datapoints-export-selector-file-exporter", inputs: ["exportConfig"], outputs: ["onDownloadButtonStateChange"] }, { kind: "ngmodule", type: ModalModule }, { kind: "component", type: i1.ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }] }); }
2283
+ changePreviewAvailability(isAvailable) {
2284
+ this.isPreviewAvailable = isAvailable;
2285
+ }
2286
+ changePreviewLoading(isLoading) {
2287
+ this.isPreviewLoading = isLoading;
2288
+ }
2289
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DatapointsExportSelectorModalComponent, deps: [{ token: i1$1.BsModalRef }, { token: i1$1.BsModalService }], target: i0.ɵɵFactoryTarget.Component }); }
2290
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: DatapointsExportSelectorModalComponent, isStandalone: true, selector: "c8y-datapoints-export-selector-modal", host: { listeners: { "document:keydown": "handleKeyboardEvent($event)" } }, viewQueries: [{ propertyName: "fileExporter", first: true, predicate: DatapointsExportSelectorFileExporterComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<c8y-modal\n [title]=\"'Generate export' | translate\"\n [labels]=\"labels\"\n [disabled]=\"!isDownloadEnabled\"\n [headerClasses]=\"'dialog-header'\"\n (onDismiss)=\"dismiss()\"\n (onClose)=\"exportAndDownload()\"\n>\n <ng-container c8y-modal-title>\n <span [c8yIcon]=\"'data-export'\"></span>\n </ng-container>\n <c8y-datapoints-export-selector-file-exporter\n [exportConfig]=\"exportConfig\"\n (onDownloadButtonStateChange)=\"changeDownloadButtonState($event)\"\n (previewAvailabilityChange)=\"changePreviewAvailability($event)\"\n (previewLoadingChange)=\"changePreviewLoading($event)\"\n ></c8y-datapoints-export-selector-file-exporter>\n @if (isPreviewAvailable) {\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Show preview' | translate }}\"\n type=\"button\"\n c8y-modal-footer\n [disabled]=\"isPreviewLoading || !isDownloadEnabled\"\n (click)=\"openPreviewModal()\"\n >\n <i [c8yIcon]=\"'eye'\"></i>\n {{ 'Show preview' | translate }}\n </button>\n }\n</c8y-modal>\n", dependencies: [{ kind: "component", type: DatapointsExportSelectorFileExporterComponent, selector: "c8y-datapoints-export-selector-file-exporter", inputs: ["exportConfig"], outputs: ["onDownloadButtonStateChange", "previewAvailabilityChange", "previewLoadingChange"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "ngmodule", type: ModalModule }, { kind: "component", type: i1.ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1871
2291
  }
1872
2292
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DatapointsExportSelectorModalComponent, decorators: [{
1873
2293
  type: Component,
1874
- args: [{ selector: 'c8y-datapoints-export-selector-modal', standalone: true, imports: [CommonModule, DatapointsExportSelectorFileExporterComponent, ModalModule], template: "<c8y-modal\n [title]=\"'Generate export' | translate\"\n [labels]=\"labels\"\n [disabled]=\"!isDownloadEnabled\"\n [headerClasses]=\"'dialog-header'\"\n (onDismiss)=\"dismiss()\"\n (onClose)=\"exportAndDownload()\"\n>\n <ng-container c8y-modal-title>\n <span [c8yIcon]=\"'data-export'\"></span>\n </ng-container>\n <c8y-datapoints-export-selector-file-exporter\n [exportConfig]=\"exportConfig\"\n (onDownloadButtonStateChange)=\"changeDownloadButtonState($event)\"\n ></c8y-datapoints-export-selector-file-exporter>\n</c8y-modal>\n" }]
1875
- }], ctorParameters: () => [{ type: i1$1.BsModalRef }], propDecorators: { datapointsExportSelectorFileExporterComponent: [{
1876
- type: ViewChild,
1877
- args: [DatapointsExportSelectorFileExporterComponent, { static: false }]
1878
- }], handleKeyboardEvent: [{
1879
- type: HostListener,
1880
- args: ['document:keydown', ['$event']]
1881
- }] } });
2294
+ args: [{ selector: 'c8y-datapoints-export-selector-modal', imports: [
2295
+ C8yTranslatePipe,
2296
+ DatapointsExportSelectorFileExporterComponent,
2297
+ IconDirective,
2298
+ ModalModule
2299
+ ], changeDetection: ChangeDetectionStrategy.OnPush, host: {
2300
+ '(document:keydown)': 'handleKeyboardEvent($event)'
2301
+ }, template: "<c8y-modal\n [title]=\"'Generate export' | translate\"\n [labels]=\"labels\"\n [disabled]=\"!isDownloadEnabled\"\n [headerClasses]=\"'dialog-header'\"\n (onDismiss)=\"dismiss()\"\n (onClose)=\"exportAndDownload()\"\n>\n <ng-container c8y-modal-title>\n <span [c8yIcon]=\"'data-export'\"></span>\n </ng-container>\n <c8y-datapoints-export-selector-file-exporter\n [exportConfig]=\"exportConfig\"\n (onDownloadButtonStateChange)=\"changeDownloadButtonState($event)\"\n (previewAvailabilityChange)=\"changePreviewAvailability($event)\"\n (previewLoadingChange)=\"changePreviewLoading($event)\"\n ></c8y-datapoints-export-selector-file-exporter>\n @if (isPreviewAvailable) {\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Show preview' | translate }}\"\n type=\"button\"\n c8y-modal-footer\n [disabled]=\"isPreviewLoading || !isDownloadEnabled\"\n (click)=\"openPreviewModal()\"\n >\n <i [c8yIcon]=\"'eye'\"></i>\n {{ 'Show preview' | translate }}\n </button>\n }\n</c8y-modal>\n" }]
2302
+ }], ctorParameters: () => [{ type: i1$1.BsModalRef }, { type: i1$1.BsModalService }], propDecorators: { fileExporter: [{ type: i0.ViewChild, args: [i0.forwardRef(() => DatapointsExportSelectorFileExporterComponent), { isSignal: true }] }] } });
1882
2303
 
1883
2304
  class DatapointsExportSelectorComponent {
1884
2305
  constructor(bsModalService, gainsightService) {
1885
2306
  this.bsModalService = bsModalService;
1886
2307
  this.gainsightService = gainsightService;
1887
- this.displayMode = 'default';
1888
- this.isOpen = new EventEmitter();
2308
+ this.displayMode = input('default', ...(ngDevMode ? [{ debugName: "displayMode" }] : []));
2309
+ /**
2310
+ * CSS class for the container element.
2311
+ * Defaults to 'd-flex p-t-4 p-b-4' if not provided.
2312
+ */
2313
+ this.containerClass = input(...(ngDevMode ? [undefined, { debugName: "containerClass" }] : []));
2314
+ /**
2315
+ * Configuration for the export selector modal.
2316
+ */
2317
+ this.exportConfig = input(...(ngDevMode ? [undefined, { debugName: "exportConfig" }] : []));
2318
+ this.isOpen = output();
1889
2319
  this.DEFAULT_CSS_STYLE = 'd-flex';
2320
+ /**
2321
+ * Check if export button should be disabled
2322
+ * Disabled when: no config provided or no datapoints configured
2323
+ */
2324
+ this.isExportDisabled = computed(() => {
2325
+ const config = this.exportConfig();
2326
+ return !config?.datapointDetails || config.datapointDetails.length === 0;
2327
+ }, ...(ngDevMode ? [{ debugName: "isExportDisabled" }] : []));
1890
2328
  }
1891
2329
  async openExportModal() {
1892
2330
  this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_DATAPOINTS_EXPORT_SELECTOR.EVENTS.EXPORT_SELECTOR, {
1893
2331
  action: PRODUCT_EXPERIENCE_DATAPOINTS_EXPORT_SELECTOR.ACTIONS.OPEN_MODAL,
1894
2332
  component: PRODUCT_EXPERIENCE_DATAPOINTS_EXPORT_SELECTOR.COMPONENTS.DATAPOINTS_EXPORT_SELECTOR
1895
2333
  });
1896
- const exportConfig = this.exportConfig;
2334
+ const exportConfig = this.exportConfig();
1897
2335
  const initialState = {
1898
2336
  exportConfig
1899
2337
  };
1900
2338
  this.isOpen.emit(true);
1901
2339
  const modalRef = this.bsModalService.show(DatapointsExportSelectorModalComponent, {
1902
- class: 'modal-lg',
2340
+ class: 'modal-sm',
1903
2341
  ariaDescribedby: 'modal-body',
1904
2342
  ariaLabelledBy: 'modal-title',
1905
2343
  initialState,
@@ -1909,20 +2347,12 @@ class DatapointsExportSelectorComponent {
1909
2347
  this.isOpen.emit(await modalRef.result);
1910
2348
  }
1911
2349
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DatapointsExportSelectorComponent, deps: [{ token: i1$1.BsModalService }, { token: i1.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
1912
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: DatapointsExportSelectorComponent, isStandalone: true, selector: "c8y-datapoints-export-selector", inputs: { displayMode: "displayMode", containerClass: "containerClass", exportConfig: "exportConfig" }, outputs: { isOpen: "isOpen" }, ngImport: i0, template: "@switch (displayMode) {\n @case ('default') {\n @if (containerClass != 'd-contents') {\n <div [ngClass]=\"containerClass || DEFAULT_CSS_STYLE\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.aria-label]=\"'Generate export' | translate\"\n tooltip=\"{{ 'Generate export' | translate }}\"\n container=\"body\"\n type=\"button\"\n data-cy=\"datapoints-export-selector--open-export-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 } @else {\n <button\n class=\"btn btn-link\"\n type=\"button\"\n (click)=\"openExportModal()\"\n [disabled]=\"!exportConfig\"\n >\n <i c8yIcon=\"data-export\"></i>\n {{ 'Generate export' | translate }}\n </button>\n }\n }\n @case ('icon-only') {\n <button\n class=\"btn btn-icon\"\n [attr.aria-label]=\"'Generate export' | translate\"\n tooltip=\"{{ 'Generate export' | translate }}\"\n container=\"body\"\n type=\"button\"\n data-cy=\"datapoints-export-selector--open-export-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 }\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i4.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"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }] }); }
2350
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: DatapointsExportSelectorComponent, isStandalone: true, selector: "c8y-datapoints-export-selector", inputs: { displayMode: { classPropertyName: "displayMode", publicName: "displayMode", isSignal: true, isRequired: false, transformFunction: null }, containerClass: { classPropertyName: "containerClass", publicName: "containerClass", isSignal: true, isRequired: false, transformFunction: null }, exportConfig: { classPropertyName: "exportConfig", publicName: "exportConfig", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { isOpen: "isOpen" }, ngImport: i0, template: "@switch (displayMode()) {\n @case ('default') {\n @if (containerClass() !== 'd-contents') {\n <div [class]=\"containerClass() || DEFAULT_CSS_STYLE\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.aria-label]=\"'Generate export' | translate\"\n tooltip=\"{{ 'Generate export' | translate }}\"\n container=\"body\"\n type=\"button\"\n data-cy=\"datapoints-export-selector--open-export-button\"\n (click)=\"openExportModal()\"\n [adaptivePosition]=\"false\"\n [disabled]=\"isExportDisabled()\"\n [delay]=\"500\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"data-export\"\n ></i>\n </button>\n </div>\n } @else {\n <button\n class=\"btn btn-link\"\n type=\"button\"\n (click)=\"openExportModal()\"\n [disabled]=\"isExportDisabled()\"\n >\n <i c8yIcon=\"data-export\"></i>\n {{ 'Generate export' | translate }}\n </button>\n }\n }\n @case ('icon-only') {\n <button\n class=\"btn btn-icon\"\n [attr.aria-label]=\"'Generate export' | translate\"\n tooltip=\"{{ 'Generate export' | translate }}\"\n container=\"body\"\n type=\"button\"\n data-cy=\"datapoints-export-selector--open-export-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 }\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { 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"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1913
2351
  }
1914
2352
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: DatapointsExportSelectorComponent, decorators: [{
1915
2353
  type: Component,
1916
- args: [{ selector: 'c8y-datapoints-export-selector', standalone: true, imports: [CommonModule, TooltipModule], template: "@switch (displayMode) {\n @case ('default') {\n @if (containerClass != 'd-contents') {\n <div [ngClass]=\"containerClass || DEFAULT_CSS_STYLE\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.aria-label]=\"'Generate export' | translate\"\n tooltip=\"{{ 'Generate export' | translate }}\"\n container=\"body\"\n type=\"button\"\n data-cy=\"datapoints-export-selector--open-export-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 } @else {\n <button\n class=\"btn btn-link\"\n type=\"button\"\n (click)=\"openExportModal()\"\n [disabled]=\"!exportConfig\"\n >\n <i c8yIcon=\"data-export\"></i>\n {{ 'Generate export' | translate }}\n </button>\n }\n }\n @case ('icon-only') {\n <button\n class=\"btn btn-icon\"\n [attr.aria-label]=\"'Generate export' | translate\"\n tooltip=\"{{ 'Generate export' | translate }}\"\n container=\"body\"\n type=\"button\"\n data-cy=\"datapoints-export-selector--open-export-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 }\n}\n" }]
1917
- }], ctorParameters: () => [{ type: i1$1.BsModalService }, { type: i1.GainsightService }], propDecorators: { displayMode: [{
1918
- type: Input
1919
- }], containerClass: [{
1920
- type: Input
1921
- }], exportConfig: [{
1922
- type: Input
1923
- }], isOpen: [{
1924
- type: Output
1925
- }] } });
2354
+ args: [{ selector: 'c8y-datapoints-export-selector', imports: [CommonModule, TooltipModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "@switch (displayMode()) {\n @case ('default') {\n @if (containerClass() !== 'd-contents') {\n <div [class]=\"containerClass() || DEFAULT_CSS_STYLE\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.aria-label]=\"'Generate export' | translate\"\n tooltip=\"{{ 'Generate export' | translate }}\"\n container=\"body\"\n type=\"button\"\n data-cy=\"datapoints-export-selector--open-export-button\"\n (click)=\"openExportModal()\"\n [adaptivePosition]=\"false\"\n [disabled]=\"isExportDisabled()\"\n [delay]=\"500\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"data-export\"\n ></i>\n </button>\n </div>\n } @else {\n <button\n class=\"btn btn-link\"\n type=\"button\"\n (click)=\"openExportModal()\"\n [disabled]=\"isExportDisabled()\"\n >\n <i c8yIcon=\"data-export\"></i>\n {{ 'Generate export' | translate }}\n </button>\n }\n }\n @case ('icon-only') {\n <button\n class=\"btn btn-icon\"\n [attr.aria-label]=\"'Generate export' | translate\"\n tooltip=\"{{ 'Generate export' | translate }}\"\n container=\"body\"\n type=\"button\"\n data-cy=\"datapoints-export-selector--open-export-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 }\n}\n" }]
2355
+ }], ctorParameters: () => [{ type: i1$1.BsModalService }, { type: i1.GainsightService }], propDecorators: { displayMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "displayMode", required: false }] }], containerClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "containerClass", required: false }] }], exportConfig: [{ type: i0.Input, args: [{ isSignal: true, alias: "exportConfig", required: false }] }], isOpen: [{ type: i0.Output, args: ["isOpen"] }] } });
1926
2356
 
1927
2357
  /**
1928
2358
  * Generated bundle index. Do not edit.