UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

2,100 lines 113 kB
import { gettext } from '@c8y/ngx-components/gettext';
import * as i1 from '@c8y/ngx-components';
import { BaseColumn, getBasicInputArrayFormFieldConfig, CommonModule, memoize, CoreModule, C8yTranslatePipe, TypeaheadComponent, IconDirective, ModalSelectionMode, SelectModalComponent, ProductExperienceDirective, PRODUCT_EXPERIENCE_EVENT_SOURCE, toObservable, ListItemComponent, ForOfDirective, HighlightComponent, C8yTranslateDirective, OperationRealtimeService } from '@c8y/ngx-components';
import * as i0 from '@angular/core';
import { Component, Injectable, HostListener, ViewChild, ChangeDetectionStrategy, Input, EventEmitter, forwardRef, Output, NgModule } from '@angular/core';
import * as i3 from '@angular/router';
import { RouterModule } from '@angular/router';
import { DeviceGridModule } from '@c8y/ngx-components/device-grid';
import { get, head, isNil, set, assign, isUndefined, isString, cloneDeep, map as map$1, omitBy, pick, remove, forEach, find, property, uniqBy, has, isEmpty, isEqual } from 'lodash-es';
import { TooltipModule } from 'ngx-bootstrap/tooltip';
import * as i2 from '@angular/common';
import { CommonModule as CommonModule$1, NgIf, AsyncPipe, NgStyle } from '@angular/common';
import { __decorate, __metadata } from 'tslib';
import * as i1$1 from '@c8y/client';
import { QueriesUtil, OperationStatus } from '@c8y/client';
import { of, from, defer, throwError, merge, NEVER, BehaviorSubject, pipe, Observable, Subject, interval } from 'rxjs';
import { map, take, switchMap, withLatestFrom, filter, takeWhile, tap, debounceTime, shareReplay, mergeMap, debounce } from 'rxjs/operators';
import * as i3$1 from '@angular/forms';
import { FormsModule, NG_VALUE_ACCESSOR, NG_VALIDATORS } from '@angular/forms';
import { saveAs } from 'file-saver';
import * as i2$1 from '@ngx-translate/core';

class DescriptionGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        this.name = 'description';
        this.path = 'description';
        this.header = gettext('Description');
        this.filterable = true;
        this.filteringConfig = {
            fields: getBasicInputArrayFormFieldConfig({
                key: 'descriptions',
                label: initialColumnConfig?.filterLabel ?? gettext('Filter items by description'),
                addText: gettext('Add next`description`'),
                tooltip: gettext('Use * as a wildcard character'),
                placeholder: initialColumnConfig?.placeholder ?? gettext('Description…')
            }),
            getFilter(model) {
                const filter = {};
                if (model.descriptions.length) {
                    filter.description = { __in: model.descriptions };
                }
                return filter;
            }
        };
        this.sortable = true;
        this.sortingConfig = {
            pathSortingConfigs: [{ path: this.path }]
        };
    }
}

class DeviceTypeCellRendererComponent {
    constructor(context) {
        this.context = context;
    }
    ngOnInit() {
        this.deviceType = get(this.context?.item, this.context?.property?.path);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DeviceTypeCellRendererComponent, deps: [{ token: i1.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: DeviceTypeCellRendererComponent, isStandalone: true, selector: "c8y-device-type-cell-renderer", ngImport: i0, template: "<span *ngIf=\"deviceType; else emptyText\">\n  {{ deviceType }}\n</span>\n<ng-template #emptyText>\n  <small class=\"text-muted\">\n    <em translate>Undefined`device type`</em>\n  </small>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: DeviceGridModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: RouterModule }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DeviceTypeCellRendererComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-device-type-cell-renderer', standalone: true, imports: [CommonModule, DeviceGridModule, TooltipModule, RouterModule], template: "<span *ngIf=\"deviceType; else emptyText\">\n  {{ deviceType }}\n</span>\n<ng-template #emptyText>\n  <small class=\"text-muted\">\n    <em translate>Undefined`device type`</em>\n  </small>\n</ng-template>\n" }]
        }], ctorParameters: () => [{ type: i1.CellRendererContext }] });

class DeviceTypeGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        this.name = 'deviceType';
        this.path = initialColumnConfig?.path ?? 'c8y_Filter.type';
        this.header = gettext('Device type');
        this.cellRendererComponent = DeviceTypeCellRendererComponent;
        this.filterable = true;
        this.filteringConfig = {
            fields: [
                ...getBasicInputArrayFormFieldConfig({
                    key: 'types',
                    label: initialColumnConfig?.filterLabel ?? gettext('Filter items by device type'),
                    addText: gettext('Add next`type`'),
                    tooltip: gettext('Use * as a wildcard character'),
                    placeholder: initialColumnConfig?.placeholder ?? 'c8y_Linux',
                    optional: true
                }),
                {
                    key: 'noDeviceType',
                    type: 'switch',
                    templateOptions: {
                        label: gettext('No device type')
                    }
                }
            ],
            getFilter(model) {
                const filter = { __or: {} };
                if (model.types?.length) {
                    filter.__or = {
                        'c8y_Filter.type': { __in: model.types }
                    };
                }
                if (model.noDeviceType) {
                    filter.__or = {
                        ...filter.__or,
                        __or: {
                            __not: { __has: 'c8y_Filter.type' },
                            'c8y_Filter.type': ''
                        }
                    };
                }
                return filter;
            }
        };
        this.sortable = true;
        this.sortingConfig = {
            pathSortingConfigs: [{ path: this.path }]
        };
    }
}

var RepositoryType;
(function (RepositoryType) {
    RepositoryType["FIRMWARE"] = "c8y_Firmware";
    RepositoryType["SOFTWARE"] = "c8y_Software";
    RepositoryType["CONFIGURATION"] = "c8y_ConfigurationDump";
    RepositoryType["PROFILE"] = "c8y_Profile";
})(RepositoryType || (RepositoryType = {}));
const REPOSITORY_BINARY_TYPES = {
    [RepositoryType.SOFTWARE]: 'c8y_SoftwareBinary',
    [RepositoryType.FIRMWARE]: 'c8y_FirmwareBinary',
    [RepositoryType.CONFIGURATION]: 'c8y_ConfigurationDumpBinary'
};
var DeviceConfigurationOperation;
(function (DeviceConfigurationOperation) {
    DeviceConfigurationOperation["UPLOAD_CONFIG"] = "c8y_UploadConfigFile";
    DeviceConfigurationOperation["DOWNLOAD_CONFIG"] = "c8y_DownloadConfigFile";
    DeviceConfigurationOperation["CONFIG"] = "c8y_Configuration";
    DeviceConfigurationOperation["SEND_CONFIG"] = "c8y_SendConfiguration";
})(DeviceConfigurationOperation || (DeviceConfigurationOperation = {}));
const PRODUCT_EXPERIENCE_REPOSITORY_SHARED = {
    SOFTWARE: {
        EVENTS: {
            REPOSITORY: 'softwareRepository',
            DEVICE_TAB: 'deviceSoftware'
        },
        COMPONENTS: {
            ADD_SOFTWARE_MODAL: 'add-software-modal',
            DEVICE_SOFTWARE_CHANGES: 'device-software-changes',
            DEVICE_SOFTWARE_LIST: 'device-software-list'
        },
        ACTIONS: {
            APPLY_SOFTWARE_CHANGES: 'applySoftwareChanges',
            CLEAR_SOFTWARE_CHANGES: 'clearSoftwareChanges',
            OPEN_INSTALL_SOFTWARE: 'openInstallSoftwareModal',
            OPEN_UPDATE_SOFTWARE: 'openUpdateSoftwareModal',
            DELETE_SOFTWARE: 'deleteSoftware'
        },
        RESULTS: {
            ADD_SOFTWARE: 'addSoftware',
            ADD_SOFTWARE_VERSION: 'addSoftwareVersion',
            EDIT_SOFTWARE: 'editSoftware'
        }
    },
    FIRMWARE: {
        EVENTS: {
            REPOSITORY: 'firmwareRepository',
            DEVICE_TAB: 'deviceFirmware'
        },
        COMPONENTS: {
            ADD_FIRMWARE_MODAL: 'add-firmware-modal',
            ADD_FIRMWAR_PATCH_MODAL: 'add-firmware-patch-modal',
            FIRMWARE_DEVICE_TAB: 'firmware-device-tab',
            DEVICE_FIRMWARE_LIST: 'device-firmware-list'
        },
        ACTIONS: {
            OPEN_INSTALL_FIRMWARE_DIALOG: 'openInstallFirmwareDialog',
            OPEN_REPLACE_FIRMWARE_DIALOG: 'openReplaceFirmwareDialog',
            OPEN_INSTALL_FIRMWARE_PATCH_DIALOG: 'openInstallFirmwarePatchDialog'
        },
        RESULTS: {
            ADD_FIRMWARE: 'addFirmware',
            ADD_FIRMWARE_VERSION: 'addFirmwareVersion',
            ADD_FIRMWARE_PATCH: 'addFirmwarePatch',
            EDIT_FIRMWARE: 'editFirmware',
            CREATE_FIRMWARE_UPDATE_OPERATION: 'createFirmwareUpdateOperation'
        }
    },
    SHARED: {
        COMPONENTS: {
            REPOSITORY_SELECT_MODAL: 'repository-select-modal',
            SELECT_CONFIGURATION_MODAL: 'select-configuration-modal'
        }
    }
};

