@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
270 lines (263 loc) • 21.6 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, Component, NgModule } from '@angular/core';
import * as i1 from '@c8y/client';
import { OperationStatus } from '@c8y/client';
import { gettext } from '@c8y/ngx-components/gettext';
import * as i2 from '@c8y/ngx-components';
import { operationStatusIcons, operationStatusClasses, ActionBarItemComponent, IconDirective, C8yTranslateDirective, ListGroupComponent, ForOfDirective, ListItemTimelineComponent, ListItemComponent, ListItemIconComponent, ListItemBodyComponent, ListItemActionComponent, EmptyStateComponent, C8yTranslatePipe, DatePipe, CoreModule, ListGroupModule, hookRoute, ViewContext } from '@c8y/ngx-components';
import { assign } from 'lodash-es';
import { switchMap, map } from 'rxjs/operators';
import * as i1$1 from '@angular/router';
import { RouterModule } from '@angular/router';
import { BehaviorSubject, pipe } from 'rxjs';
import { NgIf, NgClass, CommonModule } from '@angular/common';
import { TooltipDirective, TooltipModule } from 'ngx-bootstrap/tooltip';
import { FileDownloadComponent, SharedRepositoryModule } from '@c8y/ngx-components/repository/shared';
import { BsDropdownModule, BsDropdownConfig } from 'ngx-bootstrap/dropdown';
class DiagnosticsService {
constructor(operationService, inventoryBinary, modalService, alertService) {
this.operationService = operationService;
this.inventoryBinary = inventoryBinary;
this.modalService = modalService;
this.alertService = alertService;
this.fragment = 'c8y_DiagnosticReport';
}
isSupportedDevice(device) {
const supportedOperations = (device && device.c8y_SupportedOperations) || [];
return supportedOperations.includes(this.fragment);
}
getOperations$(device$) {
return device$.pipe(switchMap(device => this.operationService.list({
deviceId: device.id,
fragmentType: this.fragment,
dateFrom: new Date(0).toISOString(),
dateTo: new Date(Date.now()).toISOString(),
revert: true,
pageSize: 10,
withTotalPages: true
})));
}
async createOperation(deviceId) {
const operation = {
deviceId,
description: gettext('Diagnostic file request'),
[this.fragment]: {}
};
try {
await this.operationService.create(operation);
this.alertService.success(gettext('Diagnostic file request sent.'));
}
catch (error) {
this.alertService.addServerFailure(error);
}
}
async deleteOperation(operation) {
try {
const result = await this.modalService.confirm(gettext('Delete diagnostic file'), gettext('You are about to delete this diagnostic file. Do you want to proceed?'), 'danger', {
ok: gettext('Delete'),
cancel: gettext('Cancel')
});
if (result) {
this.deleteDiagnosticsBinary(operation);
}
}
catch (error) {
// Do nothing
}
}
async cancelOperation(operation) {
try {
const operationAfterUpdate = (await this.operationService.update({
id: operation.id,
status: OperationStatus.FAILED,
failureReason: gettext('Operation cancelled by user.')
})).data;
assign(operation, operationAfterUpdate);
this.alertService.success(gettext('Diagnostic file request cancelled.'));
}
catch (ex) {
this.alertService.addServerFailure(ex);
}
}
getOperation(op) {
if (!op) {
return null;
}
return op && op[this.fragment];
}
async deleteDiagnosticsBinary(op) {
const operation = this.getOperation(op);
if (operation && operation.file) {
const { file } = operation;
try {
const binaryId = this.inventoryBinary.getIdFromUrl(file);
const result = await this.inventoryBinary.delete(binaryId);
if (result) {
this.deleteDiagnosticsFragment(op);
}
}
catch (err) {
if (err.res.status === 404) {
// In case the file is already deleted via other means we want to delete the fragment
this.deleteDiagnosticsFragment(op);
}
else {
const msg = gettext('Could not delete the diagnostic file.');
this.alertService.danger(msg);
}
}
}
}
async deleteDiagnosticsFragment(op) {
const deleteOp = {
id: op.id,
status: op.status,
[this.fragment]: null
};
try {
const operationAfterUpdate = (await this.operationService.update(deleteOp)).data;
assign(op, operationAfterUpdate);
this.alertService.success(gettext('Diagnostic file deleted.'));
}
catch (error) {
this.alertService.addServerFailure(error);
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DiagnosticsService, deps: [{ token: i1.OperationService }, { token: i1.InventoryBinaryService }, { token: i2.ModalService }, { token: i2.AlertService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DiagnosticsService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DiagnosticsService, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: i1.OperationService }, { type: i1.InventoryBinaryService }, { type: i2.ModalService }, { type: i2.AlertService }] });
class DiagnosticsTabGuard {
constructor(diagnosticsService) {
this.diagnosticsService = diagnosticsService;
}
canActivate(route) {
const device = route.data.contextData || route.parent.data.contextData;
return this.diagnosticsService.isSupportedDevice(device);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DiagnosticsTabGuard, deps: [{ token: DiagnosticsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DiagnosticsTabGuard }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DiagnosticsTabGuard, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: DiagnosticsService }] });
class DiagnosticsComponent {
constructor(route, diagnosticService, operationRealtime) {
this.route = route;
this.diagnosticService = diagnosticService;
this.operationRealtime = operationRealtime;
this.statusIcons = operationStatusIcons;
this.statusClasses = operationStatusClasses;
this.deviceId = this.route.snapshot.parent.data.contextData.id;
this.device$ = new BehaviorSubject(this.route.snapshot.parent.data.contextData);
this.operations$ = this.diagnosticService.getOperations$(this.device$);
this.operationsPipe = pipe(map(ops => ops.filter(op => op[this.diagnosticService.fragment])));
this.realtimeOptions = {
entityOrId: this.deviceId,
removeOnUpdate: true,
insertOnUpdate: true
};
}
onDiagnosticRequest() {
this.diagnosticService.createOperation(this.deviceId);
}
onDelete(operation) {
this.diagnosticService.deleteOperation(operation);
}
onCancel(operation) {
this.diagnosticService.cancelOperation(operation);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DiagnosticsComponent, deps: [{ token: i1$1.ActivatedRoute }, { token: DiagnosticsService }, { token: i2.OperationRealtimeService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: DiagnosticsComponent, isStandalone: true, selector: "c8y-diagnostics", ngImport: i0, template: "<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n type=\"button\"\n title=\"{{ 'Request diagnostic file' | translate }}\"\n (click)=\"onDiagnosticRequest()\"\n >\n <i c8yIcon=\"stethoscope\"></i>\n <span translate>Request diagnostic file</span>\n </button>\n</c8y-action-bar-item>\n\n<div\n class=\"page-sticky-header hidden-xs c8y-list__item c8y-list--timeline\"\n *ngIf=\"operationCount > 0\"\n>\n <div class=\"d-flex\">\n <div class=\"c8y-list--timeline__item__date a-s-center\">\n <label>{{ 'Date' | translate }}</label>\n </div>\n <div class=\"c8y-list__item__block flex-grow\">\n <div class=\"c8y-list__item__icon\">\n <i class=\"p-l-24\"></i>\n </div>\n <div class=\"c8y-list__item__body\">\n <div class=\"content-flex-40\">\n <div class=\"col-4\">{{ 'Event' | translate }}</div>\n <div class=\"col-5 m-l-8\">{{ 'File' | translate }}</div>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n<c8y-list-group>\n <ng-template\n c8yFor\n let-operation\n [c8yForOf]=\"operations$\"\n [c8yForPipe]=\"operationsPipe\"\n [c8yForRealtime]=\"operationRealtime\"\n [c8yForRealtimeOptions]=\"realtimeOptions\"\n (c8yForCount)=\"operationCount = $event\"\n >\n <c8y-li-timeline>\n {{ operation.creationTime | c8yDate }}\n <c8y-li>\n <c8y-li-icon>\n <i\n [c8yIcon]=\"statusIcons[operation.status]\"\n [ngClass]=\"statusClasses[operation.status]\"\n [tooltip]=\"operation.status?.toString() | translate\"\n ></i>\n </c8y-li-icon>\n <c8y-li-body class=\"content-flex-40\">\n <div class=\"col-4\">\n <p class=\"text-truncate-wrap\" title=\"{{ operation.description | translate }}\">\n {{ operation.description | translate }}\n </p>\n </div>\n <div class=\"col-5\" *ngIf=\"operation.c8y_DiagnosticReport?.file\">\n <div class=\"text-truncate-wrap m-t-xs-8\">\n <span class=\"text-label-small visible-xs\" translate>File</span>\n <span title=\"{{ operation.c8y_DiagnosticReport.file }}\">\n <c8y-file-download\n url=\"{{ operation.c8y_DiagnosticReport.file }}\"\n ></c8y-file-download>\n </span>\n </div>\n </div>\n </c8y-li-body>\n <c8y-li-action\n (click)=\"onCancel(operation)\"\n *ngIf=\"operation.status === 'PENDING'\"\n icon=\"times\"\n label=\"{{ 'Cancel' | translate }}\"\n ></c8y-li-action>\n <c8y-li-action\n (click)=\"onDelete(operation)\"\n *ngIf=\"operation.status === 'SUCCESSFUL'\"\n icon=\"delete\"\n label=\"{{ 'Delete' | translate }}\"\n ></c8y-li-action>\n </c8y-li>\n </c8y-li-timeline>\n </ng-template>\n</c8y-list-group>\n\n<!-- EMPTY STATE -->\n\n<c8y-ui-empty-state\n *ngIf=\"operationCount === 0\"\n [icon]=\"'stethoscope'\"\n [title]=\"'No diagnostic files available.' | translate\"\n></c8y-ui-empty-state>\n", dependencies: [{ kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ListGroupComponent, selector: "c8y-list-group" }, { kind: "directive", type: ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "component", type: ListItemTimelineComponent, selector: "c8y-list-item-timeline, c8y-li-timeline" }, { kind: "component", type: ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: 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: "component", type: ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "component", type: FileDownloadComponent, selector: "c8y-file-download", inputs: ["url"] }, { kind: "component", type: ListItemActionComponent, selector: "c8y-list-item-action, c8y-li-action", inputs: ["label", "icon", "disabled"], outputs: ["click"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: DatePipe, name: "c8yDate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DiagnosticsComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-diagnostics', imports: [
ActionBarItemComponent,
IconDirective,
C8yTranslateDirective,
NgIf,
ListGroupComponent,
ForOfDirective,
ListItemTimelineComponent,
ListItemComponent,
ListItemIconComponent,
NgClass,
TooltipDirective,
ListItemBodyComponent,
FileDownloadComponent,
ListItemActionComponent,
EmptyStateComponent,
C8yTranslatePipe,
DatePipe
], template: "<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n type=\"button\"\n title=\"{{ 'Request diagnostic file' | translate }}\"\n (click)=\"onDiagnosticRequest()\"\n >\n <i c8yIcon=\"stethoscope\"></i>\n <span translate>Request diagnostic file</span>\n </button>\n</c8y-action-bar-item>\n\n<div\n class=\"page-sticky-header hidden-xs c8y-list__item c8y-list--timeline\"\n *ngIf=\"operationCount > 0\"\n>\n <div class=\"d-flex\">\n <div class=\"c8y-list--timeline__item__date a-s-center\">\n <label>{{ 'Date' | translate }}</label>\n </div>\n <div class=\"c8y-list__item__block flex-grow\">\n <div class=\"c8y-list__item__icon\">\n <i class=\"p-l-24\"></i>\n </div>\n <div class=\"c8y-list__item__body\">\n <div class=\"content-flex-40\">\n <div class=\"col-4\">{{ 'Event' | translate }}</div>\n <div class=\"col-5 m-l-8\">{{ 'File' | translate }}</div>\n </div>\n </div>\n </div>\n </div>\n</div>\n\n<c8y-list-group>\n <ng-template\n c8yFor\n let-operation\n [c8yForOf]=\"operations$\"\n [c8yForPipe]=\"operationsPipe\"\n [c8yForRealtime]=\"operationRealtime\"\n [c8yForRealtimeOptions]=\"realtimeOptions\"\n (c8yForCount)=\"operationCount = $event\"\n >\n <c8y-li-timeline>\n {{ operation.creationTime | c8yDate }}\n <c8y-li>\n <c8y-li-icon>\n <i\n [c8yIcon]=\"statusIcons[operation.status]\"\n [ngClass]=\"statusClasses[operation.status]\"\n [tooltip]=\"operation.status?.toString() | translate\"\n ></i>\n </c8y-li-icon>\n <c8y-li-body class=\"content-flex-40\">\n <div class=\"col-4\">\n <p class=\"text-truncate-wrap\" title=\"{{ operation.description | translate }}\">\n {{ operation.description | translate }}\n </p>\n </div>\n <div class=\"col-5\" *ngIf=\"operation.c8y_DiagnosticReport?.file\">\n <div class=\"text-truncate-wrap m-t-xs-8\">\n <span class=\"text-label-small visible-xs\" translate>File</span>\n <span title=\"{{ operation.c8y_DiagnosticReport.file }}\">\n <c8y-file-download\n url=\"{{ operation.c8y_DiagnosticReport.file }}\"\n ></c8y-file-download>\n </span>\n </div>\n </div>\n </c8y-li-body>\n <c8y-li-action\n (click)=\"onCancel(operation)\"\n *ngIf=\"operation.status === 'PENDING'\"\n icon=\"times\"\n label=\"{{ 'Cancel' | translate }}\"\n ></c8y-li-action>\n <c8y-li-action\n (click)=\"onDelete(operation)\"\n *ngIf=\"operation.status === 'SUCCESSFUL'\"\n icon=\"delete\"\n label=\"{{ 'Delete' | translate }}\"\n ></c8y-li-action>\n </c8y-li>\n </c8y-li-timeline>\n </ng-template>\n</c8y-list-group>\n\n<!-- EMPTY STATE -->\n\n<c8y-ui-empty-state\n *ngIf=\"operationCount === 0\"\n [icon]=\"'stethoscope'\"\n [title]=\"'No diagnostic files available.' | translate\"\n></c8y-ui-empty-state>\n" }]
}], ctorParameters: () => [{ type: i1$1.ActivatedRoute }, { type: DiagnosticsService }, { type: i2.OperationRealtimeService }] });
class DiagnosticsModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DiagnosticsModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: DiagnosticsModule, imports: [CoreModule,
RouterModule,
CommonModule,
ListGroupModule,
SharedRepositoryModule,
BsDropdownModule,
TooltipModule,
DiagnosticsComponent], exports: [DiagnosticsComponent] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DiagnosticsModule, providers: [
DiagnosticsService,
BsDropdownConfig,
DiagnosticsTabGuard,
hookRoute({
context: ViewContext.Device,
path: 'diagnostics',
component: DiagnosticsComponent,
label: gettext('Diagnostics'),
icon: 'stethoscope',
canActivate: [DiagnosticsTabGuard],
priority: 200
})
], imports: [CoreModule,
RouterModule,
CommonModule,
ListGroupModule,
SharedRepositoryModule,
BsDropdownModule,
TooltipModule,
DiagnosticsComponent] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DiagnosticsModule, decorators: [{
type: NgModule,
args: [{
imports: [
CoreModule,
RouterModule,
CommonModule,
ListGroupModule,
SharedRepositoryModule,
BsDropdownModule,
TooltipModule,
DiagnosticsComponent
],
exports: [DiagnosticsComponent],
providers: [
DiagnosticsService,
BsDropdownConfig,
DiagnosticsTabGuard,
hookRoute({
context: ViewContext.Device,
path: 'diagnostics',
component: DiagnosticsComponent,
label: gettext('Diagnostics'),
icon: 'stethoscope',
canActivate: [DiagnosticsTabGuard],
priority: 200
})
]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { DiagnosticsComponent, DiagnosticsModule, DiagnosticsService, DiagnosticsTabGuard };
//# sourceMappingURL=c8y-ngx-components-diagnostics.mjs.map