UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

1,078 lines 144 kB
import * as i0 from '@angular/core';
import { EventEmitter, Output, ViewChild, Component, Injectable, NgModule, Input } from '@angular/core';
import * as i1$2 from '@angular/router';
import { RouterModule } from '@angular/router';
import * as i4 from '@c8y/ngx-components';
import { gettext, ValidationPattern, BuiltInActionType, Status, memoize, NavigatorNode, hookNavigator, hookRoute, CoreModule, FormsModule, ModalSelectionMode, ViewContext } from '@c8y/ngx-components';
import * as i1$1 from '@c8y/ngx-components/repository/shared';
import { PRODUCT_EXPERIENCE_REPOSITORY_SHARED, RepositoryType, RepositoryItemNameGridColumn, DescriptionGridColumn, DeviceTypeGridColumn, TypeGridColumn, VersionsGridColumn, SoftwareTypeComponent, SharedRepositoryModule, RepositorySelectModalComponent } from '@c8y/ngx-components/repository/shared';
import * as i4$1 from '@ngx-translate/core';
import * as i1 from 'ngx-bootstrap/modal';
import * as i5 from '@angular/forms';
import { isUndefined, assign, get, head, set, filter, has } from 'lodash-es';
import { BehaviorSubject, from, Subject, merge, of, combineLatest, pipe } from 'rxjs';
import { tap, debounceTime, distinctUntilChanged, switchMap, map, shareReplay, distinctUntilKeyChanged, withLatestFrom, takeUntil, take, share, mergeMap, filter as filter$1 } from 'rxjs/operators';
import * as i7 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i6 from 'ngx-bootstrap/popover';
import { PopoverModule } from 'ngx-bootstrap/popover';
import { __decorate, __metadata } from 'tslib';
import * as i2 from '@c8y/client';
import { QueriesUtil, OperationStatus } from '@c8y/client';
import * as i10 from 'ngx-bootstrap/tooltip';
import { TooltipModule } from 'ngx-bootstrap/tooltip';
import { DeviceGridModule } from '@c8y/ngx-components/device-grid';
import * as i3 from '@c8y/ngx-components/operations/operation-details';
import { OperationDetailsModule } from '@c8y/ngx-components/operations/operation-details';

class AddSoftwareModalComponent {
    constructor(modal, repositoryService, alert) {
        this.modal = modal;
        this.repositoryService = repositoryService;
        this.alert = alert;
        this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_REPOSITORY_SHARED;
        this.saved = new EventEmitter();
        this.onInput = new BehaviorSubject('');
        this.model = {
            selected: undefined,
            version: undefined,
            description: undefined,
            deviceType: undefined,
            softwareType: undefined,
            binary: {
                file: undefined,
                url: undefined
            }
        };
        this.saving = false;
        this.softwarePreselected = false;
        this.textForSoftwareUrlPopover = gettext(`Path for binaries can vary depending on device agent implementation, for example:
    /software/binaries/software1.bin
    https://software/binary/123
    ftp://software/binary/123.tar.gz
  `);
        this.ValidationPattern = ValidationPattern;
    }
    ngOnInit() {
        this.setInitialState();
        this.loadSoftwares();
    }
    setInitialState() {
        if (this.model.selected) {
            this.softwarePreselected = true;
        }
    }
    loadSoftwares() {
        this.inputSubscription$ = this.onInput
            .pipe(tap(() => {
            if (!this.softwarePreselected) {
                this.model.description = null;
                if (this.form) {
                    this.form.form.get('description').reset();
                }
            }
        }), debounceTime(300), distinctUntilChanged(), switchMap(searchStr => this.getSoftwareResult(searchStr)))
            .subscribe(result => {
            this.softwaresResult = result;
        });
    }
    getSoftwareResult(searchStr) {
        return from(this.repositoryService.listRepositoryEntries(RepositoryType.SOFTWARE, {
            partialName: searchStr,
            skipLegacy: true
        }));
    }
    async save() {
        this.saving = true;
        this.repositoryService
            .create(this.model, RepositoryType.SOFTWARE)
            .then(savedSoftware => {
            this.successMsg();
            this.saving = false;
            this.saved.next(savedSoftware);
            this.cancel();
        })
            .catch(e => {
            this.saving = false;
            this.saved.error(e);
            this.cancel();
        });
    }
    successMsg() {
        const msg = gettext('Software added.');
        this.alert.success(msg);
    }
    cancel() {
        this.modal.hide();
        this.saved.complete();
    }
    ngOnDestroy() {
        this.inputSubscription$.unsubscribe();
    }
    onFile(dropped) {
        if (!isUndefined(dropped.url)) {
            this.model.binary = {
                url: dropped.url
            };
            return;
        }
        else if (dropped.droppedFiles) {
            this.model.binary = {
                file: dropped.droppedFiles[0].file
            };
            return;
        }
        else {
            this.model.binary = {
                file: undefined,
                url: undefined
            };
        }
    }
    onSoftwareSelect(software) {
        assign(this.model, {
            selected: software,
            description: software.description,
            deviceType: get(software, 'c8y_Filter.type'),
            softwareType: software
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AddSoftwareModalComponent, deps: [{ token: i1.BsModalRef }, { token: i1$1.RepositoryService }, { token: i4.AlertService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: AddSoftwareModalComponent, isStandalone: false, selector: "c8y-add-software-software-modal", outputs: { saved: "saved" }, viewQueries: [{ propertyName: "form", first: true, predicate: ["softwareForm"], descendants: true }], ngImport: i0, template: "<div class=\"viewport-modal\">\n  <div class=\"modal-header dialog-header\">\n    <i [c8yIcon]=\"'c8y-tools'\"></i>\n    <div class=\"modal-title\" translate id=\"addSoftwareModalTitle\">Add software</div>\n  </div>\n  <div class=\"p-16 text-center separator-bottom\" *ngIf=\"!softwarePreselected\">\n    <p class=\"text-medium text-16\" translate>Select or create new software</p>\n  </div>\n  <form\n    class=\"d-contents\"\n    autocomplete=\"off\"\n    #softwareForm=\"ngForm\"\n    (ngSubmit)=\"softwareForm.form.valid && save()\"\n  >\n    <div class=\"modal-inner-scroll\">\n      <div class=\"modal-body\" id=\"addSoftwareModalDescription\">\n        <div [hidden]=\"softwarePreselected\">\n          <c8y-form-group>\n            <label for=\"softwareName\" translate>Software</label>\n            <c8y-typeahead\n              [(ngModel)]=\"model.selected\"\n              name=\"softwareName\"\n              placeholder=\"{{ 'Select or enter' | translate }}\"\n              (onSearch)=\"onInput.next($event)\"\n              [required]=\"true\"\n            >\n              <c8y-li\n                *c8yFor=\"\n                  let software of softwaresResult;\n                  loadMore: 'auto';\n                  notFound: notFoundTemplate\n                \"\n                class=\"p-l-8 p-r-8 c8y-list__item--link\"\n                (click)=\"onSoftwareSelect(software)\"\n                [active]=\"model.selected === software\"\n              >\n                <c8y-highlight\n                  [text]=\"software.name || '--'\"\n                  [pattern]=\"onInput | async\"\n                ></c8y-highlight>\n              </c8y-li>\n              <ng-template #notFoundTemplate>\n                <c8y-li class=\"bg-level-2 p-8\" *ngIf=\"(onInput | async)?.length > 0\">\n                  <span translate>No match found.</span>\n                  <button\n                    class=\"btn btn-primary btn-xs m-l-8\"\n                    type=\"button\"\n                    title=\"{{ 'Add new`software`' | translate }}\"\n                  >\n                    {{ 'Add new`software`' | translate }}\n                  </button>\n                </c8y-li>\n              </ng-template>\n            </c8y-typeahead>\n          </c8y-form-group>\n\n          <c8y-form-group>\n            <label for=\"softwareDescription\" translate>Description</label>\n            <input\n              id=\"softwareDescription\"\n              class=\"form-control\"\n              autocomplete=\"off\"\n              name=\"description\"\n              [(ngModel)]=\"model.description\"\n              placeholder=\"{{ 'e.g. Cloud connectivity software' | translate }}\"\n              [disabled]=\"model.selected?.id\"\n              [required]=\"true\"\n              [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n            />\n          </c8y-form-group>\n\n          <c8y-form-group>\n            <label class=\"control-label\" for=\"softwareDeviceTypeFilter\">\n              {{ 'Device type filter' | translate }}\n              <button\n                class=\"btn-help\"\n                type=\"button\"\n                [attr.aria-label]=\"'Help' | translate\"\n                popover=\"{{\n                  'If the filter is set, the software 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              ></button>\n            </label>\n            <input\n              id=\"softwareDeviceTypeFilter\"\n              class=\"form-control\"\n              name=\"softwareDeviceTypeFilter\"\n              [(ngModel)]=\"model.deviceType\"\n              placeholder=\"{{ 'e.g.' | translate }} c8y_Linux\"\n              [disabled]=\"model.selected?.id\"\n              [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n            />\n          </c8y-form-group>\n\n          <c8y-form-group>\n            <label for=\"softwareType\" translate>Software type</label>\n            <c8y-software-type\n              name=\"softwareType\"\n              [(ngModel)]=\"model.softwareType\"\n              [disabled]=\"model.selected?.id\"\n            ></c8y-software-type>\n          </c8y-form-group>\n        </div>\n\n        <c8y-form-group>\n          <label for=\"softwareVersion\" translate>Version</label>\n          <input\n            id=\"softwareVersion\"\n            class=\"form-control\"\n            autocomplete=\"off\"\n            name=\"version\"\n            [(ngModel)]=\"model.version\"\n            placeholder=\"{{ 'e.g.' | translate }} 1.0.0\"\n            [required]=\"true\"\n            [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n          />\n        </c8y-form-group>\n\n        <c8y-form-group>\n          <div class=\"legend form-block m-t-40\" translate>Software file</div>\n          <c8y-file-picker\n            [maxAllowedFiles]=\"1\"\n            [allowedUploadChoices]=\"['uploadBinary', 'uploadUrl', 'provided']\"\n            (onFilesPicked)=\"onFile($event)\"\n            [fileUrlPopover]=\"textForSoftwareUrlPopover\"\n          ></c8y-file-picker>\n        </c8y-form-group>\n      </div>\n    </div>\n    <div class=\"modal-footer\">\n      <button\n        class=\"btn btn-default\"\n        type=\"button\"\n        title=\"{{ 'Cancel' | translate }}\"\n        (click)=\"cancel()\"\n        [disabled]=\"saving\"\n      >\n        {{ 'Cancel' | translate }}\n      </button>\n\n      <button\n        class=\"btn btn-primary\"\n        type=\"submit\"\n        title=\"{{ 'Add software' | translate }}\"\n        [ngClass]=\"{ 'btn-pending': saving }\"\n        [disabled]=\"\n          !softwareForm.form.valid ||\n          softwareForm.form.pristine ||\n          saving ||\n          (!model.binary?.url && !model.binary?.file)\n        \"\n        c8yProductExperience\n        [actionName]=\"PRODUCT_EXPERIENCE.SOFTWARE.EVENTS.REPOSITORY\"\n        [actionData]=\"{\n          component: PRODUCT_EXPERIENCE.SOFTWARE.COMPONENTS.ADD_SOFTWARE_MODAL,\n          result:\n            softwarePreselected || model.selected?.id\n              ? PRODUCT_EXPERIENCE.SOFTWARE.RESULTS.ADD_SOFTWARE_VERSION\n              : PRODUCT_EXPERIENCE.SOFTWARE.RESULTS.ADD_SOFTWARE\n        }\"\n      >\n        {{ 'Add software' | translate }}\n      </button>\n    </div>\n  </form>\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: 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.HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "component", type: i4.TypeaheadComponent, selector: "c8y-typeahead", inputs: ["required", "maxlength", "disabled", "allowFreeEntries", "placeholder", "displayProperty", "icon", "name", "autoClose", "hideNew", "container", "selected", "highlightFirstItem"], outputs: ["onSearch", "onIconClick"] }, { kind: "directive", type: i5.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i5.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: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i5.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i5.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i5.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { 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.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i4.FilePickerComponent, selector: "c8y-file-picker", inputs: ["maxAllowedFiles", "uploadChoice", "allowedUploadChoices", "fileUrl", "fileBinary", "config", "filePickerIndex", "fileUrlPopover"], outputs: ["onFilesPicked"] }, { kind: "directive", type: i4.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "directive", type: i6.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "component", type: i1$1.SoftwareTypeComponent, selector: "c8y-software-type", inputs: ["softwareTypeMO", "disabled", "style", "required", "placeholder", "emitResultsOnly", "showBtnInNotFoundMessage", "allowFreeEntries", "showClearSelectionOption", "clearSelectionOptionLabel", "presetSoftwareTypes"], outputs: ["onSelectSoftware"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AddSoftwareModalComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-add-software-software-modal', standalone: false, template: "<div class=\"viewport-modal\">\n  <div class=\"modal-header dialog-header\">\n    <i [c8yIcon]=\"'c8y-tools'\"></i>\n    <div class=\"modal-title\" translate id=\"addSoftwareModalTitle\">Add software</div>\n  </div>\n  <div class=\"p-16 text-center separator-bottom\" *ngIf=\"!softwarePreselected\">\n    <p class=\"text-medium text-16\" translate>Select or create new software</p>\n  </div>\n  <form\n    class=\"d-contents\"\n    autocomplete=\"off\"\n    #softwareForm=\"ngForm\"\n    (ngSubmit)=\"softwareForm.form.valid && save()\"\n  >\n    <div class=\"modal-inner-scroll\">\n      <div class=\"modal-body\" id=\"addSoftwareModalDescription\">\n        <div [hidden]=\"softwarePreselected\">\n          <c8y-form-group>\n            <label for=\"softwareName\" translate>Software</label>\n            <c8y-typeahead\n              [(ngModel)]=\"model.selected\"\n              name=\"softwareName\"\n              placeholder=\"{{ 'Select or enter' | translate }}\"\n              (onSearch)=\"onInput.next($event)\"\n              [required]=\"true\"\n            >\n              <c8y-li\n                *c8yFor=\"\n                  let software of softwaresResult;\n                  loadMore: 'auto';\n                  notFound: notFoundTemplate\n                \"\n                class=\"p-l-8 p-r-8 c8y-list__item--link\"\n                (click)=\"onSoftwareSelect(software)\"\n                [active]=\"model.selected === software\"\n              >\n                <c8y-highlight\n                  [text]=\"software.name || '--'\"\n                  [pattern]=\"onInput | async\"\n                ></c8y-highlight>\n              </c8y-li>\n              <ng-template #notFoundTemplate>\n                <c8y-li class=\"bg-level-2 p-8\" *ngIf=\"(onInput | async)?.length > 0\">\n                  <span translate>No match found.</span>\n                  <button\n                    class=\"btn btn-primary btn-xs m-l-8\"\n                    type=\"button\"\n                    title=\"{{ 'Add new`software`' | translate }}\"\n                  >\n                    {{ 'Add new`software`' | translate }}\n                  </button>\n                </c8y-li>\n              </ng-template>\n            </c8y-typeahead>\n          </c8y-form-group>\n\n          <c8y-form-group>\n            <label for=\"softwareDescription\" translate>Description</label>\n            <input\n              id=\"softwareDescription\"\n              class=\"form-control\"\n              autocomplete=\"off\"\n              name=\"description\"\n              [(ngModel)]=\"model.description\"\n              placeholder=\"{{ 'e.g. Cloud connectivity software' | translate }}\"\n              [disabled]=\"model.selected?.id\"\n              [required]=\"true\"\n              [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n            />\n          </c8y-form-group>\n\n          <c8y-form-group>\n            <label class=\"control-label\" for=\"softwareDeviceTypeFilter\">\n              {{ 'Device type filter' | translate }}\n              <button\n                class=\"btn-help\"\n                type=\"button\"\n                [attr.aria-label]=\"'Help' | translate\"\n                popover=\"{{\n                  'If the filter is set, the software 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              ></button>\n            </label>\n            <input\n              id=\"softwareDeviceTypeFilter\"\n              class=\"form-control\"\n              name=\"softwareDeviceTypeFilter\"\n              [(ngModel)]=\"model.deviceType\"\n              placeholder=\"{{ 'e.g.' | translate }} c8y_Linux\"\n              [disabled]=\"model.selected?.id\"\n              [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n            />\n          </c8y-form-group>\n\n          <c8y-form-group>\n            <label for=\"softwareType\" translate>Software type</label>\n            <c8y-software-type\n              name=\"softwareType\"\n              [(ngModel)]=\"model.softwareType\"\n              [disabled]=\"model.selected?.id\"\n            ></c8y-software-type>\n          </c8y-form-group>\n        </div>\n\n        <c8y-form-group>\n          <label for=\"softwareVersion\" translate>Version</label>\n          <input\n            id=\"softwareVersion\"\n            class=\"form-control\"\n            autocomplete=\"off\"\n            name=\"version\"\n            [(ngModel)]=\"model.version\"\n            placeholder=\"{{ 'e.g.' | translate }} 1.0.0\"\n            [required]=\"true\"\n            [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n          />\n        </c8y-form-group>\n\n        <c8y-form-group>\n          <div class=\"legend form-block m-t-40\" translate>Software file</div>\n          <c8y-file-picker\n            [maxAllowedFiles]=\"1\"\n            [allowedUploadChoices]=\"['uploadBinary', 'uploadUrl', 'provided']\"\n            (onFilesPicked)=\"onFile($event)\"\n            [fileUrlPopover]=\"textForSoftwareUrlPopover\"\n          ></c8y-file-picker>\n        </c8y-form-group>\n      </div>\n    </div>\n    <div class=\"modal-footer\">\n      <button\n        class=\"btn btn-default\"\n        type=\"button\"\n        title=\"{{ 'Cancel' | translate }}\"\n        (click)=\"cancel()\"\n        [disabled]=\"saving\"\n      >\n        {{ 'Cancel' | translate }}\n      </button>\n\n      <button\n        class=\"btn btn-primary\"\n        type=\"submit\"\n        title=\"{{ 'Add software' | translate }}\"\n        [ngClass]=\"{ 'btn-pending': saving }\"\n        [disabled]=\"\n          !softwareForm.form.valid ||\n          softwareForm.form.pristine ||\n          saving ||\n          (!model.binary?.url && !model.binary?.file)\n        \"\n        c8yProductExperience\n        [actionName]=\"PRODUCT_EXPERIENCE.SOFTWARE.EVENTS.REPOSITORY\"\n        [actionData]=\"{\n          component: PRODUCT_EXPERIENCE.SOFTWARE.COMPONENTS.ADD_SOFTWARE_MODAL,\n          result:\n            softwarePreselected || model.selected?.id\n              ? PRODUCT_EXPERIENCE.SOFTWARE.RESULTS.ADD_SOFTWARE_VERSION\n              : PRODUCT_EXPERIENCE.SOFTWARE.RESULTS.ADD_SOFTWARE\n        }\"\n      >\n        {{ 'Add software' | translate }}\n      </button>\n    </div>\n  </form>\n</div>\n" }]
        }], ctorParameters: () => [{ type: i1.BsModalRef }, { type: i1$1.RepositoryService }, { type: i4.AlertService }], propDecorators: { form: [{
                type: ViewChild,
                args: ['softwareForm', { static: false }]
            }], saved: [{
                type: Output
            }] } });