class RepositoryService {
    constructor(inventory, inventoryBinary, operation, alert, event, operationRealtime, eventBinary, serviceRegistry, globalConfigService) {
        this.inventory = inventory;
        this.inventoryBinary = inventoryBinary;
        this.operation = operation;
        this.alert = alert;
        this.event = event;
        this.operationRealtime = operationRealtime;
        this.eventBinary = eventBinary;
        this.serviceRegistry = serviceRegistry;
        this.globalConfigService = globalConfigService;
        this.dateFrom = new Date(0);
        this.dateTo = new Date(Date.now() + 86400000); // 1 day in the future
        this.queriesUtil = new QueriesUtil();
        this.advancedSoftwareService = head(this.serviceRegistry.get('asm'));
    }
    /**
     * Lists repository entries of given type.
     * @param type The type of repository entries to list.
     * @param options Extra listing options.
     */
    listRepositoryEntries(type, options) {
        const defaultOrder = [{ name: 1 }];
        const defaultFilters = { type };
        const legacyFilters = { __has: `url` };
        let filters = {};
        let fullQuery = (options && options.query) || {};
        if (!options || (options && !options.skipDefaultOrder)) {
            fullQuery = this.queriesUtil.addOrderbys(fullQuery, defaultOrder, 'prepend');
        }
        fullQuery = this.queriesUtil.addAndFilter(fullQuery, defaultFilters);
        if (options && options.partialTextFilter) {
            const { partialText, properties } = options.partialTextFilter;
            const orFilter = { __or: properties.map(property => ({ [property]: `*${partialText}*` })) };
            fullQuery = this.queriesUtil.addAndFilter(fullQuery, orFilter);
        }
        if (options && options.partialName) {
            // backwards compatibility if
            fullQuery = this.queriesUtil.addAndFilter(fullQuery, { name: `*${options.partialName}*` });
        }
        if (options && options.skipLegacy) {
            fullQuery = this.queriesUtil.addAndFilter(fullQuery, { __not: legacyFilters });
        }
        filters = {
            query: this.queriesUtil.buildQuery(fullQuery),
            pageSize: 50,
            withTotalPages: true,
            ...((options && options.params) || {})
        };
        return this.inventory.list(filters);
    }
    async create(modal, type, mo = {}) {
        switch (type) {
            case RepositoryType.FIRMWARE:
            case RepositoryType.SOFTWARE:
                return this.createRepositoryObject(modal, type);
            case RepositoryType.CONFIGURATION:
                Object.assign(modal, {
                    selected: {
                        id: mo.id,
                        name: modal.version
                    },
                    configurationType: modal.configurationType,
                    name: modal.version
                });
                if (!modal.deviceType && mo.id) {
                    modal.deviceType = null;
                }
                if (!modal.selected && mo.id) {
                    modal.configurationType = null;
                }
                const repositoryObject = this.createRepositoryObject(modal, type);
                if (mo.url) {
                    const newBinaryUrl = (await repositoryObject).url;
                    this.removeOutdatedBinary(newBinaryUrl, mo.url);
                }
                return repositoryObject;
        }
    }
    async createRepositoryObject(modal, type) {
        let binary;
        let binaryURL;
        let repositoryEntry;
        let repositoryBinary;
        const mos = [];
        const { selected: { id: selectedId }, binary: { file, url } } = modal;
        try {
            const globalParam = await this.getGlobalFragment(type);
            if (file) {
                ({ data: binary } = await this.saveBinary(file, globalParam));
                ({ self: binaryURL } = binary);
                if (type === RepositoryType.CONFIGURATION) {
                    modal.binary.url = binaryURL;
                }
                mos.push(binary);
            }
            else {
                binaryURL = url;
            }
            ({ data: repositoryEntry } = await this.createOrUpdateRepositoryEntry({ ...modal, ...globalParam }, type));
            if (isNil(selectedId)) {
                mos.push(repositoryEntry);
            }
            if (type !== RepositoryType.CONFIGURATION) {
                ({ data: repositoryBinary } = await this.createRepositoryBinary({ ...modal, ...globalParam }, binaryURL, type, repositoryEntry));
                mos.push(repositoryBinary);
            }
            if (file) {
                await this.linkBinary(repositoryBinary, binary, repositoryEntry);
            }
            return repositoryEntry;
        }
        catch (error) {
            this.cleanUp(mos);
            this.errorMsg();
            // Propagate error
            throw error;
        }
    }
    saveBinary(file, global) {
        return this.inventoryBinary.create(file, global);
    }
    async createOrUpdateRepositoryEntry(modal, type) {
        const { selected: { id, name }, description, deviceType, c8y_Global, binary } = modal;
        const mo = {
            id,
            name,
            description,
            type,
            c8y_Global
        };
        if (deviceType && type !== RepositoryType.CONFIGURATION) {
            set(mo, 'c8y_Filter.type', deviceType);
        }
        if ((deviceType || id) && type === RepositoryType.CONFIGURATION) {
            set(mo, 'deviceType', deviceType);
        }
        if (modal.softwareType) {
            set(mo, 'softwareType', modal.softwareType.softwareType);
        }
        if ((modal.configurationType || id) && type === RepositoryType.CONFIGURATION) {
            set(mo, 'configurationType', modal.configurationType);
        }
        if (type === RepositoryType.CONFIGURATION) {
            set(mo, 'url', binary?.url);
        }
        return id
            ? this.inventory.update(mo)
            : this.inventory.create(mo);
    }
    createRepositoryBinary(modal, binaryURL, type, parent) {
        const mo = this.prepareRepositoryBinaryMO(modal, binaryURL, type);
        return this.inventory.childAdditionsCreate(mo, parent);
    }
    prepareRepositoryBinaryMO(modal, binaryURL, type) {
        const { version, patchVersion, dependency, c8y_Global } = modal;
        const result = {
            type: REPOSITORY_BINARY_TYPES[type],
            [type]: {
                url: binaryURL
            },
            c8y_Global
        };
        if (dependency) {
            set(result, [type, 'version'], patchVersion);
            assign(result, {
                c8y_Patch: {
                    dependency: dependency.c8y_Firmware.version
                }
            });
        }
        else {
            set(result, [type, 'version'], version);
        }
        return result;
    }
    async linkBinary(repositoryBinary, binary, repositoryEntry) {
        if (repositoryBinary) {
            const { id: repositoryBinaryId } = repositoryBinary;
            if (binary) {
                const { id: binaryId } = binary;
                return this.inventory.childAdditionsAdd(binaryId, repositoryBinaryId);
            }
        }
        else
            return this.inventory.childAdditionsAdd(binary, repositoryEntry);
    }
    cleanUp(mosToDelete) {
        mosToDelete.forEach(mo => {
            const { c8y_IsBinary } = mo;
            isUndefined(c8y_IsBinary) ? this.delete(mo) : this.inventoryBinary.delete(mo);
        });
    }
    delete(entity) {
        return this.inventory.delete(entity, { forceCascade: true });
    }
    errorMsg() {
        const msg = gettext('Failed to save');
        this.alert.danger(msg);
    }
    getBaseVersionsCount$(entry) {
        if (this.isLegacyEntry(entry)) {
            return of(1);
        }
        return from(this.listBaseVersions(entry, { withTotalElements: true })).pipe(map(({ paging }) => paging.totalElements));
    }
    getBaseVersionFromMO(mo) {
        return this.isPatch(mo) ? get(mo, 'c8y_Patch.dependency') : get(mo, 'c8y_Firmware.version');
    }
    isPatch(mo) {
        return !!get(mo, 'c8y_Patch.dependency');
    }
    getPatchVersionsCount$(entry, baseVersion) {
        if (this.isLegacyEntry(baseVersion)) {
            return of(0);
        }
        return from(this.listPatchVersions(entry, baseVersion, { withTotalElements: true })).pipe(map(({ paging }) => paging.totalElements));
    }
    isLegacyEntry(entry) {
        return Boolean(entry.url);
    }
    /**
     * Lists all versions (base and patch ones) of given top level entry.
     * Versions are ordered by creation time (assuming the earlier created, the older the version).
     * @param entry Top level repository entry.
     * @param params Additional query params.
     */
    listAllVersions(entry, params = {}) {
        if (this.isLegacyEntry(entry)) {
            return this.getBaseVersionResultListForLegacyEntry(entry);
        }
        const VERSION_FILTER_ORDER = {
            __filter: {},
            __orderby: [{ 'creationTime.date': -1 }]
        };
        return this.listChildren(entry, VERSION_FILTER_ORDER, params);
    }
    /**
     * Lists base versions of given top level entry.
     * Versions are ordered by creation time (assuming the earlier created, the older the version).
     * @param entry Top level repository entry.
     * @param params Additional query params.
     */
    listBaseVersions(entry, params = {}) {
        if (this.isLegacyEntry(entry)) {
            return this.getBaseVersionResultListForLegacyEntry(entry);
        }
        const NO_PATCH_FILTER_ORDER = {
            __filter: {
                __not: { __has: 'c8y_Patch' }
            },
            __orderby: [{ 'creationTime.date': -1 }]
        };
        return this.listChildren(entry, NO_PATCH_FILTER_ORDER, params);
    }
    /**
     * Lists patch versions of given base version under the entry.
     * Versions are ordered by creation time (assuming the earlier created, the older the version).
     * @param entry Top level repository entry.
     * @param baseVersion Base version.
     * @param params Additional query params.
     */
    listPatchVersions(entry, baseVersion, params = {}) {
        const version = isString(baseVersion) ? baseVersion : get(baseVersion, 'c8y_Firmware.version');
        const PATCH_FILTER_ORDER = {
            __filter: {
                'c8y_Patch.dependency': version
            },
            __orderby: [{ 'creationTime.date': -1 }]
        };
        return this.listChildren(entry, PATCH_FILTER_ORDER, params);
    }
    /**
     * Lists patch versions of given base version under the entry including the base version.
     * Versions are ordered by creation time (assuming the earlier created, the older the version).
     * In terms of legacy base version the entry gets transformed to fit the needed data model.
     * @param entry Top level repository entry.
     * @param baseVersion Base version.
     * @param params Additional query params.
     */
    listBaseVersionAndPatches(entry, baseVersion, params = {}) {
        if (this.isLegacyEntry(entry)) {
            return Promise.resolve({
                data: [
                    Object.assign({
                        c8y_Firmware: {
                            version: entry.version,
                            url: entry.url
                        }
                    }, entry)
                ]
            });
        }
        const PATCH_FILTER_ORDER = {
            __filter: {
                __or: {
                    'c8y_Patch.dependency': baseVersion.c8y_Firmware.version,
                    'c8y_Firmware.version': baseVersion.c8y_Firmware.version
                }
            },
            __orderby: [{ 'c8y_Patch.dependency': 1 }, { 'c8y_Firmware.version': 1 }]
        };
        return this.listChildren(entry, PATCH_FILTER_ORDER, params);
    }
    listChildren(entry, filters = {}, params = {}) {
        const childrenFilters = { __bygroupid: entry.id };
        const query = this.queriesUtil.addAndFilter(filters, childrenFilters);
        // FIXME: needed because of issue in forOf directive (...)
        params.withTotalPages = true;
        return this.inventory.listQuery(query, params);
    }
    /**
     * Fetches all items from the list starting with the provided page.
     * @param firstPage The first page of the list to fetch all items for.
     */
    async fetchAllItemsFromList(firstPage) {
        let allItems;
        if (!firstPage.then) {
            allItems = [...firstPage];
        }
        else {
            let { paging, data: items } = await firstPage;
            allItems = [...items];
            while (paging && paging.nextPage) {
                ({ paging, data: items } = await paging.next());
                allItems = [...allItems, ...items];
            }
        }
        return allItems;
    }
    /**
     * Gets top level repository entry managed object for base or patch version.
     * @param mo Base or patch version managed object with parents.
     */
    getRepositoryEntryMO$(mo) {
        if (!mo) {
            return of(undefined);
        }
        const [reference] = get(mo, 'additionParents.references');
        const id = get(reference, 'managedObject.id');
        return id
            ? from(this.inventory.detail(id, { withChildren: false })).pipe(map(({ data }) => data))
            : of(undefined);
    }
    /**
     * Gets base or patch version managed object.
     * @param deviceRepositoryFragment Device repository fragment.
     * @param type Top level repository entry type.
     * @param configuration Configuration object with options:
     * - **skipLegacy** - `boolean` - Exclude legacy entries.
     * - **filters** - `object` - Filter object.
     *
     * @deprecated as it doesn't support 'missing url' case
     */
    getRepositoryBinaryMoByVersion(deviceRepositoryFragment, type, { skipLegacy = false, filters = {} } = {}) {
        const { version, url, name } = deviceRepositoryFragment;
        const repositoryBinaryType = REPOSITORY_BINARY_TYPES[type];
        let query;
        const newModelBaseVersionQuery = {
            [`${type}.version`]: version,
            [`${type}.url`]: url,
            type: repositoryBinaryType
        };
        const legacyVersionQuery = { url, type, name };
        filters = { withChildren: false, withParents: true, ...filters };
        if (skipLegacy) {
            query = {
                __and: {
                    ...newModelBaseVersionQuery
                }
            };
        }
        else {
            query = {
                __or: [{ __and: { ...newModelBaseVersionQuery } }, { __and: { ...legacyVersionQuery } }]
            };
        }
        return this.inventory.listQuery(query, filters).then(({ data }) => head(data));
    }
    getBinaryName$(binaryUrl) {
        if (!binaryUrl) {
            return of('---');
        }
        const binaryId = this.inventoryBinary.getIdFromUrl(binaryUrl);
        if (!binaryId) {
            return of(binaryUrl);
        }
        return defer(() => this.inventory.detail(binaryId).then(result => result.data)).pipe(map(mo => mo.name));
    }
    /**
     * Generates an inventory query object which can be used to find
     * repository entries of specified type matching the type of provided device.
     * @param repositoryType The type of repository entries which will be queried with the generated query.
     * @param device The device for which matching repository entries will be queried with the generated query.
     */
    getDeviceTypeQuery(repositoryType, device) {
        let result = {
            type: repositoryType
        };
        if (repositoryType === RepositoryType.CONFIGURATION) {
            if (device.type) {
                result = this.queriesUtil.addAndFilter(result, {
                    __or: [{ deviceType: device.type }, { __not: { __has: `deviceType` } }]
                });
            }
        }
        else {
            result = this.queriesUtil.addAndFilter(result, {
                __or: [
                    { 'c8y_Filter.type': device.type },
                    { 'c8y_Filter.type': '' },
                    { __not: { __has: `c8y_Filter.type` } }
                ]
            });
        }
        return result;
    }
    /**
     * Generates an inventory query object which can be used to find
     * repository entries matching the predefined software types provided in the device.
     * @param device The device for which matching repository entries will be queried with the generated query.
     * @param query The query to which the software types filters will be attached. Default value is an object containg repository type software.
     */
    getSoftwareTypeQuery(device, query) {
        let result = {
            ...(query || {}),
            type: RepositoryType.SOFTWARE
        };
        if (device.c8y_SupportedSoftwareTypes) {
            result = this.queriesUtil.addAndFilter(result, {
                __or: [device.c8y_SupportedSoftwareTypes.map(type => ({ softwareType: type }))]
            });
        }
        return result;
    }
    /**
     * Generates an inventory query object which can be used to find configuration repository entries
     * matching the type of provided device and specified configuration type.
     * @param device The device for which matching repository entries will be queried with the generated query.
     * @param configurationType Configuration type for which matching repository entries will be queried with the generated query.
     */
    getConfigurationTypeQuery(device, configurationType) {
        const query = this.getDeviceTypeQuery(RepositoryType.CONFIGURATION, device);
        return this.queriesUtil.addAndFilter(query, {
            __or: [
                { configurationType },
                { configurationType: '' },
                { __not: { __has: `configurationType` } }
            ]
        });
    }
    /**
     * Gets the list of software installed in the device in the uniform format.
     * Supports c8y_SoftwareList and c8y_Software fragments.
     * @param device The device whose software list should be returned.
     */
    getDeviceSoftwareList(device) {
        if (device.c8y_SoftwareList) {
            return cloneDeep(device.c8y_SoftwareList);
        }
        if (device.c8y_Software) {
            return map$1(device.c8y_Software, (version, name) => ({ name, version }));
        }
        return [];
    }
    /**
     * Prepares a software update operation for given device and the list of changes, and sends it to the device.
     * @param device The device which the operation should be prepared for and sent to.
     * @param changes The list of software changes which should be applied.
     */
    async createSoftwareUpdateOperation(device, changes) {
        const operation = await this.getSoftwareUpdateOperation(device, changes);
        return (await this.operation.create(operation)).data;
    }
    /**
     * Prepares a software update operation for given device and changes.
     * Returned operation type depends on device's supported operations.
     * Supports c8y_SoftwareUpdate, c8y_SoftwareList, and c8y_Software operations.
     * @param device The device for which operation should be prepared.
     * @param changes The list of software changes which should be applied.
     */
    async getSoftwareUpdateOperation(device, changes) {
        const operation = {
            deviceId: device.id,
            description: `Apply software changes: ${changes
                .map(change => `${change.action} "${change.name}"${change.version ? ` (version: ${change.version})` : ''}`)
                .join(', ')}`
        };
        if (device.c8y_SupportedOperations.includes('c8y_SoftwareUpdate')) {
            operation.c8y_SoftwareUpdate = (cloneDeep(changes) || []).map(change => omitBy(change, isNil));
        }
        else if (device.c8y_SupportedOperations.includes('c8y_SoftwareList')) {
            operation.c8y_SoftwareList = cloneDeep(await this.getCurrentSoftware(device, 'c8y_SoftwareList', []));
            changes.forEach(change => {
                const deviceSoftware = pick(omitBy(change, isNil), [
                    'name',
                    'version',
                    'url',
                    'softwareType'
                ]);
                if (change.action === 'delete') {
                    remove(operation.c8y_SoftwareList, deviceSoftware);
                }
                if (change.action === 'install') {
                    const softwareItemToUpdateIdx = operation.c8y_SoftwareList.findIndex(item => item.name === change.name);
                    if (softwareItemToUpdateIdx > -1) {
                        // update software
                        operation.c8y_SoftwareList.splice(softwareItemToUpdateIdx, 1, deviceSoftware);
                    }
                    else {
                        // install software
                        operation.c8y_SoftwareList.push(deviceSoftware);
                    }
                }
            });
        }
        else if (device.c8y_SupportedOperations.includes('c8y_Software')) {
            operation.c8y_Software = cloneDeep(await this.getCurrentSoftware(device, 'c8y_Software', {}));
            changes.forEach(change => {
                if (change.action === 'delete') {
                    delete operation.c8y_Software[change.name];
                }
                if (change.action === 'install') {
                    operation.c8y_Software[change.name] = change.version;
                }
            });
        }
        return operation;
    }
    /**
     * Extracts the list of device software changes from given operation in the context of given device.
     * @param operation The operation from which the list should be extracted.
     * @param device The target device of the operation.
     */
    async getDeviceSoftwareChangesFromOperation(operation, device) {
        if (operation.c8y_SoftwareUpdate) {
            return cloneDeep(operation.c8y_SoftwareUpdate);
        }
        if (operation.c8y_SoftwareList) {
            return await this.getDeviceSoftwareChangesFromSoftwareListOperation(operation, device);
        }
        if (operation.c8y_Software) {
            return await this.getDeviceSoftwareChangesFromSoftwareOperation(operation, device);
        }
        return [];
    }
    /**
     * Prepares a firmware update operation for given device and the selected repository binary, and sends it to the device.
     * @param device The device which the operation should be prepared for and sent to.
     * @param selectedOption The selected repository binary option.
     */
    async createFirmwareUpdateOperation(device, selectedOption) {
        const operation = this.getFirmwareUpdateOperation(device, selectedOption);
        return (await this.operation.create(operation)).data;
    }
    /**
     * Prepares a firmware update operation for given device and selected version.
     * Supports c8y_Firmware operation.
     * @param device The device for which operation should be prepared.
     * @param selectedOption Selected firmware version.
     */
    getFirmwareUpdateOperation(device, selectedOption) {
        delete selectedOption.id;
        const operation = {
            deviceId: device.id,
            description: `Update firmware to: "${selectedOption.name}"${selectedOption.version ? ` (version: ${selectedOption.version})` : ''}`,
            c8y_Firmware: { ...selectedOption }
        };
        return operation;
    }
    /**
     * Prepares a configuration file upload operation for given device and configuration type.
     * @param device The device for which operation should be prepared.
     * @param configurationType Selected configuration type.
     * @param isLegacy  A legacy operation is created without a configurationType.
     */
    getUploadConfigurationFileOperation(device, configurationType, isLegacy = false) {
        if (isLegacy) {
            return {
                deviceId: device.id,
                description: `Retrieve configuration snapshot from device ${device.name}`,
                c8y_UploadConfigFile: {}
            };
        }
        return {
            deviceId: device.id,
            description: `Retrieve ${configurationType} configuration snapshot from device ${device.name}`,
            c8y_UploadConfigFile: {
                type: configurationType
            }
        };
    }
    /**
     * Prepares a configuration file download operation for given device and configuration type.
     * @param device The device for which operation should be prepared.
     * @param configurationType Selected configuration type.
     * @param binaryUrl The url of a binary to be downloaded.
     * @param isLegacy A legacy operation is created without a configurationType.
     */
    getDownloadConfigurationFileOperation(device, configurationType, configSnapshot, isLegacy = false) {
        if (isLegacy) {
            return {
                deviceId: device.id,
                description: `Send configuration snapshot ${configSnapshot.name} to device ${device.name}`,
                c8y_DownloadConfigFile: {
                    url: configSnapshot.binaryUrl,
                    c8y_ConfigurationDump: {
                        id: configSnapshot.id
                    }
                }
            };
        }
        return {
            deviceId: device.id,
            description: `Send configuration snapshot ${configSnapshot.name} of configuration type ${configurationType} to device ${device.name}`,
            c8y_DownloadConfigFile: {
                url: configSnapshot.binaryUrl,
                type: configurationType
            }
        };
    }
    /**
     * Gets the last firmware update operation for given device.
     * Looks for c8y_Firmware operations.
     * @param deviceId The ID of the device to find an operation for.
     */
    async getLastFirmwareUpdateOperation(deviceId) {
        const filters = {
            deviceId,
            dateFrom: new Date(0).toISOString(),
            dateTo: new Date(Date.now()).toISOString(),
            revert: true,
            pageSize: 1
        };
        return this.getFirstMatchingOperation([{ ...filters, fragmentType: 'c8y_Firmware' }]);
    }
    /**
     * Gets the last software update operation for given device.
     * Looks for c8y_SoftwareUpdate, c8y_SoftwareList, or c8y_Software operations.
     * @param deviceId The ID of the device to find an operation for.
     */
    async getLastSoftwareUpdateOperation(deviceId) {
        const filters = {
            deviceId,
            dateFrom: new Date(0).toISOString(),
            dateTo: new Date(Date.now()).toISOString(),
            revert: true,
            pageSize: 1
        };
        return this.getLatestMatchingOperation([
            { ...filters, fragmentType: 'c8y_SoftwareUpdate' },
            { ...filters, fragmentType: 'c8y_SoftwareList' },
            { ...filters, fragmentType: 'c8y_Software' }
        ]);
    }
    /**
     * Iterates over the list of filters and queries the operations.
     * If a query returns at least one operation, the first one will be returned.
     * Otherwise the next query will be performed.
     * If none of the queries returns any operation, null will be returned.
     * @param filtersList The list of filters for the queries.
     */
    async getFirstMatchingOperation(filtersList) {
        let matchingOperation = null;
        for (const filters of filtersList) {
            const operations = (await this.operation.list(filters)).data;
            if (operations.length) {
                matchingOperation = operations[0];
                break;
            }
        }
        return matchingOperation;
    }
    /**
     * Iterates over the list of filters and queries the operations.
     * It compares the operations retrieved by the queries by 'creationTime'
     * and return the latest one.
     * If none of the queries returns any operation, null will be returned.
     * @param filtersList The list of filters for the queries.
     */
    async getLatestMatchingOperation(filtersList) {
        let matchingOperation = null;
        for (const filters of filtersList) {
            const operations = (await this.operation.list(filters)).data;
            if (operations.length) {
                if (matchingOperation) {
                    matchingOperation =
                        new Date(matchingOperation.creationTime).getTime() <
                            new Date(operations[0].creationTime).getTime()
                            ? operations[0]
                            : matchingOperation;
                }
                else {
                    matchingOperation = operations[0];
                }
            }
        }
        return matchingOperation;
    }
    /**
     * Creates the operation and returns an observable to track its progress.
     * Fails the observable when the operation returns FAILED status.
     * Completes the observable when the operation returns SUCCESSFUL status.
     * @param operation The operation to create and track.
     */
    createObservedOperation(operation) {
        return from(this.operation.create(operation)).pipe(map(({ data }) => data), take(1), switchMap(createdOperation => this.observeOperation(createdOperation)));
    }
    /**
     * Returns an observable to track progress of given operation.
     * Fails the observable when the operation returns FAILED status.
     * Completes the observable when the operation returns SUCCESSFUL status.
     * @param operation The operation to be observed.
     */
    observeOperation(operation) {
        const observedOperation$ = of(operation);
        const operationUpdates$ = observedOperation$.pipe(switchMap(observedOperation => this.operationRealtime.onAll$(observedOperation.deviceId)), map(({ data }) => data), withLatestFrom(observedOperation$), filter(([operationUpdate, observedOperation]) => operationUpdate.id === observedOperation.id), switchMap(([operationUpdate]) => {
            if (operationUpdate.status === OperationStatus.FAILED) {
                return throwError(operationUpdate);
            }
            return of(operationUpdate);
        }), takeWhile(operationUpdate => operationUpdate.status !== OperationStatus.SUCCESSFUL, true));
        return merge(observedOperation$, operationUpdates$);
    }
    /**
     * Gets a single event with latest creationTime for the given device Id and event type.
     * @param deviceId The device Id for which the events should be queried.
     * @param type Event type.
     */
    async getLatestConfigurationEvent(deviceId, type) {
        const eventFilter = {
            source: deviceId,
            type,
            dateFrom: this.dateFrom.toISOString(),
            dateTo: this.dateTo.toISOString(),
            pageSize: 1
        };
        const { data } = await this.event.list(eventFilter);
        return data[0];
    }
    /**
     * Gets a list of operations for the given device Id, and operation type.
     * @param deviceId The device Id for which the operation should be queried.
     * @param operationType Operation type fragment.
     */
    async getConfigFileOperationList(deviceId, operationType) {
        const operationFilter = {
            deviceId,
            fragmentType: operationType,
            dateFrom: this.dateFrom.toISOString(),
            dateTo: this.dateTo.toISOString(),
            revert: true,
            pageSize: 2000
        };
        return (await this.operation.list(operationFilter)).data;
    }
    /**
     * Gets latest uploaded configuration snapshot for the given device, and configuration type.
     * @param device The device for which the configuration snapshot was uploaded.
     * @param configurationType Selected configuration type.
     */
    async getConfigSnapshot(device, configurationType) {
        const event = await this.getLatestConfigurationEvent(device.id, configurationType);
        let configSnapshot;
        if (event) {
            configSnapshot = {
                time: event.time,
                name: event.text,
                deviceType: device.type,
                configurationType
            };
            try {
                configSnapshot.binary = await (await this.eventBinary.download(event)).text();
                if (event.c8y_IsBinary) {
                    configSnapshot.binaryType = event.c8y_IsBinary.type;
                }
            }
            catch (ex) {
                const msg = gettext('Could not get the binary.');
                this.alert.danger(msg);
            }
        }
        return configSnapshot;
    }
    async getLegacyConfigSnapshot(deviceId) {
        let configSnapshot;
        let mo;
        const device = (await this.inventory.detail(deviceId, { withChildren: false })).data;
        const snapshotId = device.c8y_ConfigurationDump && device.c8y_ConfigurationDump.id;
        if (!snapshotId) {
            return;
        }
        try {
            mo = (await this.inventory.detail(snapshotId)).data;
        }
        catch (ex) {
            // do nothing
        }
        if (mo) {
            configSnapshot = {
                time: mo.creationTime,
                name: mo.name
            };
            configSnapshot.binary = await this.getBinaryText(mo.url, { allowExternal: false });
        }
        return configSnapshot;
    }
    /**
     * Returns a binary object as text.
     * @param binaryUrl The URL to find binary
     * @param options The object with additional options:
     * - **allowExternal** - `boolean` - allows downloading external binary file
     * - **noAlerts** - `boolean` - do not display an alert message; defaults to `false`
     */
    async getBinaryText(binaryUrl, options) {
        const binaryId = this.inventoryBinary.getIdFromUrl(binaryUrl);
        let res;
        if (!binaryId) {
            if (options.allowExternal) {
                res = await this.getExternalBinaryResponse(binaryUrl, options);
            }
        }
        else {
            res = await this.getInternalBinaryResponse(binaryId, options);
        }
        if (!res) {
            return null;
        }
        return res.text();
    }
    /**
     * Returns a binary object as File.
     * @param binaryUrl The URL to find binary
     * @param options The object with additional options:
     * - **allowExternal** - `boolean` - allows downloading external binary file
     */
    async getBinaryFile(binaryUrl, options) {
        const binaryId = this.inventoryBinary.getIdFromUrl(binaryUrl);
        if (!binaryId && !options.allowExternal) {
            return null;
        }
        // @TODO: note that it doesn't solve issue with external binary here, such url won't have binaryId, so we won't know the name or contentType to use in File constructor, let's add a @FIXME comment for now?
        const { name, contentType } = (await this.inventory.detail(binaryId)).data;
        const res = !!binaryId
            ? await this.getInternalBinaryResponse(binaryId)
            : await this.getExternalBinaryResponse(binaryUrl);
        const arrayBuffer = await res.arrayBuffer();
        return new File([arrayBuffer], name, { type: contentType });
    }
    /**
     * Gets the last configuration update operation for given device.
     * Looks for c8y_Configuration and c8y_SendConfiguration operations.
     * @param deviceId The ID of the device to find an operation for.
     */
    async getLastConfigUpdateOperation(deviceId) {
        const filters = {
            deviceId,
            dateFrom: new Date(0).toISOString(),
            dateTo: new Date(Date.now()).toISOString(),
            revert: true,
            pageSize: 1
        };
        return this.getLatestMatchingOperation([
            { ...filters, fragmentType: 'c8y_Configuration' },
            { ...filters, fragmentType: 'c8y_SendConfiguration' }
        ]);
    }
    /**
     * Prepares a configuration download operation for given device and its current configuration.
     * Supports c8y_SendConfiguration operation.
     * @param device The device for which operation should be prepared.
     */
    createTextBasedConfigurationReloadOperation(device) {
        return {
            deviceId: device.id,
            description: gettext('Requested current configuration'),
            c8y_SendConfiguration: {}
        };
    }
    /**
     * Prepares a configuration update operation for the given device.
     * Supports c8y_Configuration operation.
     * @param device The device for which operation should be prepared.
     * @param config The configuration which will update the existing one.
     */
    createTextBasedConfigurationUpdateOperation(device, config) {
        return {
            deviceId: device.id,
            description: gettext('Configuration update'),
            c8y_Configuration: {
                config
            }
        };
    }
    async getBinary(binaryId) {
        try {
            return await this.inventoryBinary.download(binaryId);
        }
        catch (ex) {
            const msg = gettext('Could not get the binary.');
            this.alert.danger(msg);
        }
    }
    /**
     * Gets all available snapshots from the repository for the given device.
     * @param device The device for which the snapshots should be prepared.
     * @param configurationType Selected configuration type.
     */
    async getSnapshotsFromRepository(device, configurationType) {
        const searchQuery = this.getConfigurationTypeQuery(device, configurationType);
        const res = await this.listRepositoryEntries(RepositoryType.CONFIGURATION, {
            query: searchQuery,
            params: { pageSize: 100 }
        });
        return res.data;
    }
    /**
     * Checks if a device already have a given software installed
     * @param deviceId Id of the device to be checked
     * @param software The software to be checked
     */
    async isSoftwareInstalledOnDevice(deviceId, software) {
        const isASMAvailable = await this.advancedSoftwareService?.isASMAvailable();
        if (!isASMAvailable) {
            return false;
        }
        const queryFilter = { deviceId };
        if (software?.name) {
            set(queryFilter, 'name', software.name);
        }
        if (software?.version) {
            set(queryFilter, 'version', software.version);
        }
        return this.advancedSoftwareService.list(queryFilter).then(result => !!result.data?.length);
    }
    /**
     * Returns a binary object.
     * @param binaryId binary ID
     * @param options The object with additional options:
     * - **noAlerts** - `boolean` - do not display an alert message; defaults to `false`
     */
    async getInternalBinaryResponse(binaryId, options = {}) {
        let res;
        try {
            res = await this.inventoryBinary.download(binaryId);
        }
        catch (ex) {
            if (!options.noAlerts) {
                const msg = gettext('Could not get the binary.');
                this.alert.danger(msg);
            }
        }
        return res;
    }
    /**
     * Returns a binary object.
     * @param binaryUrl The URL to find binary
     * @param options The object with additional options:
     * - **noAlerts** - `boolean` - do not display an alert message; defaults to `false`
     */
    async getExternalBinaryResponse(binaryUrl, options = {}) {
        let res;
        try {
            const fetchRes = await fetch(binaryUrl);
            if (fetchRes.status >= 400) {
                throw res;
            }
            res = fetchRes;
        }
        catch {
            if (!options.noAlerts) {
                const msg = gettext('Could not get the external binary');
                this.alert.danger(msg);
            }
        }
        return res;
    }
    getBaseVersionResultListForLegacyEntry(entry) {
        return Promise.resolve({
            res: {},
            data: [
                {
                    ...entry,
                    [entry.type]: {
                        version: entry.version,
                        url: entry.url
                    }
                }
            ]
        });
    }
    async getDeviceSoftwareChangesFromSoftwareListOperation(operation, device) {
        const changes = [];
        const deviceSoftwareList = await this.getCurrentSoftware(device, 'c8y_SoftwareList', []);
        forEach(operation.c8y_SoftwareList, operationSoftware => {
            const deviceSoftware = find(deviceSoftwareList, { name: operationSoftware.name });
            if ((operationSoftware && operationSoftware.version) !==
                (deviceSoftware && deviceSoftware.version)) {
                changes.push({
                    ...operationSoftware,
                    action: 'install'
                });
            }
        });
        forEach(deviceSoftwareList, deviceSoftware => {
            const operationSoftware = find(operation.c8y_SoftwareList, { name: deviceSoftware.name });
            if ((operationSoftware && operationSoftware.version) !==
                (deviceSoftware && deviceSoftware.version)) {
                const installChange = changes.find(change => deviceSoftware.name === change.name && change.action === 'install');
                // check that this software is not an installation software change, otherwise it's an update and not a removal
                if (!installChange) {
                    changes.push({
                        ...deviceSoftware,
                        action: 'delete'
                    });
                }
            }
        });
        return changes;
    }
    async getDeviceSoftwareChangesFromSoftwareOperation(operation, device) {
        const changes = [];
        const deviceSoftware = await this.getCurrentSoftware(device, 'c8y_Software', {});
        forEach(deviceSoftware, (deviceSoftwareVersion, deviceSoftwareName) => {
            if (operation.c8y_Software[deviceSoftwareName] !== deviceSoftwareVersion) {
                changes.push({
                    name: deviceSoftwareName,
                    version: deviceSoftwareVersion,
                    action: 'delete'
                });
            }
        });
        forEach(operation.c8y_Software, (operationSoftwareVersion, operationSoftwareName) => {
            const deviceSoftwareVersion = deviceSoftware && deviceSoftware[operationSoftwareName];
            if (deviceSoftwareVersion !== operationSoftwareVersion) {
                changes.push({
                    name: operationSoftwareName,
                    version: operationSoftwareVersion,
                    action: 'install'
                });
            }
        });
        return changes;
    }
    async getCurrentSoftware(device, swFragment, defaultValue) {
        const isASMAvailable = await this.advancedSoftwareService?.isASMAvailable();
        if (isASMAvailable) {
            let softwareResultList = await this.advancedSoftwareService.list({ deviceId: device.id, pageSize: 100 });
            let list = (softwareResultList?.data || []).map(sw => pick(omitBy(sw, isNil), ['name', 'version', 'url', 'softwareType']));
            while (softwareResultList.paging?.nextPage) {
                softwareResultList = await softwareResultList.paging.next();
                list = [
                    ...list,
                    ...(softwareResultList?.data || []).map(sw => pick(omitBy(sw, isNil), ['name', 'version', 'url', 'softwareType']))
                ];
            }
            if (!list?.length) {
                return defaultValue;
            }
            return Array.isArray(defaultValue) ? list : this.softwareListToLegacy(list);
        }
        else {
            return device[swFragment] || defaultValue;
        }
    }
    softwareListToLegacy(list) {
        return (list || []).reduce((prev, curr) => ({ ...prev, [curr.name]: curr.version }), {});
    }
    async getGlobalFragment(type) {
        return (await this.globalConfigService.getGlobalParam(type)) ? { c8y_Global: {} } : undefined;
    }
    async removeOutdatedBinary(newBinaryURL, oldBinaryURL) {
        const existingBinaryId = await this.inventoryBinary.getIdFromUrl(oldBinaryURL);
        const newBinaryId = await this.inventoryBinary.getIdFromUrl(newBinaryURL);
        if (existingBinaryId && existingBinaryId !== newBinaryId) {
            await this.inventoryBinary.delete(existingBinaryId);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RepositoryService, deps: [{ token: i1$1.InventoryService }, { token: i1$1.InventoryBinaryService }, { token: i1$1.OperationService }, { token: i1.AlertService }, { token: i1$1.EventService }, { token: i1.OperationRealtimeService }, { token: i1$1.EventBinaryService }, { token: i1.ServiceRegistry }, { token: i1.GlobalConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RepositoryService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RepositoryService, decorators: [{
            type: Injectable
        }], ctorParameters: () => [{ type: i1$1.InventoryService }, { type: i1$1.InventoryBinaryService }, { type: i1$1.OperationService }, { type: i1.AlertService }, { type: i1$1.EventService }, { type: i1.OperationRealtimeService }, { type: i1$1.EventBinaryService }, { type: i1.ServiceRegistry }, { type: i1.GlobalConfigService }] });

class FileCellRendererComponent {
    constructor(context, inventoryBinaryService, repositoryService) {
        this.context = context;
        this.inventoryBinaryService = inventoryBinaryService;
        this.repositoryService = repositoryService;
    }
    isBinaryFile() {
        return this.context.item?.url
            ? !!this.inventoryBinaryService.getIdFromUrl(this.context.item.url)
            : false;
    }
    getBinaryName(configuration) {
        return this.repositoryService.getBinaryName$(configuration.url);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileCellRendererComponent, deps: [{ token: i1.CellRendererContext }, { token: i1$1.InventoryBinaryService }, { token: RepositoryService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: FileCellRendererComponent, isStandalone: true, selector: "c8y-file-cell-renderer", providers: [RepositoryService], ngImport: i0, template: "<small\n  title=\"{{ getBinaryName(context.item) | async }}\"\n  *ngIf=\"isBinaryFile(); else noFile\"\n>\n  {{ getBinaryName(context.item) | async }}\n</small>\n<ng-template #noFile>\n  <small title=\"{{ context.item?.url }}\">\n    {{ context.item?.url }}\n  </small>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] }); }
}
__decorate([
    memoize(property('id')),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", void 0)
], FileCellRendererComponent.prototype, "getBinaryName", null);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileCellRendererComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-file-cell-renderer', standalone: true, imports: [CommonModule], providers: [RepositoryService], template: "<small\n  title=\"{{ getBinaryName(context.item) | async }}\"\n  *ngIf=\"isBinaryFile(); else noFile\"\n>\n  {{ getBinaryName(context.item) | async }}\n</small>\n<ng-template #noFile>\n  <small title=\"{{ context.item?.url }}\">\n    {{ context.item?.url }}\n  </small>\n</ng-template>\n" }]
        }], ctorParameters: () => [{ type: i1.CellRendererContext }, { type: i1$1.InventoryBinaryService }, { type: RepositoryService }], propDecorators: { getBinaryName: [] } });

class FileGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        this.name = 'file';
        this.header = gettext('File');
        this.cellRendererComponent = FileCellRendererComponent;
        this.filterable = false;
        this.sortable = false;
    }
}

