@c8y/ngx-components 1024.16.17 → 1024.16.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs +216 -51
- package/fesm2022/c8y-ngx-components-datapoints-export-selector.mjs.map +1 -1
- package/package.json +1 -1
- package/types/c8y-ngx-components-datapoints-export-selector.d.ts +99 -1
- package/types/c8y-ngx-components-datapoints-export-selector.d.ts.map +1 -1
|
@@ -350,10 +350,9 @@ class DataFetchingService {
|
|
|
350
350
|
* @returns A map where the key is the data point ID and the value is an array of data point series.
|
|
351
351
|
*/
|
|
352
352
|
groupSeriesByDeviceId(datapointDetails) {
|
|
353
|
-
return datapointDetails.reduce((map,
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
map.set(source, [...existingValue, value]);
|
|
353
|
+
return datapointDetails.reduce((map, datapoint) => {
|
|
354
|
+
const existingValue = map.get(datapoint.source) ?? [];
|
|
355
|
+
map.set(datapoint.source, [...existingValue, this.getSeriesName(datapoint)]);
|
|
357
356
|
return map;
|
|
358
357
|
}, new Map());
|
|
359
358
|
}
|
|
@@ -373,7 +372,7 @@ class DataFetchingService {
|
|
|
373
372
|
* Unique key to distinguish between different series from same source,
|
|
374
373
|
* e.g.: c8y_Acceleration.accelerationX, c8y_Acceleration.accelerationY, c8y_Acceleration.accelerationZ
|
|
375
374
|
*/
|
|
376
|
-
const seriesKey =
|
|
375
|
+
const seriesKey = this.getSeriesName(details);
|
|
377
376
|
if (valuesGroupedBySource[details.source][seriesKey]) {
|
|
378
377
|
unit = valuesGroupedBySource[details.source][seriesKey].seriesDetails.unit;
|
|
379
378
|
data = valuesGroupedBySource[details.source][seriesKey].values;
|
|
@@ -409,29 +408,71 @@ class DataFetchingService {
|
|
|
409
408
|
return false;
|
|
410
409
|
}
|
|
411
410
|
}
|
|
411
|
+
/**
|
|
412
|
+
* Returns sources of the given data points that the user is permitted to read,
|
|
413
|
+
* one entry per permitted data point.
|
|
414
|
+
*
|
|
415
|
+
* @deprecated Use `getDatapointsWithPermissionsToRead` instead — permissions can differ
|
|
416
|
+
* between data points of the same source (inventory role permissions are scoped per fragment type).
|
|
417
|
+
* @param datapointDetails - The data points selected for export.
|
|
418
|
+
* @returns A promise that resolves to the sources of the permitted data points.
|
|
419
|
+
*/
|
|
412
420
|
async getSourcesWithPermissionsToRead(datapointDetails) {
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
421
|
+
const permittedDatapoints = await this.getDatapointsWithPermissionsToRead(datapointDetails);
|
|
422
|
+
return permittedDatapoints.map(({ source }) => String(source));
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Returns the subset of the given data points that the user is permitted to read.
|
|
426
|
+
*
|
|
427
|
+
* Each probe request lists the exact series to export, as required for measurement READ
|
|
428
|
+
* permissions scoped to specific fragment types. When a probe grouping all series of a source
|
|
429
|
+
* is rejected, each series is probed individually, so readable data points are not blocked
|
|
430
|
+
* by unreadable ones.
|
|
431
|
+
*
|
|
432
|
+
* Example flow for data points `Cloud.speed` and `c8y_Battery.level` on source `123` plus
|
|
433
|
+
* `Cloud.level` on source `456`, with an inventory role permitting only the `Cloud` fragment:
|
|
434
|
+
* ```
|
|
435
|
+
* GET /series?source=123&series=Cloud.speed&series=c8y_Battery.level → 403, probe each series:
|
|
436
|
+
* GET /series?source=123&series=Cloud.speed → 200 (readable)
|
|
437
|
+
* GET /series?source=123&series=c8y_Battery.level → 403 (dropped)
|
|
438
|
+
* GET /series?source=456&series=Cloud.level → 200 (readable)
|
|
439
|
+
*
|
|
440
|
+
* Returns the data points of Cloud.speed and Cloud.level.
|
|
441
|
+
* ```
|
|
442
|
+
*
|
|
443
|
+
* @param datapointDetails - The data points selected for export.
|
|
444
|
+
* @returns A promise that resolves to the data points the user is permitted to read.
|
|
445
|
+
*/
|
|
446
|
+
async getDatapointsWithPermissionsToRead(datapointDetails) {
|
|
447
|
+
const datapointsBySource = this.groupDatapointsBySource(datapointDetails);
|
|
448
|
+
const readableGroups = await Promise.all(Array.from(datapointsBySource.values(), datapoints => this.getReadableDatapointsOfSource(datapoints)));
|
|
449
|
+
const readableDatapoints = new Set(readableGroups.flat());
|
|
450
|
+
// Filter the original array to keep the caller's data point order.
|
|
451
|
+
return datapointDetails.filter(datapoint => readableDatapoints.has(datapoint));
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Fetches series data for export while deriving read permissions from the responses,
|
|
455
|
+
* so no separate permission probes are needed for readable sources.
|
|
456
|
+
*
|
|
457
|
+
* The data request itself acts as the permission check: when a source group is rejected
|
|
458
|
+
* with 403, each series is probed individually and only the readable ones are refetched.
|
|
459
|
+
*
|
|
460
|
+
* @param exportConfig - The export configuration providing the data points, date range and aggregation.
|
|
461
|
+
* @returns A promise that resolves to the prepared export data and the readable data points.
|
|
462
|
+
*/
|
|
463
|
+
async fetchAndPrepareSeriesDataWithPermissions(exportConfig) {
|
|
464
|
+
const datapointsBySource = this.groupDatapointsBySource(exportConfig.datapointDetails);
|
|
465
|
+
const groupResults = await Promise.all(Array.from(datapointsBySource.values(), datapoints => this.fetchReadableSeriesOfSource(datapoints, exportConfig)));
|
|
466
|
+
const readableSet = new Set(groupResults.flatMap(result => result.readableDatapoints));
|
|
467
|
+
// Filter the original array to keep the caller's data point order.
|
|
468
|
+
const readableDatapoints = exportConfig.datapointDetails.filter(datapoint => readableSet.has(datapoint));
|
|
469
|
+
const fetchedDataGroupedBySource = groupResults
|
|
470
|
+
.map(result => result.sourceItem)
|
|
471
|
+
.filter(sourceItem => sourceItem !== null);
|
|
472
|
+
return {
|
|
473
|
+
dataToExport: this.processSeriesData(readableDatapoints, fetchedDataGroupedBySource),
|
|
474
|
+
readableDatapoints
|
|
475
|
+
};
|
|
435
476
|
}
|
|
436
477
|
/**
|
|
437
478
|
* Adjusts the given date by adding the specified number of minutes and setting seconds to 0.
|
|
@@ -529,7 +570,7 @@ class DataFetchingService {
|
|
|
529
570
|
const diffPercent = target !== null && target !== undefined && diff !== null ? (diff / target) * 100 : null;
|
|
530
571
|
return {
|
|
531
572
|
...detail,
|
|
532
|
-
label: detail.label ||
|
|
573
|
+
label: detail.label || this.getSeriesName(detail),
|
|
533
574
|
target: target ?? null,
|
|
534
575
|
current,
|
|
535
576
|
diff,
|
|
@@ -537,10 +578,10 @@ class DataFetchingService {
|
|
|
537
578
|
unit
|
|
538
579
|
};
|
|
539
580
|
}
|
|
540
|
-
catch
|
|
581
|
+
catch {
|
|
541
582
|
return {
|
|
542
583
|
...detail,
|
|
543
|
-
label: detail.label ||
|
|
584
|
+
label: detail.label || this.getSeriesName(detail),
|
|
544
585
|
target: detail.target ?? null,
|
|
545
586
|
current: null,
|
|
546
587
|
diff: null,
|
|
@@ -583,21 +624,133 @@ class DataFetchingService {
|
|
|
583
624
|
return measurements;
|
|
584
625
|
}
|
|
585
626
|
async fetchAndPrepareSeriesDataToExport(exportConfig) {
|
|
586
|
-
const
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
627
|
+
const { dataToExport } = await this.fetchAndPrepareSeriesDataWithPermissions(exportConfig);
|
|
628
|
+
return dataToExport;
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Groups the given data points by their source.
|
|
632
|
+
*
|
|
633
|
+
* @param datapointDetails - The data points to group.
|
|
634
|
+
* @returns A map where the key is the source ID and the value is the data points of that source.
|
|
635
|
+
*/
|
|
636
|
+
groupDatapointsBySource(datapointDetails) {
|
|
637
|
+
return datapointDetails.reduce((map, datapoint) => {
|
|
638
|
+
const group = map.get(datapoint.source) ?? [];
|
|
639
|
+
map.set(datapoint.source, [...group, datapoint]);
|
|
640
|
+
return map;
|
|
641
|
+
}, new Map());
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Returns the data points of a single source that the user is permitted to read.
|
|
645
|
+
* Starts with one probe covering all series of the source; when that probe is rejected,
|
|
646
|
+
* each series is probed individually, so readable data points are not blocked by unreadable ones.
|
|
647
|
+
*
|
|
648
|
+
* @param datapoints - The data points of one source.
|
|
649
|
+
* @returns A promise that resolves to the readable data points.
|
|
650
|
+
*/
|
|
651
|
+
async getReadableDatapointsOfSource(datapoints) {
|
|
652
|
+
const source = datapoints[0].source;
|
|
653
|
+
const allSeries = datapoints.map(datapoint => this.getSeriesName(datapoint));
|
|
654
|
+
if (await this.isSeriesReadable(source, allSeries)) {
|
|
655
|
+
return datapoints;
|
|
656
|
+
}
|
|
657
|
+
return datapoints.length === 1 ? [] : this.filterReadableDatapoints(datapoints);
|
|
658
|
+
}
|
|
659
|
+
/**
|
|
660
|
+
* Fetches the series data of a single source, deriving which of its data points are readable.
|
|
661
|
+
* A 403 for the grouped request triggers per-series probes and a refetch of the readable series;
|
|
662
|
+
* any other failure yields no readable data points, matching a rejected permission probe.
|
|
663
|
+
*
|
|
664
|
+
* @param datapoints - The data points of one source.
|
|
665
|
+
* @param exportConfig - The export configuration providing the date range and aggregation.
|
|
666
|
+
* @returns A promise that resolves to the readable data points and their fetched series data.
|
|
667
|
+
*/
|
|
668
|
+
async fetchReadableSeriesOfSource(datapoints, exportConfig) {
|
|
669
|
+
const fetchGroup = async (groupToFetch) => {
|
|
670
|
+
try {
|
|
671
|
+
return await this.fetchSeriesData({
|
|
672
|
+
dateFrom: exportConfig.dateFrom,
|
|
673
|
+
dateTo: exportConfig.dateTo,
|
|
674
|
+
source: groupToFetch[0].source,
|
|
675
|
+
series: groupToFetch.map(datapoint => this.getSeriesName(datapoint)),
|
|
676
|
+
aggregationType: exportConfig.aggregation
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
catch (error) {
|
|
680
|
+
// A rejection (fetchSeriesData rethrows only 422) is terminal for this source — the 403
|
|
681
|
+
// fallback below does not apply — so surface the failure instead of propagating it.
|
|
682
|
+
this.alertService.addServerFailure(error);
|
|
683
|
+
return undefined;
|
|
684
|
+
}
|
|
685
|
+
};
|
|
686
|
+
const fetched = await fetchGroup(datapoints);
|
|
687
|
+
if (fetched?.res?.status === 200) {
|
|
688
|
+
return {
|
|
689
|
+
readableDatapoints: datapoints,
|
|
690
|
+
sourceItem: { source: datapoints[0].source, data: fetched.data }
|
|
595
691
|
};
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
692
|
+
}
|
|
693
|
+
const noneReadable = { readableDatapoints: [], sourceItem: null };
|
|
694
|
+
// Only an authorization failure justifies falling back to per-series probes.
|
|
695
|
+
if (fetched?.res?.status !== 403 || datapoints.length === 1) {
|
|
696
|
+
return noneReadable;
|
|
697
|
+
}
|
|
698
|
+
const readableDatapoints = await this.filterReadableDatapoints(datapoints);
|
|
699
|
+
if (readableDatapoints.length === 0) {
|
|
700
|
+
return noneReadable;
|
|
701
|
+
}
|
|
702
|
+
const refetched = await fetchGroup(readableDatapoints);
|
|
703
|
+
if (refetched?.res?.status !== 200) {
|
|
704
|
+
return noneReadable;
|
|
705
|
+
}
|
|
706
|
+
return {
|
|
707
|
+
readableDatapoints,
|
|
708
|
+
sourceItem: { source: readableDatapoints[0].source, data: refetched.data }
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Probes each data point individually and returns those the user is permitted to read.
|
|
713
|
+
*
|
|
714
|
+
* @param datapoints - The data points to probe.
|
|
715
|
+
* @returns A promise that resolves to the readable data points.
|
|
716
|
+
*/
|
|
717
|
+
async filterReadableDatapoints(datapoints) {
|
|
718
|
+
const probedDatapoints = await Promise.all(datapoints.map(async (datapoint) => (await this.isSeriesReadable(datapoint.source, [this.getSeriesName(datapoint)]))
|
|
719
|
+
? datapoint
|
|
720
|
+
: null));
|
|
721
|
+
return probedDatapoints.filter(datapoint => datapoint !== null);
|
|
722
|
+
}
|
|
723
|
+
/**
|
|
724
|
+
* Returns the series name (`valueFragmentType.valueFragmentSeries`) of a data point.
|
|
725
|
+
*/
|
|
726
|
+
getSeriesName({ valueFragmentType, valueFragmentSeries }) {
|
|
727
|
+
return `${valueFragmentType}.${valueFragmentSeries}`;
|
|
728
|
+
}
|
|
729
|
+
/**
|
|
730
|
+
* Probes whether the user is permitted to read the given series of a source.
|
|
731
|
+
* Only the response status matters, so the date range is intentionally empty (now..now)
|
|
732
|
+
* to keep the probe free of measurement values — it is not a data fetch.
|
|
733
|
+
*
|
|
734
|
+
* @param source - The ID of the managed object the series belong to.
|
|
735
|
+
* @param series - The series names (`valueFragmentType.valueFragmentSeries`) to probe.
|
|
736
|
+
* @returns A promise that resolves to true when the probe request succeeds.
|
|
737
|
+
*/
|
|
738
|
+
async isSeriesReadable(source, series) {
|
|
739
|
+
const dateFrom = new Date();
|
|
740
|
+
const rawFilter = {
|
|
741
|
+
dateFrom,
|
|
742
|
+
dateTo: dateFrom,
|
|
743
|
+
source,
|
|
744
|
+
series
|
|
745
|
+
};
|
|
746
|
+
try {
|
|
747
|
+
const { res } = await this.fetchSeriesData(rawFilter);
|
|
748
|
+
return res?.status === 200;
|
|
749
|
+
}
|
|
750
|
+
catch {
|
|
751
|
+
// A failed probe means the series cannot be read; must not reject the whole permission check.
|
|
752
|
+
return false;
|
|
753
|
+
}
|
|
601
754
|
}
|
|
602
755
|
prepareSeriesFilter(filters, roundSeconds) {
|
|
603
756
|
const { dateFrom, dateTo, source, series, aggregationType } = filters;
|
|
@@ -1421,14 +1574,24 @@ class DatapointsExportSelectorFileExporterComponent {
|
|
|
1421
1574
|
this.isListTypeOfExport = this.exportConfig().exportType === 'latestWithDetails';
|
|
1422
1575
|
this.isDataScopeVisible = !this.isListTypeOfExport;
|
|
1423
1576
|
this.emitPreviewAvailability();
|
|
1424
|
-
|
|
1425
|
-
|
|
1577
|
+
let permittedDatapoints;
|
|
1578
|
+
let initialSeriesData = [];
|
|
1579
|
+
if (this.isListTypeOfExport) {
|
|
1580
|
+
permittedDatapoints = await this.dataFetchingService.getDatapointsWithPermissionsToRead(this.exportConfig().datapointDetails);
|
|
1581
|
+
}
|
|
1582
|
+
else {
|
|
1583
|
+
// The initial data fetch doubles as the permission check to avoid separate probe requests.
|
|
1584
|
+
const { dataToExport, readableDatapoints } = await this.dataFetchingService.fetchAndPrepareSeriesDataWithPermissions(this.exportConfig());
|
|
1585
|
+
permittedDatapoints = readableDatapoints;
|
|
1586
|
+
initialSeriesData = dataToExport;
|
|
1587
|
+
}
|
|
1588
|
+
if (permittedDatapoints.length === 0) {
|
|
1426
1589
|
this.isCheckingPermissions = false;
|
|
1427
1590
|
this.cdr.markForCheck();
|
|
1428
1591
|
return;
|
|
1429
1592
|
}
|
|
1430
|
-
if (
|
|
1431
|
-
this.exportConfig().datapointDetails =
|
|
1593
|
+
if (permittedDatapoints.length !== this.exportConfig().datapointDetails.length) {
|
|
1594
|
+
this.exportConfig().datapointDetails = permittedDatapoints;
|
|
1432
1595
|
}
|
|
1433
1596
|
const hasFullExportPermission = await this.dataFetchingService.hasPermissionToUseMeasurementsApi(this.exportConfig());
|
|
1434
1597
|
if (!hasFullExportPermission) {
|
|
@@ -1445,7 +1608,9 @@ class DatapointsExportSelectorFileExporterComponent {
|
|
|
1445
1608
|
await this.loadListExportData();
|
|
1446
1609
|
}
|
|
1447
1610
|
else {
|
|
1448
|
-
|
|
1611
|
+
// Reuse the data fetched by the permission check instead of fetching it again.
|
|
1612
|
+
this.dataToExport = initialSeriesData;
|
|
1613
|
+
this.determineShowingPreviewOrEmptyState();
|
|
1449
1614
|
this.handleExportModeChanges();
|
|
1450
1615
|
}
|
|
1451
1616
|
this.handleDateSelectorChanges();
|
|
@@ -2380,11 +2545,11 @@ class DatapointsExportSelectorComponent {
|
|
|
2380
2545
|
this.isOpen.emit(await modalRef.result);
|
|
2381
2546
|
}
|
|
2382
2547
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: DatapointsExportSelectorComponent, deps: [{ token: i1$1.BsModalService }, { token: i1.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2383
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", 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 }); }
|
|
2548
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", 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 data-cy=\"datapoints-export-selector--open-export-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 }); }
|
|
2384
2549
|
}
|
|
2385
2550
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: DatapointsExportSelectorComponent, decorators: [{
|
|
2386
2551
|
type: Component,
|
|
2387
|
-
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" }]
|
|
2552
|
+
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 data-cy=\"datapoints-export-selector--open-export-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" }]
|
|
2388
2553
|
}], 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"] }] } });
|
|
2389
2554
|
|
|
2390
2555
|
/**
|