class SoftwareListComponent {
    constructor(repositoryService, gridService, modalService, bsModalService, translateService, alertService, router, activatedRoute) {
        this.repositoryService = repositoryService;
        this.gridService = gridService;
        this.modalService = modalService;
        this.bsModalService = bsModalService;
        this.translateService = translateService;
        this.alertService = alertService;
        this.router = router;
        this.activatedRoute = activatedRoute;
        this.sizeRequestDone = false;
        this.refresh$ = new EventEmitter();
        this.columns = [
            new RepositoryItemNameGridColumn({
                filterLabel: gettext('Filter software by name')
            }),
            new DescriptionGridColumn({
                filterLabel: gettext('Filter software by description'),
                placeholder: gettext('Cloud connectivity software')
            }),
            new DeviceTypeGridColumn({ filterLabel: gettext('Filter software by device type') }),
            new TypeGridColumn({
                header: gettext('Software type'),
                filterLabel: gettext('Filter by software type'),
                example: 'yum',
                path: 'softwareType',
                repositoryType: RepositoryType.SOFTWARE
            }),
            new VersionsGridColumn()
        ];
        this.actionControls = [];
        this.pagination = {
            pageSize: 50,
            currentPage: 1
        };
        this.noResultsMessage = gettext('No results to display.');
        this.noDataMessage = gettext('No software to display.');
        this.noResultsSubtitle = gettext('Refine your search terms or check your spelling.');
        this.noDataSubtitle = gettext('Add a new software by clicking below.');
        this.serverSideDataCallback = this.onDataSourceModifier.bind(this);
    }
    ngOnInit() {
        this.actionControls.push({
            type: BuiltInActionType.Edit,
            callback: this.editSoftware.bind(this)
        });
        this.actionControls.push({
            type: BuiltInActionType.Delete,
            callback: this.deleteSoftware.bind(this)
        });
    }
    async onDataSourceModifier(dataSourceModifier) {
        const dataRequest = this.repositoryService.listRepositoryEntries(RepositoryType.SOFTWARE, {
            query: this.gridService.getQueryObj(dataSourceModifier.columns),
            skipDefaultOrder: true,
            params: {
                pageSize: dataSourceModifier.pagination.pageSize,
                currentPage: dataSourceModifier.pagination.currentPage
            }
        });
        const filtererdSizeRequest = this.repositoryService
            .listRepositoryEntries(RepositoryType.SOFTWARE, {
            skipDefaultOrder: true,
            query: this.gridService.getQueryObj(dataSourceModifier.columns),
            params: { pageSize: 1 }
        })
            .then(response => response?.paging?.totalPages);
        this.sizeRequest = this.repositoryService
            .listRepositoryEntries(RepositoryType.SOFTWARE, {
            skipDefaultOrder: true,
            params: { pageSize: 1 }
        })
            .then(response => {
            this.sizeRequestDone = true;
            return response?.paging?.totalPages;
        });
        const [dataResponse, size, filteredSize] = await Promise.all([
            dataRequest,
            this.sizeRequest,
            filtererdSizeRequest
        ]);
        const { res, data, paging } = dataResponse;
        const serverSideDataResult = {
            res,
            data,
            paging,
            filteredSize,
            size
        };
        return serverSideDataResult;
    }
    addSoftware() {
        const config = {
            class: 'modal-sm',
            ariaDescribedby: 'addSoftwareModalDescription',
            ariaLabelledBy: 'addSoftwareModalTitle',
            ignoreBackdropClick: true,
            keyboard: false
        };
        const modalRef = this.bsModalService.show(AddSoftwareModalComponent, config);
        modalRef.content.saved.subscribe(savedSoftware => this.editSoftware(savedSoftware));
    }
    editSoftware(software) {
        this.router.navigate([software.id], { relativeTo: this.activatedRoute });
    }
    async deleteSoftware(software) {
        try {
            const title = gettext('Delete software');
            const body = `
        ${this.translateService.instant(gettext('You are about to delete software "{{ name }}" with all its versions.'), { name: software.name })}
        ${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.SOFTWARE.EVENTS.REPOSITORY });
            await this.repositoryService.delete(software);
            this.alertService.success(gettext('Software deleted.'));
            this.refresh$.next();
        }
        catch (ex) {
            // only if not cancel from modal
            if (ex) {
                this.alertService.addServerFailure(ex);
            }
        }
    }
    trackByName(_index, column) {
        return column.name;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareListComponent, deps: [{ token: i1$1.RepositoryService }, { token: i4.DataGridService }, { token: i4.ModalService }, { token: i1.BsModalService }, { token: i4$1.TranslateService }, { token: i4.AlertService }, { token: i1$2.Router }, { token: i1$2.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: SoftwareListComponent, isStandalone: false, selector: "c8y-software-list", ngImport: i0, template: "<c8y-title>\n  {{ 'Software repository' | translate }}\n</c8y-title>\n<c8y-breadcrumb>\n  <c8y-breadcrumb-item\n    icon=\"c8y-management\"\n    label=\"{{ 'Management' | translate }}\"\n  ></c8y-breadcrumb-item>\n  <c8y-breadcrumb-item\n    icon=\"c8y-tools\"\n    label=\"{{ 'Software repository' | translate }}\"\n  ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n  <button\n    class=\"btn btn-link\"\n    title=\"{{ 'Add software' | translate }}\"\n    type=\"button\"\n    (click)=\"addSoftware()\"\n  >\n    <i c8yIcon=\"plus-circle\"></i>\n    {{ 'Add software' | translate }}\n  </button>\n</c8y-action-bar-item>\n\n<c8y-help\n  src=\"/docs/device-management-application/managing-device-data/#managing-software\"\n></c8y-help>\n\n<div class=\"content-fullpage border-top border-bottom\">\n  <c8y-data-grid\n    [title]=\"'Software' | translate\"\n    [refresh]=\"refresh$\"\n    [pagination]=\"pagination\"\n    [columns]=\"columns\"\n    [actionControls]=\"actionControls\"\n    [infiniteScroll]=\"'auto'\"\n    [serverSideDataCallback]=\"serverSideDataCallback\"\n  >\n    <c8y-ui-empty-state\n      [icon]=\"stats?.size > 0 ? 'search' : 'c8y-tools'\"\n      [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n      [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : (noDataSubtitle | translate)\"\n      *emptyStateContext=\"let stats\"\n      [horizontal]=\"stats?.size > 0\"\n    >\n      <p *ngIf=\"stats?.size === 0\">\n        <button\n          class=\"btn btn-primary\"\n          [title]=\"'Add software' | translate\"\n          type=\"button\"\n          (click)=\"addSoftware()\"\n        >\n          {{ 'Add software' | translate }}\n        </button>\n      </p>\n    </c8y-ui-empty-state>\n    <ng-container *ngFor=\"let column of columns; trackBy: trackByName\">\n      <c8y-column [name]=\"column.name\"></c8y-column>\n    </ng-container>\n  </c8y-data-grid>\n</div>\n", dependencies: [{ kind: "directive", type: i7.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i7.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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.EmptyStateContextDirective, selector: "[emptyStateContext]" }, { kind: "directive", type: i4.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i4.ColumnDirective, selector: "c8y-column", inputs: ["name"] }, { kind: "component", type: i4.DataGridComponent, selector: "c8y-data-grid", inputs: ["title", "loadMoreItemsLabel", "loadingItemsLabel", "showSearch", "refresh", "columns", "rows", "pagination", "childNodePagination", "infiniteScroll", "serverSideDataCallback", "selectable", "singleSelection", "selectionPrimaryKey", "displayOptions", "actionControls", "bulkActionControls", "headerActionControls", "searchText", "configureColumnsEnabled", "showCounterWarning", "activeClassName", "expandableRows", "treeGrid", "hideReload", "childNodesProperty", "parentNodeLabelProperty"], outputs: ["rowMouseOver", "rowMouseLeave", "rowClick", "onConfigChange", "onBeforeFilter", "onBeforeSearch", "onFilter", "itemsSelect", "onReload", "onAddCustomColumn", "onRemoveCustomColumn", "onColumnFilterReset", "onSort", "onPageSizeChange", "onColumnReordered", "onColumnVisibilityChange"] }, { kind: "component", type: i4.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: i4.HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareListComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-software-list', standalone: false, template: "<c8y-title>\n  {{ 'Software repository' | translate }}\n</c8y-title>\n<c8y-breadcrumb>\n  <c8y-breadcrumb-item\n    icon=\"c8y-management\"\n    label=\"{{ 'Management' | translate }}\"\n  ></c8y-breadcrumb-item>\n  <c8y-breadcrumb-item\n    icon=\"c8y-tools\"\n    label=\"{{ 'Software repository' | translate }}\"\n  ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n  <button\n    class=\"btn btn-link\"\n    title=\"{{ 'Add software' | translate }}\"\n    type=\"button\"\n    (click)=\"addSoftware()\"\n  >\n    <i c8yIcon=\"plus-circle\"></i>\n    {{ 'Add software' | translate }}\n  </button>\n</c8y-action-bar-item>\n\n<c8y-help\n  src=\"/docs/device-management-application/managing-device-data/#managing-software\"\n></c8y-help>\n\n<div class=\"content-fullpage border-top border-bottom\">\n  <c8y-data-grid\n    [title]=\"'Software' | translate\"\n    [refresh]=\"refresh$\"\n    [pagination]=\"pagination\"\n    [columns]=\"columns\"\n    [actionControls]=\"actionControls\"\n    [infiniteScroll]=\"'auto'\"\n    [serverSideDataCallback]=\"serverSideDataCallback\"\n  >\n    <c8y-ui-empty-state\n      [icon]=\"stats?.size > 0 ? 'search' : 'c8y-tools'\"\n      [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n      [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : (noDataSubtitle | translate)\"\n      *emptyStateContext=\"let stats\"\n      [horizontal]=\"stats?.size > 0\"\n    >\n      <p *ngIf=\"stats?.size === 0\">\n        <button\n          class=\"btn btn-primary\"\n          [title]=\"'Add software' | translate\"\n          type=\"button\"\n          (click)=\"addSoftware()\"\n        >\n          {{ 'Add software' | translate }}\n        </button>\n      </p>\n    </c8y-ui-empty-state>\n    <ng-container *ngFor=\"let column of columns; trackBy: trackByName\">\n      <c8y-column [name]=\"column.name\"></c8y-column>\n    </ng-container>\n  </c8y-data-grid>\n</div>\n" }]
        }], ctorParameters: () => [{ type: i1$1.RepositoryService }, { type: i4.DataGridService }, { type: i4.ModalService }, { type: i1.BsModalService }, { type: i4$1.TranslateService }, { type: i4.AlertService }, { type: i1$2.Router }, { type: i1$2.ActivatedRoute }] });

class SoftwareDetailsComponent {
    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.isSoftwareTypeChanged = false;
        this.updateSoftware$ = new Subject();
        this.softwareUpdated$ = new Subject();
        this.baseVersionsUpdated$ = new Subject();
        this.software$ = merge(this.activatedRoute.params.pipe(map(params => params.id), switchMap(id => from(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 => from(this.inventoryService.detail(id).then(result => result.data))), tap(() => this.reloading$.next(false))), this.softwareUpdated$).pipe(shareReplay(1));
        this.baseVersions$ = merge(this.software$.pipe(distinctUntilKeyChanged('id')), this.baseVersionsUpdated$, this.reload$).pipe(switchMap(() => this.software$), switchMap(software => this.repositoryService.listBaseVersions(software)), shareReplay(1));
        this.isLegacy$ = this.software$.pipe(map(software => this.repositoryService.isLegacyEntry(software)), shareReplay(1));
        this.destroy$ = new Subject();
    }
    ngOnInit() {
        this.updateSoftware$
            .pipe(withLatestFrom(this.software$), switchMap(([softwarePartial, software]) => this.inventoryService.update({
            id: software.id,
            ...softwarePartial
        })), map(({ data }) => data), tap(software => this.softwareUpdated$.next(software)), tap(() => this.alertService.success(gettext('Saved.'))), tap(() => this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_REPOSITORY_SHARED.SOFTWARE.EVENTS.REPOSITORY, {
            result: PRODUCT_EXPERIENCE_REPOSITORY_SHARED.SOFTWARE.RESULTS.EDIT_SOFTWARE
        })), takeUntil(this.destroy$))
            .subscribe();
        this.software$.subscribe(software => {
            this.softwareTypeObject = software;
        });
    }
    getBinaryName$(binaryUrl) {
        return this.repositoryService.getBinaryName$(binaryUrl);
    }
    addBaseVersion() {
        this.software$
            .pipe(take(1), switchMap(software => {
            const initialState = {
                model: {
                    selected: software,
                    description: software.description
                }
            };
            const config = {
                class: 'modal-sm',
                ariaDescribedby: 'addSoftwareModalDescription',
                ariaLabelledBy: 'addSoftwareModalTitle',
                ignoreBackdropClick: true,
                keyboard: false,
                initialState
            };
            const modalRef = this.bsModalService.show(AddSoftwareModalComponent, config);
            return modalRef.content.saved;
        }))
            .subscribe(() => this.baseVersionsUpdated$.next());
    }
    async deleteBaseVersion(baseVersion) {
        try {
            const title = gettext('Delete software');
            const body = `
        ${this.translateService.instant(gettext('You are about to delete software {{ version }}.'), { version: baseVersion.c8y_Software.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);
            const isLastVersion = await this.baseVersions$
                .pipe(map(versions => versions?.data?.length === 1), take(1))
                .toPromise();
            if (isLastVersion) {
                await this.repositoryService.delete(this.softwareTypeObject);
                this.router.navigateByUrl('/software');
            }
            else {
                await this.repositoryService.delete(baseVersion);
                this.baseVersionsUpdated$.next();
            }
            this.alertService.success(gettext('Software deleted.'));
        }
        catch (ex) {
            // only if not cancel from modal
            if (ex) {
                this.alertService.addServerFailure(ex);
            }
        }
    }
    onSelectSoftwareType(software) {
        this.isSoftwareTypeChanged = !(this.softwareTypeObject?.softwareType === software?.softwareType);
        this.softwareTypeObject = software;
    }
    ngOnDestroy() {
        this.destroy$.next(true);
        this.destroy$.unsubscribe();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareDetailsComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i2.InventoryService }, { token: i1$1.RepositoryService }, { token: i4.AlertService }, { token: i4$1.TranslateService }, { token: i4.ModalService }, { token: i1.BsModalService }, { token: i4.GainsightService }, { token: i1$2.Router }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: SoftwareDetailsComponent, isStandalone: false, selector: "c8y-software-details", viewQueries: [{ propertyName: "softwareType", first: true, predicate: SoftwareTypeComponent, descendants: true, static: true }], ngImport: i0, template: "<c8y-title>\n  {{ (software$ | 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=\"#/software\"\n    label=\"{{ 'Software repository' | translate }}\"\n    icon=\"c8y-tools\"\n  ></c8y-breadcrumb-item>\n  <c8y-breadcrumb-item\n    label=\"{{ (software$ | async)?.name }}\"\n    icon=\"c8y-tools\"\n  ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n  <button\n    class=\"btn btn-link\"\n    type=\"button\"\n    title=\"{{ 'Add software' | translate }}\"\n    (click)=\"addBaseVersion()\"\n    *ngIf=\"!(isLegacy$ | async)\"\n  >\n    <i c8yIcon=\"plus-circle\"></i>\n    {{ 'Add software' | 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\n      c8yIcon=\"refresh\"\n      [ngClass]=\"{ 'icon-spin': reloading$ | async }\"\n    ></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 overflow-visible\">\n        <div class=\"content-flex-70\">\n          <div class=\"text-center\">\n            <i class=\"c8y-icon-duocolor icon-48 c8y-icon c8y-icon-tools\"></i>\n            <p>\n              <small class=\"label label-info\">Software</small>\n            </p>\n          </div>\n          <div class=\"flex-grow col-10\">\n            <div class=\"row\">\n              <div class=\"col-sm-6\">\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]=\"(software$ | async)?.name\"\n                      #nameModel=\"ngModel\"\n                      placeholder=\"{{ 'e.g. My software' | translate }}\"\n                      [ngStyle]=\"{ 'width.ch': (software$ | async)?.name?.length + 2 || 31 }\"\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                        (click)=\"updateSoftware$.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-sm-6\">\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]=\"(software$ | async)?.description\"\n                      #descriptionModel=\"ngModel\"\n                      placeholder=\"{{ 'e.g. Cloud connectivity software' | translate }}\"\n                      [ngStyle]=\"{ 'width.ch': (software$ | async)?.description?.length + 2 || 31 }\"\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                        (click)=\"\n                          updateSoftware$.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>\n            <div class=\"row\">\n              <div class=\"col-sm-6\">\n                <c8y-form-group>\n                  <label class=\"control-label\">\n                    {{ 'Device type' | translate }}\n                    <button\n                      class=\"btn-help\"\n                      type=\"button\"\n                      [attr.aria-label]=\"'Help' | translate\"\n                      popover=\"{{\n                        'If the filter is set, the software 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                      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]=\"(software$ | async)?.c8y_Filter?.type\"\n                      #deviceTypeModel=\"ngModel\"\n                      placeholder=\"{{ 'e.g.' | translate }} c8y_Linux\"\n                      [ngStyle]=\"{ 'width.ch': (software$ | async)?.type?.length + 2 || 31 }\"\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                        (click)=\"\n                          updateSoftware$.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 class=\"col-sm-6\">\n                <c8y-form-group>\n                  <label class=\"control-label\">\n                    {{ 'Software type' | translate }}\n                  </label>\n                  <div class=\"input-group input-group-editable\">\n                    <c8y-software-type\n                      [softwareTypeMO]=\"softwareTypeObject\"\n                      [style]=\"{ 'width.ch': softwareTypeObject?.softwareType?.length + 2 || 31 }\"\n                      (onSelectSoftware)=\"onSelectSoftwareType($event)\"\n                    ></c8y-software-type>\n                    <div class=\"input-group-btn\">\n                      <button\n                        class=\"btn btn-primary\"\n                        type=\"button\"\n                        title=\"{{ 'Save' | translate }}\"\n                        [ngClass]=\"isSoftwareTypeChanged ? '' : 'hidden'\"\n                        [disabled]=\"softwareTypeObject?.softwareType === ''\"\n                        (click)=\"\n                          updateSoftware$.next({ softwareType: softwareTypeObject.softwareType });\n                          softwareType.resetInput();\n                          isSoftwareTypeChanged = false\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 sticky-top bg-component\">\n          <div\n            class=\"card-title\"\n            translate\n          >\n            Versions\n          </div>\n        </div>\n\n        <div class=\"card-block p-t-0 p-b-24\">\n          <c8y-ui-empty-state\n            *ngIf=\"(baseVersions$ | async)?.data.length === 0\"\n            [icon]=\"'c8y-tools'\"\n            [title]=\"'No versions to display.' | translate\"\n            [subtitle]=\"'Add a new version by clicking below.' | translate\"\n          >\n            <p>\n              <button\n                class=\"btn btn-primary\"\n                type=\"button\"\n                title=\"{{ 'Add software' | translate }}\"\n                (click)=\"addBaseVersion()\"\n              >\n                {{ 'Add software' | translate }}\n              </button>\n            </p>\n          </c8y-ui-empty-state>\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            >\n              <c8y-li-icon>\n                <i c8yIcon=\"c8y-tools\"></i>\n              </c8y-li-icon>\n\n              <c8y-li-body class=\"content-flex-50\">\n                <div class=\"col-4\">\n                  <p\n                    class=\"text-truncate-wrap\"\n                    title=\"{{ baseVersion.c8y_Software.version }}\"\n                  >\n                    {{ baseVersion.c8y_Software.version }}\n                  </p>\n                </div>\n                <div class=\"col-5\">\n                  <p class=\"text-truncate-wrap\">\n                    <span\n                      class=\"text-label-small m-r-8\"\n                      translate\n                    >\n                      File\n                    </span>\n                    <ng-container\n                      *ngIf=\"baseVersion?.c8y_Software?.url === '$PROVIDED'; else fileDownload\"\n                    >\n                      <span title=\"{{ 'Provided by device' | translate }}\">\n                        {{ 'Provided by device' | translate }}\n                      </span>\n                    </ng-container>\n\n                    <ng-template #fileDownload>\n                      <span title=\"{{ getBinaryName$(baseVersion.c8y_Software.url) | async }}\">\n                        <c8y-file-download [url]=\"baseVersion.c8y_Software.url\"></c8y-file-download>\n                      </span>\n                    </ng-template>\n                  </p>\n                </div>\n                <div class=\"col-2 d-flex a-i-start\">\n                  <span\n                    *ngIf=\"isLegacy$ | async\"\n                    class=\"label label-warning m-l-auto-sm\"\n                  >\n                    {{ 'Legacy' | translate }}\n                  </span>\n\n                  <div\n                    class=\"fit-h-20\"\n                    *ngIf=\"!(isLegacy$ | async)\"\n                  >\n                    <button\n                      class=\"btn btn-danger btn-xs visible-xs m-l-auto m-r-8 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>\n                <div\n                  *ngIf=\"!(isLegacy$ | async)\"\n                  class=\"m-l-auto fit-h-20 hidden-xs\"\n                >\n                  <button\n                    class=\"btn btn-dot text-danger showOnHover\"\n                    type=\"button\"\n                    data-cy=\"software-details-component--Delete-button\"\n                    [attr.aria-label]=\"'Delete' | translate\"\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>\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: "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: i5.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: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i5.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: "directive", type: i6.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: i1$1.FileDownloadComponent, selector: "c8y-file-download", inputs: ["url"] }, { kind: "component", type: i1$1.SoftwareTypeComponent, selector: "c8y-software-type", inputs: ["softwareTypeMO", "disabled", "style", "required", "placeholder", "emitResultsOnly", "showBtnInNotFoundMessage", "allowFreeEntries", "showClearSelectionOption", "clearSelectionOptionLabel", "presetSoftwareTypes"], outputs: ["onSelectSoftware"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }] }); }
}
__decorate([
    memoize(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", void 0)
], SoftwareDetailsComponent.prototype, "getBinaryName$", null);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareDetailsComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-software-details', standalone: false, template: "<c8y-title>\n  {{ (software$ | 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=\"#/software\"\n    label=\"{{ 'Software repository' | translate }}\"\n    icon=\"c8y-tools\"\n  ></c8y-breadcrumb-item>\n  <c8y-breadcrumb-item\n    label=\"{{ (software$ | async)?.name }}\"\n    icon=\"c8y-tools\"\n  ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n  <button\n    class=\"btn btn-link\"\n    type=\"button\"\n    title=\"{{ 'Add software' | translate }}\"\n    (click)=\"addBaseVersion()\"\n    *ngIf=\"!(isLegacy$ | async)\"\n  >\n    <i c8yIcon=\"plus-circle\"></i>\n    {{ 'Add software' | 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\n      c8yIcon=\"refresh\"\n      [ngClass]=\"{ 'icon-spin': reloading$ | async }\"\n    ></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 overflow-visible\">\n        <div class=\"content-flex-70\">\n          <div class=\"text-center\">\n            <i class=\"c8y-icon-duocolor icon-48 c8y-icon c8y-icon-tools\"></i>\n            <p>\n              <small class=\"label label-info\">Software</small>\n            </p>\n          </div>\n          <div class=\"flex-grow col-10\">\n            <div class=\"row\">\n              <div class=\"col-sm-6\">\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]=\"(software$ | async)?.name\"\n                      #nameModel=\"ngModel\"\n                      placeholder=\"{{ 'e.g. My software' | translate }}\"\n                      [ngStyle]=\"{ 'width.ch': (software$ | async)?.name?.length + 2 || 31 }\"\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                        (click)=\"updateSoftware$.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-sm-6\">\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]=\"(software$ | async)?.description\"\n                      #descriptionModel=\"ngModel\"\n                      placeholder=\"{{ 'e.g. Cloud connectivity software' | translate }}\"\n                      [ngStyle]=\"{ 'width.ch': (software$ | async)?.description?.length + 2 || 31 }\"\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                        (click)=\"\n                          updateSoftware$.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>\n            <div class=\"row\">\n              <div class=\"col-sm-6\">\n                <c8y-form-group>\n                  <label class=\"control-label\">\n                    {{ 'Device type' | translate }}\n                    <button\n                      class=\"btn-help\"\n                      type=\"button\"\n                      [attr.aria-label]=\"'Help' | translate\"\n                      popover=\"{{\n                        'If the filter is set, the software 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                      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]=\"(software$ | async)?.c8y_Filter?.type\"\n                      #deviceTypeModel=\"ngModel\"\n                      placeholder=\"{{ 'e.g.' | translate }} c8y_Linux\"\n                      [ngStyle]=\"{ 'width.ch': (software$ | async)?.type?.length + 2 || 31 }\"\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                        (click)=\"\n                          updateSoftware$.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 class=\"col-sm-6\">\n                <c8y-form-group>\n                  <label class=\"control-label\">\n                    {{ 'Software type' | translate }}\n                  </label>\n                  <div class=\"input-group input-group-editable\">\n                    <c8y-software-type\n                      [softwareTypeMO]=\"softwareTypeObject\"\n                      [style]=\"{ 'width.ch': softwareTypeObject?.softwareType?.length + 2 || 31 }\"\n                      (onSelectSoftware)=\"onSelectSoftwareType($event)\"\n                    ></c8y-software-type>\n                    <div class=\"input-group-btn\">\n                      <button\n                        class=\"btn btn-primary\"\n                        type=\"button\"\n                        title=\"{{ 'Save' | translate }}\"\n                        [ngClass]=\"isSoftwareTypeChanged ? '' : 'hidden'\"\n                        [disabled]=\"softwareTypeObject?.softwareType === ''\"\n                        (click)=\"\n                          updateSoftware$.next({ softwareType: softwareTypeObject.softwareType });\n                          softwareType.resetInput();\n                          isSoftwareTypeChanged = false\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 sticky-top bg-component\">\n          <div\n            class=\"card-title\"\n            translate\n          >\n            Versions\n          </div>\n        </div>\n\n        <div class=\"card-block p-t-0 p-b-24\">\n          <c8y-ui-empty-state\n            *ngIf=\"(baseVersions$ | async)?.data.length === 0\"\n            [icon]=\"'c8y-tools'\"\n            [title]=\"'No versions to display.' | translate\"\n            [subtitle]=\"'Add a new version by clicking below.' | translate\"\n          >\n            <p>\n              <button\n                class=\"btn btn-primary\"\n                type=\"button\"\n                title=\"{{ 'Add software' | translate }}\"\n                (click)=\"addBaseVersion()\"\n              >\n                {{ 'Add software' | translate }}\n              </button>\n            </p>\n          </c8y-ui-empty-state>\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            >\n              <c8y-li-icon>\n                <i c8yIcon=\"c8y-tools\"></i>\n              </c8y-li-icon>\n\n              <c8y-li-body class=\"content-flex-50\">\n                <div class=\"col-4\">\n                  <p\n                    class=\"text-truncate-wrap\"\n                    title=\"{{ baseVersion.c8y_Software.version }}\"\n                  >\n                    {{ baseVersion.c8y_Software.version }}\n                  </p>\n                </div>\n                <div class=\"col-5\">\n                  <p class=\"text-truncate-wrap\">\n                    <span\n                      class=\"text-label-small m-r-8\"\n                      translate\n                    >\n                      File\n                    </span>\n                    <ng-container\n                      *ngIf=\"baseVersion?.c8y_Software?.url === '$PROVIDED'; else fileDownload\"\n                    >\n                      <span title=\"{{ 'Provided by device' | translate }}\">\n                        {{ 'Provided by device' | translate }}\n                      </span>\n                    </ng-container>\n\n                    <ng-template #fileDownload>\n                      <span title=\"{{ getBinaryName$(baseVersion.c8y_Software.url) | async }}\">\n                        <c8y-file-download [url]=\"baseVersion.c8y_Software.url\"></c8y-file-download>\n                      </span>\n                    </ng-template>\n                  </p>\n                </div>\n                <div class=\"col-2 d-flex a-i-start\">\n                  <span\n                    *ngIf=\"isLegacy$ | async\"\n                    class=\"label label-warning m-l-auto-sm\"\n                  >\n                    {{ 'Legacy' | translate }}\n                  </span>\n\n                  <div\n                    class=\"fit-h-20\"\n                    *ngIf=\"!(isLegacy$ | async)\"\n                  >\n                    <button\n                      class=\"btn btn-danger btn-xs visible-xs m-l-auto m-r-8 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>\n                <div\n                  *ngIf=\"!(isLegacy$ | async)\"\n                  class=\"m-l-auto fit-h-20 hidden-xs\"\n                >\n                  <button\n                    class=\"btn btn-dot text-danger showOnHover\"\n                    type=\"button\"\n                    data-cy=\"software-details-component--Delete-button\"\n                    [attr.aria-label]=\"'Delete' | translate\"\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>\n          </c8y-list-group>\n        </div>\n      </div>\n    </div>\n  </div>\n</div>\n" }]
        }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i2.InventoryService }, { type: i1$1.RepositoryService }, { type: i4.AlertService }, { type: i4$1.TranslateService }, { type: i4.ModalService }, { type: i1.BsModalService }, { type: i4.GainsightService }, { type: i1$2.Router }], propDecorators: { softwareType: [{
                type: ViewChild,
                args: [SoftwareTypeComponent, { static: true }]
            }], getBinaryName$: [] } });