class RepositoryItemNameCellRendererComponent {
    constructor(context) {
        this.context = context;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RepositoryItemNameCellRendererComponent, deps: [{ token: i1.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: RepositoryItemNameCellRendererComponent, isStandalone: true, selector: "c8y-repository-item-name-cell-renderer", ngImport: i0, template: `
    <a
      class="interact"
      [title]="context.item.name"
      *ngIf="context?.property?.callback; else router"
      (click)="context.property.callback(context.item)"
    >
      {{ context.item.name }}
    </a>
    <ng-template #router>
      <a class="interact" [title]="context.item.name" [routerLink]="[context.item.id]">
        {{ context.item.name }}
      </a>
    </ng-template>
  `, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: DeviceGridModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i3.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RepositoryItemNameCellRendererComponent, decorators: [{
            type: Component,
            args: [{
                    template: `
    <a
      class="interact"
      [title]="context.item.name"
      *ngIf="context?.property?.callback; else router"
      (click)="context.property.callback(context.item)"
    >
      {{ context.item.name }}
    </a>
    <ng-template #router>
      <a class="interact" [title]="context.item.name" [routerLink]="[context.item.id]">
        {{ context.item.name }}
      </a>
    </ng-template>
  `,
                    selector: 'c8y-repository-item-name-cell-renderer',
                    standalone: true,
                    imports: [CommonModule, DeviceGridModule, TooltipModule, RouterModule]
                }]
        }], ctorParameters: () => [{ type: i1.CellRendererContext }] });

class RepositoryItemNameGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        this.name = 'name';
        this.path = 'name';
        this.header = gettext('Name');
        this.cellRendererComponent = RepositoryItemNameCellRendererComponent;
        this.filterable = true;
        this.filteringConfig = {
            fields: getBasicInputArrayFormFieldConfig({
                key: 'names',
                label: initialColumnConfig?.filterLabel ?? gettext('Filter items by name'),
                addText: gettext('Add next`name`'),
                tooltip: gettext('Use * as a wildcard character'),
                placeholder: initialColumnConfig?.placeholder ?? gettext('Cloud connectivity')
            }),
            getFilter(model) {
                const filter = {};
                if (model.names.length) {
                    filter.name = { __in: model.names };
                }
                return filter;
            }
        };
        this.sortable = true;
        this.sortingConfig = {
            pathSortingConfigs: [{ path: this.path }]
        };
    }
}

