@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
198 lines • 93.6 kB
JavaScript
import { __decorate, __metadata } from "tslib";
import { Component } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { InventoryService } from '@c8y/client';
import { AlertService, GainsightService, ModalService, Status, gettext, memoize } from '@c8y/ngx-components';
import { PRODUCT_EXPERIENCE_REPOSITORY_SHARED, RepositoryService } from '@c8y/ngx-components/repository/shared';
import { TranslateService } from '@ngx-translate/core';
import { property } from 'lodash-es';
import { BsModalService } from 'ngx-bootstrap/modal';
import { BehaviorSubject, Subject, combineLatest, defer, merge } from 'rxjs';
import { distinctUntilKeyChanged, map, shareReplay, switchMap, take, takeUntil, tap, withLatestFrom } from 'rxjs/operators';
import { AddFirmwareModalComponent } from './add-firmware-modal.component';
import { AddFirmwarePatchModalComponent } from './add-firmware-patch-modal.component';
import * as i0 from "@angular/core";
import * as i1 from "@angular/router";
import * as i2 from "@c8y/client";
import * as i3 from "@c8y/ngx-components/repository/shared";
import * as i4 from "@c8y/ngx-components";
import * as i5 from "@ngx-translate/core";
import * as i6 from "ngx-bootstrap/modal";
import * as i7 from "@angular/common";
import * as i8 from "@angular/forms";
import * as i9 from "ngx-bootstrap/popover";
import * as i10 from "ngx-bootstrap/tooltip";
export class FirmwareDetailsComponent {
constructor(activatedRoute, inventoryService, repositoryService, alertService, translateService, modalService, bsModalService, gainsightService, router) {
this.activatedRoute = activatedRoute;
this.inventoryService = inventoryService;
this.repositoryService = repositoryService;
this.alertService = alertService;
this.translateService = translateService;
this.modalService = modalService;
this.bsModalService = bsModalService;
this.gainsightService = gainsightService;
this.router = router;
this.reload$ = new Subject();
this.reloading$ = new BehaviorSubject(false);
this.updateFirmware$ = new Subject();
this.firmwareUpdated$ = new Subject();
this.baseVersionsUpdated$ = new Subject();
this.patchVersionsUpdated$ = new Subject();
this.firmware$ = merge(this.activatedRoute.params.pipe(map(params => params.id), switchMap(id => defer(() => this.inventoryService.detail(id).then(result => result.data)))), this.reload$.pipe(tap(() => this.reloading$.next(true)), switchMap(() => this.activatedRoute.params), map(params => params.id), switchMap(id => defer(() => this.inventoryService.detail(id).then(result => result.data))), tap(() => this.reloading$.next(false))), this.firmwareUpdated$).pipe(shareReplay(1));
this.baseVersions$ = merge(this.firmware$.pipe(distinctUntilKeyChanged('id')), this.baseVersionsUpdated$, this.patchVersionsUpdated$, this.reload$).pipe(switchMap(() => this.firmware$), switchMap(firmware => this.repositoryService.listBaseVersions(firmware)), shareReplay(1));
this.isLegacy$ = this.firmware$.pipe(map(firmware => this.repositoryService.isLegacyEntry(firmware)), shareReplay(1));
this.canAddPatchVersions$ = combineLatest(this.isLegacy$, this.baseVersions$.pipe(map(({ data }) => data.length > 0))).pipe(map(([isLegacy, hasBaseVersions]) => !isLegacy && hasBaseVersions));
this.expanded = {};
this.destroy$ = new Subject();
}
ngOnInit() {
this.updateFirmware$
.pipe(withLatestFrom(this.firmware$), switchMap(([firmwarePartial, firmware]) => this.inventoryService.update({
id: firmware.id,
...firmwarePartial
})), map(({ data }) => data), tap(firmware => this.firmwareUpdated$.next(firmware)), tap(() => this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_REPOSITORY_SHARED.FIRMWARE.EVENTS.REPOSITORY, {
result: PRODUCT_EXPERIENCE_REPOSITORY_SHARED.FIRMWARE.RESULTS.EDIT_FIRMWARE
})), tap(() => this.alertService.success(gettext('Saved.'))), takeUntil(this.destroy$))
.subscribe();
this.firmware$.subscribe(firmware => {
this.firmware = firmware;
});
}
getPatchVersionsCount$(baseVersion) {
return merge(this.firmware$.pipe(distinctUntilKeyChanged('id')), this.baseVersionsUpdated$, this.patchVersionsUpdated$, this.reload$).pipe(switchMap(() => this.firmware$), switchMap(firmware => this.repositoryService.getPatchVersionsCount$(firmware, baseVersion)), shareReplay(1));
}
getBinaryName$(binaryUrl) {
return this.repositoryService.getBinaryName$(binaryUrl);
}
getPatchVersions$(baseVersion) {
return merge(this.firmware$.pipe(distinctUntilKeyChanged('id')), this.patchVersionsUpdated$, this.reload$).pipe(switchMap(() => this.firmware$), switchMap(firmware => this.repositoryService.listPatchVersions(firmware, baseVersion)), shareReplay(1));
}
addBaseVersion() {
this.firmware$
.pipe(take(1), switchMap(firmware => {
const initialState = {
model: {
selected: firmware,
description: firmware.description
}
};
const config = {
class: 'modal-sm',
ignoreBackdropClick: true,
keyboard: false,
ariaDescribedby: 'addFirmwareModalDescription',
ariaLabelledBy: 'addFirmwareModalTitle',
initialState
};
const modalRef = this.bsModalService.show(AddFirmwareModalComponent, config);
return modalRef.content.saved;
}))
.subscribe(() => this.baseVersionsUpdated$.next());
}
addPatchVersion() {
this.firmware$
.pipe(take(1), switchMap(firmware => {
const initialState = {
model: {
selected: firmware
}
};
const config = {
class: 'modal-sm',
ignoreBackdropClick: true,
keyboard: false,
ariaDescribedby: 'addFirmwarePatchModalDescription',
ariaLabelledBy: 'addFirmwarePatchModalTitle',
initialState
};
const modalRef = this.bsModalService.show(AddFirmwarePatchModalComponent, config);
return modalRef.content.saved;
}))
.subscribe(() => this.patchVersionsUpdated$.next());
}
async deleteBaseVersion(baseVersion) {
try {
const title = gettext('Delete firmware');
const body = `
${this.translateService.instant(gettext('You are about to delete firmware {{ version }} with all its patches.'), { version: baseVersion.c8y_Firmware.version })}
${this.translateService.instant(gettext('This operation is irreversible.'))}
${this.translateService.instant(gettext('Do you want to proceed?'))}
`;
const labels = {
ok: gettext('Delete')
};
await this.modalService.confirm(title, body, Status.DANGER, labels, {}, { eventName: PRODUCT_EXPERIENCE_REPOSITORY_SHARED.FIRMWARE.EVENTS.REPOSITORY });
const isLastVersion = await this.baseVersions$
.pipe(map(versions => versions?.data?.length === 1), take(1))
.toPromise();
if (isLastVersion) {
await this.repositoryService.delete(this.firmware);
this.router.navigateByUrl('/firmware');
}
else {
await this.repositoryService.delete(baseVersion);
this.baseVersionsUpdated$.next();
}
this.alertService.success(gettext('Firmware deleted.'));
}
catch (ex) {
// only if not cancel from modal
if (ex) {
this.alertService.addServerFailure(ex);
}
}
}
async deletePatchVersion(patchVersion) {
try {
const title = gettext('Delete firmware patch');
const body = `
${this.translateService.instant(gettext('You are about to delete firmware patch {{ version }}.'), { version: patchVersion.c8y_Firmware.version })}
${this.translateService.instant(gettext('This operation is irreversible.'))}
${this.translateService.instant(gettext('Do you want to proceed?'))}
`;
const labels = {
ok: gettext('Delete')
};
await this.modalService.confirm(title, body, Status.DANGER, labels, {}, { eventName: PRODUCT_EXPERIENCE_REPOSITORY_SHARED.FIRMWARE.EVENTS.REPOSITORY });
await this.repositoryService.delete(patchVersion);
this.alertService.success(gettext('Firmware patch deleted.'));
this.patchVersionsUpdated$.next();
}
catch (ex) {
// only if not cancel from modal
if (ex) {
this.alertService.addServerFailure(ex);
}
}
}
ngOnDestroy() {
this.destroy$.next(true);
this.destroy$.unsubscribe();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FirmwareDetailsComponent, deps: [{ token: i1.ActivatedRoute }, { token: i2.InventoryService }, { token: i3.RepositoryService }, { token: i4.AlertService }, { token: i5.TranslateService }, { token: i4.ModalService }, { token: i6.BsModalService }, { token: i4.GainsightService }, { token: i1.Router }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: FirmwareDetailsComponent, selector: "c8y-firmware-details", ngImport: i0, template: "<c8y-title>\n {{ (firmware$ | async)?.name }}\n</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n label=\"{{ 'Management' | translate }}\"\n icon=\"c8y-management\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n path=\"#/firmware\"\n label=\"{{ 'Firmware repository' | translate }}\"\n icon=\"c8y-firmware\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n label=\"{{ (firmware$ | async)?.name }}\"\n icon=\"c8y-firmware\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n *ngIf=\"!(isLegacy$ | async)\"\n class=\"btn btn-link\"\n type=\"button\"\n title=\"{{ 'Add firmware' | translate }}\"\n data-cy=\"firmware-details--add-firmware-btn\"\n (click)=\"addBaseVersion()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add firmware' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n *ngIf=\"canAddPatchVersions$ | async\"\n class=\"btn btn-link\"\n type=\"button\"\n title=\"{{ 'Add firmware patch' | translate }}\"\n data-cy=\"firmware-details--add-firmware-patch-btn\"\n (click)=\"addPatchVersion()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add firmware patch' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n type=\"button\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"reload$.next()\"\n >\n <i c8yIcon=\"refresh\" [ngClass]=\"{ 'icon-spin': reloading$ | async }\"></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<div class=\"row\">\n <div class=\"col-lg-12 col-lg-max\">\n <div class=\"card card--fullpage\">\n <div class=\"card-block bg-level-1 flex-no-shrink p-t-24 p-b-24\">\n <div class=\"content-flex-70\">\n <div class=\"text-center\">\n <i class=\"c8y-icon-duocolor icon-48 c8y-icon c8y-icon-firmware\"></i>\n <p>\n <small class=\"label label-info\">Firmware</small>\n </p>\n </div>\n <div class=\"flex-grow col-10\">\n <div class=\"row\">\n <div class=\"col-md-4\">\n <c8y-form-group>\n <label class=\"control-label\">\n {{ 'Name' | translate }}\n </label>\n <div class=\"input-group input-group-editable\">\n <input\n #nameInput\n type=\"text\"\n class=\"form-control\"\n [ngModel]=\"(firmware$ | async)?.name\"\n #nameModel=\"ngModel\"\n placeholder=\"{{ 'e.g. My firmware' | translate }}\"\n data-cy=\"firmware-details--name-input\"\n [ngStyle]=\"{ 'width.ch': (firmware$ | async)?.name?.length + 2 || 36 }\"\n required\n />\n <span></span>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-primary\"\n type=\"button\"\n title=\"{{ 'Save' | translate }}\"\n data-cy=\"firmware-details--name-save-btn\"\n (click)=\"updateFirmware$.next({ name: nameInput.value }); nameModel.reset()\"\n [disabled]=\"nameInput.value.length == 0\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </c8y-form-group>\n </div>\n <div class=\"col-md-4\">\n <c8y-form-group>\n <label class=\"control-label\">\n {{ 'Description' | translate }}\n </label>\n <div class=\"input-group input-group-editable\">\n <input\n #descriptionInput\n type=\"text\"\n class=\"form-control\"\n [ngModel]=\"(firmware$ | async)?.description\"\n #descriptionModel=\"ngModel\"\n placeholder=\"{{ 'e.g. Firmware for hardware revision B' | translate }}\"\n data-cy=\"firmware-details--description-input\"\n [ngStyle]=\"{ 'width.ch': (firmware$ | async)?.description?.length || 36 }\"\n />\n <span></span>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-primary\"\n type=\"button\"\n title=\"{{ 'Save' | translate }}\"\n data-cy=\"firmware-details--description-save-btn\"\n (click)=\"\n updateFirmware$.next({ description: descriptionInput.value });\n descriptionModel.reset()\n \"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </c8y-form-group>\n </div>\n <div class=\"col-md-4\">\n <c8y-form-group>\n <label class=\"control-label\">\n {{ 'Device type filter' | translate }}\n\n <button\n class=\"btn-help\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{\n 'If the filter is set, the firmware will show up for installation only for devices of that type. If no filter is set, it will be available for all devices.'\n | translate\n }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n >\n <i c8yIcon=\"question-circle-o\"></i>\n </button>\n </label>\n <div class=\"input-group input-group-editable\">\n <input\n #deviceTypeInput\n type=\"text\"\n class=\"form-control\"\n [ngModel]=\"(firmware$ | async)?.c8y_Filter?.type\"\n #deviceTypeModel=\"ngModel\"\n placeholder=\"{{ 'e.g.' | translate }} c8y_Linux\"\n data-cy=\"firmware-details--device-type-filter-input\"\n [ngStyle]=\"{ 'width.ch': (firmware$ | async)?.type?.length || 36 }\"\n />\n <span></span>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-primary\"\n type=\"button\"\n title=\"{{ 'Save' | translate }}\"\n data-cy=\"firmware-details--device-type-filter-save-btn\"\n (click)=\"\n updateFirmware$.next({ c8y_Filter: { type: deviceTypeInput.value } });\n deviceTypeModel.reset()\n \"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </c8y-form-group>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"card-header separator-top-bottom bg-component sticky-top\">\n <div class=\"card-title\" translate>Versions and patches</div>\n </div>\n\n <div class=\"card-block p-t-0 p-b-24\">\n <div *ngIf=\"(baseVersions$ | async)?.data.length === 0\">\n <c8y-ui-empty-state\n [icon]=\"'c8y-firmware'\"\n [title]=\"'No versions to display.' | translate\"\n [subtitle]=\"'Add a new version by clicking below.' | translate\"\n [horizontal]=\"true\"\n >\n <button\n class=\"btn btn-sm btn-default m-t-8\"\n type=\"button\"\n title=\"{{ 'Add firmware' | translate }}\"\n (click)=\"addBaseVersion()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add firmware' | translate }}\n </button>\n </c8y-ui-empty-state>\n </div>\n\n <c8y-list-group *ngIf=\"(baseVersions$ | async)?.data.length > 0\">\n <c8y-li\n *c8yFor=\"let baseVersion of baseVersions$ | async; let i = index; loadMore: 'auto'\"\n [emptyActions]=\"!(getPatchVersions$(baseVersion) | async)?.data.length\"\n [collapsed]=\"!expanded[baseVersion.id]\"\n (collapsedChange)=\"expanded[baseVersion.id] = !$event\"\n >\n <c8y-li-icon>\n <i c8yIcon=\"c8y-firmware\"></i>\n </c8y-li-icon>\n\n <c8y-li-body class=\"content-flex-50\">\n <div class=\"col-4\">\n <p class=\"text-truncate\" title=\"{{ baseVersion.c8y_Firmware.version }}\">\n {{ baseVersion.c8y_Firmware.version }}\n </p>\n </div>\n <div class=\"col-5\">\n <p class=\"text-truncate\">\n <span class=\"text-label-small m-r-8\" translate>File</span>\n <span title=\"{{ getBinaryName$(baseVersion.c8y_Firmware.url) | async }}\">\n <c8y-file-download\n url=\"{{ baseVersion.c8y_Firmware.url }}\"\n ></c8y-file-download>\n </span>\n </p>\n </div>\n <div class=\"col-2 d-flex a-i-start\">\n <span *ngIf=\"isLegacy$ | async\" class=\"label label-warning m-l-auto-sm\">\n {{ 'Legacy' | translate }}\n </span>\n\n <span *ngIf=\"!(isLegacy$ | async)\">\n <span *ngIf=\"(getPatchVersionsCount$(baseVersion) | async) === null\">\n <span class=\"label label-info\">\n <i c8yIcon=\"circle-o-notch\" class=\"icon-spin\"></i>\n </span>\n </span>\n <span *ngIf=\"(getPatchVersionsCount$(baseVersion) | async) !== null\">\n <span [ngPlural]=\"getPatchVersionsCount$(baseVersion) | async\">\n <ng-template ngPluralCase=\"=0\">\n <span class=\"label label-default m-l-auto-sm\">\n <span translate>No patches</span>\n </span>\n </ng-template>\n <ng-template ngPluralCase=\"=1\">\n <span class=\"label label-info\">\n <span translate>1 patch</span>\n </span>\n </ng-template>\n <ng-template ngPluralCase=\"other\">\n <span class=\"label label-info\">\n <span\n ngNonBindable\n translate\n [translateParams]=\"{\n count: getPatchVersionsCount$(baseVersion) | async\n }\"\n >\n {{ count }} patches\n </span>\n </span>\n </ng-template>\n </span>\n </span>\n </span>\n </div>\n <div class=\"fit-h-20 visible-xs\" *ngIf=\"!(isLegacy$ | async)\">\n <button\n class=\"btn btn-default btn-sm m-t-8\"\n type=\"button\"\n title=\"{{ 'Delete' | translate }}\"\n (click)=\"deleteBaseVersion(baseVersion)\"\n >\n <i c8yIcon=\"delete\"></i>\n {{ 'Delete' | translate }}\n </button>\n </div>\n <div *ngIf=\"!(isLegacy$ | async)\" class=\"m-l-auto fit-h-20 p-r-8 hidden-xs\">\n <button\n class=\"btn btn-dot btn-dot--danger showOnHover\"\n type=\"button\"\n [attr.aria-label]=\"'Delete' | translate\"\n data-cy=\"firmware-details--delete-base-version\"\n tooltip=\"{{ 'Delete' | translate }}\"\n [delay]=\"500\"\n (click)=\"deleteBaseVersion(baseVersion)\"\n >\n <i c8yIcon=\"delete\"></i>\n </button>\n </div>\n </c8y-li-body>\n <c8y-li-collapse *ngIf=\"(getPatchVersions$(baseVersion) | async)?.data.length\">\n <c8y-list-group class=\"separator-top\">\n <c8y-li\n *c8yFor=\"\n let patchVersion of getPatchVersions$(baseVersion) | async;\n let i = index;\n loadMore: 'auto'\n \"\n >\n <c8y-li-icon>\n <i c8yIcon=\"c8y-firmware\"></i>\n </c8y-li-icon>\n <c8y-li-body class=\"content-flex-50\">\n <div class=\"col-4\">\n {{ patchVersion.c8y_Firmware.version }}\n </div>\n <div class=\"col-5\">\n <div class=\"text-truncate\">\n <span class=\"text-label-small m-r-8\" translate>File</span>\n <c8y-file-download\n url=\"{{ patchVersion.c8y_Firmware.url }}\"\n ></c8y-file-download>\n </div>\n </div>\n <div class=\"visible-xs m-t-8\">\n <button\n class=\"btn btn-danger btn-xs\"\n type=\"button\"\n title=\"{{ 'Delete' | translate }}\"\n data-cy=\"firmware-details--delete-patch-version\"\n (click)=\"deletePatchVersion(patchVersion)\"\n >\n <i c8yIcon=\"delete\"></i>\n {{ 'Delete' | translate }}\n </button>\n </div>\n <div class=\"m-l-auto p-r-8 hidden-xs fit-h-20\">\n <button\n class=\"btn btn-dot text-danger showOnHover\"\n type=\"button\"\n [attr.aria-label]=\"'Delete' | translate\"\n tooltip=\"{{ 'Delete' | translate }}\"\n placement=\"right\"\n [delay]=\"500\"\n (click)=\"deletePatchVersion(patchVersion)\"\n >\n <i c8yIcon=\"delete\" data-cy=\"firmware-details--Remove-icon\"></i>\n </button>\n </div>\n </c8y-li-body>\n </c8y-li>\n </c8y-list-group>\n </c8y-li-collapse>\n </c8y-li>\n </c8y-list-group>\n </div>\n </div>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i7.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i7.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i7.NgPlural, selector: "[ngPlural]", inputs: ["ngPlural"] }, { kind: "directive", type: i7.NgPluralCase, selector: "[ngPluralCase]" }, { kind: "component", type: i4.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i4.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i4.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i4.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i4.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i4.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i4.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: i4.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: i8.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i8.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i8.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i8.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i4.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i4.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: i4.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i4.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i4.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i4.ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "component", type: i4.ListItemCollapseComponent, selector: "c8y-list-item-collapse, c8y-li-collapse", inputs: ["collapseWay"] }, { kind: "directive", type: i9.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "directive", type: i10.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: i3.FileDownloadComponent, selector: "c8y-file-download", inputs: ["url"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }] }); }
}
__decorate([
memoize(property('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], FirmwareDetailsComponent.prototype, "getPatchVersionsCount$", null);
__decorate([
memoize(),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], FirmwareDetailsComponent.prototype, "getBinaryName$", null);
__decorate([
memoize(property('id')),
__metadata("design:type", Function),
__metadata("design:paramtypes", [Object]),
__metadata("design:returntype", void 0)
], FirmwareDetailsComponent.prototype, "getPatchVersions$", null);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FirmwareDetailsComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-firmware-details', template: "<c8y-title>\n {{ (firmware$ | async)?.name }}\n</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n label=\"{{ 'Management' | translate }}\"\n icon=\"c8y-management\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n path=\"#/firmware\"\n label=\"{{ 'Firmware repository' | translate }}\"\n icon=\"c8y-firmware\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n label=\"{{ (firmware$ | async)?.name }}\"\n icon=\"c8y-firmware\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n *ngIf=\"!(isLegacy$ | async)\"\n class=\"btn btn-link\"\n type=\"button\"\n title=\"{{ 'Add firmware' | translate }}\"\n data-cy=\"firmware-details--add-firmware-btn\"\n (click)=\"addBaseVersion()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add firmware' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n *ngIf=\"canAddPatchVersions$ | async\"\n class=\"btn btn-link\"\n type=\"button\"\n title=\"{{ 'Add firmware patch' | translate }}\"\n data-cy=\"firmware-details--add-firmware-patch-btn\"\n (click)=\"addPatchVersion()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add firmware patch' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n type=\"button\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"reload$.next()\"\n >\n <i c8yIcon=\"refresh\" [ngClass]=\"{ 'icon-spin': reloading$ | async }\"></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<div class=\"row\">\n <div class=\"col-lg-12 col-lg-max\">\n <div class=\"card card--fullpage\">\n <div class=\"card-block bg-level-1 flex-no-shrink p-t-24 p-b-24\">\n <div class=\"content-flex-70\">\n <div class=\"text-center\">\n <i class=\"c8y-icon-duocolor icon-48 c8y-icon c8y-icon-firmware\"></i>\n <p>\n <small class=\"label label-info\">Firmware</small>\n </p>\n </div>\n <div class=\"flex-grow col-10\">\n <div class=\"row\">\n <div class=\"col-md-4\">\n <c8y-form-group>\n <label class=\"control-label\">\n {{ 'Name' | translate }}\n </label>\n <div class=\"input-group input-group-editable\">\n <input\n #nameInput\n type=\"text\"\n class=\"form-control\"\n [ngModel]=\"(firmware$ | async)?.name\"\n #nameModel=\"ngModel\"\n placeholder=\"{{ 'e.g. My firmware' | translate }}\"\n data-cy=\"firmware-details--name-input\"\n [ngStyle]=\"{ 'width.ch': (firmware$ | async)?.name?.length + 2 || 36 }\"\n required\n />\n <span></span>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-primary\"\n type=\"button\"\n title=\"{{ 'Save' | translate }}\"\n data-cy=\"firmware-details--name-save-btn\"\n (click)=\"updateFirmware$.next({ name: nameInput.value }); nameModel.reset()\"\n [disabled]=\"nameInput.value.length == 0\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </c8y-form-group>\n </div>\n <div class=\"col-md-4\">\n <c8y-form-group>\n <label class=\"control-label\">\n {{ 'Description' | translate }}\n </label>\n <div class=\"input-group input-group-editable\">\n <input\n #descriptionInput\n type=\"text\"\n class=\"form-control\"\n [ngModel]=\"(firmware$ | async)?.description\"\n #descriptionModel=\"ngModel\"\n placeholder=\"{{ 'e.g. Firmware for hardware revision B' | translate }}\"\n data-cy=\"firmware-details--description-input\"\n [ngStyle]=\"{ 'width.ch': (firmware$ | async)?.description?.length || 36 }\"\n />\n <span></span>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-primary\"\n type=\"button\"\n title=\"{{ 'Save' | translate }}\"\n data-cy=\"firmware-details--description-save-btn\"\n (click)=\"\n updateFirmware$.next({ description: descriptionInput.value });\n descriptionModel.reset()\n \"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </c8y-form-group>\n </div>\n <div class=\"col-md-4\">\n <c8y-form-group>\n <label class=\"control-label\">\n {{ 'Device type filter' | translate }}\n\n <button\n class=\"btn-help\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{\n 'If the filter is set, the firmware will show up for installation only for devices of that type. If no filter is set, it will be available for all devices.'\n | translate\n }}\"\n placement=\"right\"\n triggers=\"focus\"\n container=\"body\"\n >\n <i c8yIcon=\"question-circle-o\"></i>\n </button>\n </label>\n <div class=\"input-group input-group-editable\">\n <input\n #deviceTypeInput\n type=\"text\"\n class=\"form-control\"\n [ngModel]=\"(firmware$ | async)?.c8y_Filter?.type\"\n #deviceTypeModel=\"ngModel\"\n placeholder=\"{{ 'e.g.' | translate }} c8y_Linux\"\n data-cy=\"firmware-details--device-type-filter-input\"\n [ngStyle]=\"{ 'width.ch': (firmware$ | async)?.type?.length || 36 }\"\n />\n <span></span>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-primary\"\n type=\"button\"\n title=\"{{ 'Save' | translate }}\"\n data-cy=\"firmware-details--device-type-filter-save-btn\"\n (click)=\"\n updateFirmware$.next({ c8y_Filter: { type: deviceTypeInput.value } });\n deviceTypeModel.reset()\n \"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </c8y-form-group>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"card-header separator-top-bottom bg-component sticky-top\">\n <div class=\"card-title\" translate>Versions and patches</div>\n </div>\n\n <div class=\"card-block p-t-0 p-b-24\">\n <div *ngIf=\"(baseVersions$ | async)?.data.length === 0\">\n <c8y-ui-empty-state\n [icon]=\"'c8y-firmware'\"\n [title]=\"'No versions to display.' | translate\"\n [subtitle]=\"'Add a new version by clicking below.' | translate\"\n [horizontal]=\"true\"\n >\n <button\n class=\"btn btn-sm btn-default m-t-8\"\n type=\"button\"\n title=\"{{ 'Add firmware' | translate }}\"\n (click)=\"addBaseVersion()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add firmware' | translate }}\n </button>\n </c8y-ui-empty-state>\n </div>\n\n <c8y-list-group *ngIf=\"(baseVersions$ | async)?.data.length > 0\">\n <c8y-li\n *c8yFor=\"let baseVersion of baseVersions$ | async; let i = index; loadMore: 'auto'\"\n [emptyActions]=\"!(getPatchVersions$(baseVersion) | async)?.data.length\"\n [collapsed]=\"!expanded[baseVersion.id]\"\n (collapsedChange)=\"expanded[baseVersion.id] = !$event\"\n >\n <c8y-li-icon>\n <i c8yIcon=\"c8y-firmware\"></i>\n </c8y-li-icon>\n\n <c8y-li-body class=\"content-flex-50\">\n <div class=\"col-4\">\n <p class=\"text-truncate\" title=\"{{ baseVersion.c8y_Firmware.version }}\">\n {{ baseVersion.c8y_Firmware.version }}\n </p>\n </div>\n <div class=\"col-5\">\n <p class=\"text-truncate\">\n <span class=\"text-label-small m-r-8\" translate>File</span>\n <span title=\"{{ getBinaryName$(baseVersion.c8y_Firmware.url) | async }}\">\n <c8y-file-download\n url=\"{{ baseVersion.c8y_Firmware.url }}\"\n ></c8y-file-download>\n </span>\n </p>\n </div>\n <div class=\"col-2 d-flex a-i-start\">\n <span *ngIf=\"isLegacy$ | async\" class=\"label label-warning m-l-auto-sm\">\n {{ 'Legacy' | translate }}\n </span>\n\n <span *ngIf=\"!(isLegacy$ | async)\">\n <span *ngIf=\"(getPatchVersionsCount$(baseVersion) | async) === null\">\n <span class=\"label label-info\">\n <i c8yIcon=\"circle-o-notch\" class=\"icon-spin\"></i>\n </span>\n </span>\n <span *ngIf=\"(getPatchVersionsCount$(baseVersion) | async) !== null\">\n <span [ngPlural]=\"getPatchVersionsCount$(baseVersion) | async\">\n <ng-template ngPluralCase=\"=0\">\n <span class=\"label label-default m-l-auto-sm\">\n <span translate>No patches</span>\n </span>\n </ng-template>\n <ng-template ngPluralCase=\"=1\">\n <span class=\"label label-info\">\n <span translate>1 patch</span>\n </span>\n </ng-template>\n <ng-template ngPluralCase=\"other\">\n <span class=\"label label-info\">\n <span\n ngNonBindable\n translate\n [translateParams]=\"{\n count: getPatchVersionsCount$(baseVersion) | async\n }\"\n >\n {{ count }} patches\n </span>\n </span>\n </ng-template>\n </span>\n </span>\n </span>\n </div>\n <div class=\"fit-h-20 visible-xs\" *ngIf=\"!(isLegacy$ | async)\">\n <button\n class=\"btn btn-default btn-sm m-t-8\"\n type=\"button\"\n title=\"{{ 'Delete' | translate }}\"\n (click)=\"deleteBaseVersion(baseVersion)\"\n >\n <i c8yIcon=\"delete\"></i>\n {{ 'Delete' | translate }}\n </button>\n </div>\n <div *ngIf=\"!(isLegacy$ | async)\" class=\"m-l-auto fit-h-20 p-r-8 hidden-xs\">\n <button\n class=\"btn btn-dot btn-dot--danger showOnHover\"\n type=\"button\"\n [attr.aria-label]=\"'Delete' | translate\"\n data-cy=\"firmware-details--delete-base-version\"\n tooltip=\"{{ 'Delete' | translate }}\"\n [delay]=\"500\"\n (click)=\"deleteBaseVersion(baseVersion)\"\n >\n <i c8yIcon=\"delete\"></i>\n </button>\n </div>\n </c8y-li-body>\n <c8y-li-collapse *ngIf=\"(getPatchVersions$(baseVersion) | async)?.data.length\">\n <c8y-list-group class=\"separator-top\">\n <c8y-li\n *c8yFor=\"\n let patchVersion of getPatchVersions$(baseVersion) | async;\n let i = index;\n loadMore: 'auto'\n \"\n >\n <c8y-li-icon>\n <i c8yIcon=\"c8y-firmware\"></i>\n </c8y-li-icon>\n <c8y-li-body class=\"content-flex-50\">\n <div class=\"col-4\">\n {{ patchVersion.c8y_Firmware.version }}\n </div>\n <div class=\"col-5\">\n <div class=\"text-truncate\">\n <span class=\"text-label-small m-r-8\" translate>File</span>\n <c8y-file-download\n url=\"{{ patchVersion.c8y_Firmware.url }}\"\n ></c8y-file-download>\n </div>\n </div>\n <div class=\"visible-xs m-t-8\">\n <button\n class=\"btn btn-danger btn-xs\"\n type=\"button\"\n title=\"{{ 'Delete' | translate }}\"\n data-cy=\"firmware-details--delete-patch-version\"\n (click)=\"deletePatchVersion(patchVersion)\"\n >\n <i c8yIcon=\"delete\"></i>\n {{ 'Delete' | translate }}\n </button>\n </div>\n <div class=\"m-l-auto p-r-8 hidden-xs fit-h-20\">\n <button\n class=\"btn btn-dot text-danger showOnHover\"\n type=\"button\"\n [attr.aria-label]=\"'Delete' | translate\"\n tooltip=\"{{ 'Delete' | translate }}\"\n placement=\"right\"\n [delay]=\"500\"\n (click)=\"deletePatchVersion(patchVersion)\"\n >\n <i c8yIcon=\"delete\" data-cy=\"firmware-details--Remove-icon\"></i>\n </button>\n </div>\n </c8y-li-body>\n </c8y-li>\n </c8y-list-group>\n </c8y-li-collapse>\n </c8y-li>\n </c8y-list-group>\n </div>\n </div>\n </div>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.ActivatedRoute }, { type: i2.InventoryService }, { type: i3.RepositoryService }, { type: i4.AlertService }, { type: i5.TranslateService }, { type: i4.ModalService }, { type: i6.BsModalService }, { type: i4.GainsightService }, { type: i1.Router }], propDecorators: { getPatchVersionsCount$: [], getBinaryName$: [], getPatchVersions$: [] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlybXdhcmUtZGV0YWlscy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9yZXBvc2l0b3J5L2Zpcm13YXJlL2xpc3QvZmlybXdhcmUtZGV0YWlscy5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi9yZXBvc2l0b3J5L2Zpcm13YXJlL2xpc3QvZmlybXdhcmUtZGV0YWlscy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLFNBQVMsRUFBcUIsTUFBTSxlQUFlLENBQUM7QUFDN0QsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN6RCxPQUFPLEVBQStCLGdCQUFnQixFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzVFLE9BQU8sRUFDTCxZQUFZLEVBQ1osZ0JBQWdCLEVBQ2hCLFlBQVksRUFDWixNQUFNLEVBQ04sT0FBTyxFQUNQLE9BQU8sRUFDUixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFFTCxvQ0FBb0MsRUFDcEMsaUJBQWlCLEVBQ2xCLE1BQU0sdUNBQXVDLENBQUM7QUFDL0MsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNyQyxPQUFPLEVBQUUsY0FBYyxFQUFnQixNQUFNLHFCQUFxQixDQUFDO0FBQ25FLE9BQU8sRUFBRSxlQUFlLEVBQWMsT0FBTyxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ3pGLE9BQU8sRUFDTCx1QkFBdUIsRUFDdkIsR0FBRyxFQUNILFdBQVcsRUFDWCxTQUFTLEVBQ1QsSUFBSSxFQUNKLFNBQVMsRUFDVCxHQUFHLEVBQ0gsY0FBYyxFQUNmLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDM0UsT0FBTyxFQUFFLDhCQUE4QixFQUFFLE1BQU0sc0NBQXNDLENBQUM7Ozs7Ozs7Ozs7OztBQU10RixNQUFNLE9BQU8sd0JBQXdCO0lBa0RuQyxZQUNVLGNBQThCLEVBQzlCLGdCQUFrQyxFQUNsQyxpQkFBb0MsRUFDcEMsWUFBMEIsRUFDMUIsZ0JBQWtDLEVBQ2xDLFlBQTBCLEVBQzFCLGNBQThCLEVBQzlCLGdCQUFrQyxFQUNsQyxNQUFjO1FBUmQsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBQzlCLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBa0I7UUFDbEMsc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFtQjtRQUNwQyxpQkFBWSxHQUFaLFlBQVksQ0FBYztRQUMxQixxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQWtCO1FBQ2xDLGlCQUFZLEdBQVosWUFBWSxDQUFjO1FBQzFCLG1CQUFjLEdBQWQsY0FBYyxDQUFnQjtRQUM5QixxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQWtCO1FBQ2xDLFdBQU0sR0FBTixNQUFNLENBQVE7UUExRHhCLFlBQU8sR0FBa0IsSUFBSSxPQUFPLEVBQUUsQ0FBQztRQUN2QyxlQUFVLEdBQTZCLElBQUksZUFBZSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBR2xFLG9CQUFlLEdBQXFDLElBQUksT0FBTyxFQUFFLENBQUM7UUFDbEUscUJBQWdCLEdBQTRCLElBQUksT0FBTyxFQUFFLENBQUM7UUFDMUQseUJBQW9CLEdBQWtCLElBQUksT0FBTyxFQUFFLENBQUM7UUFDcEQsMEJBQXFCL