class SoftwareRepositoryNavigationFactory {
    constructor() {
        this.node = new NavigatorNode({
            label: gettext('Software repository'),
            path: 'software',
            icon: 'c8y-tools',
            parent: gettext('Management'),
            priority: 900
        });
    }
    get() {
        return this.node;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryNavigationFactory, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryNavigationFactory }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryNavigationFactory, decorators: [{
            type: Injectable
        }], ctorParameters: () => [] });

class SoftwareRepositoryListModule {
    static forRoot() {
        return {
            ngModule: SoftwareRepositoryListModule,
            providers: [
                hookNavigator(SoftwareRepositoryNavigationFactory),
                hookRoute([
                    {
                        path: 'software',
                        component: SoftwareListComponent
                    },
                    {
                        path: 'software/:id',
                        component: SoftwareDetailsComponent
                    }
                ])
            ]
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryListModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryListModule, declarations: [SoftwareListComponent, SoftwareDetailsComponent, AddSoftwareModalComponent], imports: [CommonModule,
            CoreModule,
            FormsModule,
            DeviceGridModule,
            PopoverModule,
            TooltipModule,
            RouterModule,
            SharedRepositoryModule] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryListModule, imports: [CommonModule,
            CoreModule,
            FormsModule,
            DeviceGridModule,
            PopoverModule,
            TooltipModule,
            RouterModule,
            SharedRepositoryModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryListModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [
                        CommonModule,
                        CoreModule,
                        FormsModule,
                        DeviceGridModule,
                        PopoverModule,
                        TooltipModule,
                        RouterModule,
                        SharedRepositoryModule
                    ],
                    declarations: [SoftwareListComponent, SoftwareDetailsComponent, AddSoftwareModalComponent]
                }]
        }] });