class TypeCellRendererComponent {
    constructor(context) {
        this.context = context;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TypeCellRendererComponent, deps: [{ token: i1.CellRendererContext }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: TypeCellRendererComponent, isStandalone: true, selector: "c8y-type-cell-renderer", ngImport: i0, template: "<span\n  class=\"label label-info\"\n  *ngIf=\"!!context?.item?.[context?.property?.path]; else emptyText\"\n>\n  {{ context.item[context.property.path] }}\n</span>\n<ng-template #emptyText>\n  <small class=\"text-muted\">\n    <em translate>Undefined`type`</em>\n  </small>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CommonModule$1 }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TypeCellRendererComponent, decorators: [{
            type: Component,
            args: [{ standalone: true, selector: 'c8y-type-cell-renderer', imports: [CommonModule$1], template: "<span\n  class=\"label label-info\"\n  *ngIf=\"!!context?.item?.[context?.property?.path]; else emptyText\"\n>\n  {{ context.item[context.property.path] }}\n</span>\n<ng-template #emptyText>\n  <small class=\"text-muted\">\n    <em translate>Undefined`type`</em>\n  </small>\n</ng-template>\n" }]
        }], ctorParameters: () => [{ type: i1.CellRendererContext }] });

class TypeFilteringFormRendererComponent {
    constructor(context, changeDetectorRef, repositoryService, elementRef) {
        this.context = context;
        this.changeDetectorRef = changeDetectorRef;
        this.repositoryService = repositoryService;
        this.elementRef = elementRef;
        this.types$ = NEVER;
        this.search$ = new BehaviorSubject(null);
        this.filterPipe = pipe(tap());
        this.typeaheadPlaceholder = gettext('Start typing to search, for example, {{ example }}');
        this.queriesUtil = new QueriesUtil();
        this.types = new Set();
        this.path = context.property.path;
        this.types$ = this.search$.pipe(debounceTime(300), tap(() => this.types.clear()), switchMap((searchString) => {
            let query = this.queriesUtil.prependOrderbys({}, [{ [this.path]: 1 }]);
            const filter = !!searchString
                ? {
                    [this.path]: {
                        __eq: `*${searchString}*`
                    }
                }
                : {
                    __has: this.path
                };
            query = this.queriesUtil.addAndFilter(query, filter);
            return this.repositoryService.listRepositoryEntries(this.context.property.repositoryType, {
                skipDefaultOrder: true,
                query,
                params: {
                    pageSize: 200
                }
            });
        }));
        this.filterPipe = pipe(map(this.removeDuplicatesType.bind(this)), tap(() => setTimeout(() => this.changeDetectorRef.detectChanges(), 0)));
    }
    onEnterKeyUp(event) {
        event.stopPropagation();
        this.applyFilter();
    }
    onEscapeKeyDown(event) {
        event.stopPropagation();
        this.context.resetFilter();
    }
    ngOnInit() {
        const column = this.context.property;
        this.selectedType = cloneDeep(column.externalFilterQuery || {});
    }
    ngAfterViewInit() {
        this.typeahead?.searchControl?.nativeElement?.focus();
        try {
            this.elementRef.nativeElement.parentElement.parentElement.style.overflow = 'visible';
        }
        catch (ex) {
            // intentionally empty
        }
    }
    applyFilter() {
        this.context.applyFilter({
            externalFilterQuery: {
                model: this.selectedType,
                chips: [
                    {
                        value: this.selectedType,
                        displayValue: this.selectedType?.[this.path],
                        path: [this.path],
                        columnName: this.context.property.name,
                        remove: () => {
                            return {
                                columnName: this.context.property.name,
                                externalFilterQuery: {
                                    model: null,
                                    chips: []
                                }
                            };
                        }
                    }
                ]
            }
        });
    }
    removeDuplicatesType(list) {
        const uniqueByType = uniqBy(list, this.path).filter((mo) => !this.types.has(mo[this.path]));
        uniqueByType.forEach((mo) => this.types.add(mo[this.path]));
        return uniqueByType;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TypeFilteringFormRendererComponent, deps: [{ token: i1.FilteringFormRendererContext }, { token: i0.ChangeDetectorRef }, { token: RepositoryService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: TypeFilteringFormRendererComponent, isStandalone: true, selector: "c8y-type-filtering-form-renderer", host: { listeners: { "keyup.enter": "onEnterKeyUp($event)", "keydown.escape": "onEscapeKeyDown($event)" } }, viewQueries: [{ propertyName: "typeahead", first: true, predicate: TypeaheadComponent, descendants: true }], ngImport: i0, template: "<c8y-form-group>\n  <label>\n    {{ context?.property?.filterLabel | translate }}\n  </label>\n  <c8y-typeahead\n    placeholder=\"{{ typeaheadPlaceholder | translate: { example: context?.property?.example } }}\"\n    [name]=\"path\"\n    [(ngModel)]=\"selectedType\"\n    [displayProperty]=\"path\"\n    (onSearch)=\"search$.next($event)\"\n  >\n    <c8y-li\n      class=\"p-l-8 p-r-8 c8y-list__item--link\"\n      *c8yFor=\"let type of types$; pipe: filterPipe; loadMore: 'auto'\"\n      (click)=\"$event.stopPropagation(); selectedType = type; typeahead.dropdown.hide()\"\n      [active]=\"selectedType?.[path] === type?.[path]\"\n    >\n      <c8y-highlight\n        [text]=\"type?.[path] || '--'\"\n        [pattern]=\"search$.value\"\n      ></c8y-highlight>\n    </c8y-li>\n  </c8y-typeahead>\n</c8y-form-group>\n\n<div class=\"data-grid__dropdown__footer d-flex separator-top\">\n  <button\n    class=\"btn btn-default btn-sm m-r-8 flex-grow\"\n    title=\"{{ 'Reset' | translate }}\"\n    (click)=\"context.resetFilter()\"\n    translate\n  >\n    Reset\n  </button>\n\n  <button\n    class=\"btn btn-primary btn-sm flex-grow\"\n    title=\"{{ 'Apply' | translate }}\"\n    (click)=\"applyFilter()\"\n    translate\n  >\n    Apply\n  </button>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule$1 }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i1.ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: CoreModule }, { kind: "component", type: i1.HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "component", type: i1.TypeaheadComponent, selector: "c8y-typeahead", inputs: ["required", "maxlength", "disabled", "allowFreeEntries", "placeholder", "displayProperty", "icon", "name", "autoClose", "hideNew", "container", "selected", "title", "highlightFirstItem"], outputs: ["onSearch", "onIconClick"] }, { kind: "component", type: i1.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: i1.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.Default }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TypeFilteringFormRendererComponent, decorators: [{
            type: Component,
            args: [{ standalone: true, changeDetection: ChangeDetectionStrategy.Default, selector: 'c8y-type-filtering-form-renderer', imports: [CommonModule$1, C8yTranslatePipe, CommonModule, FormsModule, CoreModule], template: "<c8y-form-group>\n  <label>\n    {{ context?.property?.filterLabel | translate }}\n  </label>\n  <c8y-typeahead\n    placeholder=\"{{ typeaheadPlaceholder | translate: { example: context?.property?.example } }}\"\n    [name]=\"path\"\n    [(ngModel)]=\"selectedType\"\n    [displayProperty]=\"path\"\n    (onSearch)=\"search$.next($event)\"\n  >\n    <c8y-li\n      class=\"p-l-8 p-r-8 c8y-list__item--link\"\n      *c8yFor=\"let type of types$; pipe: filterPipe; loadMore: 'auto'\"\n      (click)=\"$event.stopPropagation(); selectedType = type; typeahead.dropdown.hide()\"\n      [active]=\"selectedType?.[path] === type?.[path]\"\n    >\n      <c8y-highlight\n        [text]=\"type?.[path] || '--'\"\n        [pattern]=\"search$.value\"\n      ></c8y-highlight>\n    </c8y-li>\n  </c8y-typeahead>\n</c8y-form-group>\n\n<div class=\"data-grid__dropdown__footer d-flex separator-top\">\n  <button\n    class=\"btn btn-default btn-sm m-r-8 flex-grow\"\n    title=\"{{ 'Reset' | translate }}\"\n    (click)=\"context.resetFilter()\"\n    translate\n  >\n    Reset\n  </button>\n\n  <button\n    class=\"btn btn-primary btn-sm flex-grow\"\n    title=\"{{ 'Apply' | translate }}\"\n    (click)=\"applyFilter()\"\n    translate\n  >\n    Apply\n  </button>\n</div>\n" }]
        }], ctorParameters: () => [{ type: i1.FilteringFormRendererContext }, { type: i0.ChangeDetectorRef }, { type: RepositoryService }, { type: i0.ElementRef }], propDecorators: { typeahead: [{
                type: ViewChild,
                args: [TypeaheadComponent, { static: false }]
            }], onEnterKeyUp: [{
                type: HostListener,
                args: ['keyup.enter', ['$event']]
            }], onEscapeKeyDown: [{
                type: HostListener,
                args: ['keydown.escape', ['$event']]
            }] } });

class TypeGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        this.name = 'type';
        this.path = initialColumnConfig?.path ?? 'type';
        this.header = initialColumnConfig?.header ?? gettext('Type');
        this.repositoryType = initialColumnConfig?.repositoryType;
        this.cellRendererComponent = TypeCellRendererComponent;
        this.filterable = true;
        this.filteringFormRendererComponent = TypeFilteringFormRendererComponent;
        this.filteringConfig = {
            getFilter: query => {
                const filter = {};
                if (query.model[this.path]) {
                    filter[this.path] = { __eq: query.model[this.path] };
                }
                return filter;
            }
        };
        this.sortable = true;
        this.sortingConfig = {
            pathSortingConfigs: [{ path: this.path }]
        };
    }
}

class VersionsCellRendererComponent {
    constructor(context, repositoryService) {
        this.context = context;
        this.repositoryService = repositoryService;
        this.isLegacy = this.repositoryService.isLegacyEntry.bind(this.repositoryService);
        this.item = context.item;
    }
    getBaseVersionsCount$(item) {
        return this.repositoryService.getBaseVersionsCount$(item).pipe(shareReplay(1));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: VersionsCellRendererComponent, deps: [{ token: i1.CellRendererContext }, { token: RepositoryService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: VersionsCellRendererComponent, isStandalone: true, selector: "c8y-versions-cell-renderer", ngImport: i0, template: "@if (isLegacy(item)) {\n  <span\n    class=\"label label-warning m-l-auto-sm\"\n    translate\n  >\n    Legacy\n  </span>\n} @else {\n  @if (getBaseVersionsCount$(item) | async; as baseVersionsCount) {\n    <span class=\"badge badge-info m-l-auto-sm\">\n      {{ baseVersionsCount }}\n    </span>\n  } @else {\n    <span class=\"badge badge-info m-l-auto-sm\">\n      <i\n        class=\"icon-spin\"\n        c8yIcon=\"circle-o-notch\"\n      ></i>\n    </span>\n  }\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "ngmodule", type: DeviceGridModule }, { kind: "ngmodule", type: TooltipModule }, { kind: "ngmodule", type: RouterModule }, { kind: "pipe", type: i2.AsyncPipe, name: "async" }] }); }
}
__decorate([
    memoize(property('id')),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", Observable)
], VersionsCellRendererComponent.prototype, "getBaseVersionsCount$", null);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: VersionsCellRendererComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-versions-cell-renderer', standalone: true, imports: [CommonModule, DeviceGridModule, TooltipModule, RouterModule], template: "@if (isLegacy(item)) {\n  <span\n    class=\"label label-warning m-l-auto-sm\"\n    translate\n  >\n    Legacy\n  </span>\n} @else {\n  @if (getBaseVersionsCount$(item) | async; as baseVersionsCount) {\n    <span class=\"badge badge-info m-l-auto-sm\">\n      {{ baseVersionsCount }}\n    </span>\n  } @else {\n    <span class=\"badge badge-info m-l-auto-sm\">\n      <i\n        class=\"icon-spin\"\n        c8yIcon=\"circle-o-notch\"\n      ></i>\n    </span>\n  }\n}\n" }]
        }], ctorParameters: () => [{ type: i1.CellRendererContext }, { type: RepositoryService }], propDecorators: { getBaseVersionsCount$: [] } });