class DeviceSoftwareService {
    /**
     * Indicates whether device software data is currently being loaded.
     */
    get loading$() {
        return this.loadingSubject$.asObservable().pipe(share());
    }
    constructor(serviceRegistry) {
        this.serviceRegistry = serviceRegistry;
        this.reloadSubject$ = new BehaviorSubject(null);
        this.loadingSubject$ = new Subject();
    }
    /**
     * Trigger device software data reload.
     */
    reload() {
        this.reloadSubject$.next();
    }
    /**
     * Retrieves the software list that is installed on a given device.
     *
     * @param deviceId ID of the device to retrieve software data for
     * @param filterCriteria Criteria that software items are filtered by.
     * @param legacySoftwareList If provided no data will be fetched from backend. The provided software list
     * will be filtered by the specified filter criteria.
     *
     * @returns The software items installed on the specified device filtered by the specified criteria.
     */
    getSoftwareList(deviceId, filterCriteria, legacySoftwareList) {
        this.loadingSubject$.next(true);
        return this.reloadSubject$.pipe(switchMap(() => {
            const softwareList$ = !!legacySoftwareList
                ? this.getLegacySoftwareList(legacySoftwareList, filterCriteria)
                : this.getAdvancedSoftwareList(deviceId, filterCriteria);
            return softwareList$.then(resultList => {
                this.loadingSubject$.next(false);
                return resultList;
            });
        }), share());
    }
    getAdvancedSoftwareList(deviceId, filterCriteria) {
        const queryFilter = {
            deviceId,
            currentPage: 1,
            pageSize: 50,
            withTotalPages: true
        };
        const advancedSoftwareService = head(this.serviceRegistry.get('asm'));
        if (filterCriteria?.name) {
            set(queryFilter, 'name', `*${filterCriteria.name}*`);
        }
        if (filterCriteria?.softwareType) {
            set(queryFilter, 'type', `${filterCriteria.softwareType}`);
        }
        return advancedSoftwareService.list(queryFilter);
    }
    getLegacySoftwareList(legacySoftwareList, filterCriteria) {
        const data = filterCriteria
            ? legacySoftwareList.filter(item => {
                let match = true;
                if (filterCriteria?.name) {
                    match = match && item.name?.includes(filterCriteria.name);
                }
                if (filterCriteria?.softwareType) {
                    match = match && item.softwareType === filterCriteria.softwareType;
                }
                return match;
            })
            : legacySoftwareList;
        return Promise.resolve({
            data,
            res: null,
            paging: {
                totalPages: data.length
            }
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceSoftwareService, deps: [{ token: i4.ServiceRegistry }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceSoftwareService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceSoftwareService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }], ctorParameters: () => [{ type: i4.ServiceRegistry }] });

class DeviceSoftwareListComponent {
    set softwareList(softwareList) {
        if (softwareList !== null) {
            this.legacySoftwareList$.next(softwareList);
        }
    }
    constructor(deviceSoftwareService) {
        this.deviceSoftwareService = deviceSoftwareService;
        this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_REPOSITORY_SHARED;
        this.filterCriteria$ = of(null);
        this.update = new EventEmitter();
        this.remove = new EventEmitter();
        this.onListEmpty = new EventEmitter();
        this.alreadyInstalledMessage = gettext('This software is already installed on the device');
        this.supportsSoftwareOperations = false;
        this.operationTypes = ['c8y_SoftwareUpdate', 'c8y_SoftwareList', 'c8y_Software'];
        this.legacySoftwareList$ = new BehaviorSubject([]);
        this.destroyed$ = new Subject();
    }
    ngOnInit() {
        this.softwareItems$ = combineLatest([
            this.filterCriteria$.pipe(debounceTime(300), distinctUntilChanged()),
            this.legacySoftwareList$
        ]).pipe(switchMap(([filterCriteria, legacySoftwareList]) => this.deviceSoftwareService
            .getSoftwareList(this.device?.id, filterCriteria, legacySoftwareList)
            .pipe(map(resultList => ({ resultList, filterCriteria })))), tap(({ resultList, filterCriteria }) => {
            this.notifyListEmpty(!resultList?.paging?.totalPages && !filterCriteria);
            this.noSearchResults = !resultList?.paging?.totalPages && !!filterCriteria;
        }), map(({ resultList }) => resultList), share(), takeUntil(this.destroyed$));
        const supportedOperations = get(this.device, 'c8y_SupportedOperations', []);
        this.supportsSoftwareOperations = this.operationTypes.some(operationType => supportedOperations.indexOf(operationType) > -1);
    }
    ngAfterContentInit() {
        this.showUpdate = this.update.observers.length > 0;
        this.showRemove = this.remove.observers.length > 0;
    }
    isSoftwareGoingToBeChanged(software) {
        const relevantChanges = filter(this.deviceSoftwareChanges, software);
        return relevantChanges.length > 0;
    }
    ngOnDestroy() {
        this.destroyed$.next();
        this.destroyed$.complete();
    }
    notifyListEmpty(isEmpty) {
        this.emptyList = isEmpty;
        this.onListEmpty.emit(isEmpty);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceSoftwareListComponent, deps: [{ token: DeviceSoftwareService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DeviceSoftwareListComponent, isStandalone: false, selector: "c8y-device-software-list", inputs: { softwareList: "softwareList", device: "device", deviceSoftwareChanges: "deviceSoftwareChanges", filterCriteria$: "filterCriteria$" }, outputs: { update: "update", remove: "remove", onListEmpty: "onListEmpty" }, ngImport: i0, template: "<c8y-list-group class=\"no-border-2nd-last\">\n  <c8y-li\n    [ngClass]=\"{ disabled: isSoftwareGoingToBeChanged(software) }\"\n    *c8yFor=\"let software of softwareItems$\"\n  >\n    <!-- SOFTWARE ICON -->\n    <c8y-li-icon>\n      <i c8yIcon=\"c8y-tools\"></i>\n    </c8y-li-icon>\n\n    <c8y-li-body class=\"content-flex-20\">\n      <div title=\"{{ software.name }}\" class=\"col-9\">\n        <p class=\"d-flex\">\n          <!-- SOFTWARE NAME -->\n          <span class=\"text-truncate\">\n            {{ software.name }}\n          </span>\n          <!-- SOFTWARE TYPE-->\n          <span class=\"text-truncate\">\n            <span class=\"label label-primary m-l-8\">{{ software.softwareType }}</span>\n          </span>\n        </p>\n        <!-- SOFTWARE VERSION -->\n        <p class=\"d-flex a-i-center\">\n          <span class=\"text-truncate text-label-small m-r-4\" translate>Version</span>\n          <span class=\"text-truncate m-r-4\" title=\"{{ software.version }}\">\n            {{ software.version }}\n          </span>\n          <i\n            *ngIf=\"software.installed\"\n            c8yIcon=\"warning\"\n            class=\"text-warning a-s-center\"\n            [tooltip]=\"\n              alreadyInstalledMessage\n                | translate: { name: software.name, version: software.version }\n            \"\n            container=\"body\"\n            placement=\"top\"\n            [delay]=\"500\"\n          ></i>\n        </p>\n      </div>\n\n      <div\n        *ngIf=\"supportsSoftwareOperations && (showUpdate || showRemove)\"\n        class=\"col-3 text-right m-0 flex-grow d-flex a-i-center\"\n      >\n        <!-- UPDATE SOFTWARE -->\n        <button\n          class=\"btn btn-default btn-xs m-l-auto m-r-4\"\n          type=\"button\"\n          title=\"{{ 'Update`software,verb`' | translate }}\"\n          *ngIf=\"showUpdate && !isSoftwareGoingToBeChanged(software)\"\n          (click)=\"update.emit(software)\"\n          c8yProductExperience\n          [actionName]=\"PRODUCT_EXPERIENCE.SOFTWARE.EVENTS.DEVICE_TAB\"\n          [actionData]=\"{\n            component: PRODUCT_EXPERIENCE.SOFTWARE.COMPONENTS.DEVICE_SOFTWARE_LIST,\n            action: PRODUCT_EXPERIENCE.SOFTWARE.ACTIONS.OPEN_UPDATE_SOFTWARE\n          }\"\n        >\n          {{ 'Update`software,verb`' | translate }}\n        </button>\n\n        <!-- REMOVE SOFTWARE -->\n        <button\n          class=\"btn btn-dot btn-dot--danger m-l-4\"\n          type=\"button\"\n          [attr.aria-label]=\"'Remove`software,verb`' | translate\"\n          tooltip=\"{{ 'Remove`software,verb`' | translate }}\"\n          placement=\"bottom\"\n          container=\"body\"\n          [delay]=\"500\"\n          c8yProductExperience\n          [actionName]=\"PRODUCT_EXPERIENCE.SOFTWARE.EVENTS.DEVICE_TAB\"\n          [actionData]=\"{\n            component: PRODUCT_EXPERIENCE.SOFTWARE.COMPONENTS.DEVICE_SOFTWARE_LIST,\n            action: PRODUCT_EXPERIENCE.SOFTWARE.ACTIONS.DELETE_SOFTWARE\n          }\"\n          *ngIf=\"showRemove && !isSoftwareGoingToBeChanged(software)\"\n          (click)=\"remove.emit(software)\"\n        >\n          <i c8yIcon=\"minus-circle\"></i>\n        </button>\n      </div>\n    </c8y-li-body>\n  </c8y-li>\n</c8y-list-group>\n<!-- NO SEARCH RESULTS STATE -->\n<div class=\"card-block\" *ngIf=\"noSearchResults || emptyList\">\n  <ng-content *ngIf=\"emptyList\" select=\".c8y-empty-state:not(.c8y-no-results-state)\"></ng-content>\n  <ng-content *ngIf=\"noSearchResults\" select=\".c8y-no-results-state\"></ng-content>\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: 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.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: "directive", type: i4.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { 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: "pipe", type: i4.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceSoftwareListComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-device-software-list', standalone: false, template: "<c8y-list-group class=\"no-border-2nd-last\">\n  <c8y-li\n    [ngClass]=\"{ disabled: isSoftwareGoingToBeChanged(software) }\"\n    *c8yFor=\"let software of softwareItems$\"\n  >\n    <!-- SOFTWARE ICON -->\n    <c8y-li-icon>\n      <i c8yIcon=\"c8y-tools\"></i>\n    </c8y-li-icon>\n\n    <c8y-li-body class=\"content-flex-20\">\n      <div title=\"{{ software.name }}\" class=\"col-9\">\n        <p class=\"d-flex\">\n          <!-- SOFTWARE NAME -->\n          <span class=\"text-truncate\">\n            {{ software.name }}\n          </span>\n          <!-- SOFTWARE TYPE-->\n          <span class=\"text-truncate\">\n            <span class=\"label label-primary m-l-8\">{{ software.softwareType }}</span>\n          </span>\n        </p>\n        <!-- SOFTWARE VERSION -->\n        <p class=\"d-flex a-i-center\">\n          <span class=\"text-truncate text-label-small m-r-4\" translate>Version</span>\n          <span class=\"text-truncate m-r-4\" title=\"{{ software.version }}\">\n            {{ software.version }}\n          </span>\n          <i\n            *ngIf=\"software.installed\"\n            c8yIcon=\"warning\"\n            class=\"text-warning a-s-center\"\n            [tooltip]=\"\n              alreadyInstalledMessage\n                | translate: { name: software.name, version: software.version }\n            \"\n            container=\"body\"\n            placement=\"top\"\n            [delay]=\"500\"\n          ></i>\n        </p>\n      </div>\n\n      <div\n        *ngIf=\"supportsSoftwareOperations && (showUpdate || showRemove)\"\n        class=\"col-3 text-right m-0 flex-grow d-flex a-i-center\"\n      >\n        <!-- UPDATE SOFTWARE -->\n        <button\n          class=\"btn btn-default btn-xs m-l-auto m-r-4\"\n          type=\"button\"\n          title=\"{{ 'Update`software,verb`' | translate }}\"\n          *ngIf=\"showUpdate && !isSoftwareGoingToBeChanged(software)\"\n          (click)=\"update.emit(software)\"\n          c8yProductExperience\n          [actionName]=\"PRODUCT_EXPERIENCE.SOFTWARE.EVENTS.DEVICE_TAB\"\n          [actionData]=\"{\n            component: PRODUCT_EXPERIENCE.SOFTWARE.COMPONENTS.DEVICE_SOFTWARE_LIST,\n            action: PRODUCT_EXPERIENCE.SOFTWARE.ACTIONS.OPEN_UPDATE_SOFTWARE\n          }\"\n        >\n          {{ 'Update`software,verb`' | translate }}\n        </button>\n\n        <!-- REMOVE SOFTWARE -->\n        <button\n          class=\"btn btn-dot btn-dot--danger m-l-4\"\n          type=\"button\"\n          [attr.aria-label]=\"'Remove`software,verb`' | translate\"\n          tooltip=\"{{ 'Remove`software,verb`' | translate }}\"\n          placement=\"bottom\"\n          container=\"body\"\n          [delay]=\"500\"\n          c8yProductExperience\n          [actionName]=\"PRODUCT_EXPERIENCE.SOFTWARE.EVENTS.DEVICE_TAB\"\n          [actionData]=\"{\n            component: PRODUCT_EXPERIENCE.SOFTWARE.COMPONENTS.DEVICE_SOFTWARE_LIST,\n            action: PRODUCT_EXPERIENCE.SOFTWARE.ACTIONS.DELETE_SOFTWARE\n          }\"\n          *ngIf=\"showRemove && !isSoftwareGoingToBeChanged(software)\"\n          (click)=\"remove.emit(software)\"\n        >\n          <i c8yIcon=\"minus-circle\"></i>\n        </button>\n      </div>\n    </c8y-li-body>\n  </c8y-li>\n</c8y-list-group>\n<!-- NO SEARCH RESULTS STATE -->\n<div class=\"card-block\" *ngIf=\"noSearchResults || emptyList\">\n  <ng-content *ngIf=\"emptyList\" select=\".c8y-empty-state:not(.c8y-no-results-state)\"></ng-content>\n  <ng-content *ngIf=\"noSearchResults\" select=\".c8y-no-results-state\"></ng-content>\n</div>\n" }]
        }], ctorParameters: () => [{ type: DeviceSoftwareService }], propDecorators: { softwareList: [{
                type: Input
            }], device: [{
                type: Input
            }], deviceSoftwareChanges: [{
                type: Input
            }], filterCriteria$: [{
                type: Input
            }], update: [{
                type: Output
            }], remove: [{
                type: Output
            }], onListEmpty: [{
                type: Output
            }] } });

class DeviceSoftwareChangesComponent {
    constructor() {
        this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_REPOSITORY_SHARED;
        this.clear = new EventEmitter();
        this.drop = new EventEmitter();
        this.apply = new EventEmitter();
        this.hideSoftwareChanges = new EventEmitter();
        this.changes$ = new BehaviorSubject([]);
        this.installations$ = this.changes$.pipe(map(changes => {
            return changes.filter(change => change.action === 'install');
        }));
        this.removals$ = this.changes$.pipe(map(changes => {
            return changes.filter(change => change.action === 'delete');
        }));
    }
    get applyButtonLabel() {
        return this.changesInProgress ? gettext('Applying changes…') : gettext('Apply changes');
    }
    ngOnChanges(changes) {
        if (changes.changes) {
            this.changes$.next(changes.changes.currentValue);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceSoftwareChangesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DeviceSoftwareChangesComponent, isStandalone: false, selector: "c8y-device-software-changes", inputs: { changes: "changes", changesInProgress: "changesInProgress", deviceSoftwareChangesOperation: "deviceSoftwareChangesOperation" }, outputs: { clear: "clear", drop: "drop", apply: "apply", hideSoftwareChanges: "hideSoftwareChanges" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"inner-scroll d-flex d-col\">\n  <div class=\"card-header separator sticky-top visible-sm visible-xs\">\n    <button\n      class=\"btn btn-dot text-primary\"\n      [title]=\"'Back' | translate\"\n      type=\"button\"\n      (click)=\"hideSoftwareChanges.emit()\"\n    >\n      <i c8yIcon=\"chevron-left\"></i>\n      <span translate>Back</span>\n    </button>\n  </div>\n  <div class=\"card-header separator large-padding sticky-top\">\n    <div\n      class=\"card-title\"\n      translate\n    >\n      Software changes\n    </div>\n  </div>\n  <div class=\"flex-grow\">\n    <fieldset\n      class=\"card-block large-padding bg-level-2 p-0\"\n      id=\"operation-block\"\n      *ngIf=\"deviceSoftwareChangesOperation\"\n    >\n      <c8y-operation-details [operation]=\"deviceSoftwareChangesOperation\"></c8y-operation-details>\n    </fieldset>\n  </div>\n  <div\n    class=\"flex-grow inner-scroll\"\n    id=\"software-changes-list\"\n  >\n    <div\n      class=\"card-block large-padding\"\n      *ngIf=\"(changes$ | async).length === 0; else changesList\"\n    >\n      <div class=\"c8y-empty-state\">\n        <div class=\"h1 c8y-icon c8y-icon-device-control c8y-icon-duocolor\"></div>\n        <p>\n          <strong translate>No software changes.</strong>\n          <br />\n          <small translate>Selected actions will be displayed here.</small>\n        </p>\n      </div>\n    </div>\n\n    <ng-template #changesList>\n      <fieldset\n        class=\"card-block p-t-0 p-b-0\"\n        *ngIf=\"(installations$ | async).length > 0\"\n        [disabled]=\"changesInProgress\"\n      >\n        <div\n          class=\"form-block legend\"\n          translate\n        >\n          Installations`software`\n        </div>\n        <c8y-device-software-list\n          [softwareList]=\"installations$ | async\"\n          (remove)=\"drop.emit($event)\"\n        ></c8y-device-software-list>\n      </fieldset>\n\n      <fieldset\n        class=\"card-block p-t-0 p-b-0\"\n        *ngIf=\"(removals$ | async).length > 0\"\n        [disabled]=\"changesInProgress\"\n      >\n        <div\n          class=\"form-block legend\"\n          translate\n        >\n          Removals`software`\n        </div>\n        <c8y-device-software-list\n          [softwareList]=\"removals$ | async\"\n          (remove)=\"drop.emit($event)\"\n        ></c8y-device-software-list>\n      </fieldset>\n    </ng-template>\n  </div>\n  <div\n    class=\"card-footer separator large-padding sticky-bottom\"\n    *ngIf=\"(changes$ | async).length > 0\"\n  >\n    <button\n      class=\"btn btn-default\"\n      title=\"{{ 'Clear changes' | translate }}\"\n      type=\"button\"\n      (click)=\"clear.emit()\"\n      [disabled]=\"changesInProgress\"\n      translate\n      c8yProductExperience\n      [actionName]=\"PRODUCT_EXPERIENCE.SOFTWARE.EVENTS.DEVICE_TAB\"\n      [actionData]=\"{\n        component: PRODUCT_EXPERIENCE.SOFTWARE.COMPONENTS.DEVICE_SOFTWARE_CHANGES,\n        action: PRODUCT_EXPERIENCE.SOFTWARE.ACTIONS.CLEAR_SOFTWARE_CHANGES\n      }\"\n    >\n      Clear`changes`\n    </button>\n    <button\n      class=\"btn btn-primary\"\n      title=\"{{ applyButtonLabel | translate }}\"\n      type=\"button\"\n      [ngClass]=\"{ 'btn-pending': changesInProgress }\"\n      [disabled]=\"changesInProgress\"\n      (click)=\"apply.emit(); hideSoftwareChanges.emit()\"\n      c8yProductExperience\n      [actionName]=\"PRODUCT_EXPERIENCE.SOFTWARE.EVENTS.DEVICE_TAB\"\n      [actionData]=\"{\n        component: PRODUCT_EXPERIENCE.SOFTWARE.COMPONENTS.DEVICE_SOFTWARE_CHANGES,\n        action: PRODUCT_EXPERIENCE.SOFTWARE.ACTIONS.APPLY_SOFTWARE_CHANGES\n      }\"\n    >\n      {{ applyButtonLabel | translate }}\n    </button>\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: i4.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i4.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i4.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "component", type: i3.OperationDetailsComponent, selector: "c8y-operation-details", inputs: ["operation"] }, { kind: "component", type: DeviceSoftwareListComponent, selector: "c8y-device-software-list", inputs: ["softwareList", "device", "deviceSoftwareChanges", "filterCriteria$"], outputs: ["update", "remove", "onListEmpty"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeviceSoftwareChangesComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-device-software-changes', standalone: false, template: "<div class=\"inner-scroll d-flex d-col\">\n  <div class=\"card-header separator sticky-top visible-sm visible-xs\">\n    <button\n      class=\"btn btn-dot text-primary\"\n      [title]=\"'Back' | translate\"\n      type=\"button\"\n      (click)=\"hideSoftwareChanges.emit()\"\n    >\n      <i c8yIcon=\"chevron-left\"></i>\n      <span translate>Back</span>\n    </button>\n  </div>\n  <div class=\"card-header separator large-padding sticky-top\">\n    <div\n      class=\"card-title\"\n      translate\n    >\n      Software changes\n    </div>\n  </div>\n  <div class=\"flex-grow\">\n    <fieldset\n      class=\"card-block large-padding bg-level-2 p-0\"\n      id=\"operation-block\"\n      *ngIf=\"deviceSoftwareChangesOperation\"\n    >\n      <c8y-operation-details [operation]=\"deviceSoftwareChangesOperation\"></c8y-operation-details>\n    </fieldset>\n  </div>\n  <div\n    class=\"flex-grow inner-scroll\"\n    id=\"software-changes-list\"\n  >\n    <div\n      class=\"card-block large-padding\"\n      *ngIf=\"(changes$ | async).length === 0; else changesList\"\n    >\n      <div class=\"c8y-empty-state\">\n        <div class=\"h1 c8y-icon c8y-icon-device-control c8y-icon-duocolor\"></div>\n        <p>\n          <strong translate>No software changes.</strong>\n          <br />\n          <small translate>Selected actions will be displayed here.</small>\n        </p>\n      </div>\n    </div>\n\n    <ng-template #changesList>\n      <fieldset\n        class=\"card-block p-t-0 p-b-0\"\n        *ngIf=\"(installations$ | async).length > 0\"\n        [disabled]=\"changesInProgress\"\n      >\n        <div\n          class=\"form-block legend\"\n          translate\n        >\n          Installations`software`\n        </div>\n        <c8y-device-software-list\n          [softwareList]=\"installations$ | async\"\n          (remove)=\"drop.emit($event)\"\n        ></c8y-device-software-list>\n      </fieldset>\n\n      <fieldset\n        class=\"card-block p-t-0 p-b-0\"\n        *ngIf=\"(removals$ | async).length > 0\"\n        [disabled]=\"changesInProgress\"\n      >\n        <div\n          class=\"form-block legend\"\n          translate\n        >\n          Removals`software`\n        </div>\n        <c8y-device-software-list\n          [softwareList]=\"removals$ | async\"\n          (remove)=\"drop.emit($event)\"\n        ></c8y-device-software-list>\n      </fieldset>\n    </ng-template>\n  </div>\n  <div\n    class=\"card-footer separator large-padding sticky-bottom\"\n    *ngIf=\"(changes$ | async).length > 0\"\n  >\n    <button\n      class=\"btn btn-default\"\n      title=\"{{ 'Clear changes' | translate }}\"\n      type=\"button\"\n      (click)=\"clear.emit()\"\n      [disabled]=\"changesInProgress\"\n      translate\n      c8yProductExperience\n      [actionName]=\"PRODUCT_EXPERIENCE.SOFTWARE.EVENTS.DEVICE_TAB\"\n      [actionData]=\"{\n        component: PRODUCT_EXPERIENCE.SOFTWARE.COMPONENTS.DEVICE_SOFTWARE_CHANGES,\n        action: PRODUCT_EXPERIENCE.SOFTWARE.ACTIONS.CLEAR_SOFTWARE_CHANGES\n      }\"\n    >\n      Clear`changes`\n    </button>\n    <button\n      class=\"btn btn-primary\"\n      title=\"{{ applyButtonLabel | translate }}\"\n      type=\"button\"\n      [ngClass]=\"{ 'btn-pending': changesInProgress }\"\n      [disabled]=\"changesInProgress\"\n      (click)=\"apply.emit(); hideSoftwareChanges.emit()\"\n      c8yProductExperience\n      [actionName]=\"PRODUCT_EXPERIENCE.SOFTWARE.EVENTS.DEVICE_TAB\"\n      [actionData]=\"{\n        component: PRODUCT_EXPERIENCE.SOFTWARE.COMPONENTS.DEVICE_SOFTWARE_CHANGES,\n        action: PRODUCT_EXPERIENCE.SOFTWARE.ACTIONS.APPLY_SOFTWARE_CHANGES\n      }\"\n    >\n      {{ applyButtonLabel | translate }}\n    </button>\n  </div>\n</div>\n" }]
        }], propDecorators: { changes: [{
                type: Input
            }], changesInProgress: [{
                type: Input
            }], deviceSoftwareChangesOperation: [{
                type: Input
            }], clear: [{
                type: Output
            }], drop: [{
                type: Output
            }], apply: [{
                type: Output
            }], hideSoftwareChanges: [{
                type: Output
            }] } });