class VersionsGridColumn extends BaseColumn {
    constructor(initialColumnConfig) {
        super(initialColumnConfig);
        this.name = 'versions';
        this.header = gettext('Versions');
        this.cellRendererComponent = VersionsCellRendererComponent;
        this.sortable = false;
    }
}

var LinkRenderType;
(function (LinkRenderType) {
    LinkRenderType[LinkRenderType["DOWNLOAD"] = 0] = "DOWNLOAD";
    LinkRenderType[LinkRenderType["LINK"] = 1] = "LINK";
    LinkRenderType[LinkRenderType["TEXTONLY"] = 2] = "TEXTONLY";
})(LinkRenderType || (LinkRenderType = {}));

class FileDownloadComponent {
    constructor(repositoryService, inventoryBinaryService, alertService) {
        this.repositoryService = repositoryService;
        this.inventoryBinaryService = inventoryBinaryService;
        this.alertService = alertService;
        this.linkRenderType = LinkRenderType;
        this.isDownloading = false;
    }
    getBinaryName$(binaryUrl) {
        return this.repositoryService.getBinaryName$(binaryUrl);
    }
    determineBehavior() {
        let result;
        if (this.inventoryBinaryService.getIdFromUrl(this.url)) {
            result = LinkRenderType.DOWNLOAD;
        }
        else if (this.url.match(/\/\//g)) {
            result = LinkRenderType.LINK;
        }
        else {
            result = LinkRenderType.TEXTONLY;
        }
        return result;
    }
    async downloadFile() {
        try {
            this.isDownloading = true;
            const binary = await this.repositoryService.getBinaryFile(this.url, {
                allowExternal: false
            });
            this.isDownloading = false;
            saveAs(binary);
        }
        catch (ex) {
            this.isDownloading = false;
            if (ex) {
                this.alertService.addServerFailure(ex);
            }
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileDownloadComponent, deps: [{ token: RepositoryService }, { token: i1$1.InventoryBinaryService }, { token: i1.AlertService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: FileDownloadComponent, isStandalone: true, selector: "c8y-file-download", inputs: { url: "url" }, ngImport: i0, template: "<a\n  *ngIf=\"determineBehavior() === linkRenderType.LINK\"\n  href=\"{{ url }}\"\n  class=\"pointer\"\n  target=\"_blank\"\n  rel=\"noopener noreferrer\"\n>\n  {{ getBinaryName$(url) | async }}\n</a>\n\n<span *ngIf=\"determineBehavior() === linkRenderType.TEXTONLY\">{{\n  getBinaryName$(url) | async\n}}</span>\n\n<span *ngIf=\"determineBehavior() === linkRenderType.DOWNLOAD\">\n  <a *ngIf=\"!isDownloading\" class=\"pointer\" (click)=\"downloadFile()\">\n    {{ getBinaryName$(url) | async }}\n  </a>\n\n  <span *ngIf=\"isDownloading\">\n    <i c8yIcon=\"spinner\" class=\"icon-spin\"></i> {{ 'Downloading\u2026' | translate }}\n  </span>\n</span>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
__decorate([
    memoize(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Object]),
    __metadata("design:returntype", void 0)
], FileDownloadComponent.prototype, "getBinaryName$", null);
__decorate([
    memoize(),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", Number)
], FileDownloadComponent.prototype, "determineBehavior", null);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: FileDownloadComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-file-download', imports: [NgIf, IconDirective, AsyncPipe, C8yTranslatePipe], template: "<a\n  *ngIf=\"determineBehavior() === linkRenderType.LINK\"\n  href=\"{{ url }}\"\n  class=\"pointer\"\n  target=\"_blank\"\n  rel=\"noopener noreferrer\"\n>\n  {{ getBinaryName$(url) | async }}\n</a>\n\n<span *ngIf=\"determineBehavior() === linkRenderType.TEXTONLY\">{{\n  getBinaryName$(url) | async\n}}</span>\n\n<span *ngIf=\"determineBehavior() === linkRenderType.DOWNLOAD\">\n  <a *ngIf=\"!isDownloading\" class=\"pointer\" (click)=\"downloadFile()\">\n    {{ getBinaryName$(url) | async }}\n  </a>\n\n  <span *ngIf=\"isDownloading\">\n    <i c8yIcon=\"spinner\" class=\"icon-spin\"></i> {{ 'Downloading\u2026' | translate }}\n  </span>\n</span>\n" }]
        }], ctorParameters: () => [{ type: RepositoryService }, { type: i1$1.InventoryBinaryService }, { type: i1.AlertService }], propDecorators: { url: [{
                type: Input
            }], getBinaryName$: [], determineBehavior: [] } });

// MODAL STRUCTURE
// - selectModalObject (repository entry (repositoryCategory) -> type c8y_Firmware/c8y_Software)
//   -- ISelectModalOption (repository binary entry (repositoryBinary) => type c8y_FirmwareBinary/c8y_SoftwareBinary)
//   -- ISelectModalOption...
// - selectModalObject...
/**
 * RepositorySelectModalComponent displays repository entries options and allows to select them.
 *
 * ```typescript
 * import { take } from 'rxjs/operators';
 * import { RepositorySelectModalComponent, ModalSelectionMode, RepositoryType } from '@c8y/ngx-components/repository/shared';
 *
 * const initialState = {
 *   repositoryType: RepositoryType.FIRMWARE,
 *   title: gettext('Install firmware'),
 *   subTitle: gettext('Available firmwares matching the device type'),
 *   icon: 'c8y-firmware',
 *   mode: ModalSelectionMode.SINGLE,
 *   labels: { ok: gettext('Install') },
 *   disableSelected: false
 * };
 *
 * const modal = this.bsModal.show(RepositorySelectModalComponent, {
 *   ignoreBackdropClick: true,
 *   initialState
 * });
 *
 * modal.content.load.next();
 * modal.content.resultEmitter.pipe(take(1)).subscribe((firmware) => {
 * })
 * ```
 */
class RepositorySelectModalComponent {
    constructor(repositoryService, translateService) {
        this.repositoryService = repositoryService;
        this.translateService = translateService;
        this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_REPOSITORY_SHARED;
        /**
         * Optional
         * Allows to provide custom data.
         * ```typescript
         * import { from } from 'rxjs';
         *
         * const repositoryEntry = { name: 'ExampleEntry', type: 'c8y_Firmware' };
         * const versions = [{ c8y_Firmware: { version: '1.0.0', url: 'http://example.com' } }];
         *
         * const initialState = {repositoryEntriesWithVersions$: from({ ...repositoryEntry, versions })};
         * ```
         */
        this.repositoryEntriesWithVersions$ = undefined;
        /**
         * Optional
         * Allows to use custom badges templates.
         * ```typescript
         * import { gettext } from '@c8y/ngx-components/gettext';
         *
         * const badgeTemplates = { '=1': gettext('{{count}} version'), other: gettext('{{count}} versions') };
         * const initialState = { badgeTemplates };
         * ```
         */
        this.badgeTemplates = { '=1': gettext('{{count}} version'), other: gettext('{{count}} versions') };
        /**
         * Optional
         * Allows to provide custom modal title.
         */
        this.title = gettext('Select repository entry');
        /**
         * Loads the content of the modal.
         * Must be invoked by the modal's caller.
         */
        this.load = new Subject();
        /**
         * Triggers an update of the item list emitted.
         */
        this.updateInstallableList$ = new Subject();
        /**
         * Optional
         * Emits a filter criteria object currently entered in the filter input.
         * Use it to filter the items if you use custom repositoryEntriesWithVersions$.
         */
        this.searchTerm = new BehaviorSubject({});
        /**
         * Optional
         * Allows to provide device type query to restrict search criteria.
         * Only takes effect when repositoryEntriesWithVersions$ is not provided,
         * otherwise modal's caller have to provide already filtered data in the repositoryEntriesWithVersions$.
         */
        this.deviceTypeQuery = {};
        /**
         * Optional
         * Allows to provide query to restrict search criteria.
         * Only takes effect when repositoryEntriesWithVersions$ is not provided,
         * otherwise modal's caller have to provide already filtered data in the repositoryEntriesWithVersions$.
         */
        this.searchQuery = {};
        /**
         * Optional
         * Allows to provide custom labels for the buttons responsible for confirm/dismiss modal actions.
         */
        this.labels = { ok: gettext('Save') };
        /**
         * Optional
         * Allows to hide the name filter input field.
         * By default, the filter input field is displayed.
         */
        this.showFilter = true;
        /**
         * Optional
         * Allows to show a warning that the search criteria should be narrowed down.
         * By default, this warning is hidden.
         */
        this.areMoreEntries = false;
        /**
         * Emits whenever a new repository binary have been selected in the modal.
         */
        this.onChoiceUpdated = new EventEmitter();
        /**
         * Emits the list of selected options.
         */
        this.resultEmitter = new EventEmitter();
        /**
         * Optional
         * Allows to change selection mode.
         * Supported options:
         *   * single: only single option can be selected.
         *   * multiple: multiple options can be selected.
         */
        this.mode = ModalSelectionMode.SINGLE;
        /**
         * Allows to block selection of the other versions from the same repository entry.
         */
        this.disableSelected = true;
        this.filterCriteria = {};
        this.repositoryEntries$ = this.load.pipe(switchMap(() => this.repositoryEntriesWithVersions$), mergeMap(mos => this.aggregate(mos)), tap(items => {
            this.areMoreEntries = items.length >= this.PAGE_SIZE ? true : false;
        }), tap(items => (this.repositoryEntries = items)));
        this.modalEntries = merge(this.repositoryEntries$, this.updateInstallableList$.pipe(map((updateItemEvent) => {
            const itemToUpdate = (this.repositoryEntries || []).find(item => item.groupId === updateItemEvent.object.groupId);
            if (itemToUpdate) {
                const optionToUpdate = (itemToUpdate.options || []).find(option => option.obj.id === updateItemEvent.object.selectedId);
                if (optionToUpdate) {
                    optionToUpdate.template = updateItemEvent.template;
                    if (updateItemEvent.mapper) {
                        optionToUpdate.obj = updateItemEvent.mapper(optionToUpdate.obj);
                    }
                }
            }
            return this.repositoryEntries;
        })));
        this.PAGE_SIZE = 100;
        this.queriesUtil = new QueriesUtil();
    }
    ngOnInit() {
        if (!this.repositoryType) {
            throw new Error('Repository type must be defined');
        }
        if (!this.repositoryEntriesWithVersions$) {
            this.repositoryEntriesWithVersions$ = of(1).pipe(mergeMap(() => this.repositoryService.listRepositoryEntries(this.repositoryType, {
                query: this.queriesUtil.addAndFilter(this.deviceTypeQuery, has(this.searchQuery, 'name')
                    ? { ...this.searchQuery, name: `*${this.searchQuery.name}*` }
                    : this.searchQuery),
                params: { pageSize: this.PAGE_SIZE }
            })), map(({ data }) => data), map(mos => this.getAndAssignRepositoryBinaries(mos)));
        }
    }
    getAndAssignRepositoryBinaries(mos) {
        mos.forEach(mo => {
            mo.versions = this.repositoryService.listAllVersions(mo);
        });
        return mos;
    }
    search(filterCriteria) {
        this.filterCriteria = omitBy({
            ...this.filterCriteria,
            ...filterCriteria
        }, isEmpty);
        if (!isEqual(this.filterCriteria, this.searchQuery)) {
            this.searchTerm.next(this.filterCriteria);
            this.searchQuery = this.filterCriteria;
            this.load.next();
        }
    }
    result(selectedItems) {
        this.resultEmitter.emit(selectedItems);
    }
    async aggregate(mos) {
        const repositoryType = this.repositoryType;
        const selectedItems = this.selected;
        return Promise.all(mos.map(async (repositoryEntry) => {
            const options = this.getSelectModalOptions(await this.repositoryService.fetchAllItemsFromList(repositoryEntry.versions), selectedItems, repositoryEntry, repositoryType);
            const selectModalObject = this.getSelectModalObject(repositoryEntry, options);
            return selectModalObject;
        }));
    }
    getSelectModalOptions(versions, selectedItems, repositoryEntry, repositoryType) {
        const selectModalOptions = [];
        versions.forEach(repositoryBinary => {
            const isSelected = this.isBinaryRepositorySelected(selectedItems, repositoryEntry, repositoryBinary, repositoryType);
            const { version } = repositoryBinary[`${repositoryType}`];
            const bodyValue = version || `(${this.translateService.instant(gettext('not specified`version`'))})`;
            const bodyClass = version ? '' : 'text-muted';
            selectModalOptions.push({
                body: [
                    {
                        value: bodyValue,
                        class: bodyClass
                    }
                ],
                obj: {
                    id: repositoryBinary.id,
                    name: repositoryEntry.name,
                    version,
                    ...(get(repositoryBinary, 'c8y_Patch.dependency') && {
                        dependency: get(repositoryBinary, 'c8y_Patch.dependency')
                    }),
                    ...(get(repositoryBinary, 'c8y_Patch') && { isPatch: true }),
                    url: repositoryBinary[`${repositoryType}`].url,
                    softwareType: repositoryEntry.softwareType
                },
                selected: isSelected
            });
        });
        return selectModalOptions;
    }
    isBinaryRepositorySelected(selectedItems, repositoryEntry, repositoryBinary, repositoryType) {
        const isSelected = selectedItems
            ? selectedItems.filter(repositoryFragment => repositoryFragment.name === repositoryEntry.name &&
                repositoryFragment.version === repositoryBinary[`${repositoryType}`].version).length > 0
            : false;
        return isSelected;
    }
    getSelectModalObject(repositoryEntry, options) {
        const label = options.length === 1
            ? this.translateService.instant(this.badgeTemplates['=1'], { count: options.length })
            : this.translateService.instant(this.badgeTemplates.other, { count: options.length });
        const selectModalObject = {
            groupId: repositoryEntry.id,
            body: [
                { value: repositoryEntry.name, class: 'text-truncate' },
                { value: repositoryEntry.description, class: 'text-truncate text-muted' }
            ],
            additionalInformation: { value: label, class: 'label label-info' },
            options
        };
        return selectModalObject;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RepositorySelectModalComponent, deps: [{ token: RepositoryService }, { token: i2$1.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: RepositorySelectModalComponent, isStandalone: true, selector: "c8y-repository-select-modal", providers: [
            {
                provide: PRODUCT_EXPERIENCE_EVENT_SOURCE,
                useExisting: forwardRef(() => RepositorySelectModalComponent)
            }
        ], ngImport: i0, template: "<c8y-select-modal\n  [icon]=\"icon\"\n  [title]=\"title\"\n  [subTitle]=\"subTitle\"\n  [items]=\"modalEntries | async\"\n  [mode]=\"mode\"\n  [disableSelected]=\"disableSelected\"\n  [labels]=\"labels\"\n  [showFilter]=\"showFilter\"\n  [additionalFilterTemplate]=\"additionalFilterTemplate\"\n  [areMoreEntries]=\"areMoreEntries\"\n  [noItemsMessage]=\"noItemsMessage\"\n  [hideEmptyItems]=\"hideEmptyItems\"\n  (search)=\"search({ name: $event })\"\n  (onChoiceUpdated)=\"onChoiceUpdated.emit($event)\"\n  (result)=\"result($event)\"\n  c8yProductExperience\n  inherit\n  suppressDataOverriding\n  [actionData]=\"{ component: PRODUCT_EXPERIENCE.SHARED.COMPONENTS.REPOSITORY_SELECT_MODAL }\"\n></c8y-select-modal>\n", dependencies: [{ kind: "component", type: SelectModalComponent, selector: "c8y-select-modal", inputs: ["icon", "title", "subTitle", "items", "mode", "disableSelected", "showFilter", "additionalFilterTemplate", "areMoreEntries", "labels", "noItemsMessage", "hideEmptyItems"], outputs: ["result", "search", "onChoiceUpdated"] }, { kind: "directive", type: ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: RepositorySelectModalComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-repository-select-modal', providers: [
                        {
                            provide: PRODUCT_EXPERIENCE_EVENT_SOURCE,
                            useExisting: forwardRef(() => RepositorySelectModalComponent)
                        }
                    ], imports: [SelectModalComponent, ProductExperienceDirective, AsyncPipe], template: "<c8y-select-modal\n  [icon]=\"icon\"\n  [title]=\"title\"\n  [subTitle]=\"subTitle\"\n  [items]=\"modalEntries | async\"\n  [mode]=\"mode\"\n  [disableSelected]=\"disableSelected\"\n  [labels]=\"labels\"\n  [showFilter]=\"showFilter\"\n  [additionalFilterTemplate]=\"additionalFilterTemplate\"\n  [areMoreEntries]=\"areMoreEntries\"\n  [noItemsMessage]=\"noItemsMessage\"\n  [hideEmptyItems]=\"hideEmptyItems\"\n  (search)=\"search({ name: $event })\"\n  (onChoiceUpdated)=\"onChoiceUpdated.emit($event)\"\n  (result)=\"result($event)\"\n  c8yProductExperience\n  inherit\n  suppressDataOverriding\n  [actionData]=\"{ component: PRODUCT_EXPERIENCE.SHARED.COMPONENTS.REPOSITORY_SELECT_MODAL }\"\n></c8y-select-modal>\n" }]
        }], ctorParameters: () => [{ type: RepositoryService }, { type: i2$1.TranslateService }] });