class InstalledSoftwareComponent {
    constructor(repository, bsModal) {
        this.repository = repository;
        this.bsModal = bsModal;
        this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_REPOSITORY_SHARED;
        this.changes = new EventEmitter();
        this.showSoftwareChanges = new EventEmitter();
        this.alreadyInstalledMessage = gettext('{{ name }} (v. {{ version }}) is already installed on this device');
        this.showFilter = false;
        this.supportsSoftwareOperations = false;
        this.textFilter$ = new BehaviorSubject('');
        this.softwareTypeFilter$ = new BehaviorSubject('');
        this.operationTypes = ['c8y_SoftwareUpdate', 'c8y_SoftwareList', 'c8y_Software'];
        this.destroyed$ = new Subject();
        this.filterCriteria$ = combineLatest([this.textFilter$, this.softwareTypeFilter$]).pipe(map(([textFilter, softwareTypeFilter]) => ({
            name: textFilter,
            softwareType: softwareTypeFilter
        })), map(filterCriteria => !filterCriteria.name && !filterCriteria.softwareType ? null : filterCriteria));
        this.queriesUtil = new QueriesUtil();
    }
    ngOnInit() {
        const supportedOperations = get(this.device, 'c8y_SupportedOperations', []);
        this.supportsSoftwareOperations = this.operationTypes.some(operationType => supportedOperations.indexOf(operationType) > -1);
    }
    installSoftware() {
        const { resultEmitter, choiceEmitter, updateInstallableList$ } = this.displaySoftwareSelectModal({
            title: gettext('Install software'),
            subTitle: gettext('Available softwares matching the device type'),
            labels: { ok: gettext('Install') },
            noItemsMessage: gettext('No matching software available.'),
            showAdditionalFilter: true,
            additionalFilterTemplate: this.softwareTypeTemplate,
            repositoryEntriesWithVersions$: of([]),
            repositoryEntriesWithVersionsFn$: modal => this.getInstallableSoftwareListWithVersions$(modal.content.searchTerm)
        });
        resultEmitter.pipe(takeUntil(this.destroyed$)).subscribe(softwareToInstall => {
            this.emitSoftwareInstall(softwareToInstall);
            this.showSoftwareChanges.emit();
        });
        choiceEmitter
            .pipe(this.isSoftwareInstalledOnDevicePipe(updateInstallableList$), takeUntil(this.destroyed$))
            .subscribe(({ item }) => updateInstallableList$.next({
            object: item,
            template: this.alreadyInstalledWarningTemplate,
            mapper: object => {
                object.installed = true;
                return object;
            }
        }));
    }
    updateSoftware(softwareToUpdate) {
        const { resultEmitter, choiceEmitter, updateInstallableList$ } = this.displaySoftwareSelectModal({
            title: gettext('Update software'),
            subTitle: gettext('Select one of the available software versions'),
            labels: { ok: gettext('Update') },
            noItemsMessage: gettext('No other software versions available.'),
            showFilter: false,
            repositoryEntriesWithVersions$: this.getSingleSoftwareWithVersions$(softwareToUpdate)
        });
        resultEmitter.pipe(takeUntil(this.destroyed$)).subscribe(softwareToInstall => {
            this.emitSoftwareInstall(softwareToInstall);
            this.showSoftwareChanges.emit();
        });
        choiceEmitter
            .pipe(this.isSoftwareInstalledOnDevicePipe(updateInstallableList$), takeUntil(this.destroyed$))
            .subscribe(({ item }) => updateInstallableList$.next({
            object: item,
            template: this.alreadyInstalledWarningTemplate,
            mapper: object => {
                object.installed = true;
                return object;
            }
        }));
    }
    removeSoftware(softwareToRemove) {
        this.emitSoftwareRemoval([softwareToRemove]);
    }
    getInstallableSoftwareListWithVersions$(searchTerm$) {
        const installedSoftwareNames = (this.softwareList || []).map(s => s.name);
        return searchTerm$.pipe(distinctUntilChanged(), switchMap(searchTerm => this.repository.listRepositoryEntries(RepositoryType.SOFTWARE, {
            query: searchTerm.softwareType
                ? this.queriesUtil.addAndFilter(this.typesQuery, {
                    softwareType: searchTerm.softwareType
                })
                : this.typesQuery,
            partialName: searchTerm?.name,
            params: { pageSize: 100 }
        })), map(({ data }) => data), map(softwareList => {
            return softwareList.filter(software => {
                return !installedSoftwareNames.includes(software.name);
            });
        }), map(softwareList => this.attachVersions(softwareList)), shareReplay(1));
    }
    getSingleSoftwareWithVersions$(software) {
        return from(this.repository.listRepositoryEntries(RepositoryType.SOFTWARE, {
            query: { name: software.name }
        })).pipe(map(({ data }) => data), map(softwareList => this.attachVersions(softwareList)), shareReplay(1));
    }
    attachVersions(softwareList) {
        softwareList.forEach(software => {
            software.versions = this.repository.listBaseVersions(software);
        });
        return softwareList;
    }
    displaySoftwareSelectModal(initialStateOverrides) {
        const initialState = {
            repositoryType: RepositoryType.SOFTWARE,
            mode: ModalSelectionMode.MULTI,
            icon: 'c8y-tools',
            disableSelected: false,
            selected: this.softwareList,
            hideEmptyItems: true,
            ...initialStateOverrides
        };
        const modal = this.bsModal.show(RepositorySelectModalComponent, {
            ignoreBackdropClick: true,
            class: 'modal-sm',
            ariaDescribedby: 'modal-body',
            ariaLabelledBy: 'modal-title',
            initialState
        });
        if (initialStateOverrides.repositoryEntriesWithVersionsFn$) {
            modal.content.repositoryEntriesWithVersions$ =
                initialStateOverrides.repositoryEntriesWithVersionsFn$(modal);
        }
        this.modalSearch = modal.content.search.bind(modal.content);
        modal.content.load.next();
        return {
            resultEmitter: modal.content.resultEmitter,
            choiceEmitter: modal.content.onChoiceUpdated,
            updateInstallableList$: modal.content.updateInstallableList$
        };
    }
    search(filterCriteria) {
        if (this.modalSearch) {
            this.modalSearch(filterCriteria);
        }
    }
    emitSoftwareInstall(items) {
        this.changes.emit(items.map(item => {
            return { ...item, action: 'install' };
        }));
    }
    emitSoftwareRemoval(items) {
        this.changes.emit(items.map(item => {
            return { ...item, action: 'delete' };
        }));
    }
    ngOnDestroy() {
        this.destroyed$.next();
        this.destroyed$.complete();
    }
    isSoftwareInstalledOnDevicePipe(updateInstallableList$) {
        return pipe(tap((item) => updateInstallableList$.next({ object: item, template: this.loadingTemplate })), map(item => ({
            item,
            software: ((item.options || []).find(option => option.obj.id === item.selectedId) || {}).obj
        })), mergeMap(({ item, software }) => from(this.repository.isSoftwareInstalledOnDevice(this.device.id, software)).pipe(map(installed => ({ item, installed })))), tap(({ item }) => updateInstallableList$.next({ object: item })), filter$1(({ installed }) => !!installed));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: InstalledSoftwareComponent, deps: [{ token: i1$1.RepositoryService }, { token: i1.BsModalService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: InstalledSoftwareComponent, isStandalone: false, selector: "c8y-installed-software", inputs: { device: "device", softwareList: "softwareList", deviceSoftwareChanges: "deviceSoftwareChanges", deviceSoftwareChangesInProgress: "deviceSoftwareChangesInProgress", typesQuery: "typesQuery" }, outputs: { changes: "changes", showSoftwareChanges: "showSoftwareChanges" }, viewQueries: [{ propertyName: "alreadyInstalledWarningTemplate", first: true, predicate: ["alreadyInstalledWarning"], descendants: true, static: true }, { propertyName: "loadingTemplate", first: true, predicate: ["loading"], descendants: true, static: true }, { propertyName: "softwareTypeTemplate", first: true, predicate: ["softwareType"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"d-flex d-col flex-grow\">\n  <div class=\"card-header large-padding separator sticky-top\">\n    <div\n      class=\"card-title\"\n      translate\n    >\n      Installed software\n    </div>\n  </div>\n  <div class=\"flex-grow\">\n    <fieldset\n      class=\"card-block large-padding overflow-visible separator-bottom\"\n      *ngIf=\"showFilter\"\n    >\n      <div class=\"row\">\n        <div class=\"col-xs-6\">\n          <div class=\"input-group input-group-search\">\n            <label\n              class=\"sr-only\"\n              for=\"filter\"\n            >\n              {{ 'Filter\u2026' | translate }}\n            </label>\n            <input\n              class=\"form-control\"\n              title=\"{{ 'Filter\u2026' | translate }}\"\n              id=\"filter\"\n              placeholder=\"{{ 'Filter\u2026' | translate }}\"\n              type=\"search\"\n              [ngModel]=\"textFilter$ | async\"\n              (ngModelChange)=\"textFilter$.next($event)\"\n            />\n            <span class=\"input-group-addon\">\n              <i\n                c8yIcon=\"search\"\n                *ngIf=\"(textFilter$ | async).length === 0\"\n              ></i>\n              <i\n                class=\"text-muted\"\n                c8yIcon=\"times\"\n                *ngIf=\"(textFilter$ | async).length > 0\"\n                (click)=\"textFilter$.next('')\"\n              ></i>\n            </span>\n            <span\n              class=\"sr-only\"\n              for=\"search\"\n              translate\n            >\n              Filter\u2026\n            </span>\n          </div>\n        </div>\n        <div class=\"col-xs-6\">\n          <c8y-software-type\n            [required]=\"false\"\n            [emitResultsOnly]=\"true\"\n            [showBtnInNotFoundMessage]=\"false\"\n            [allowFreeEntries]=\"false\"\n            [placeholder]=\"'Filter by software type\u2026' | translate\"\n            [showClearSelectionOption]=\"true\"\n            [presetSoftwareTypes]=\"device.c8y_SupportedSoftwareTypes\"\n            (onSelectSoftware)=\"softwareTypeFilter$.next($event?.softwareType)\"\n          ></c8y-software-type>\n        </div>\n      </div>\n    </fieldset>\n\n    <fieldset\n      class=\"flex-grow inner-scroll\"\n      id=\"software-list\"\n      [disabled]=\"deviceSoftwareChangesInProgress\"\n    >\n      <!-- NOT EMPTY STATE -->\n      <c8y-device-software-list\n        class=\"d-block p-l-16 p-r-16\"\n        container=\"body\"\n        [device]=\"device\"\n        [filterCriteria$]=\"filterCriteria$\"\n        [softwareList]=\"softwareList\"\n        [deviceSoftwareChanges]=\"deviceSoftwareChanges\"\n        (update)=\"updateSoftware($event)\"\n        (remove)=\"removeSoftware($event)\"\n        (onListEmpty)=\"showFilter = !$event\"\n      >\n        <!-- EMPTY STATE -->\n        <div class=\"c8y-empty-state text-center\">\n          <div class=\"h1 c8y-icon c8y-icon-tools c8y-icon-duocolor\"></div>\n          <p>\n            <strong translate>No software installed.</strong>\n            <br />\n            <small translate>Click below to install software into this device.</small>\n          </p>\n        </div>\n        <!-- NO SEARCH RESULTS STATE -->\n        <div class=\"c8y-empty-state c8y-no-results-state text-center\">\n          <div class=\"h1 c8y-icon c8y-icon-tools c8y-icon-duocolor\"></div>\n          <p>\n            <strong translate>No software matches your filter criteria.</strong>\n            <br />\n            <small translate>Try changing your search criteria.</small>\n          </p>\n        </div>\n      </c8y-device-software-list>\n    </fieldset>\n  </div>\n  <!-- INSTALL SOFTWARE-->\n  <div\n    class=\"card-footer large-padding separator sticky-bottom d-flex j-c-between bg-level-0\"\n    [ngClass]=\"{ 'visible-sm visible-xs': !supportsSoftwareOperations }\"\n  >\n    <button\n      class=\"btn btn-default\"\n      title=\"{{ 'Install software' | translate }}\"\n      *ngIf=\"supportsSoftwareOperations\"\n      (click)=\"installSoftware()\"\n      [disabled]=\"deviceSoftwareChangesInProgress\"\n      c8yProductExperience\n      [actionName]=\"PRODUCT_EXPERIENCE.SOFTWARE.EVENTS.DEVICE_TAB\"\n      [actionData]=\"{\n        component: PRODUCT_EXPERIENCE.SOFTWARE.COMPONENTS.DEVICE_SOFTWARE_LIST,\n        action: PRODUCT_EXPERIENCE.SOFTWARE.ACTIONS.OPEN_INSTALL_SOFTWARE\n      }\"\n    >\n      <i c8yIcon=\"plus-circle\"></i>\n      {{ 'Install software' | translate }}\n    </button>\n    <button\n      class=\"btn btn-clean text-primary visible-sm visible-xs\"\n      [title]=\"'Show &quot;Software changes&quot;' | translate\"\n      (click)=\"showSoftwareChanges.emit()\"\n    >\n      <span translate>Show \"Software changes\"</span>\n      <i c8yIcon=\"chevron-right\"></i>\n    </button>\n  </div>\n</div>\n\n<ng-template\n  #alreadyInstalledWarning\n  let-item\n  let-option=\"option\"\n>\n  <i\n    class=\"text-warning a-s-center\"\n    c8yIcon=\"warning\"\n    [tooltip]=\"\n      alreadyInstalledMessage\n        | translate: { name: item.body[0].value, version: option.body[0].value }\n    \"\n  ></i>\n</ng-template>\n\n<ng-template #loading>\n  <div class=\"p-relative d-flex m-l-auto\">\n    <i\n      class=\"icon-spin\"\n      c8yIcon=\"circle-o-notch\"\n    ></i>\n  </div>\n</ng-template>\n\n<ng-template #softwareType>\n  <c8y-software-type\n    additionalFilter\n    [required]=\"false\"\n    [placeholder]=\"'Filter by software type\u2026' | translate\"\n    (onSelectSoftware)=\"search({ softwareType: $event?.softwareType })\"\n    [emitResultsOnly]=\"true\"\n    [showBtnInNotFoundMessage]=\"false\"\n    [allowFreeEntries]=\"false\"\n    [showClearSelectionOption]=\"true\"\n    [presetSoftwareTypes]=\"device.c8y_SupportedSoftwareTypes\"\n  ></c8y-software-type>\n</ng-template>\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: i4.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i4.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i5.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: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i4.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "component", type: i1$1.SoftwareTypeComponent, selector: "c8y-software-type", inputs: ["softwareTypeMO", "disabled", "style", "required", "placeholder", "emitResultsOnly", "showBtnInNotFoundMessage", "allowFreeEntries", "showClearSelectionOption", "clearSelectionOptionLabel", "presetSoftwareTypes"], outputs: ["onSelectSoftware"] }, { 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: DeviceSoftwareListComponent, selector: "c8y-device-software-list", inputs: ["softwareList", "device", "deviceSoftwareChanges", "filterCriteria$"], outputs: ["update", "remove", "onListEmpty"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: InstalledSoftwareComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-installed-software', standalone: false, template: "<div class=\"d-flex d-col flex-grow\">\n  <div class=\"card-header large-padding separator sticky-top\">\n    <div\n      class=\"card-title\"\n      translate\n    >\n      Installed software\n    </div>\n  </div>\n  <div class=\"flex-grow\">\n    <fieldset\n      class=\"card-block large-padding overflow-visible separator-bottom\"\n      *ngIf=\"showFilter\"\n    >\n      <div class=\"row\">\n        <div class=\"col-xs-6\">\n          <div class=\"input-group input-group-search\">\n            <label\n              class=\"sr-only\"\n              for=\"filter\"\n            >\n              {{ 'Filter\u2026' | translate }}\n            </label>\n            <input\n              class=\"form-control\"\n              title=\"{{ 'Filter\u2026' | translate }}\"\n              id=\"filter\"\n              placeholder=\"{{ 'Filter\u2026' | translate }}\"\n              type=\"search\"\n              [ngModel]=\"textFilter$ | async\"\n              (ngModelChange)=\"textFilter$.next($event)\"\n            />\n            <span class=\"input-group-addon\">\n              <i\n                c8yIcon=\"search\"\n                *ngIf=\"(textFilter$ | async).length === 0\"\n              ></i>\n              <i\n                class=\"text-muted\"\n                c8yIcon=\"times\"\n                *ngIf=\"(textFilter$ | async).length > 0\"\n                (click)=\"textFilter$.next('')\"\n              ></i>\n            </span>\n            <span\n              class=\"sr-only\"\n              for=\"search\"\n              translate\n            >\n              Filter\u2026\n            </span>\n          </div>\n        </div>\n        <div class=\"col-xs-6\">\n          <c8y-software-type\n            [required]=\"false\"\n            [emitResultsOnly]=\"true\"\n            [showBtnInNotFoundMessage]=\"false\"\n            [allowFreeEntries]=\"false\"\n            [placeholder]=\"'Filter by software type\u2026' | translate\"\n            [showClearSelectionOption]=\"true\"\n            [presetSoftwareTypes]=\"device.c8y_SupportedSoftwareTypes\"\n            (onSelectSoftware)=\"softwareTypeFilter$.next($event?.softwareType)\"\n          ></c8y-software-type>\n        </div>\n      </div>\n    </fieldset>\n\n    <fieldset\n      class=\"flex-grow inner-scroll\"\n      id=\"software-list\"\n      [disabled]=\"deviceSoftwareChangesInProgress\"\n    >\n      <!-- NOT EMPTY STATE -->\n      <c8y-device-software-list\n        class=\"d-block p-l-16 p-r-16\"\n        container=\"body\"\n        [device]=\"device\"\n        [filterCriteria$]=\"filterCriteria$\"\n        [softwareList]=\"softwareList\"\n        [deviceSoftwareChanges]=\"deviceSoftwareChanges\"\n        (update)=\"updateSoftware($event)\"\n        (remove)=\"removeSoftware($event)\"\n        (onListEmpty)=\"showFilter = !$event\"\n      >\n        <!-- EMPTY STATE -->\n        <div class=\"c8y-empty-state text-center\">\n          <div class=\"h1 c8y-icon c8y-icon-tools c8y-icon-duocolor\"></div>\n          <p>\n            <strong translate>No software installed.</strong>\n            <br />\n            <small translate>Click below to install software into this device.</small>\n          </p>\n        </div>\n        <!-- NO SEARCH RESULTS STATE -->\n        <div class=\"c8y-empty-state c8y-no-results-state text-center\">\n          <div class=\"h1 c8y-icon c8y-icon-tools c8y-icon-duocolor\"></div>\n          <p>\n            <strong translate>No software matches your filter criteria.</strong>\n            <br />\n            <small translate>Try changing your search criteria.</small>\n          </p>\n        </div>\n      </c8y-device-software-list>\n    </fieldset>\n  </div>\n  <!-- INSTALL SOFTWARE-->\n  <div\n    class=\"card-footer large-padding separator sticky-bottom d-flex j-c-between bg-level-0\"\n    [ngClass]=\"{ 'visible-sm visible-xs': !supportsSoftwareOperations }\"\n  >\n    <button\n      class=\"btn btn-default\"\n      title=\"{{ 'Install software' | translate }}\"\n      *ngIf=\"supportsSoftwareOperations\"\n      (click)=\"installSoftware()\"\n      [disabled]=\"deviceSoftwareChangesInProgress\"\n      c8yProductExperience\n      [actionName]=\"PRODUCT_EXPERIENCE.SOFTWARE.EVENTS.DEVICE_TAB\"\n      [actionData]=\"{\n        component: PRODUCT_EXPERIENCE.SOFTWARE.COMPONENTS.DEVICE_SOFTWARE_LIST,\n        action: PRODUCT_EXPERIENCE.SOFTWARE.ACTIONS.OPEN_INSTALL_SOFTWARE\n      }\"\n    >\n      <i c8yIcon=\"plus-circle\"></i>\n      {{ 'Install software' | translate }}\n    </button>\n    <button\n      class=\"btn btn-clean text-primary visible-sm visible-xs\"\n      [title]=\"'Show &quot;Software changes&quot;' | translate\"\n      (click)=\"showSoftwareChanges.emit()\"\n    >\n      <span translate>Show \"Software changes\"</span>\n      <i c8yIcon=\"chevron-right\"></i>\n    </button>\n  </div>\n</div>\n\n<ng-template\n  #alreadyInstalledWarning\n  let-item\n  let-option=\"option\"\n>\n  <i\n    class=\"text-warning a-s-center\"\n    c8yIcon=\"warning\"\n    [tooltip]=\"\n      alreadyInstalledMessage\n        | translate: { name: item.body[0].value, version: option.body[0].value }\n    \"\n  ></i>\n</ng-template>\n\n<ng-template #loading>\n  <div class=\"p-relative d-flex m-l-auto\">\n    <i\n      class=\"icon-spin\"\n      c8yIcon=\"circle-o-notch\"\n    ></i>\n  </div>\n</ng-template>\n\n<ng-template #softwareType>\n  <c8y-software-type\n    additionalFilter\n    [required]=\"false\"\n    [placeholder]=\"'Filter by software type\u2026' | translate\"\n    (onSelectSoftware)=\"search({ softwareType: $event?.softwareType })\"\n    [emitResultsOnly]=\"true\"\n    [showBtnInNotFoundMessage]=\"false\"\n    [allowFreeEntries]=\"false\"\n    [showClearSelectionOption]=\"true\"\n    [presetSoftwareTypes]=\"device.c8y_SupportedSoftwareTypes\"\n  ></c8y-software-type>\n</ng-template>\n" }]
        }], ctorParameters: () => [{ type: i1$1.RepositoryService }, { type: i1.BsModalService }], propDecorators: { device: [{
                type: Input
            }], softwareList: [{
                type: Input
            }], deviceSoftwareChanges: [{
                type: Input
            }], deviceSoftwareChangesInProgress: [{
                type: Input
            }], typesQuery: [{
                type: Input
            }], changes: [{
                type: Output
            }], showSoftwareChanges: [{
                type: Output
            }], alreadyInstalledWarningTemplate: [{
                type: ViewChild,
                args: ['alreadyInstalledWarning', { static: true }]
            }], loadingTemplate: [{
                type: ViewChild,
                args: ['loading', { static: true }]
            }], softwareTypeTemplate: [{
                type: ViewChild,
                args: ['softwareType', { static: true }]
            }] } });

class SoftwareDeviceTabComponent {
    constructor(route, repository, inventory, deviceSoftwareService, serviceRegistry) {
        this.route = route;
        this.repository = repository;
        this.inventory = inventory;
        this.deviceSoftwareService = deviceSoftwareService;
        this.serviceRegistry = serviceRegistry;
        this.deviceId = this.route.snapshot.parent.data.contextData.id;
        this.device$ = new BehaviorSubject(this.route.snapshot.parent.data.contextData);
        this.typesQuery$ = this.device$.pipe(map(device => {
            const deviceTypeQuery = this.repository.getDeviceTypeQuery(RepositoryType.SOFTWARE, device);
            return this.repository.getSoftwareTypeQuery(device, deviceTypeQuery);
        }));
        this.changes$ = new BehaviorSubject([]);
        this.changesOperation$ = new BehaviorSubject(null);
        this.changesInProgress$ = this.changesOperation$.pipe(map(operation => this.isInProgress(operation)));
        this.reloading = false;
        this.showSoftwareChanges = false;
    }
    async ngOnInit() {
        const advancedSoftwareService = head(this.serviceRegistry.get('asm'));
        this.list$ = this.device$.pipe(switchMap(device => advancedSoftwareService
            ? advancedSoftwareService
                .isASMAvailable()
                .then(isASMAvailable => ({ isASMAvailable, device }))
            : of({ isASMAvailable: false, device })), map(({ isASMAvailable, device }) => 
        // with ASM available software items will be retrieved directly in the
        // device-software-list component
        isASMAvailable ? undefined : this.repository.getDeviceSoftwareList(device)));
        await this.loadDevice();
        await this.loadOperation();
    }
    addChanges(requestedChanges) {
        let stagedChanges = [...this.changes$.value];
        requestedChanges.forEach(requestedChange => {
            const alreadyStaged = stagedChanges.some(stagedChange => this.areSameChanges(stagedChange, requestedChange));
            if (!alreadyStaged) {
                stagedChanges = [...stagedChanges, requestedChange];
            }
        });
        this.changes$.next(stagedChanges);
    }
    dropChange(changeToBeDropped) {
        let stagedChanges = [...this.changes$.value];
        stagedChanges = stagedChanges.filter(stagedChange => !this.areSameChanges(stagedChange, changeToBeDropped));
        this.changes$.next(stagedChanges);
    }
    areSameChanges(change1, change2) {
        return (change1.name === change2.name &&
            change1.version === change2.version &&
            change1.action === change2.action);
    }
    clearChanges() {
        this.changes$.next([]);
    }
    async loadDevice() {
        this.reloading = true;
        this.deviceSoftwareService.reload();
        const device = await Promise.all([
            this.deviceSoftwareService.loading$
                .pipe(filter$1(loading => !loading), take(1))
                .toPromise(),
            this.inventory.detail(this.deviceId, { withChildren: false }).then(result => result.data)
        ]).then(([_, device]) => device);
        this.device$.next(device);
        this.reloading = false;
    }
    async applyChanges() {
        const operation = await this.repository.createSoftwareUpdateOperation(this.device$.value, this.changes$.value);
        await this.trackOperation(operation);
    }
    async loadOperation() {
        const operation = await this.repository.getLastSoftwareUpdateOperation(this.deviceId);
        await this.trackOperation(operation);
    }
    async trackOperation(operation) {
        if ([OperationStatus.SUCCESSFUL, OperationStatus.FAILED].includes(operation?.status)) {
            this.changesOperation$.next(undefined);
        }
        else
            this.changesOperation$.next(operation);
        if (this.isInProgress(operation)) {
            await this.displayChangesFromOperation(operation);
            this.repository.observeOperation(operation).subscribe(operationUpdate => {
                this.changesOperation$.next(operationUpdate);
                if (operationUpdate.status === OperationStatus.SUCCESSFUL) {
                    this.clearChanges();
                    this.loadDevice();
                }
            }, operationUpdate => {
                this.changesOperation$.next(operationUpdate);
            });
        }
    }
    async displayChangesFromOperation(operation) {
        const changes = await this.repository.getDeviceSoftwareChangesFromOperation(operation, this.device$.value);
        this.changes$.next(changes);
    }
    isInProgress(operation) {
        return (operation && [OperationStatus.PENDING, OperationStatus.EXECUTING].includes(operation.status));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareDeviceTabComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i1$1.RepositoryService }, { token: i2.InventoryService }, { token: DeviceSoftwareService }, { token: i4.ServiceRegistry }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: SoftwareDeviceTabComponent, isStandalone: false, selector: "c8y-software-device-tab", ngImport: i0, template: "<c8y-action-bar-item [placement]=\"'right'\">\n  <button\n    class=\"btn btn-link\"\n    title=\"{{ 'Reload' | translate }}\"\n    (click)=\"loadDevice()\"\n  >\n    <i\n      c8yIcon=\"refresh\"\n      [ngClass]=\"{ 'icon-spin': reloading }\"\n    ></i>\n    {{ 'Reload' | translate }}\n  </button>\n</c8y-action-bar-item>\n\n<div class=\"card split-view--7-5 m-b-0\">\n  <c8y-installed-software\n    class=\"split-view__list\"\n    [device]=\"device$ | async\"\n    [typesQuery]=\"typesQuery$ | async\"\n    [softwareList]=\"list$ | async\"\n    [deviceSoftwareChanges]=\"changes$ | async\"\n    [deviceSoftwareChangesInProgress]=\"changesInProgress$ | async\"\n    (changes)=\"addChanges($event)\"\n    (showSoftwareChanges)=\"showSoftwareChanges = true\"\n  ></c8y-installed-software>\n  <c8y-device-software-changes\n    class=\"bg-level-1 split-view__detail\"\n    [ngClass]=\"{ 'split-view__detail--selected': showSoftwareChanges }\"\n    [deviceSoftwareChangesOperation]=\"changesOperation$ | async\"\n    [changes]=\"changes$ | async\"\n    [changesInProgress]=\"changesInProgress$ | async\"\n    (clear)=\"clearChanges()\"\n    (drop)=\"dropChange($event)\"\n    (apply)=\"applyChanges()\"\n    (hideSoftwareChanges)=\"showSoftwareChanges = false\"\n  ></c8y-device-software-changes>\n</div>\n", dependencies: [{ kind: "directive", type: i7.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i4.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: i4.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: InstalledSoftwareComponent, selector: "c8y-installed-software", inputs: ["device", "softwareList", "deviceSoftwareChanges", "deviceSoftwareChangesInProgress", "typesQuery"], outputs: ["changes", "showSoftwareChanges"] }, { kind: "component", type: DeviceSoftwareChangesComponent, selector: "c8y-device-software-changes", inputs: ["changes", "changesInProgress", "deviceSoftwareChangesOperation"], outputs: ["clear", "drop", "apply", "hideSoftwareChanges"] }, { kind: "pipe", type: i7.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareDeviceTabComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-software-device-tab', standalone: false, template: "<c8y-action-bar-item [placement]=\"'right'\">\n  <button\n    class=\"btn btn-link\"\n    title=\"{{ 'Reload' | translate }}\"\n    (click)=\"loadDevice()\"\n  >\n    <i\n      c8yIcon=\"refresh\"\n      [ngClass]=\"{ 'icon-spin': reloading }\"\n    ></i>\n    {{ 'Reload' | translate }}\n  </button>\n</c8y-action-bar-item>\n\n<div class=\"card split-view--7-5 m-b-0\">\n  <c8y-installed-software\n    class=\"split-view__list\"\n    [device]=\"device$ | async\"\n    [typesQuery]=\"typesQuery$ | async\"\n    [softwareList]=\"list$ | async\"\n    [deviceSoftwareChanges]=\"changes$ | async\"\n    [deviceSoftwareChangesInProgress]=\"changesInProgress$ | async\"\n    (changes)=\"addChanges($event)\"\n    (showSoftwareChanges)=\"showSoftwareChanges = true\"\n  ></c8y-installed-software>\n  <c8y-device-software-changes\n    class=\"bg-level-1 split-view__detail\"\n    [ngClass]=\"{ 'split-view__detail--selected': showSoftwareChanges }\"\n    [deviceSoftwareChangesOperation]=\"changesOperation$ | async\"\n    [changes]=\"changes$ | async\"\n    [changesInProgress]=\"changesInProgress$ | async\"\n    (clear)=\"clearChanges()\"\n    (drop)=\"dropChange($event)\"\n    (apply)=\"applyChanges()\"\n    (hideSoftwareChanges)=\"showSoftwareChanges = false\"\n  ></c8y-device-software-changes>\n</div>\n" }]
        }], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i1$1.RepositoryService }, { type: i2.InventoryService }, { type: DeviceSoftwareService }, { type: i4.ServiceRegistry }] });

class SoftwareDeviceTabGuard {
    constructor() {
        this.operations = ['c8y_SoftwareUpdate', 'c8y_SoftwareList', 'c8y_Software'];
    }
    canActivate(route) {
        const device = get(route, 'data.contextData') || get(route, 'parent.data.contextData');
        return (this.isAnyOperationSupported(device) ||
            has(device, 'c8y_Software') ||
            has(device, 'c8y_SoftwareList') ||
            has(device, 'c8y_SupportedSoftwareTypes'));
    }
    isAnyOperationSupported(device) {
        const supportedOperations = device?.c8y_SupportedOperations || [];
        return this.operations.some(operation => supportedOperations.indexOf(operation) >= 0);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareDeviceTabGuard, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareDeviceTabGuard }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareDeviceTabGuard, decorators: [{
            type: Injectable
        }] });

class SoftwareRepositoryDeviceTabModule {
    static forRoot() {
        return {
            ngModule: SoftwareRepositoryDeviceTabModule,
            providers: [
                SoftwareDeviceTabGuard,
                hookRoute({
                    context: ViewContext.Device,
                    path: 'software',
                    component: SoftwareDeviceTabComponent,
                    label: gettext('Software'),
                    icon: 'c8y-tools',
                    priority: 499,
                    canActivate: [SoftwareDeviceTabGuard]
                })
            ]
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryDeviceTabModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryDeviceTabModule, declarations: [SoftwareDeviceTabComponent,
            InstalledSoftwareComponent,
            DeviceSoftwareListComponent,
            DeviceSoftwareChangesComponent], imports: [CommonModule,
            CoreModule,
            RouterModule,
            SharedRepositoryModule,
            OperationDetailsModule,
            TooltipModule] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryDeviceTabModule, imports: [CommonModule,
            CoreModule,
            RouterModule,
            SharedRepositoryModule,
            OperationDetailsModule,
            TooltipModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryDeviceTabModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [
                        CommonModule,
                        CoreModule,
                        RouterModule,
                        SharedRepositoryModule,
                        OperationDetailsModule,
                        TooltipModule
                    ],
                    declarations: [
                        SoftwareDeviceTabComponent,
                        InstalledSoftwareComponent,
                        DeviceSoftwareListComponent,
                        DeviceSoftwareChangesComponent
                    ]
                }]
        }] });

class SoftwareRepositoryModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryModule, imports: [SoftwareRepositoryDeviceTabModule, SoftwareRepositoryListModule] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryModule, imports: [SoftwareRepositoryDeviceTabModule.forRoot(), SoftwareRepositoryListModule.forRoot()] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SoftwareRepositoryModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [SoftwareRepositoryDeviceTabModule.forRoot(), SoftwareRepositoryListModule.forRoot()]
                }]
        }] });

/**
 * Generated bundle index. Do not edit.
 */

export { AddSoftwareModalComponent, DeviceSoftwareChangesComponent, DeviceSoftwareListComponent, DeviceSoftwareService, InstalledSoftwareComponent, SoftwareDetailsComponent, SoftwareDeviceTabComponent, SoftwareDeviceTabGuard, SoftwareListComponent, SoftwareRepositoryDeviceTabModule, SoftwareRepositoryListModule, SoftwareRepositoryModule };
//# sourceMappingURL=c8y-ngx-components-repository-software.mjs.map