class SoftwareTypeComponent {
    set presetSoftwareTypes(types) {
        if (!isEmpty(types)) {
            this.presetSoftwareTypes$ = toObservable(types).pipe(map(types => types.map(softwareType => typeof softwareType === 'string'
                ? { softwareType }
                : softwareType)));
        }
    }
    constructor(repositoryService, changeDetectorRef, translateService) {
        this.repositoryService = repositoryService;
        this.changeDetectorRef = changeDetectorRef;
        this.translateService = translateService;
        this.required = true;
        this.placeholder = this.translateService.instant(gettext('e.g. {{ example }}'), {
            example: 'yum'
        });
        this.emitResultsOnly = false;
        this.showBtnInNotFoundMessage = true;
        this.allowFreeEntries = true;
        this.showClearSelectionOption = false;
        this.clearSelectionOptionLabel = gettext('All software types');
        this.onSelectSoftware = new EventEmitter();
        this.filterPipe = pipe(tap());
        this.search$ = new BehaviorSubject(null);
        this.queriesUtil = new QueriesUtil();
        this.softwareTypes = new Set();
        this.filterPipe = pipe(map(this.removeDuplicatesBySoftwareType.bind(this)));
    }
    ngOnInit() {
        this.softwaresResult$ = this.search$.pipe(debounce(() => interval(300)), tap(() => this.softwareTypes.clear()), switchMap((searchString) => {
            if (!this.emitResultsOnly || !searchString) {
                this.onSelectSoftware.emit(this.softwareTypeMO);
            }
            return this.getSoftwareByTypeResult(searchString);
        }), shareReplay(1));
        this.notFoundTemplateToUse = this.showBtnInNotFoundMessage
            ? this.notFoundTypeAddNewTemplate
            : this.notFoundTypeTemplate;
    }
    getSoftwareByTypeResult(searchString) {
        return this.presetSoftwareTypes$
            ? this.searchInPreset(searchString)
            : this.searchInRepository(searchString);
    }
    selectSoftware(software) {
        this.softwareTypeMO = software;
        this.onSelectSoftware.emit(software);
        this.deviceSoftwareTypeModel.searchControlModel.control.markAsDirty();
        this.deviceSoftwareTypeModel.onChange(software);
    }
    clearSoftware() {
        this.softwareTypeMO = undefined;
        this.search$.next('');
        this.onSelectSoftware.emit();
    }
    resetInput() {
        this.deviceSoftwareTypeModel.reset();
    }
    writeValue(value) {
        this.deviceSoftwareTypeModel.writeValue(value);
    }
    registerOnChange(fn) {
        this.deviceSoftwareTypeModel.registerOnChange(fn);
    }
    registerOnTouched(fn) {
        this.deviceSoftwareTypeModel.registerOnTouched(fn);
    }
    setDisabledState(isDisabled) {
        this.deviceSoftwareTypeModel.setDisabledState(isDisabled);
    }
    validate(control) {
        return this.deviceSoftwareTypeModel.validate(control);
    }
    searchInPreset(searchString) {
        return this.presetSoftwareTypes$.pipe(map(types => ({
            data: types.filter(type => !searchString || type.softwareType.indexOf(searchString) > -1),
            res: undefined,
            statistics: { currentPage: 1, pageSize: types?.length, totalPages: 1 }
        })));
    }
    searchInRepository(searchString) {
        let query = this.queriesUtil.prependOrderbys({}, [{ softwareType: 1 }]);
        const filter = !!searchString
            ? {
                softwareType: {
                    __eq: `*${searchString}*`
                }
            }
            : {
                __has: 'softwareType'
            };
        query = this.queriesUtil.addAndFilter(query, filter);
        return this.repositoryService.listRepositoryEntries(RepositoryType.SOFTWARE, {
            query,
            params: {
                pageSize: 200
            }
        });
    }
    removeDuplicatesBySoftwareType(list) {
        const uniqueBySoftwareType = uniqBy(list, 'softwareType').filter((sw) => !this.softwareTypes.has(sw.softwareType));
        uniqueBySoftwareType.forEach((sw) => this.softwareTypes.add(sw.softwareType));
        return uniqueBySoftwareType;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SoftwareTypeComponent, deps: [{ token: RepositoryService }, { token: i0.ChangeDetectorRef }, { token: i2$1.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: SoftwareTypeComponent, isStandalone: true, selector: "c8y-software-type", inputs: { softwareTypeMO: "softwareTypeMO", disabled: "disabled", style: "style", required: "required", placeholder: "placeholder", emitResultsOnly: "emitResultsOnly", showBtnInNotFoundMessage: "showBtnInNotFoundMessage", allowFreeEntries: "allowFreeEntries", showClearSelectionOption: "showClearSelectionOption", clearSelectionOptionLabel: "clearSelectionOptionLabel", presetSoftwareTypes: "presetSoftwareTypes" }, outputs: { onSelectSoftware: "onSelectSoftware" }, providers: [
            {
                provide: NG_VALUE_ACCESSOR,
                multi: true,
                useExisting: forwardRef(() => SoftwareTypeComponent)
            },
            {
                provide: NG_VALIDATORS,
                useExisting: forwardRef(() => SoftwareTypeComponent),
                multi: true
            }
        ], viewQueries: [{ propertyName: "deviceSoftwareTypeModel", first: true, predicate: ["deviceSoftwareTypeModel"], descendants: true }, { propertyName: "notFoundTypeAddNewTemplate", first: true, predicate: ["notFoundTypeAddNewTemplate"], descendants: true, static: true }, { propertyName: "notFoundTypeTemplate", first: true, predicate: ["notFoundTypeTemplate"], descendants: true, static: true }], ngImport: i0, template: "<c8y-typeahead\n  [(ngModel)]=\"softwareTypeMO\"\n  [required]=\"required\"\n  [disabled]=\"disabled\"\n  name=\"softwareType\"\n  [placeholder]=\"placeholder\"\n  [allowFreeEntries]=\"allowFreeEntries\"\n  #deviceSoftwareTypeModel\n  (onSearch)=\"search$.next($event)\"\n  displayProperty=\"softwareType\"\n  [ngStyle]=\"style\"\n>\n  <c8y-li\n    *ngIf=\"showClearSelectionOption\"\n    class=\"p-l-8 p-r-8 c8y-list__item--link\"\n    (click)=\"clearSoftware()\"\n    [active]=\"!softwareTypeMO?.softwareType\"\n  >\n    <span>{{ clearSelectionOptionLabel | translate }}</span>\n  </c8y-li>\n  <c8y-li\n    *c8yFor=\"\n      let software of softwaresResult$;\n      pipe: filterPipe;\n      loadMore: 'auto';\n      notFound: notFoundTemplateToUse\n    \"\n    class=\"p-l-8 p-r-8 c8y-list__item--link\"\n    (click)=\"selectSoftware(software)\"\n    [active]=\"softwareTypeMO?.softwareType === software.softwareType\"\n  >\n    <c8y-highlight\n      [text]=\"software.softwareType || '--'\"\n      [pattern]=\"search$ | async\"\n    ></c8y-highlight>\n  </c8y-li>\n  <ng-template #notFoundTypeAddNewTemplate>\n    <c8y-li class=\"bg-level-2 p-8\" *ngIf=\"(search$ | async)?.length > 0\">\n      <span translate>No match found.</span>\n      <button\n        title=\"{{ 'Add new`software type`' | translate }}\"\n        type=\"button\"\n        class=\"btn btn-primary btn-xs m-l-8\"\n        translate\n      >\n        Add new`software type`\n      </button>\n    </c8y-li>\n  </ng-template>\n  <ng-template #notFoundTypeTemplate>\n    <c8y-li\n      class=\"bg-level-2 p-8\"\n      *ngIf=\"(search$ | async)?.length > 0 && (softwaresResult$ | async)?.data?.length === 0\"\n    >\n      <span translate>No match found. Refine your search terms or check your spelling.</span>\n    </c8y-li>\n  </ng-template>\n</c8y-typeahead>\n", dependencies: [{ kind: "component", type: TypeaheadComponent, selector: "c8y-typeahead", inputs: ["required", "maxlength", "disabled", "allowFreeEntries", "placeholder", "displayProperty", "icon", "name", "autoClose", "hideNew", "container", "selected", "title", "highlightFirstItem"], outputs: ["onSearch", "onIconClick"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "directive", type: ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "component", type: HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SoftwareTypeComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-software-type', providers: [
                        {
                            provide: NG_VALUE_ACCESSOR,
                            multi: true,
                            useExisting: forwardRef(() => SoftwareTypeComponent)
                        },
                        {
                            provide: NG_VALIDATORS,
                            useExisting: forwardRef(() => SoftwareTypeComponent),
                            multi: true
                        }
                    ], imports: [
                        TypeaheadComponent,
                        FormsModule,
                        NgStyle,
                        NgIf,
                        ListItemComponent,
                        ForOfDirective,
                        HighlightComponent,
                        C8yTranslateDirective,
                        AsyncPipe,
                        C8yTranslatePipe
                    ], template: "<c8y-typeahead\n  [(ngModel)]=\"softwareTypeMO\"\n  [required]=\"required\"\n  [disabled]=\"disabled\"\n  name=\"softwareType\"\n  [placeholder]=\"placeholder\"\n  [allowFreeEntries]=\"allowFreeEntries\"\n  #deviceSoftwareTypeModel\n  (onSearch)=\"search$.next($event)\"\n  displayProperty=\"softwareType\"\n  [ngStyle]=\"style\"\n>\n  <c8y-li\n    *ngIf=\"showClearSelectionOption\"\n    class=\"p-l-8 p-r-8 c8y-list__item--link\"\n    (click)=\"clearSoftware()\"\n    [active]=\"!softwareTypeMO?.softwareType\"\n  >\n    <span>{{ clearSelectionOptionLabel | translate }}</span>\n  </c8y-li>\n  <c8y-li\n    *c8yFor=\"\n      let software of softwaresResult$;\n      pipe: filterPipe;\n      loadMore: 'auto';\n      notFound: notFoundTemplateToUse\n    \"\n    class=\"p-l-8 p-r-8 c8y-list__item--link\"\n    (click)=\"selectSoftware(software)\"\n    [active]=\"softwareTypeMO?.softwareType === software.softwareType\"\n  >\n    <c8y-highlight\n      [text]=\"software.softwareType || '--'\"\n      [pattern]=\"search$ | async\"\n    ></c8y-highlight>\n  </c8y-li>\n  <ng-template #notFoundTypeAddNewTemplate>\n    <c8y-li class=\"bg-level-2 p-8\" *ngIf=\"(search$ | async)?.length > 0\">\n      <span translate>No match found.</span>\n      <button\n        title=\"{{ 'Add new`software type`' | translate }}\"\n        type=\"button\"\n        class=\"btn btn-primary btn-xs m-l-8\"\n        translate\n      >\n        Add new`software type`\n      </button>\n    </c8y-li>\n  </ng-template>\n  <ng-template #notFoundTypeTemplate>\n    <c8y-li\n      class=\"bg-level-2 p-8\"\n      *ngIf=\"(search$ | async)?.length > 0 && (softwaresResult$ | async)?.data?.length === 0\"\n    >\n      <span translate>No match found. Refine your search terms or check your spelling.</span>\n    </c8y-li>\n  </ng-template>\n</c8y-typeahead>\n" }]
        }], ctorParameters: () => [{ type: RepositoryService }, { type: i0.ChangeDetectorRef }, { type: i2$1.TranslateService }], propDecorators: { softwareTypeMO: [{
                type: Input
            }], disabled: [{
                type: Input
            }], style: [{
                type: Input
            }], required: [{
                type: Input
            }], placeholder: [{
                type: Input
            }], emitResultsOnly: [{
                type: Input
            }], showBtnInNotFoundMessage: [{
                type: Input
            }], allowFreeEntries: [{
                type: Input
            }], showClearSelectionOption: [{
                type: Input
            }], clearSelectionOptionLabel: [{
                type: Input
            }], presetSoftwareTypes: [{
                type: Input
            }], deviceSoftwareTypeModel: [{
                type: ViewChild,
                args: ['deviceSoftwareTypeModel']
            }], notFoundTypeAddNewTemplate: [{
                type: ViewChild,
                args: ['notFoundTypeAddNewTemplate', { static: true }]
            }], notFoundTypeTemplate: [{
                type: ViewChild,
                args: ['notFoundTypeTemplate', { static: true }]
            }], onSelectSoftware: [{
                type: Output
            }] } });

class SharedRepositoryModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SharedRepositoryModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: SharedRepositoryModule, imports: [RepositorySelectModalComponent, FileDownloadComponent, SoftwareTypeComponent], exports: [RepositorySelectModalComponent, FileDownloadComponent, SoftwareTypeComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SharedRepositoryModule, providers: [RepositoryService, OperationRealtimeService], imports: [RepositorySelectModalComponent, SoftwareTypeComponent] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SharedRepositoryModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [RepositorySelectModalComponent, FileDownloadComponent, SoftwareTypeComponent],
                    providers: [RepositoryService, OperationRealtimeService],
                    exports: [RepositorySelectModalComponent, FileDownloadComponent, SoftwareTypeComponent]
                }]
        }] });

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

export { DescriptionGridColumn, DeviceConfigurationOperation, DeviceTypeCellRendererComponent, DeviceTypeGridColumn, FileCellRendererComponent, FileDownloadComponent, FileGridColumn, LinkRenderType, PRODUCT_EXPERIENCE_REPOSITORY_SHARED, REPOSITORY_BINARY_TYPES, RepositoryItemNameCellRendererComponent, RepositoryItemNameGridColumn, RepositorySelectModalComponent, RepositoryService, RepositoryType, SharedRepositoryModule, SoftwareTypeComponent, TypeCellRendererComponent, TypeFilteringFormRendererComponent, TypeGridColumn, VersionsCellRendererComponent, VersionsGridColumn };
//# sourceMappingURL=c8y-ngx-components-repository-shared.mjs.map