UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

2,355 lines 185 kB
import * as i0 from '@angular/core';
import { EventEmitter, Injectable, ViewChild, Input, Component, Pipe, Output, forwardRef, inject, NgModule } from '@angular/core';
import * as i3$1 from '@c8y/client';
import { ApplicationAvailability, ApplicationType } from '@c8y/client';
import { gettext } from '@c8y/ngx-components/gettext';
import * as i1 from '@c8y/ngx-components';
import { PackageType, Status, WizardHeaderComponent, IconDirective, WizardBodyComponent, FormGroupComponent, DropAreaComponent, MessagesComponent, MessageDirective, OperationResultComponent, WizardFooterComponent, C8yTranslateDirective, C8yTranslatePipe, AppIconComponent, IfAllowedDirective, HumanizeAppNamePipe, RequiredInputPlaceholderDirective, LoadingComponent, C8yStepper, TypeaheadComponent, ForOfDirective, ListItemComponent, ListItemIconComponent, HighlightComponent, internalApps, FilterInputComponent, PluginsService, EmptyStateComponent, MarkdownToHtmlPipe, CoreModule, hookWizard } from '@c8y/ngx-components';
import * as i3 from '@ngx-translate/core';
import { saveAs } from 'file-saver';
import { groupBy, uniqBy, get, pick, omit, isUndefined, kebabCase, cloneDeep } from 'lodash-es';
import { BehaviorSubject, defer, merge, combineLatest, Subject, pipe } from 'rxjs';
import { map, shareReplay, debounceTime, take, filter, distinctUntilKeyChanged, tap, switchMap, takeUntil } from 'rxjs/operators';
import { satisfies, gt, coerce, lt } from 'semver';
import { NgIf, NgFor, AsyncPipe, NgClass, NgPlural, NgPluralCase, TitleCasePipe } from '@angular/common';
import { PopoverDirective, PopoverModule } from 'ngx-bootstrap/popover';
import * as i1$1 from '@angular/forms';
import { FormsModule, Validators, ReactiveFormsModule, NG_VALUE_ACCESSOR, FormControl } from '@angular/forms';
import * as i4 from '@angular/router';
import { TooltipDirective, TooltipModule } from 'ngx-bootstrap/tooltip';
import { BsDropdownDirective, BsDropdownToggleDirective, BsDropdownMenuDirective, BsDropdownModule } from 'ngx-bootstrap/dropdown';
import { CdkTrapFocus, A11yModule } from '@angular/cdk/a11y';
import { IconSelectorWrapperComponent, IconSelectorModule } from '@c8y/ngx-components/icon-selector';
import * as i1$2 from 'ngx-bootstrap/modal';
import { CdkStep } from '@angular/cdk/stepper';

/** Wizard types  */
var EcosystemWizards;
(function (EcosystemWizards) {
    EcosystemWizards["APPLICATION_UPLOAD"] = "ecosystemApplicationUpload";
    EcosystemWizards["MICROSERVICE_UPLOAD"] = "ecosystemMicroserviceUpload";
    EcosystemWizards["PACKAGE_UPLOAD"] = "ecosystemPackageUpload";
    EcosystemWizards["BLUEPRINT_DEPLOYMENT"] = "ecosystemBlueprintDeployment";
    EcosystemWizards["LICENSE_CONFIRM"] = "ecosystemLicenseConfirm";
    EcosystemWizards["ARCHIVED_CONFIRM"] = "ecosystemArchivedConfirm";
})(EcosystemWizards || (EcosystemWizards = {}));
var ERROR_TYPE;
(function (ERROR_TYPE) {
    ERROR_TYPE["TYPE_VALIDATION"] = "TYPE_VALIDATION";
    ERROR_TYPE["ALREADY_SUBSCRIBED"] = "ALREADY_SUBSCRIBED";
    ERROR_TYPE["ALREADY_EXIST"] = "ALREADY_EXIST";
    ERROR_TYPE["INTERNAL_ERROR"] = "INTERNAL_ERROR";
    ERROR_TYPE["NO_MANIFEST_FILE"] = "NO_MANIFEST_FILE";
    ERROR_TYPE["INVALID_PACKAGE"] = "INVALID_PACKAGE";
    ERROR_TYPE["INVALID_APPLICATION"] = "INVALID_APPLICATION";
    ERROR_TYPE["MICROSERVICE_NAME_TOO_LONG"] = "MICROSERVICE_NAME_TOO_LONG";
    ERROR_TYPE["APPLICATION_CREATION_FAILED"] = "APPLICATION_CREATION_FAILED";
    ERROR_TYPE["KEY_OR_CONTEXT_PATH_MISMATCH"] = "KEY_OR_CONTEXT_PATH_MISMATCH";
    ERROR_TYPE["VERSION_NOT_FOUND"] = "VERSION_NOT_FOUND";
})(ERROR_TYPE || (ERROR_TYPE = {}));
const PRODUCT_EXPERIENCE_ECOSYSTEM = {
    APPLICATIONS: {
        EVENTS: {
            AVAILABILITY: 'availability',
            APPLICATION_CARD: 'applicationCard',
            APPLICATION_PROPERTIES: 'applicationProperties',
            DEPLOY_APPLICATION: 'deployApplication',
            DUPLICATE_APPLICATION: 'duplicateApplication',
            INSTALLED_PLUGINS: 'installedPlugins',
            PACKAGE_PLUGINS: 'packagePlugins',
            PACKAGE_VERSIONS: 'packageVersions',
            FILTER_LIST: 'filterList'
        },
        COMPONENTS: {
            APPLICATION_CARD: 'application-card',
            APPLICATION_PLUGINS: 'application-plugins',
            APPLICATION_PROPERTIES: 'application-properties',
            DEPLOY_APPLICATION: 'deploy-application',
            DUPLICATE_APPLICATION_PROPERTIES: 'duplicate-application-properties',
            PLUGIN_LIST: 'plugin-list',
            PACKAGE_VERSIONS: 'package-versions-list',
            UPDATE_PLUGIN_OF_APP: 'update-plugin-of-app',
            LIST_FILTERS: 'list-filters',
            PACKAGE_DETAILS: 'package-details'
        },
        ACTIONS: {
            AVAILABILITY_CHANGE: 'availabilityChange',
            CANCEL: 'cancel',
            CLONE: 'clone',
            CHANGE_PLUGIN_VERSION: 'changePluginVersion',
            DELETE: 'delete',
            DOWNLOAD: 'download',
            DEPLOY_APPLICATION: 'deployApplication',
            EDIT: 'edit',
            INSTALL_PLUGIN: 'installPlugin',
            INSTALL_PLUGINS: 'installPlugins',
            UNINSTALL_PLUGIN: 'uninstallPlugin',
            SELECT_VERSION: 'selectVersion',
            SET_AS_LATEST: 'setAsLatest',
            UPDATE_AVAILABLE: 'updateAvailable',
            UPLOAD: 'upload',
            SET_FILTER_TERM: 'setFilterTerm',
            SET_PREDEFINED_FILTERS: 'setPredefinedFilters',
            RESET_FILTER: 'resetFilter',
            INSTALL_PLUGINS_INITIATED: 'installPluginsInitiated',
            DEPLOY_APPLICATION_INITIATED: 'deployApplicationInitiated'
        },
        RESULTS: {
            DEPLOYED: 'deployed',
            DUPLICATED: 'duplicated',
            PLUGIN_INSTALLED: 'pluginInstalled',
            PLUGIN_REMOVED: 'pluginRemoved',
            PLUGIN_VERSION_CHANGED: 'pluginVersionChanged',
            SERVER_FAILURE: 'serverFailure',
            SUCCESS: 'success'
        }
    }
};

const ERROR_MESSAGES = {
    [ERROR_TYPE.ALREADY_EXIST]: gettext('Could not deploy the application, as an application with the same name`KEEP_ORIGINAL`, context-path`KEEP_ORIGINAL` or key`KEEP_ORIGINAL` exists already.'),
    [ERROR_TYPE.TYPE_VALIDATION]: gettext('Wrong file format. Expected a *.zip file with a valid manifest.'),
    [ERROR_TYPE.ALREADY_SUBSCRIBED]: gettext('Could not subscribe to the microservice because another application with the same context path is already subscribed.'),
    [ERROR_TYPE.NO_MANIFEST_FILE]: gettext('Could not find a manifest.'),
    [ERROR_TYPE.INVALID_PACKAGE]: gettext('You have not uploaded a valid package.'),
    [ERROR_TYPE.INVALID_APPLICATION]: gettext('You have not uploaded a valid application.'),
    [ERROR_TYPE.INTERNAL_ERROR]: gettext('An internal error occurred, try to upload again.'),
    [ERROR_TYPE.MICROSERVICE_NAME_TOO_LONG]: gettext('Microservice name "{{ name }}" must not be longer than {{ maxChars }} characters.'),
    [ERROR_TYPE.APPLICATION_CREATION_FAILED]: gettext('Application creation failed.'),
    [ERROR_TYPE.KEY_OR_CONTEXT_PATH_MISMATCH]: gettext('The "contextPath`KEEP_ORIGINAL`" or "key`KEEP_ORIGINAL`" of the uploaded archive do not match with the existing application.'),
    [ERROR_TYPE.VERSION_NOT_FOUND]: gettext('The selected version was not found on the server.')
};
const APP_STATE = {
    SUBSCRIBED: {
        label: gettext('Subscribed`application`'),
        class: 'label-primary',
        tooltip: gettext('Provided by parent tenant.')
    },
    CUSTOM: {
        label: gettext('Custom`application`'),
        class: 'label-info',
        tooltip: gettext('Manually uploaded to the platform.')
    },
    EXTERNAL: {
        label: gettext('External`application`'),
        class: 'label-warning',
        tooltip: gettext('Application hosted outside of the platform.')
    },
    UNPACKED: {
        label: gettext('Unpacked`application`'),
        class: 'label-success',
        tooltip: gettext('Deployed from a package available under "Packages".')
    },
    PACKAGE_BLUEPRINT: {
        label: gettext('Blueprint'),
        class: 'label-success',
        tooltip: gettext('Contains an application and may include plugins.')
    },
    PACKAGE_PLUGIN: {
        label: gettext('Plugins'),
        class: 'label-info',
        tooltip: gettext('Contains only plugins.')
    },
    PACKAGE_UNKNOWN: {
        label: gettext('Unknown`package-type`'),
        class: 'label-info',
        tooltip: gettext('Package contents could not be determined.')
    }
};
const PACKAGE_TYPE_LABELS = {
    [PackageType.COMMUNITY]: {
        label: gettext('COMMUNITY`Package created by the developer community.`'),
        tooltip: gettext('Package created by the developer community.')
    },
    [PackageType.OFFICIAL]: {
        label: gettext('OFFICIAL`Package maintained by Cumulocity.`'),
        tooltip: gettext('Package maintained by Cumulocity.')
    },
    [PackageType.UNKNOWN]: {
        label: gettext('CUSTOM`Package maintained by an unknown source.`'),
        tooltip: gettext('Package maintainer unknown.')
    },
    [PackageType.ARCHIVED]: {
        label: gettext('ARCHIVED`Package out of maintenance.`'),
        tooltip: gettext('The package was marked by the author as archived.')
    }
};
const packageProperties = [
    {
        label: gettext('Latest version'),
        key: 'version'
    },
    {
        label: gettext('Author'),
        key: 'author'
    },
    {
        label: gettext('Keywords'),
        key: 'keywords'
    },
    {
        label: gettext('Source'),
        key: 'repository',
        transform: (repository) => (repository?.url ? repository.url : repository),
        type: 'link',
        action: (e, link) => window.open(link, '_blank', 'noopener,noreferrer')
    },
    {
        label: gettext('Homepage'),
        key: 'homepage',
        type: 'link',
        action: (e, link) => window.open(link, '_blank', 'noopener,noreferrer')
    },
    {
        label: gettext('License'),
        key: 'license'
    }
];

class EcosystemError extends Error {
    constructor(type) {
        super(ERROR_MESSAGES[type]);
        this.type = type;
    }
}

const CUMULOCITY_JSON = 'cumulocity.json';
const MICROSERVICE_NAME_MAX_LENGTH = 23;
class EcosystemService {
    constructor(modal, alertService, humanizeAppName, translateService, applicationService, appStateService, zipService, tenantService, inventoryService, wizardModalService, pluginService) {
        this.modal = modal;
        this.alertService = alertService;
        this.humanizeAppName = humanizeAppName;
        this.translateService = translateService;
        this.applicationService = applicationService;
        this.appStateService = appStateService;
        this.zipService = zipService;
        this.tenantService = tenantService;
        this.inventoryService = inventoryService;
        this.wizardModalService = wizardModalService;
        this.pluginService = pluginService;
        this.appDeleted = new EventEmitter();
        this.progress = new BehaviorSubject(null);
        this.appsGroupedByContextPath$ = defer(() => this.getWebApplications()).pipe(map(webApps => groupBy(webApps, 'contextPath')), shareReplay({ bufferSize: 1, refCount: true }));
    }
    getUniqueAppConfig(srcApp, existingApps) {
        let app = {
            name: srcApp.name,
            key: srcApp.key,
            contextPath: srcApp.contextPath
        };
        for (let retryNo = 0; retryNo < 9;) {
            if (this.checkIfAppNameKeyPathExists(existingApps, app, retryNo)) {
                retryNo++;
                app = {
                    name: [srcApp.name, retryNo].join('-'),
                    key: [srcApp.key, retryNo].join('-'),
                    contextPath: [srcApp.contextPath, retryNo].join('-')
                };
            }
            else {
                return app;
            }
        }
        return app;
    }
    /**
     * Verify versions compatibility for blueprints. If a blueprint version
     * is not compatible, a warning is shown.
     *
     * @param blueprint The blueprint to install.
     * @returns true if the installation can continue or false if it should be aborted.
     */
    async verifyBlueprintVersionsCompatibility(blueprint) {
        const api = await this.getPlatformVersion();
        if (blueprint.versioningMatrix) {
            try {
                const pluginApiVersion = blueprint.versioningMatrix[blueprint.version].api;
                if (!satisfies(api, pluginApiVersion)) {
                    return await this.showModal(blueprint, false, api);
                }
            }
            catch {
                return await this.showModal(blueprint, false, api);
            }
        }
        return true;
    }
    /**
     * Verify versions compatibility for plugins. In case a version does not exist in the
     * versioningMatrix we don't do anything due to backward compatibility. If a plugin version
     * is not compatible, a warning is shown.
     *
     * @param pluginsToInstall The list of plugins to install.
     * @returns true if the installation can continue or false if it should be aborted.
     */
    async verifyPluginVersionsCompatibility(pluginsToInstall, app) {
        const api = await this.getPlatformVersion();
        const sdk = app.manifest?.webSdkVersion;
        for (const plugin of pluginsToInstall) {
            if (plugin.versioningMatrix) {
                try {
                    const pluginSdkVersion = plugin.versioningMatrix[plugin.version].sdk;
                    const pluginApiVersion = plugin.versioningMatrix[plugin.version].api;
                    if (!satisfies(sdk, pluginSdkVersion) || !satisfies(api, pluginApiVersion)) {
                        return await this.showModal(plugin, true, api, sdk);
                    }
                }
                catch {
                    return await this.showModal(plugin, false, api, sdk);
                }
            }
        }
        return true;
    }
    /**
     * Community plugins need to verify the license agreement. If a package is a community
     * package, the license is shown.
     *
     * @param pluginsToInstall The list of plugins to install.
     * @returns true if the installation can continue.
     */
    async verifyLicenses(pluginsToInstall) {
        let _resolve;
        const result = new Promise(resolve => {
            _resolve = resolve;
        });
        pluginsToInstall = pluginsToInstall.filter(plugin => plugin.type !== PackageType.CUSTOM && plugin.type !== PackageType.OFFICIAL);
        if (pluginsToInstall.length === 0) {
            return Promise.resolve(true);
        }
        const initialState = {
            id: EcosystemWizards.LICENSE_CONFIRM,
            componentInitialState: {
                pluginsToInstall
            }
        };
        const modalOptions = { initialState };
        const wizard = this.wizardModalService.show(modalOptions);
        wizard.content.onClose.subscribe(confirmed => {
            _resolve(confirmed);
        });
        return result;
    }
    /**
     * If the plugin is archived, a warning should be shown.
     *
     * @param pluginsToInstall The list of plugins to install.
     * @returns true if the installation can continue.
     */
    async verifyArchived(pluginsToInstall) {
        let _resolve;
        const result = new Promise(resolve => {
            _resolve = resolve;
        });
        pluginsToInstall = pluginsToInstall.filter(plugin => plugin.type === PackageType.ARCHIVED);
        if (pluginsToInstall.length === 0) {
            return Promise.resolve(true);
        }
        const initialState = {
            id: EcosystemWizards.ARCHIVED_CONFIRM
        };
        const modalOptions = { initialState };
        const wizard = this.wizardModalService.show(modalOptions);
        wizard.content.onClose.subscribe(confirmed => {
            _resolve(confirmed);
        });
        return result;
    }
    /**
     * @description
     * Compares currently deployed application version with application version tagged as "latest"
     *
     * @param {string} currentApplicationVersion Deployed application version
     * @param {object} latestApp Latest application version object
     *
     * @returns {boolean} Returns true if latest version is greater than current, otherwise false
     */
    shouldUpgradePackage(currentApplicationVersion, latestApp) {
        const latestApplicationVersion = latestApp?.version;
        if (!latestApplicationVersion || !currentApplicationVersion) {
            return false;
        }
        return gt(coerce(latestApplicationVersion), coerce(currentApplicationVersion));
    }
    /**
     * @description
     * Gets an object that contains searched tag
     *
     * @param {array} applicationVersions Array with all available versions
     * @param {string} tagName Searched tag
     *
     * @returns {object} Returns an object with searched tag
     */
    getApplicationVersionObjectByTag(applicationVersions, tagName) {
        return applicationVersions?.find(element => element.tags.includes(tagName));
    }
    async getApplication(appId) {
        return (await this.applicationService.detail(appId)).data;
    }
    getApplications(customFilter = {}) {
        const filter = {
            pageSize: 2000,
            withTotalPages: true
        };
        Object.assign(filter, customFilter);
        const currentTenant = this.appStateService.currentTenant.value;
        return this.applicationService.listByTenant(currentTenant.name, filter);
    }
    async getMicroservices() {
        const apps = (await this.getApplications()).data;
        const microservices = apps.filter(app => this.isMicroservice(app));
        return microservices.sort((a, b) => a.name.localeCompare(b.name));
    }
    async getWebApplications(customFilter = {}) {
        const apps = (await this.getApplications(customFilter)).data;
        const webApps = apps.filter(app => this.isApplication(app));
        return webApps.sort((a, b) => a.name.localeCompare(b.name));
    }
    async getFeatureApplications(customFilter = {}) {
        const apps = (await this.getApplications(customFilter)).data;
        const webApps = apps.filter(app => this.isFeature(app));
        return webApps.sort((a, b) => a.name.localeCompare(b.name));
    }
    async getPackageApplications(customFilter = {}) {
        const filterCallback = app => this.isPackage(app);
        return this.getApplicationsFiltered(customFilter, filterCallback);
    }
    async getHostedAndPackageApplications(customFilter = {}) {
        const filterCallback = app => this.isPackage(app) || this.isApplication(app);
        return this.getApplicationsFiltered(customFilter, filterCallback);
    }
    async getApplicationsFiltered(customFilter = {}, filterCallback = (app) => !!app) {
        const filter = Object.assign({}, customFilter);
        const sharedFilter = Object.assign({
            availability: ApplicationAvailability.SHARED,
            type: 'HOSTED',
            pageSize: 2000
        }, customFilter);
        const [{ data: apps }, { data: shared }] = await Promise.all([
            this.getApplications(filter),
            this.applicationService.list(sharedFilter)
        ]);
        const webApps = [...apps, ...shared].filter(filterCallback);
        // an app could be subscribed to a tenant, but also have it's availability set to SHARED, in that case it would occur twice.
        const uniqWebApps = uniqBy(webApps, (app) => app.id);
        return uniqWebApps.sort((a, b) => a.name.localeCompare(b.name));
    }
    async isMicroserviceHostingAllowed() {
        const { data: apps } = await this.applicationService.listByName('feature-microservice-hosting');
        return !!apps.filter(app => app.owner?.tenant?.id === 'management').length;
    }
    canOpenAppInBrowser(app) {
        const isNotAFeature = !this.isFeature(app);
        const hasProperType = [ApplicationType.HOSTED, ApplicationType.EXTERNAL].includes(app.type);
        const isNotPackage = !this.isPackage(app);
        return isNotAFeature && hasProperType && isNotPackage;
    }
    openApp(app) {
        window.open(this.applicationService.getHref(app), '_blank', 'noopener,noreferrer');
    }
    async canDeleteApp(app) {
        return (this.isOwner(app) && (!this.isCurrentApp(app) || (await this.hasSubscribedAppParent(app))));
    }
    isOwner(app) {
        const currentTenant = this.appStateService.currentTenant.value;
        const appOwner = get(app, 'owner.tenant.id');
        return currentTenant?.name === appOwner;
    }
    isFeature(app) {
        return !!app.name.match(/feature-/);
    }
    isMicroservice(app) {
        return app.type === 'MICROSERVICE';
    }
    isExternal(app) {
        return app.type === 'EXTERNAL';
    }
    isPackage(app) {
        return app.manifest?.isPackage === true;
    }
    isPlugin(app) {
        return app.manifest?.package === 'plugin';
    }
    cancelAppCreation(app) {
        if (this.xhr) {
            this.xhr.abort();
        }
        if (app) {
            this.applicationService.delete(app);
        }
    }
    updateUploadProgress(event) {
        if (event.lengthComputable) {
            const currentProgress = this.progress.value;
            this.progress.next(currentProgress + (event.loaded / event.total) * (95 - currentProgress));
        }
    }
    setAppActiveVersion(app, activeVersionId) {
        return this.applicationService.update({ id: app.id, activeVersionId });
    }
    setPackageVersionTag(app, version, tags) {
        return this.applicationService.setPackageVersionTag(app, version, tags);
    }
    deletePackageVersion(app, params) {
        return this.applicationService.deleteVersionPackage(app, params);
    }
    getHumanizedAppName(app) {
        return this.humanizeAppName.transform(app.name).pipe(debounceTime(250), take(1)).toPromise();
    }
    createConfig(app, formGroupValue) {
        const { id, type, availability } = app;
        let config = pick(formGroupValue, ['name', 'key', 'contextPath']);
        config = {
            ...config,
            isSetup: true,
            id,
            type,
            availability
        };
        return config;
    }
    async listArchives(appId) {
        const filter = {
            pageSize: 100
        };
        return (await this.applicationService.binary(appId).list(filter)).data;
    }
    async deleteArchive(archive, app) {
        const humanizedArchiveName = await this.getHumanizedAppName(archive);
        try {
            await this.modal.confirm(gettext('Delete archive'), this.translateService.instant(gettext(`You are about to delete archive "{{ humanizedArchiveName }}". Do you want to proceed?`), { humanizedArchiveName }), Status.DANGER, { ok: gettext('Delete'), cancel: gettext('Cancel') });
            await this.applicationService.binary(app).delete(archive.id);
            this.alertService.success(gettext('Archive deleted.'));
        }
        catch (ex) {
            if (ex) {
                this.alertService.danger(get(ex, 'data.message'), ex.data);
            }
            throw new Error('Cancelled');
        }
    }
    async getArchiveManagedObject(binaryId) {
        return (await this.inventoryService.detail(binaryId)).data;
    }
    async downloadArchive(app, archive) {
        try {
            const binary = await this.getBinary(app, archive);
            const fileBinary = new Blob([binary], { type: 'application/x-zip-compressed' });
            saveAs(fileBinary, archive.name);
        }
        catch (e) {
            // empty
        }
    }
    async updateApp(app, deleteOnFailure = false) {
        try {
            return await this.applicationService.update(app);
        }
        catch (ex) {
            this.alertError(ex);
            if (deleteOnFailure) {
                await this.applicationService.delete(app.id);
                throw new EcosystemError(ERROR_TYPE.APPLICATION_CREATION_FAILED);
            }
        }
    }
    async deleteApp(app, silent = false) {
        const humanizedAppName = await this.getHumanizedAppName(app);
        if (!silent) {
            await this.modal.confirm(gettext('Delete application'), this.translateService.instant(gettext(`You are about to delete application "{{ humanizedAppName }}". Do you want to proceed?`), { humanizedAppName }), Status.DANGER, { ok: gettext('Delete'), cancel: gettext('Cancel') });
        }
        await this.applicationService.delete(app.id);
        if (!silent) {
            this.alertService.success(gettext('Application deleted.'));
        }
        this.appDeleted.emit(app);
    }
    async checkIfSubscribed(app) {
        const currentTenant = await this.tenantService.current();
        const subscribedApps = currentTenant.data.applications.references;
        return subscribedApps.some(application => application.application.id === app.id);
    }
    async subscribeApp(app) {
        const currentTenant = this.appStateService.currentTenant.value;
        try {
            await this.tenantService.subscribeApplication(currentTenant, app);
            this.alertService.success(gettext('Successfully subscribed to application.'));
        }
        catch (ex) {
            this.alertError(ex);
        }
    }
    async unsubscribeApp(app) {
        const currentTenant = this.appStateService.currentTenant.value;
        try {
            await this.tenantService.unsubscribeApplication(currentTenant, app);
            this.alertService.success(gettext('Successfully unsubscribed from application.'));
        }
        catch (ex) {
            this.alertError(ex);
        }
    }
    async isValidAppType(archive, appType) {
        try {
            const currentType = await this.getAppType(archive);
            if (currentType !== appType) {
                throw new EcosystemError(ERROR_TYPE.TYPE_VALIDATION);
            }
            else {
                this.progress.next(this.progress.value + 10);
                return true;
            }
        }
        catch (ex) {
            throw new EcosystemError(ERROR_TYPE.TYPE_VALIDATION);
        }
    }
    async uploadArchiveToApp(archive, app, isNewVersion = false) {
        let uploadOverrides;
        if (isNewVersion) {
            uploadOverrides = await this.getUploadOverrides(archive, app);
        }
        const binaryService = this.applicationService.binary(app);
        this.xhr = binaryService.uploadWithProgressXhr(archive, this.updateUploadProgress.bind(this), '', uploadOverrides);
        const binaryMo = await binaryService.getXMLHttpResponse(this.xhr);
        // TODO commented it due to: https://cumulocity.atlassian.net/browse/MTM-48553
        // Add it back when BE fixes issues with activeVersion.
        // if (isNewVersion) {
        //   return await this.getApplication(app);
        // }
        const notInitialPackage = app.applicationVersions?.length > 0;
        if (notInitialPackage) {
            return (await this.applicationService.update({ id: app.id })).data;
        }
        return (await this.setAppActiveVersion(app, (binaryMo.binaryId || binaryMo.id))).data;
    }
    async validateArchiveToAppCompatibility(archive, app) {
        const appType = await this.getAppType(archive);
        if (appType !== app.type) {
            throw new EcosystemError(ERROR_TYPE.INVALID_APPLICATION);
        }
        else {
            this.progress.next(this.progress.value + 10);
        }
        if (this.isMicroservice(app)) {
            return;
        }
        const manifest = await this.getCumulocityJson(archive);
        // A user can upload an app without a Cumulocity JSON file (e.g. a react app).
        // This is allowed and should not trigger a validation error.
        if (!manifest) {
            return;
        }
        await this.validatePackageKeyAndContextPath(manifest, app);
    }
    async getCumulocityJson(archive) {
        try {
            const c8yManifest = await this.getCumulocityJson$(archive).toPromise();
            return c8yManifest;
        }
        catch (ex) {
            return null;
        }
    }
    async createAppForArchive(archive, isPackageTypeArchive = false) {
        let isPackage = false;
        const appType = await this.getAppType(archive);
        let appModel = {};
        const supportedAppTypes = [ApplicationType.HOSTED, ApplicationType.MICROSERVICE];
        if (supportedAppTypes.includes(appType)) {
            try {
                appModel = await this.getCumulocityJson$(archive).toPromise();
                isPackage = appModel.isPackage;
            }
            catch (e) {
                // do nothing, we allow having HOSTED applications without the manifest file
            }
        }
        const name = this.getBaseNameFromArchiveOrAppModel(archive, appType, appModel);
        const clearedName = this.removeForbiddenCharacters(name);
        const key = this.getAppKey(appModel, clearedName);
        const contextPath = this.getContextPath(appModel, name);
        const appToSave = {
            type: appType,
            name,
            key,
            contextPath
        };
        if (isPackageTypeArchive && !isPackage) {
            throw new EcosystemError(ERROR_TYPE.INVALID_PACKAGE);
        }
        else if (!isPackageTypeArchive && isPackage) {
            throw new EcosystemError(ERROR_TYPE.INVALID_APPLICATION);
        }
        else if (this.isNameLengthExceeded(name, appType)) {
            const error = new Error();
            error.name = ERROR_TYPE.MICROSERVICE_NAME_TOO_LONG;
            error.message = this.translateService.instant(ERROR_MESSAGES[error.name], {
                name,
                maxChars: MICROSERVICE_NAME_MAX_LENGTH
            });
            throw error;
        }
        return (await this.applicationService.create({
            ...appToSave,
            manifest: {
                isPackage,
                ...(appModel?.package && { package: appModel.package })
            }
        })).data;
    }
    async reactivateArchive(app) {
        try {
            await this.applicationService.reactivateArchive(app.id);
            this.alertService.success(gettext('Application reactivated.'));
        }
        catch (ex) {
            this.alertError(ex);
        }
    }
    async removeOldestArchive(app, archives) {
        try {
            await this.modal.confirm(gettext('Delete oldest archive and continue'), gettext('Up to 6 archives can be saved in the platform. If you upload a new archive, the oldest archive that is not active will be deleted. Do you want to proceed?'), Status.INFO, { ok: gettext('Delete and continue') });
            const archiveToDelete = archives[archives.length - 2];
            await this.applicationService.binary(app).delete(archiveToDelete.id);
            this.alertService.success(gettext('Archive deleted.'));
        }
        catch (ex) {
            if (ex) {
                this.alertError(ex);
            }
            else {
                return Promise.reject('cancelled');
            }
        }
    }
    async deployApp(selectedPackage, formGroupValue, model) {
        // Create new app config
        const config = this.createConfig(selectedPackage, formGroupValue);
        const requestedVersion = model.selected.version;
        let cleanManifest;
        try {
            const manifest = await this.applicationService.getAppManifest(selectedPackage, requestedVersion);
            cleanManifest = omit(manifest, ['name', 'contextPath', 'key']);
        }
        catch (ex) {
            throw new EcosystemError(ERROR_TYPE.VERSION_NOT_FOUND);
        }
        config.isSetup = true;
        config.manifest = cleanManifest;
        config.availability = ApplicationAvailability.PRIVATE;
        config.manifest.isPackage = false;
        config.manifest.source = selectedPackage.id;
        config.manifest.package = 'blueprint';
        // because of a issue with SHARED availability we always should check again
        // if the app not exist already
        const allExistingApps = await this.getHostedAndPackageApplications();
        const doesAppKeyOrContextPathExist = this.checkIfAppNameKeyPathExists(allExistingApps, config);
        if (doesAppKeyOrContextPathExist) {
            throw new EcosystemError(ERROR_TYPE.ALREADY_EXIST);
        }
        // Create new app
        const newApp = (await this.applicationService.create(config)).data;
        try {
            // Binary upload can fail if SHARED package
            // in this case, catch error and fall back to
            // clone API.
            await this.uploadBinaryFromOtherPackage(selectedPackage, newApp, model.selected.binaryId, requestedVersion);
        }
        catch (error) {
            if (error?.res?.status === 404) {
                await this.fallbackToClone(newApp, selectedPackage, requestedVersion);
            }
        }
        // update the icon if a custom one is selected
        if (formGroupValue.icon) {
            await this.applicationService.update({
                id: newApp.id,
                config: { icon: formGroupValue.icon }
            });
        }
        return newApp;
    }
    async fallbackToClone(application, selectedPackage, requestedVersion) {
        let wasSuccess = true;
        let clonedPkg;
        try {
            clonedPkg = (await this.applicationService.clone(selectedPackage, requestedVersion)).data;
            await this.uploadBinaryFromOtherPackage(selectedPackage, application, clonedPkg.activeVersionId, requestedVersion, clonedPkg);
        }
        catch (error) {
            this.alertError(error);
            wasSuccess = false;
        }
        finally {
            await this.deleteApp(clonedPkg, true);
        }
        return wasSuccess;
    }
    async uploadBinaryFromOtherPackage(selectedPackage, applicationToUploadBinaryTo, binaryId, requestedVersion, useBinariesFrom) {
        const { data: binaryDetails } = await this.inventoryService.detail(binaryId);
        // Get binary from specific package version
        const binary = await this.getBinary(useBinariesFrom || selectedPackage, {
            id: binaryId
        });
        // Create zip
        const fileBinary = new Blob([binary], { type: binaryDetails.contentType });
        const file = new File([fileBinary], binaryDetails.name, {
            type: binaryDetails.contentType
        });
        // Upload binary to new app
        await this.uploadArchiveToApp(file, applicationToUploadBinaryTo);
        // update the app manifest
        await this.updateAppManifest(applicationToUploadBinaryTo, selectedPackage, requestedVersion);
    }
    getAppState(app) {
        if (!this.isOwner(app)) {
            return APP_STATE.SUBSCRIBED;
        }
        else if (this.isUnpacked(app)) {
            return APP_STATE.UNPACKED;
        }
        else if (app.type === ApplicationType.EXTERNAL) {
            return APP_STATE.EXTERNAL;
        }
        return APP_STATE.CUSTOM;
    }
    getPackageContentState(app) {
        if (!this.isPackage(app)) {
            return;
        }
        if (this.isPackageBlueprint(app)) {
            return APP_STATE.PACKAGE_BLUEPRINT;
        }
        if (this.isPluginsPackage(app)) {
            return APP_STATE.PACKAGE_PLUGIN;
        }
        return APP_STATE.PACKAGE_UNKNOWN;
    }
    isPackageBlueprint(app) {
        return this.isPackage(app) && app.manifest.package === 'blueprint';
    }
    isPluginsPackage(app) {
        return this.isPackage(app) && app.manifest.package === 'plugin';
    }
    isUnpacked(app) {
        return !!app.manifest?.source;
    }
    hasExports(app) {
        return !!app.manifest?.exports?.length;
    }
    isApplication(app) {
        return (app.type !== ApplicationType.MICROSERVICE && !this.isFeature(app) && !this.isPackage(app));
    }
    isCustomMicroservice(app) {
        return this.isOwner(app) && app.type === ApplicationType.MICROSERVICE;
    }
    async getBinary(app, archive) {
        let binary;
        try {
            const res = await this.applicationService.binary(app).downloadArchive(archive.id);
            binary = await res.arrayBuffer();
        }
        catch (ex) {
            const msg = gettext('Could not get the binary.');
            this.alertService.danger(msg);
        }
        return binary;
    }
    async isOverwrittenByCustomApp(app) {
        return !this.isOwner(app) && (await this.hasSubscribedAppParent(app));
    }
    async hasSubscribedAppParent(app) {
        const appsGroupedByContextPath = await this.appsGroupedByContextPath$.pipe(take(1)).toPromise();
        return app.contextPath && appsGroupedByContextPath[app.contextPath]?.length === 2;
    }
    /**
     * @deprecated
     */
    setAvailabilityToPrivateIfNotSetAlready(app) {
        app.availability = ApplicationAvailability.PRIVATE;
        return app;
    }
    /**
     * Shows an error dialog.
     * @param error Either a server error or an internal [[EcosystemError]].
     */
    alertError(error) {
        if (error instanceof EcosystemError) {
            this.alertService.danger(error.message);
        }
        else {
            this.alertService.addServerFailure(error);
        }
    }
    async validatePackageKeyAndContextPath(manifest, app) {
        const contextPath = get(manifest, 'contextPath');
        const appKey = get(manifest, 'key');
        if (contextPath !== app.contextPath || appKey !== app.key) {
            throw new EcosystemError(ERROR_TYPE.KEY_OR_CONTEXT_PATH_MISMATCH);
        }
    }
    filterContainString(name, filterTerm) {
        const term = filterTerm.toLowerCase().trim();
        return name && name.toLowerCase().indexOf(term) > -1;
    }
    async updateAppManifest(application, selectedPackage, requestedVersion) {
        const { id } = application;
        const cleanedApp = this.removeAppProperties(application);
        let manifest = selectedPackage.manifest || {};
        if (requestedVersion) {
            try {
                const versionedAppManifest = await this.applicationService.getAppManifest(selectedPackage, requestedVersion);
                manifest = versionedAppManifest;
            }
            catch (ex) {
                throw new EcosystemError(ERROR_TYPE.VERSION_NOT_FOUND);
            }
        }
        cleanedApp.manifest = manifest;
        cleanedApp.manifest.isPackage = false;
        cleanedApp.manifest.source = selectedPackage.id;
        return await this.applicationService
            .binary(id)
            .updateFiles([{ path: CUMULOCITY_JSON, contents: JSON.stringify(cleanedApp) }]);
    }
    /**
     * Creates object containing properties for filtering applications on lists.
     *
     * @param {object} app Application to create filter properties from.
     * @returns {object} Properties to filter by applications list.
     */
    getAppFilterProps(app) {
        return {
            type: this.pluginService.getPackageType(app),
            availability: this.getAppState(app)?.label,
            content: this.getPackageContentState(app)?.label
        };
    }
    checkIfAppNameKeyPathExists(existingApps, app, retryNo) {
        if (isUndefined(retryNo)) {
            return existingApps.find(existingApp => existingApp.name === app.name ||
                existingApp.key === app.key ||
                existingApp.contextPath === app.contextPath);
        }
        return existingApps.find(existingApp => existingApp.name === app.name ||
            existingApp.key === app.key ||
            existingApp.contextPath === app.contextPath ||
            existingApp.name === [app.name, retryNo].join('-') ||
            existingApp.key === [app.key, retryNo].join('-') ||
            existingApp.contextPath === [app.contextPath, retryNo].join('-'));
    }
    async showModal(packageType, isPlugin, apiVersion, sdkVersion) {
        try {
            const messages = {
                plugin: {
                    title: gettext('Plugin installation'),
                    body: sdkVersion
                        ? gettext('The current version of the plugin that you are trying to install does not satisfy the requirements for the following API version "{{ apiVersion }}" or SDK version "{{ sdkVersion }}". Do you want to proceed?')
                        : gettext('The current version of the plugin that you are trying to install does not satisfy the requirements for the following API version "{{ apiVersion }}". Do you want to proceed?')
                },
                blueprint: {
                    title: gettext('Blueprint installation'),
                    body: sdkVersion
                        ? gettext('The current version of the blueprint that you are trying to install does not satisfy the requirements for the following API version "{{ apiVersion }}" or SDK version "{{ sdkVersion }}". Do you want to proceed?')
                        : gettext('The current version of the blueprint that you are trying to install does not satisfy the requirements for the following API version "{{ apiVersion }}". Do you want to proceed?')
                }
            };
            const entityType = isPlugin ? 'plugin' : 'blueprint';
            const selectedMessages = messages[entityType];
            const translatedBody = this.translateService.instant(selectedMessages.body, {
                name: packageType.name,
                apiVersion,
                sdkVersion
            });
            await this.modal.confirm(selectedMessages.title, translatedBody, 'warning', {
                ok: gettext('Continue'),
                cancel: gettext('Cancel')
            });
        }
        catch {
            // modal canceled
            return false;
        }
        return true;
    }
    async getPlatformVersion() {
        return await this.appStateService.state$
            .pipe(take(1), map(state => state?.versions?.backend), filter(backendVersion => !!backendVersion))
            .toPromise();
    }
    getAppKey(appModel, name) {
        let key = appModel?.key;
        if (!key) {
            key = `${kebabCase(name)}-key`;
        }
        return key;
    }
    getContextPath(appModel, name) {
        return appModel?.contextPath || name.toLowerCase();
    }
    removeForbiddenCharacters(str) {
        return str.replace(/[^a-zA-Z0-9-_]/g, '');
    }
    isCurrentApp(app) {
        const currentApp = this.appStateService.state.app;
        return currentApp.contextPath === app.contextPath;
    }
    getCumulocityJson$(archive) {
        return this.zipService.getJsonData(archive, {
            filename: CUMULOCITY_JSON
        });
    }
    getAppType(archive) {
        return this.getCumulocityJson$(archive)
            .toPromise()
            .then(data => get(data, 'type') ||
            (get(data, 'apiVersion') ? ApplicationType.MICROSERVICE : ApplicationType.HOSTED))
            .catch(() => ApplicationType.HOSTED);
    }
    getBaseNameFromArchiveOrAppModel(archive, appType, appModel) {
        let baseName = appModel?.name || archive.name.replace(/\.zip$/i, '');
        if (appType === 'MICROSERVICE') {
            baseName = this.removeVersionFromName(baseName);
        }
        return baseName;
    }
    removeAppProperties(app) {
        const tempApp = cloneDeep(app);
        const propertiesToRemove = ['id', 'owner', 'activeVersionId', 'self', 'type'];
        propertiesToRemove.forEach(prop => delete tempApp[prop]);
        return tempApp;
    }
    async getUploadOverrides(archive, app) {
        const { version } = await this.getCumulocityJson$(archive).toPromise();
        const isInitialPackage = app.applicationVersions?.length === 0;
        return {
            listUrl: 'versions',
            headers: {
                Accept: 'application/vnd.com.nsn.cumulocity.applicationVersion+json;charset=UTF-8;ver=0.9'
            },
            bodyFileProperty: 'applicationBinary',
            requestBody: {
                applicationVersion: { version, ...(isInitialPackage && { tags: ['latest'] }) }
            }
        };
    }
    removeVersionFromName(name) {
        const versionRegExp = /-\d+\.\d+\.\d+(\.\d+)?(-\d+)?(.*)$/;
        return name.replace(versionRegExp, '');
    }
    isNameLengthExceeded(name, appType) {
        return name.length > MICROSERVICE_NAME_MAX_LENGTH && appType === ApplicationType.MICROSERVICE;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: EcosystemService, deps: [{ token: i1.ModalService }, { token: i1.AlertService }, { token: i1.HumanizeAppNamePipe }, { token: i3.TranslateService }, { token: i3$1.ApplicationService }, { token: i1.AppStateService }, { token: i1.ZipService }, { token: i3$1.TenantService }, { token: i3$1.InventoryService }, { token: i1.WizardModalService }, { token: i1.PluginsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: EcosystemService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: EcosystemService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }], ctorParameters: () => [{ type: i1.ModalService }, { type: i1.AlertService }, { type: i1.HumanizeAppNamePipe }, { type: i3.TranslateService }, { type: i3$1.ApplicationService }, { type: i1.AppStateService }, { type: i1.ZipService }, { type: i3$1.TenantService }, { type: i3$1.InventoryService }, { type: i1.WizardModalService }, { type: i1.PluginsService }] });

class PackageAvailabilityService {
    constructor(appState, alert, modal, application, gainsightService, translateService) {
        this.appState = appState;
        this.alert = alert;
        this.modal = modal;
        this.application = application;
        this.gainsightService = gainsightService;
        this.translateService = translateService;
        this.CURRENT_LOCATION = location.href;
        this.availabilities = [
            { label: gettext('Private`package availability`'), value: ApplicationAvailability.PRIVATE },
            { label: gettext('Market`package availability`'), value: ApplicationAvailability.MARKET },
            { label: gettext('Shared`package availability`'), value: ApplicationAvailability.SHARED }
        ];
    }
    async askIfAvailabilityShouldBeSetTo(applicationPackage, availability) {
        // availability does not matter for tenant that do not have or can create subtenants
        if (!this.appState.currentTenant.value?.allowCreateTenants) {
            return applicationPackage;
        }
        try {
            await this.openAvailabilityModal(availability);
            // user confirmed changing availability
            return await this.setAvailability(applicationPackage, availability);
        }
        catch {
            // user canceled changing availability
            return applicationPackage;
        }
    }
    async setAvailability(applicationPackage, availability) {
        try {
            const { data: app } = await this.application.updateApplicationAvailability(applicationPackage, availability);
            this.alert.success(gettext('Updated package availability.'));
            this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.AVAILABILITY, {
                action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.AVAILABILITY_CHANGE,
                result: availability.toString().toLocaleLowerCase(),
                url: this.CURRENT_LOCATION
            });
            return app;
        }
        catch (e) {
            this.alert.warning(gettext('Failed to set package availability.'));
            this.alert.addServerFailure(e);
            this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.AVAILABILITY, {
                action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.AVAILABILITY_CHANGE,
                result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
                url: this.CURRENT_LOCATION
            });
            return applicationPackage;
        }
    }
    getConfirmationBody(availability) {
        switch (availability) {
            case ApplicationAvailability.SHARED:
                return gettext('Do you want to set the package availability to "Shared"? This will make the package available to all subtenants without explicitly subscribing the package.');
            case ApplicationAvailability.MARKET:
                return gettext('Do you want to set the package availability to "Market"? This will make the package available to your own tenant and needs to be subscribed to subtenants individually.');
            case ApplicationAvailability.PRIVATE:
                return gettext('Do you want to set the package availability to "Private"? This will make the package only available to your own tenant.');
            default:
                return '';
        }
    }
    async openAvailabilityModal(availability) {
        const body = this.getConfirmationBody(availability);
        const availabilityLabel = this.availabilities.find(obj => obj.value === availability).label;
        await this.modal.confirm(gettext('Package availability'), body, 'info', {
            ok: this.translateService.instant(gettext('Set to "{{ packageAvailability }}"'), {
                packageAvailability: this.translateService.instant(availabilityLabel)
            }),
            cancel: gettext('Cancel')
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PackageAvailabilityService, deps: [{ token: i1.AppStateService }, { token: i1.AlertService }, { token: i1.ModalService }, { token: i3$1.ApplicationService }, { token: i1.GainsightService }, { token: i3.TranslateService }], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PackageAvailabilityService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PackageAvailabilityService, decorators: [{
            type: Injectable,
            args: [{ providedIn: 'root' }]
        }], ctorParameters: () => [{ type: i1.AppStateService }, { type: i1.AlertService }, { type: i1.ModalService }, { type: i3$1.ApplicationService }, { type: i1.GainsightService }, { type: i3.TranslateService }] });

class AddApplicationComponent {
    constructor(ecosystemService, alertService, applicationService, wizardComponent, translateService, packageAvailability) {
        this.ecosystemService = ecosystemService;
        this.alertService = alertService;
        this.applicationService = applicationService;
        this.wizardComponent = wizardComponent;
        this.translateService = translateService;
        this.packageAvailability = packageAvailability;
        this.canGoBack = false;
        this.applicationType = 'application';
        this.canOpenInBrowser = false;
        this.selectedAvailability = ApplicationAvailability.PRIVATE;
        this.availabilityHelpPopoverText = gettext(`
      <p class="m-b-8"><b>Shared</b> availability will make the package available to all subtenants without explicitly subscribing the package.</p>
      <p class="m-b-8"><b>Market</b> availability will make the package available to your own tenant and needs to be subscribed to subtenants individually.</p>
      <p class="m-b-8"><b>Private</b> availability will make the package only available to your own tenant.</p>
  `);
        this.uploadCanceled = false;
    }
    get progress() {
        return this.ecosystemService.progress;
    }
    onFileDroppedEvent(event) {
        if (event && event.length > 0) {
            const file = event[0].file;
            this.onFile(file);
        }
    }
    async onFile(file) {
        this.isLoading = true;
        this.errorMessage = null;
        this.progress.next(0);
        try {
            this.createdApp = await this.createApplicationHandler(file);
            if (this.applicationType === 'package') {
                this.createdApp = await this.packageAvailability.setAvailability(this.createdApp, this.selectedAvailability);
            }
            await this.uploadApplicationHandler(file, this.createdApp);
            this.canOpenInBrowser = this.ecosystemService.canOpenAppInBrowser(this.createdApp);
            this.isAppCreated = true;
        }
        catch (ex) {
            this.ecosystemService.cancelAppCreation(this.createdApp);
            this.createdApp = null;
            this.dropAreaComponent.onDelete();
            // prepare translation of static message if it exists
            const staticErrorMessage = ERROR_MESSAGES[ex.message] && this.translateService.instant(ERROR_MESSAGES[ex.message]);
            // if there is no static message, use dynamic one from the exception
            this.errorMessage = staticErrorMessage ?? ex.message;
            if (!this.errorMessage && !this.uploadCanceled) {
                this.alertService.addServerFailure(ex);
            }
        }
        this.progress.next(100);
        this.isLoading = false;
    }
    getHref(app) {
        return this.applicationService.getHref(app);
    }
    cancel() {
        this.cancelFileUpload();
        this.wizardComponent.close();
    }
    done() {
        this.wizardComponent.close();
    }
    back() {
        this.wizardComponent.reset();
    }
    cancelFileUpload() {
        this.uploadCanceled = true;
        this.ecosystemService.cancelAppCreation(this.createdApp);
        this.createdApp = null;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AddApplicationComponent, deps: [{ token: EcosystemService }, { token: i1.AlertService }, { token: i3$1.ApplicationService }, { token: i1.WizardComponent }, { token: i3.TranslateService }, { token: PackageAvailabilityService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: AddApplicationComponent, isStandalone: true, selector: "c8y-add-application", inputs: { headerText: "headerText", headerIcon: "headerIcon", successText: "successText", createApplicationHandler: "createApplicationHandler", uploadApplicationHandler: "uploadApplicationHandler", canGoBack: "canGoBack", applicationType: "applicationType" }, viewQueries: [{ propertyName: "dropAreaComponent", first: true, predicate: DropAreaComponent, descendants: true }], ngImport: i0, template: "<c8y-wizard-header>\n  <i [c8yIcon]=\"headerIcon\"></i>\n  <h4 id=\"modal-title\">{{ headerText | translate }}</h4>\n</c8y-wizard-header>\n\n<c8y-wizard-body>\n  <p class=\"p-16 text-center text-medium separator-bottom sticky-top bg-component\">\n    {{ 'Upload a *.zip file' | translate }}\n  </p>\n  <c8y-form-group\n    class=\"m-t-16 m-l-auto m-r-auto\"\n    style=\"max-width: 265px\"\n    id=\"modal-body\"\n    *ngIf=\"!isAppCreated; else appCreated\"\n    [hasError]=\"!!errorMessage\"\n  >\n    <c8y-drop-area\n      class=\"drop-area\"\n      (dropped)=\"onFileDroppedEvent($event)\"\n      [accept]=\"'.zip'\"\n      [loading]=\"isLoading\"\n      [maxAllowedFiles]=\"1\"\n      [progress]=\"progress | async\"\n    ></c8y-drop-area>\n    <c8y-messages>\n      <c8y-message *ngIf=\"errorMessage\">\n        {{ errorMessage | translate }}\n      </c8y-message>\n    </c8y-messages>\n  </c8y-form-group>\n  <div class=\"card-block\" *ngIf=\"applicationType === 'package'\">\n    <c8y-form-group>\n      <label\n        class=\"m-r-8 d-inline-block\"\n        id=\"availabilitySelectorLabel\"\n        for=\"availabilitySelector\"\n      >\n        {{ 'Select extension availability' | translate }}\n      </label>\n      <button\n        class=\"btn-help btn-help--sm\"\n        [attr.aria-label]=\"'Help' | translate\"\n        [popover]=\"availabilityHelpPopover\"\n        placement=\"top\"\n        triggers=\"focus\"\n        type=\"button\"\n      ></button>\n      <div class=\"c8y-select-wrapper\">\n        <select\n          class=\"form-control\"\n          id=\"availabilitySelector\"\n          name=\"availabilitySelector\"\n          [(ngModel)]=\"selectedAvailability\"\n        >\n          <option\n            *ngFor=\"let availability of packageAvailability.availabilities\"\n            [ngValue]=\"availability.value\"\n          >\n            {{ availability.label | translate }}\n          </option>\n        </select>\n      </div>\n    </c8y-form-group>\n  </div>\n  <ng-template #appCreated>\n    <div\n      class=\"d-flex a-i-center j-c-center\"\n      style=\"min-height: 285px\"\n    >\n      <c8y-operation-result\n        class=\"lead\"\n        type=\"success\"\n        text=\"{{ successText | translate }}\"\n        [vertical]=\"true\"\n        [size]=\"84\"\n      ></c8y-operation-result>\n    </div>\n  </ng-template>\n  <ng-template #availabilityHelpPopover>\n    <div [innerHtml]=\"availabilityHelpPopoverText | translate\"></div>\n  </ng-template>\n</c8y-wizard-body>\n\n<c8y-wizard-footer>\n  <button\n    class=\"btn btn-default\"\n    title=\"{{ 'Back' | translate }}\"\n    type=\"button\"\n    (click)=\"back()\"\n    *ngIf=\"!isAppCreated && canGoBack\"\n    translate\n  >\n    Back\n  </button>\n  <button\n    class=\"btn btn-default\"\n    title=\"{{ 'Cancel' | translate }}\"\n    type=\"button\"\n    (click)=\"cancel()\"\n    *ngIf=\"!isAppCreated\"\n    translate\n  >\n    Cancel\n  </button>\n  <button\n    class=\"btn btn-default\"\n    title=\"{{ 'Done' | translate }}\"\n    type=\"button\"\n    (click)=\"done()\"\n    *ngIf=\"isAppCreated\"\n    translate\n  >\n    Done\n  </button>\n  <a\n    class=\"btn btn-primary\"\n    title=\"{{ 'Open' | translate }}\"\n    target=\"_blank\"\n    (click)=\"$event.stopPropagation()\"\n    *ngIf=\"isAppCreated && canOpenInBrowser\"\n    [href]=\"getHref(createdApp)\"\n    rel=\"noopener noreferrer\"\n  >\n    <i\n      class=\"m-r-4\"\n      c8yIcon=\"external-link\"\n    ></i>\n    {{ 'Open' | translate }}\n  </a>\n</c8y-wizard-footer>\n", dependencies: [{ kind: "component", type: WizardHeaderComponent, selector: "c8y-wizard-header" }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: WizardBodyComponent, selector: "c8y-wizard-body" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: DropAreaComponent, selector: "c8y-drop-area", inputs: ["formControl", "title", "message", "icon", "loadingMessage", "forceHideList", "alwaysShow", "clickToOpen", "loading", "progress", "maxAllowedFiles", "files", "maxFileSizeInMegaBytes", "accept"], outputs: ["dropped"] }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "directive", type: PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1$1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: OperationResultComponent, selector: "c8y-operation-result", inputs: ["text", "vertical", "size", "type"] }, { kind: "component", type: WizardFooterComponent, selector: "c8y-wizard-footer" }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: AddApplicationComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-add-application', imports: [
                        WizardHeaderComponent,
                        IconDirective,
                        WizardBodyComponent,
                        NgIf,
                        FormGroupComponent,
                        DropAreaComponent,
                        MessagesComponent,
                        MessageDirective,
                        PopoverDirective,
                        FormsModule,
                        NgFor,
                        OperationResultComponent,
                        WizardFooterComponent,
                        C8yTranslateDirective,
                        C8yTranslatePipe,
                        AsyncPipe
                    ], template: "<c8y-wizard-header>\n  <i [c8yIcon]=\"headerIcon\"></i>\n  <h4 id=\"modal-title\">{{ headerText | translate }}</h4>\n</c8y-wizard-header>\n\n<c8y-wizard-body>\n  <p class=\"p-16 text-center text-medium separator-bottom sticky-top bg-component\">\n    {{ 'Upload a *.zip file' | translate }}\n  </p>\n  <c8y-form-group\n    class=\"m-t-16 m-l-auto m-r-auto\"\n    style=\"max-width: 265px\"\n    id=\"modal-body\"\n    *ngIf=\"!isAppCreated; else appCreated\"\n    [hasError]=\"!!errorMessage\"\n  >\n    <c8y-drop-area\n      class=\"drop-area\"\n      (dropped)=\"onFileDroppedEvent($event)\"\n      [accept]=\"'.zip'\"\n      [loading]=\"isLoading\"\n      [maxAllowedFiles]=\"1\"\n      [progress]=\"progress | async\"\n    ></c8y-drop-area>\n    <c8y-messages>\n      <c8y-message *ngIf=\"errorMessage\">\n        {{ errorMessage | translate }}\n      </c8y-message>\n    </c8y-messages>\n  </c8y-form-group>\n  <div class=\"card-block\" *ngIf=\"applicationType === 'package'\">\n    <c8y-form-group>\n      <label\n        class=\"m-r-8 d-inline-block\"\n        id=\"availabilitySelectorLabel\"\n        for=\"availabilitySelector\"\n      >\n        {{ 'Select extension availability' | translate }}\n      </label>\n      <button\n        class=\"btn-help btn-help--sm\"\n        [attr.aria-label]=\"'Help' | translate\"\n        [popover]=\"availabilityHelpPopover\"\n        placement=\"top\"\n        triggers=\"focus\"\n        type=\"button\"\n      ></button>\n      <div class=\"c8y-select-wrapper\">\n        <select\n          class=\"form-control\"\n          id=\"availabilitySelector\"\n          name=\"availabilitySelector\"\n          [(ngModel)]=\"selectedAvailability\"\n        >\n          <option\n            *ngFor=\"let availability of packageAvailability.availabilities\"\n            [ngValue]=\"availability.value\"\n          >\n            {{ availability.label | translate }}\n          </option>\n        </select>\n      </div>\n    </c8y-form-group>\n  </div>\n  <ng-template #appCreated>\n    <div\n      class=\"d-flex a-i-center j-c-center\"\n      style=\"min-height: 285px\"\n    >\n      <c8y-operation-result\n        class=\"lead\"\n        type=\"success\"\n        text=\"{{ successText | translate }}\"\n        [vertical]=\"true\"\n        [size]=\"84\"\n      ></c8y-operation-result>\n    </div>\n  </ng-template>\n  <ng-template #availabilityHelpPopover>\n    <div [innerHtml]=\"availabilityHelpPopoverText | translate\"></div>\n  </ng-template>\n</c8y-wizard-body>\n\n<c8y-wizard-footer>\n  <button\n    class=\"btn btn-default\"\n    title=\"{{ 'Back' | translate }}\"\n    type=\"button\"\n    (click)=\"back()\"\n    *ngIf=\"!isAppCreated && canGoBack\"\n    translate\n  >\n    Back\n  </button>\n  <button\n    class=\"btn btn-default\"\n    title=\"{{ 'Cancel' | translate }}\"\n    type=\"button\"\n    (click)=\"cancel()\"\n    *ngIf=\"!isAppCreated\"\n    translate\n  >\n    Cancel\n  </button>\n  <button\n    class=\"btn btn-default\"\n    title=\"{{ 'Done' | translate }}\"\n    type=\"button\"\n    (click)=\"done()\"\n    *ngIf=\"isAppCreated\"\n    translate\n  >\n    Done\n  </button>\n  <a\n    class=\"btn btn-primary\"\n    title=\"{{ 'Open' | translate }}\"\n    target=\"_blank\"\n    (click)=\"$event.stopPropagation()\"\n    *ngIf=\"isAppCreated && canOpenInBrowser\"\n    [href]=\"getHref(createdApp)\"\n    rel=\"noopener noreferrer\"\n  >\n    <i\n      class=\"m-r-4\"\n      c8yIcon=\"external-link\"\n    ></i>\n    {{ 'Open' | translate }}\n  </a>\n</c8y-wizard-footer>\n" }]
        }], ctorParameters: () => [{ type: EcosystemService }, { type: i1.AlertService }, { type: i3$1.ApplicationService }, { type: i1.WizardComponent }, { type: i3.TranslateService }, { type: PackageAvailabilityService }], propDecorators: { headerText: [{
                type: Input
            }], headerIcon: [{
                type: Input
            }], successText: [{
                type: Input
            }], createApplicationHandler: [{
                type: Input
            }], uploadApplicationHandler: [{
                type: Input
            }], canGoBack: [{
                type: Input
            }], applicationType: [{
                type: Input
            }], dropAreaComponent: [{
                type: ViewChild,
                args: [DropAreaComponent]
            }] } });

class TranslatePackageLabelPipe {
    constructor(translate) {
        this.translate = translate;
    }
    transform(rawPackageLabel) {
        const isOneOfTheKnownOnes = !!PACKAGE_TYPE_LABELS[rawPackageLabel?.toUpperCase()];
        if (isOneOfTheKnownOnes) {
            return this.translate.instant(PACKAGE_TYPE_LABELS[rawPackageLabel?.toUpperCase()].label);
        }
        return rawPackageLabel;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TranslatePackageLabelPipe, deps: [{ token: i3.TranslateService }], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: TranslatePackageLabelPipe, isStandalone: true, name: "translatePackageLabel" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: TranslatePackageLabelPipe, decorators: [{
            type: Pipe,
            args: [{ name: 'translatePackageLabel' }]
        }], ctorParameters: () => [{ type: i3.TranslateService }] });

class ApplicationCardComponent {
    get openButtonTitle() {
        return !this.disableOpenInBrowser
            ? gettext('Open')
            : gettext('This application is overridden.');
    }
    constructor(applicationService, ecosystemService, alertService, router, wizardModalService, alert, pluginService, gainsightService) {
        this.applicationService = applicationService;
        this.ecosystemService = ecosystemService;
        this.alertService = alertService;
        this.router = router;
        this.wizardModalService = wizardModalService;
        this.alert = alert;
        this.pluginService = pluginService;
        this.gainsightService = gainsightService;
        this.CURRENT_LOCATION = location.href;
        this.canEdit = true;
        this.onAppDeleted = new EventEmitter();
        this.onAppCloned = new EventEmitter();
        this.packageTypeLabels = PACKAGE_TYPE_LABELS;
        this.PACKAGE_TYPE = PackageType;
        this.UNPACKED_LABEL = APP_STATE.UNPACKED.label;
        this.CANNOT_DELETE_HINT = gettext(`Subscribed or current applications can't be deleted. Delete the application on the parent tenant or unsubscribe it from the current.`);
        this.PACKAGE_CONTENT_UNDETERMINED_LABEL = gettext('Package contents could not be determined.');
    }
    async ngOnInit() {
        this.appState = this.ecosystemService.getAppState(this.app);
        this.canOpenInBrowser = this.ecosystemService.canOpenAppInBrowser(this.app);
        this.packageType = this.pluginService.getPackageType(this.app);
        this.disableOpenInBrowser =
            this.canOpenInBrowser && (await this.ecosystemService.isOverwrittenByCustomApp(this.app));
        this.canDelete = await this.ecosystemService.canDeleteApp(this.app);
        this.isPackage = this.ecosystemService.isPackage(this.app);
        this.packageContentState = this.ecosystemService.getPackageContentState(this.app);
        this.isPlugin = this.ecosystemService.isPlugin(this.app);
        this.isFeature = this.ecosystemService.isFeature(this.app);
        this.isMicroservice = this.ecosystemService.isMicroservice(this.app);
        this.isExternal = this.ecosystemService.isExternal(this.app);
        this.canClone = !this.isMicroservice && !this.isPlugin;
        this.isUnpacked = this.ecosystemService.isUnpacked(this.app);
        this.isShowVersion = this.shouldShowVersion();
        await this.applicationUpdateCheck();
    }
    shouldShowVersion() {
        return !!this.app.manifest?.version;
    }
    detail() {
        this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.APPLICATION_CARD, {
            component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.APPLICATION_CARD,
            action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.EDIT,
            url: this.CURRENT_LOCATION
        });
        if (this.isMicroservice) {
            this.router.navigateByUrl(`/ecosystem/microservice/microservices/${this.app.id}`);
            return;
        }
        if (this.isPackage) {
            this.router.navigateByUrl(`/ecosystem/extension/extensions/${this.app.id}`);
            return;
        }
        if (this.isFeature) {
            this.router.navigateByUrl(`/ecosystem/application/features/${this.app.id}`);
            return;
        }
        this.router.navigateByUrl(`/ecosystem/application/applications/${this.app.id}`);
    }
    openApp() {
        this.ecosystemService.openApp(this.app);
    }
    async delete() {
        try {
            await this.ecosystemService.deleteApp(this.app);
            this.onAppDeleted.emit();
            this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.APPLICATION_CARD, {
                component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.APPLICATION_CARD,
                action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DELETE,
                url: this.CURRENT_LOCATION
            });
        }
        catch (ex) {
            if (ex) {
                this.alertService.addServerFailure(ex);
                this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.APPLICATION_CARD, {
                    component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.APPLICATION_CARD,
                    result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
                    url: this.CURRENT_LOCATION
                });
            }
        }
    }
    async clone() {
        const wizardConfig = {
            headerText: 'Add Application',
            headerIcon: 'c8y-atom'
        };
        const initialState = {
            wizardConfig,
            componentInitialState: {
                selectedApp: new BehaviorSubject(this.app)
            },
            id: 'duplicateApplication'
        };
        const modalOptions = { initialState };
        const modalRef = this.wizardModalService.show(modalOptions);
        modalRef.content.onClose.subscribe(() => {
            this.onAppCloned.next();
        });
        this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.APPLICATION_CARD, {
            component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.APPLICATION_CARD,
            action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.CLONE,
            url: this.CURRENT_LOCATION
        });
    }
    async applicationUpdateCheck() {
        if (this.app.manifest?.source) {
            try {
                this.blueprintApplicationVersion = (await this.applicationService.listVersions(this.app.manifest?.source)).data;
                this.latestApplicationVersion = this.ecosystemService.getApplicationVersionObjectByTag(this.blueprintApplicationVersion, 'latest');
                this.shouldUpgradePackage = this.ecosystemService.shouldUpgradePackage(this.app.manifest?.version, this.latestApplicationVersion);
            }
            catch (error) {
                if (!this.blueprintApplicationVersion) {
                    return;
                }
                this.alert.addServerFailure(error);
            }
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ApplicationCardComponent, deps: [{ token: i3$1.ApplicationService }, { token: EcosystemService }, { token: i1.AlertService }, { token: i4.Router }, { token: i1.WizardModalService }, { token: i1.AlertService }, { token: i1.PluginsService }, { token: i1.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: ApplicationCardComponent, isStandalone: true, selector: "c8y-application-card", inputs: { app: "app", canEdit: "canEdit" }, outputs: { onAppDeleted: "onAppDeleted", onAppCloned: "onAppCloned" }, ngImport: i0, template: "<div\n  class=\"card pointer card--d-col notFeature\"\n  data-cy=\"application-card--extensions-list\"\n  *ngIf=\"!isFeature\"\n>\n  <div\n    class=\"card-block text-center card-column-40\"\n    data-cy=\"application-card--package-name\"\n    (click)=\"detail()\"\n  >\n    <button\n      class=\"card__ribbon btn-clean\"\n      [attr.aria-label]=\"\n        (app.label || app.manifest?.label | translatePackageLabel) +\n        ': ' +\n        (packageTypeLabels[packageType].tooltip | translate)\n      \"\n      tooltip=\"{{ packageTypeLabels[packageType].tooltip | translate }}\"\n      placement=\"right\"\n      type=\"button\"\n      *ngIf=\"packageType !== PACKAGE_TYPE.CUSTOM\"\n      [delay]=\"500\"\n    >\n      <span\n        [ngClass]=\"{\n          'bg-info': packageType === PACKAGE_TYPE.COMMUNITY,\n          'bg-primary': packageType === PACKAGE_TYPE.OFFICIAL,\n          'bg-warning': packageType === PACKAGE_TYPE.ARCHIVED\n        }\"\n      >\n        {{ app.label || app.manifest?.label | translatePackageLabel }}\n      </span>\n    </button>\n    <div class=\"card-appicon\">\n      <c8y-app-icon\n        *ngIf=\"!isPackage && !isFeature && !isMicroservice && !isExternal\"\n        [app]=\"app\"\n        [contextPath]=\"app.contextPath\"\n        [name]=\"app.name\"\n      ></c8y-app-icon>\n      <i\n        c8yIcon=\"big-parcel\"\n        *ngIf=\"isPackage\"\n      ></i>\n      <i\n        c8yIcon=\"microchip\"\n        *ngIf=\"isMicroservice\"\n      ></i>\n      <i\n        c8yIcon=\"globe1\"\n        *ngIf=\"isExternal\"\n      ></i>\n    </div>\n    <div style=\"line-height: 1.3\">\n      <p class=\"e2e-appCardName text-medium text-break-word\">\n        {{ app | humanizeAppName | async }}\n      </p>\n      <ng-container *ngIf=\"isShowVersion\">\n        <p class=\"small text-muted\">\n          <em>{{ app.manifest.version }}</em>\n          <button\n            class=\"btn-clean m-l-4\"\n            [attr.aria-label]=\"'Update available' | translate\"\n            [tooltip]=\"'Update available' | translate\"\n            *ngIf=\"shouldUpgradePackage && isUnpacked\"\n          >\n            <i\n              class=\"text-warning icon-16\"\n              c8yIcon=\"exclamation-triangle\"\n            ></i>\n          </button>\n        </p>\n      </ng-container>\n      <p\n        class=\"small text-break-word\"\n        *ngIf=\"app.manifest?.author\"\n      >\n        {{ app.manifest.author }}\n      </p>\n    </div>\n  </div>\n  <div\n    class=\"card-block p-0 no-min-height card--d-col card-column-80 flex-grow\"\n    (click)=\"detail()\"\n  >\n    <div class=\"card-block no-min-height p-t-0 p-b-0 card-column-80\">\n      <div class=\"text-center-grid\">\n        <div class=\"p-b-8 card-hidden-grid\"></div>\n        <p\n          class=\"small l-h-tight p-b-8 p-l-0 p-r-0 text-break-word\"\n          *ngIf=\"app.description || app.manifest?.description\"\n        >\n          {{ app.description || app.manifest?.description | translate }}\n        </p>\n        <p\n          class=\"small l-h-tight p-b-8 p-l-0 p-r-0\"\n          *ngIf=\"!app.description && !app.manifest?.description\"\n        >\n          <em class=\"text-muted\">{{ 'No description available.' | translate }}</em>\n        </p>\n      </div>\n    </div>\n    <div\n      class=\"card-block no-min-height p-t-0 p-b-0 d-flex card-column-20 text-center-grid flex-wrap gap-8\"\n    >\n      <button\n        class=\"btn-clean\"\n        [attr.aria-label]=\"\n          ((isUnpacked ? UNPACKED_LABEL : appState?.label) | translate) +\n          ': ' +\n          (appState?.tooltip | translate)\n        \"\n        [tooltip]=\"appState?.tooltip | translate\"\n        placement=\"top\"\n        [delay]=\"500\"\n      >\n        <span\n          class=\"label\"\n          [ngClass]=\"appState?.class\"\n        >\n          {{ appState?.label | translate }}\n        </span>\n      </button>\n      <button\n        class=\"btn-clean\"\n        [attr.aria-label]=\"\n          (packageContentState?.label | translate) +\n            ': ' +\n            (packageContentState?.tooltip\n              ? packageContentState?.tooltip\n              : PACKAGE_CONTENT_UNDETERMINED_LABEL) | translate\n        \"\n        [tooltip]=\"\n          (packageContentState?.tooltip\n            ? packageContentState?.tooltip\n            : PACKAGE_CONTENT_UNDETERMINED_LABEL\n          ) | translate\n        \"\n        placement=\"top\"\n        *ngIf=\"isPackage\"\n      >\n        <span\n          class=\"label\"\n          [ngClass]=\"packageContentState?.class ? packageContentState?.class : 'label-danger'\"\n        >\n          {{\n            packageContentState?.label || packageTypeLabels[PACKAGE_TYPE.UNKNOWN].label | translate\n          }}\n        </span>\n      </button>\n    </div>\n    <div class=\"card-footer no-min-height p-t-0 p-b-0 card-column-20 text-center-grid\">\n      <div class=\"p-b-16 card-hidden-list\"></div>\n      <button\n        class=\"btn btn-sm btn-default\"\n        [title]=\"openButtonTitle | translate\"\n        type=\"button\"\n        (click)=\"openApp(); $event.stopPropagation()\"\n        *ngIf=\"canOpenInBrowser\"\n        [disabled]=\"disableOpenInBrowser\"\n      >\n        <i\n          class=\"m-r-4\"\n          c8yIcon=\"external-link\"\n        ></i>\n        {{ 'Open' | translate }}\n      </button>\n      <div class=\"p-b-32 card-hidden-list\"></div>\n    </div>\n  </div>\n  <div class=\"p-r-40 card-hidden-grid\"></div>\n  <div\n    class=\"card-actions m-t-0\"\n    *ngIf=\"canEdit || canOpenInBrowser || canDelete\"\n  >\n    <div\n      class=\"dropdown\"\n      #appCardDropdown=\"bs-dropdown\"\n      dropdown\n      [cdkTrapFocus]=\"appCardDropdown.isOpen\"\n    >\n      <button\n        class=\"dropdown-toggle c8y-dropdown\"\n        title=\"{{ 'Settings' | translate }}\"\n        data-cy=\"application-card--settings-button\"\n        type=\"button\"\n        dropdownToggle\n      >\n        <i c8yIcon=\"ellipsis-v\"></i>\n      </button>\n      <ul\n        class=\"dropdown-menu dropdown-menu-right\"\n        *dropdownMenu\n      >\n        <li *ngIf=\"canEdit\">\n          <button\n            title=\"{{ 'Edit' | translate }}\"\n            data-cy=\"application-card--edit-button\"\n            (click)=\"detail()\"\n          >\n            <i\n              class=\"m-r-4\"\n              c8yIcon=\"pencil\"\n            ></i>\n            {{ 'Edit' | translate }}\n          </button>\n        </li>\n        <ng-container *c8yIfAllowed=\"['ROLE_APPLICATION_MANAGEMENT_ADMIN']\">\n          <li>\n            <button\n              [title]=\"canDelete ? ('Delete' | translate) : (CANNOT_DELETE_HINT | translate)\"\n              type=\"button\"\n              data-cy=\"application-card--delete-button\"\n              [disabled]=\"!canDelete\"\n              (click)=\"delete()\"\n            >\n              <i\n                class=\"m-r-4\"\n                c8yIcon=\"delete\"\n              ></i>\n              {{ 'Delete' | translate }}\n            </button>\n          </li>\n          <li *ngIf=\"canClone\">\n            <button\n              [title]=\"'Clone`package,verb`' | translate\"\n              type=\"button\"\n              *ngIf=\"isPackage\"\n              (click)=\"clone()\"\n            >\n              <i\n                class=\"m-r-4\"\n                c8yIcon=\"copy\"\n              ></i>\n              {{ 'Clone`package,verb`' | translate }}\n            </button>\n            <button\n              [title]=\"'Clone`application,verb`' | translate\"\n              type=\"button\"\n              *ngIf=\"!isPackage\"\n              (click)=\"clone()\"\n            >\n              <i\n                class=\"m-r-4\"\n                c8yIcon=\"copy\"\n              ></i>\n              {{ 'Clone`application,verb`' | translate }}\n            </button>\n          </li>\n        </ng-container>\n      </ul>\n    </div>\n  </div>\n</div>\n\n<button\n  class=\"card pointer card--d-col\"\n  type=\"button\"\n  (click)=\"detail()\"\n  *ngIf=\"isFeature\"\n>\n  <div class=\"card-block text-center card-column-40\">\n    <div class=\"card-appicon\">\n      <c8y-app-icon\n        *ngIf=\"!isPackage && !isFeature && !isMicroservice && !isExternal\"\n        [app]=\"app\"\n        [contextPath]=\"app.contextPath\"\n        [name]=\"app.name\"\n      ></c8y-app-icon>\n      <i c8yIcon=\"tab\"></i>\n    </div>\n    <div>\n      <p\n        class=\"e2e-appCardName text-medium\"\n        title=\"{{ app | humanizeAppName | async }}\"\n      >\n        {{ app | humanizeAppName | async }}\n      </p>\n      <ng-container *ngIf=\"isShowVersion\">\n        <p class=\"small text-muted\">\n          <em>{{ app.manifest.version }}</em>\n          <i\n            class=\"text-warning m-l-4\"\n            c8yIcon=\"exclamation-triangle\"\n            [tooltip]=\"'Update available' | translate\"\n            *ngIf=\"shouldUpgradePackage && isUnpacked\"\n          ></i>\n        </p>\n      </ng-container>\n    </div>\n  </div>\n  <div class=\"card-block p-0 no-min-height card--d-col card-column-80 flex-grow\">\n    <div class=\"card-block no-min-height p-t-0 p-b-0 card-column-80\">\n      <div\n        class=\"text-center-grid\"\n        *ngIf=\"app.description || app.manifest?.description\"\n      >\n        <div class=\"p-b-8 card-hidden-grid\"></div>\n        <p class=\"small l-h-tight p-b-8 p-l-0 p-r-0\">\n          {{ app.description || app.manifest?.description | translate }}\n        </p>\n      </div>\n    </div>\n    <div class=\"card-block no-min-height p-t-0 p-b-0 card-column-20 text-center-grid\">\n      <span\n        class=\"label\"\n        [ngClass]=\"appState.class\"\n      >\n        {{ appState.label | translate }}\n      </span>\n    </div>\n    <div\n      class=\"card-block no-min-height p-t-0 p-b-0 card-column-20 text-center-grid\"\n      *ngIf=\"isPackage\"\n    >\n      <span\n        class=\"label\"\n        [ngClass]=\"packageContentState.class\"\n      >\n        {{ packageContentState.label | translate }}\n      </span>\n    </div>\n    <div class=\"p-b-32 card-hidden-list\"></div>\n  </div>\n</button>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: AppIconComponent, selector: "c8y-app-icon", inputs: ["contextPath", "name", "app"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "directive", type: BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "directive", type: IfAllowedDirective, selector: "[c8yIfAllowed]", inputs: ["c8yIfAllowed", "c8yIfAllowedAllowAny"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: HumanizeAppNamePipe, name: "humanizeAppName" }, { kind: "pipe", type: TranslatePackageLabelPipe, name: "translatePackageLabel" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ApplicationCardComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-application-card', imports: [
                        NgIf,
                        TooltipDirective,
                        NgClass,
                        AppIconComponent,
                        IconDirective,
                        BsDropdownDirective,
                        CdkTrapFocus,
                        BsDropdownToggleDirective,
                        BsDropdownMenuDirective,
                        IfAllowedDirective,
                        C8yTranslatePipe,
                        AsyncPipe,
                        HumanizeAppNamePipe,
                        TranslatePackageLabelPipe
                    ], template: "<div\n  class=\"card pointer card--d-col notFeature\"\n  data-cy=\"application-card--extensions-list\"\n  *ngIf=\"!isFeature\"\n>\n  <div\n    class=\"card-block text-center card-column-40\"\n    data-cy=\"application-card--package-name\"\n    (click)=\"detail()\"\n  >\n    <button\n      class=\"card__ribbon btn-clean\"\n      [attr.aria-label]=\"\n        (app.label || app.manifest?.label | translatePackageLabel) +\n        ': ' +\n        (packageTypeLabels[packageType].tooltip | translate)\n      \"\n      tooltip=\"{{ packageTypeLabels[packageType].tooltip | translate }}\"\n      placement=\"right\"\n      type=\"button\"\n      *ngIf=\"packageType !== PACKAGE_TYPE.CUSTOM\"\n      [delay]=\"500\"\n    >\n      <span\n        [ngClass]=\"{\n          'bg-info': packageType === PACKAGE_TYPE.COMMUNITY,\n          'bg-primary': packageType === PACKAGE_TYPE.OFFICIAL,\n          'bg-warning': packageType === PACKAGE_TYPE.ARCHIVED\n        }\"\n      >\n        {{ app.label || app.manifest?.label | translatePackageLabel }}\n      </span>\n    </button>\n    <div class=\"card-appicon\">\n      <c8y-app-icon\n        *ngIf=\"!isPackage && !isFeature && !isMicroservice && !isExternal\"\n        [app]=\"app\"\n        [contextPath]=\"app.contextPath\"\n        [name]=\"app.name\"\n      ></c8y-app-icon>\n      <i\n        c8yIcon=\"big-parcel\"\n        *ngIf=\"isPackage\"\n      ></i>\n      <i\n        c8yIcon=\"microchip\"\n        *ngIf=\"isMicroservice\"\n      ></i>\n      <i\n        c8yIcon=\"globe1\"\n        *ngIf=\"isExternal\"\n      ></i>\n    </div>\n    <div style=\"line-height: 1.3\">\n      <p class=\"e2e-appCardName text-medium text-break-word\">\n        {{ app | humanizeAppName | async }}\n      </p>\n      <ng-container *ngIf=\"isShowVersion\">\n        <p class=\"small text-muted\">\n          <em>{{ app.manifest.version }}</em>\n          <button\n            class=\"btn-clean m-l-4\"\n            [attr.aria-label]=\"'Update available' | translate\"\n            [tooltip]=\"'Update available' | translate\"\n            *ngIf=\"shouldUpgradePackage && isUnpacked\"\n          >\n            <i\n              class=\"text-warning icon-16\"\n              c8yIcon=\"exclamation-triangle\"\n            ></i>\n          </button>\n        </p>\n      </ng-container>\n      <p\n        class=\"small text-break-word\"\n        *ngIf=\"app.manifest?.author\"\n      >\n        {{ app.manifest.author }}\n      </p>\n    </div>\n  </div>\n  <div\n    class=\"card-block p-0 no-min-height card--d-col card-column-80 flex-grow\"\n    (click)=\"detail()\"\n  >\n    <div class=\"card-block no-min-height p-t-0 p-b-0 card-column-80\">\n      <div class=\"text-center-grid\">\n        <div class=\"p-b-8 card-hidden-grid\"></div>\n        <p\n          class=\"small l-h-tight p-b-8 p-l-0 p-r-0 text-break-word\"\n          *ngIf=\"app.description || app.manifest?.description\"\n        >\n          {{ app.description || app.manifest?.description | translate }}\n        </p>\n        <p\n          class=\"small l-h-tight p-b-8 p-l-0 p-r-0\"\n          *ngIf=\"!app.description && !app.manifest?.description\"\n        >\n          <em class=\"text-muted\">{{ 'No description available.' | translate }}</em>\n        </p>\n      </div>\n    </div>\n    <div\n      class=\"card-block no-min-height p-t-0 p-b-0 d-flex card-column-20 text-center-grid flex-wrap gap-8\"\n    >\n      <button\n        class=\"btn-clean\"\n        [attr.aria-label]=\"\n          ((isUnpacked ? UNPACKED_LABEL : appState?.label) | translate) +\n          ': ' +\n          (appState?.tooltip | translate)\n        \"\n        [tooltip]=\"appState?.tooltip | translate\"\n        placement=\"top\"\n        [delay]=\"500\"\n      >\n        <span\n          class=\"label\"\n          [ngClass]=\"appState?.class\"\n        >\n          {{ appState?.label | translate }}\n        </span>\n      </button>\n      <button\n        class=\"btn-clean\"\n        [attr.aria-label]=\"\n          (packageContentState?.label | translate) +\n            ': ' +\n            (packageContentState?.tooltip\n              ? packageContentState?.tooltip\n              : PACKAGE_CONTENT_UNDETERMINED_LABEL) | translate\n        \"\n        [tooltip]=\"\n          (packageContentState?.tooltip\n            ? packageContentState?.tooltip\n            : PACKAGE_CONTENT_UNDETERMINED_LABEL\n          ) | translate\n        \"\n        placement=\"top\"\n        *ngIf=\"isPackage\"\n      >\n        <span\n          class=\"label\"\n          [ngClass]=\"packageContentState?.class ? packageContentState?.class : 'label-danger'\"\n        >\n          {{\n            packageContentState?.label || packageTypeLabels[PACKAGE_TYPE.UNKNOWN].label | translate\n          }}\n        </span>\n      </button>\n    </div>\n    <div class=\"card-footer no-min-height p-t-0 p-b-0 card-column-20 text-center-grid\">\n      <div class=\"p-b-16 card-hidden-list\"></div>\n      <button\n        class=\"btn btn-sm btn-default\"\n        [title]=\"openButtonTitle | translate\"\n        type=\"button\"\n        (click)=\"openApp(); $event.stopPropagation()\"\n        *ngIf=\"canOpenInBrowser\"\n        [disabled]=\"disableOpenInBrowser\"\n      >\n        <i\n          class=\"m-r-4\"\n          c8yIcon=\"external-link\"\n        ></i>\n        {{ 'Open' | translate }}\n      </button>\n      <div class=\"p-b-32 card-hidden-list\"></div>\n    </div>\n  </div>\n  <div class=\"p-r-40 card-hidden-grid\"></div>\n  <div\n    class=\"card-actions m-t-0\"\n    *ngIf=\"canEdit || canOpenInBrowser || canDelete\"\n  >\n    <div\n      class=\"dropdown\"\n      #appCardDropdown=\"bs-dropdown\"\n      dropdown\n      [cdkTrapFocus]=\"appCardDropdown.isOpen\"\n    >\n      <button\n        class=\"dropdown-toggle c8y-dropdown\"\n        title=\"{{ 'Settings' | translate }}\"\n        data-cy=\"application-card--settings-button\"\n        type=\"button\"\n        dropdownToggle\n      >\n        <i c8yIcon=\"ellipsis-v\"></i>\n      </button>\n      <ul\n        class=\"dropdown-menu dropdown-menu-right\"\n        *dropdownMenu\n      >\n        <li *ngIf=\"canEdit\">\n          <button\n            title=\"{{ 'Edit' | translate }}\"\n            data-cy=\"application-card--edit-button\"\n            (click)=\"detail()\"\n          >\n            <i\n              class=\"m-r-4\"\n              c8yIcon=\"pencil\"\n            ></i>\n            {{ 'Edit' | translate }}\n          </button>\n        </li>\n        <ng-container *c8yIfAllowed=\"['ROLE_APPLICATION_MANAGEMENT_ADMIN']\">\n          <li>\n            <button\n              [title]=\"canDelete ? ('Delete' | translate) : (CANNOT_DELETE_HINT | translate)\"\n              type=\"button\"\n              data-cy=\"application-card--delete-button\"\n              [disabled]=\"!canDelete\"\n              (click)=\"delete()\"\n            >\n              <i\n                class=\"m-r-4\"\n                c8yIcon=\"delete\"\n              ></i>\n              {{ 'Delete' | translate }}\n            </button>\n          </li>\n          <li *ngIf=\"canClone\">\n            <button\n              [title]=\"'Clone`package,verb`' | translate\"\n              type=\"button\"\n              *ngIf=\"isPackage\"\n              (click)=\"clone()\"\n            >\n              <i\n                class=\"m-r-4\"\n                c8yIcon=\"copy\"\n              ></i>\n              {{ 'Clone`package,verb`' | translate }}\n            </button>\n            <button\n              [title]=\"'Clone`application,verb`' | translate\"\n              type=\"button\"\n              *ngIf=\"!isPackage\"\n              (click)=\"clone()\"\n            >\n              <i\n                class=\"m-r-4\"\n                c8yIcon=\"copy\"\n              ></i>\n              {{ 'Clone`application,verb`' | translate }}\n            </button>\n          </li>\n        </ng-container>\n      </ul>\n    </div>\n  </div>\n</div>\n\n<button\n  class=\"card pointer card--d-col\"\n  type=\"button\"\n  (click)=\"detail()\"\n  *ngIf=\"isFeature\"\n>\n  <div class=\"card-block text-center card-column-40\">\n    <div class=\"card-appicon\">\n      <c8y-app-icon\n        *ngIf=\"!isPackage && !isFeature && !isMicroservice && !isExternal\"\n        [app]=\"app\"\n        [contextPath]=\"app.contextPath\"\n        [name]=\"app.name\"\n      ></c8y-app-icon>\n      <i c8yIcon=\"tab\"></i>\n    </div>\n    <div>\n      <p\n        class=\"e2e-appCardName text-medium\"\n        title=\"{{ app | humanizeAppName | async }}\"\n      >\n        {{ app | humanizeAppName | async }}\n      </p>\n      <ng-container *ngIf=\"isShowVersion\">\n        <p class=\"small text-muted\">\n          <em>{{ app.manifest.version }}</em>\n          <i\n            class=\"text-warning m-l-4\"\n            c8yIcon=\"exclamation-triangle\"\n            [tooltip]=\"'Update available' | translate\"\n            *ngIf=\"shouldUpgradePackage && isUnpacked\"\n          ></i>\n        </p>\n      </ng-container>\n    </div>\n  </div>\n  <div class=\"card-block p-0 no-min-height card--d-col card-column-80 flex-grow\">\n    <div class=\"card-block no-min-height p-t-0 p-b-0 card-column-80\">\n      <div\n        class=\"text-center-grid\"\n        *ngIf=\"app.description || app.manifest?.description\"\n      >\n        <div class=\"p-b-8 card-hidden-grid\"></div>\n        <p class=\"small l-h-tight p-b-8 p-l-0 p-r-0\">\n          {{ app.description || app.manifest?.description | translate }}\n        </p>\n      </div>\n    </div>\n    <div class=\"card-block no-min-height p-t-0 p-b-0 card-column-20 text-center-grid\">\n      <span\n        class=\"label\"\n        [ngClass]=\"appState.class\"\n      >\n        {{ appState.label | translate }}\n      </span>\n    </div>\n    <div\n      class=\"card-block no-min-height p-t-0 p-b-0 card-column-20 text-center-grid\"\n      *ngIf=\"isPackage\"\n    >\n      <span\n        class=\"label\"\n        [ngClass]=\"packageContentState.class\"\n      >\n        {{ packageContentState.label | translate }}\n      </span>\n    </div>\n    <div class=\"p-b-32 card-hidden-list\"></div>\n  </div>\n</button>\n" }]
        }], ctorParameters: () => [{ type: i3$1.ApplicationService }, { type: EcosystemService }, { type: i1.AlertService }, { type: i4.Router }, { type: i1.WizardModalService }, { type: i1.AlertService }, { type: i1.PluginsService }, { type: i1.GainsightService }], propDecorators: { app: [{
                type: Input
            }], canEdit: [{
                type: Input
            }], onAppDeleted: [{
                type: Output
            }], onAppCloned: [{
                type: Output
            }] } });

class ApplicationPropertiesFormComponent {
    constructor(formBuilder) {
        this.formBuilder = formBuilder;
        this.disabled = false;
        this.initForm();
    }
    ngOnChanges(changes) {
        if (changes.application &&
            changes.application.currentValue !== changes.application.previousValue) {
            this.setForm(this.application);
        }
        if (changes.disabled && changes.disabled.currentValue !== changes.disabled.previousValue) {
            changes.disabled.currentValue ? this.formGroup.disable() : this.formGroup.enable();
        }
    }
    initForm() {
        this.formGroup = this.formBuilder.group({
            name: [Validators.required, Validators.maxLength(120)],
            key: [Validators.required, Validators.maxLength(120)],
            contextPath: [Validators.required, Validators.maxLength(120)],
            icon: [undefined, [Validators.minLength(1)]]
        });
    }
    setForm(applicationConfig) {
        this.formGroup.patchValue({ ...applicationConfig });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ApplicationPropertiesFormComponent, deps: [{ token: i1$1.FormBuilder }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: ApplicationPropertiesFormComponent, isStandalone: true, selector: "c8y-application-properties-form", inputs: { application: "application", disabled: "disabled" }, usesOnChanges: true, ngImport: i0, template: "<form\n  class=\"c8y-wizard-form text-left\"\n  name=\"appDeployForm\"\n  (ngSubmit)=\"(formGroup.valid)\"\n  [formGroup]=\"formGroup\"\n  novalidate\n>\n  <c8y-form-group>\n    <label\n      for=\"name\"\n      translate\n    >\n      Name\n    </label>\n    <input\n      class=\"form-control\"\n      placeholder=\"{{ 'e.g. My application' | translate }}\"\n      name=\"name\"\n      type=\"text\"\n      required\n      formControlName=\"name\"\n    />\n  </c8y-form-group>\n  <c8y-form-group>\n    <label\n      for=\"key\"\n      translate\n    >\n      Application key\n    </label>\n    <input\n      class=\"form-control\"\n      placeholder=\"{{ 'e.g. my-application-key' | translate }}\"\n      name=\"key\"\n      type=\"text\"\n      required\n      formControlName=\"key\"\n    />\n  </c8y-form-group>\n  <c8y-form-group>\n    <label\n      for=\"contextPath\"\n      translate\n    >\n      Path\n    </label>\n    <div class=\"input-group\">\n      <span class=\"input-group-addon\">/apps/</span>\n      <input\n        class=\"form-control\"\n        placeholder=\"{{ 'e.g. my-application' | translate }}\"\n        name=\"contextPath\"\n        type=\"text\"\n        required\n        formControlName=\"contextPath\"\n      />\n    </div>\n  </c8y-form-group>\n  <c8y-form-group>\n    <label>{{ 'Select icon' | translate }}</label>\n    <c8y-icon-selector-wrapper\n      name=\"icon\"\n      formControlName=\"icon\"\n    ></c8y-icon-selector-wrapper>\n  </c8y-form-group>\n</form>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: IconSelectorWrapperComponent, selector: "c8y-icon-selector-wrapper", inputs: ["canRemoveIcon", "selectedIcon", "iconSize"], outputs: ["onSelect"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ApplicationPropertiesFormComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-application-properties-form', imports: [
                        FormsModule,
                        ReactiveFormsModule,
                        FormGroupComponent,
                        C8yTranslateDirective,
                        RequiredInputPlaceholderDirective,
                        IconSelectorWrapperComponent,
                        C8yTranslatePipe
                    ], template: "<form\n  class=\"c8y-wizard-form text-left\"\n  name=\"appDeployForm\"\n  (ngSubmit)=\"(formGroup.valid)\"\n  [formGroup]=\"formGroup\"\n  novalidate\n>\n  <c8y-form-group>\n    <label\n      for=\"name\"\n      translate\n    >\n      Name\n    </label>\n    <input\n      class=\"form-control\"\n      placeholder=\"{{ 'e.g. My application' | translate }}\"\n      name=\"name\"\n      type=\"text\"\n      required\n      formControlName=\"name\"\n    />\n  </c8y-form-group>\n  <c8y-form-group>\n    <label\n      for=\"key\"\n      translate\n    >\n      Application key\n    </label>\n    <input\n      class=\"form-control\"\n      placeholder=\"{{ 'e.g. my-application-key' | translate }}\"\n      name=\"key\"\n      type=\"text\"\n      required\n      formControlName=\"key\"\n    />\n  </c8y-form-group>\n  <c8y-form-group>\n    <label\n      for=\"contextPath\"\n      translate\n    >\n      Path\n    </label>\n    <div class=\"input-group\">\n      <span class=\"input-group-addon\">/apps/</span>\n      <input\n        class=\"form-control\"\n        placeholder=\"{{ 'e.g. my-application' | translate }}\"\n        name=\"contextPath\"\n        type=\"text\"\n        required\n        formControlName=\"contextPath\"\n      />\n    </div>\n  </c8y-form-group>\n  <c8y-form-group>\n    <label>{{ 'Select icon' | translate }}</label>\n    <c8y-icon-selector-wrapper\n      name=\"icon\"\n      formControlName=\"icon\"\n    ></c8y-icon-selector-wrapper>\n  </c8y-form-group>\n</form>\n" }]
        }], ctorParameters: () => [{ type: i1$1.FormBuilder }], propDecorators: { application: [{
                type: Input
            }], disabled: [{
                type: Input
            }] } });

class DuplicateApplicationListComponent {
    constructor(ecosystemService, wizardComponent) {
        this.ecosystemService = ecosystemService;
        this.wizardComponent = wizardComponent;
        this.onSelectedApp = new EventEmitter();
    }
    select(selectedApp) {
        this.onSelectedApp.emit(selectedApp);
        this.stepper.next();
    }
    cancel() {
        this.wizardComponent.close();
    }
    back() {
        this.wizardComponent.reset();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DuplicateApplicationListComponent, deps: [{ token: EcosystemService }, { token: i1.WizardComponent }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: DuplicateApplicationListComponent, isStandalone: true, selector: "c8y-duplicate-application-list", inputs: { stepper: "stepper", existingApps: "existingApps" }, outputs: { onSelectedApp: "onSelectedApp" }, ngImport: i0, template: "<div class=\"c8y-wizard-list-nav\">\n  <button\n    (click)=\"select(app)\"\n    *ngFor=\"let app of existingApps\"\n    class=\"list-group-item text-truncate p-t-8 p-b-8 bg-level-0\"\n    type=\"button\"\n  >\n    <c8y-app-icon\n      [app]=\"app\"\n      [contextPath]=\"app.contextPath\"\n      [name]=\"app.name\"\n      class=\"list-group-icon\"\n    ></c8y-app-icon>\n    <span [innerText]=\"app | humanizeAppName | async\" class=\"pointer\"></span>\n    <span [ngClass]=\"ecosystemService.getAppState(app).class\" class=\"label m-l-16\">\n      {{ ecosystemService.getAppState(app).label | translate }}\n    </span>\n  </button>\n</div>\n<c8y-wizard-footer>\n  <button (click)=\"back()\" class=\"btn btn-default\" title=\"{{ 'Back' | translate }}\" type=\"button\">\n    {{ 'Back' | translate }}\n  </button>\n  <button\n    (click)=\"cancel()\"\n    class=\"btn btn-default\"\n    title=\"{{ 'Cancel' | translate }}\"\n    type=\"button\"\n  >\n    {{ 'Cancel' | translate }}\n  </button>\n</c8y-wizard-footer>\n", dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: AppIconComponent, selector: "c8y-app-icon", inputs: ["contextPath", "name", "app"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: WizardFooterComponent, selector: "c8y-wizard-footer" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: HumanizeAppNamePipe, name: "humanizeAppName" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DuplicateApplicationListComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-duplicate-application-list', imports: [
                        NgFor,
                        AppIconComponent,
                        NgClass,
                        WizardFooterComponent,
                        C8yTranslatePipe,
                        AsyncPipe,
                        HumanizeAppNamePipe
                    ], template: "<div class=\"c8y-wizard-list-nav\">\n  <button\n    (click)=\"select(app)\"\n    *ngFor=\"let app of existingApps\"\n    class=\"list-group-item text-truncate p-t-8 p-b-8 bg-level-0\"\n    type=\"button\"\n  >\n    <c8y-app-icon\n      [app]=\"app\"\n      [contextPath]=\"app.contextPath\"\n      [name]=\"app.name\"\n      class=\"list-group-icon\"\n    ></c8y-app-icon>\n    <span [innerText]=\"app | humanizeAppName | async\" class=\"pointer\"></span>\n    <span [ngClass]=\"ecosystemService.getAppState(app).class\" class=\"label m-l-16\">\n      {{ ecosystemService.getAppState(app).label | translate }}\n    </span>\n  </button>\n</div>\n<c8y-wizard-footer>\n  <button (click)=\"back()\" class=\"btn btn-default\" title=\"{{ 'Back' | translate }}\" type=\"button\">\n    {{ 'Back' | translate }}\n  </button>\n  <button\n    (click)=\"cancel()\"\n    class=\"btn btn-default\"\n    title=\"{{ 'Cancel' | translate }}\"\n    type=\"button\"\n  >\n    {{ 'Cancel' | translate }}\n  </button>\n</c8y-wizard-footer>\n" }]
        }], ctorParameters: () => [{ type: EcosystemService }, { type: i1.WizardComponent }], propDecorators: { stepper: [{
                type: Input
            }], existingApps: [{
                type: Input
            }], onSelectedApp: [{
                type: Output
            }] } });

class DuplicateApplicationPropertiesComponent {
    constructor(bsModalRef, ecosystemService, applicationService, gainsightService) {
        this.bsModalRef = bsModalRef;
        this.ecosystemService = ecosystemService;
        this.applicationService = applicationService;
        this.gainsightService = gainsightService;
        this.CURRENT_LOCATION = location.href;
        this.isFirstStep = false;
        this.duplicatedApp = new EventEmitter();
        this.disableForm = false;
        this.inProgress = false;
    }
    ngOnInit() {
        this.isSubscribedApp$ = this.selectedApp.pipe(distinctUntilKeyChanged('id'), map(app => (app ? this.ecosystemService.getAppState(app) === APP_STATE.SUBSCRIBED : true)), tap(isSubscribed => {
            this.disableForm = isSubscribed;
            this.getAppConfig();
        }));
        this.getAppConfig();
    }
    async duplicateApp() {
        const formGroupValue = this.applicationPropertiesForm.formGroup.getRawValue();
        this.inProgress = true;
        let { data: clonedApp } = await this.applicationService.clone(this.selectedApp.value);
        // TODO: remove once MTM-48474 has been merged
        clonedApp = this.ecosystemService.setAvailabilityToPrivateIfNotSetAlready(clonedApp);
        Object.assign(clonedApp, formGroupValue);
        if (formGroupValue.icon) {
            const icon = { class: formGroupValue.icon };
            clonedApp.config = { ...clonedApp.config, icon };
            if (clonedApp.manifest) {
                clonedApp.manifest.icon = icon;
            }
        }
        delete clonedApp.type;
        await this.updateApp(clonedApp);
        this.inProgress = false;
        this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.DUPLICATE_APPLICATION, {
            component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.DUPLICATE_APPLICATION_PROPERTIES,
            result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.DUPLICATED,
            url: this.CURRENT_LOCATION
        });
    }
    cancel() {
        this.bsModalRef.hide();
        this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.DUPLICATE_APPLICATION, {
            component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.DUPLICATE_APPLICATION_PROPERTIES,
            action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.CANCEL,
            url: this.CURRENT_LOCATION
        });
    }
    back() {
        this.stepper.previous();
    }
    getAppConfig() {
        if (this.disableForm) {
            const { name, key, contextPath } = this.selectedApp.value;
            this.newAppConfig = { name, key, contextPath };
        }
        else {
            this.newAppConfig = this.ecosystemService.getUniqueAppConfig(this.selectedApp.value, this.existingApps);
        }
    }
    async updateApp(clonedAppConfig) {
        try {
            const { data: app } = await this.ecosystemService.updateApp(clonedAppConfig, true);
            const manifest = await this.getAppManifest(app);
            if (manifest) {
                await this.updateManifest(app, manifest);
            }
            this.duplicatedApp.emit(app);
            this.stepper.next();
        }
        catch (err) {
            this.inProgress = false;
        }
    }
    async updateManifest(app, manifest) {
        const keysToUpdate = ['name', 'key', 'contextPath'];
        const someKeyDiffers = keysToUpdate.some(key => app[key] !== manifest[key]);
        if (someKeyDiffers) {
            keysToUpdate.forEach(key => {
                manifest[key] = app[key];
            });
            await this.applicationService.storeAppManifest(app, manifest);
        }
    }
    async getAppManifest(app) {
        if (!app?.contextPath) {
            return;
        }
        try {
            const manifest = await this.applicationService.getAppManifest(app);
            return manifest;
        }
        catch (ex) {
            return;
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DuplicateApplicationPropertiesComponent, deps: [{ token: i1$2.BsModalRef }, { token: EcosystemService }, { token: i3$1.ApplicationService }, { token: i1.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: DuplicateApplicationPropertiesComponent, isStandalone: true, selector: "c8y-duplicate-application-properties", inputs: { stepper: "stepper", existingApps: "existingApps", selectedApp: "selectedApp", isFirstStep: "isFirstStep" }, outputs: { duplicatedApp: "duplicatedApp" }, viewQueries: [{ propertyName: "applicationPropertiesForm", first: true, predicate: ApplicationPropertiesFormComponent, descendants: true }], ngImport: i0, template: "<p\n  class=\"p-16 text-center text-medium separator-bottom sticky-top bg-level-0 fit-w\"\n  *ngIf=\"!inProgress\"\n>\n  {{ 'Provide application details' | translate }}\n</p>\n\n<ng-container *ngIf=\"!inProgress\">\n  <label class=\"c8y-switch\" *ngIf=\"isSubscribedApp$ | async\">\n    <input type=\"checkbox\" [(ngModel)]=\"disableForm\" (change)=\"getAppConfig()\" />\n    <span></span> {{ 'Overrule subscribed application' | translate }}\n  </label>\n\n  <c8y-application-properties-form\n    [application]=\"newAppConfig\"\n    class=\"d-block fit-w\"\n    [disabled]=\"disableForm\"\n  ></c8y-application-properties-form>\n</ng-container>\n<c8y-loading\n  *ngIf=\"inProgress\"\n  [message]=\"'Duplicating\u2026' | translate\"\n  layout=\"application\"\n  class=\"text-center d-block\"\n></c8y-loading>\n\n<c8y-wizard-footer>\n  <button\n    *ngIf=\"!isFirstStep\"\n    (click)=\"back()\"\n    [disabled]=\"inProgress\"\n    class=\"btn btn-default\"\n    type=\"button\"\n    title=\"{{ 'Back' | translate }}\"\n  >\n    {{ 'Back' | translate }}\n  </button>\n  <button (click)=\"cancel()\" class=\"btn btn-default\" title=\"{{ 'Cancel' | translate }}\">\n    {{ 'Cancel' | translate }}\n  </button>\n  <button\n    (click)=\"duplicateApp()\"\n    [disabled]=\"inProgress\"\n    class=\"btn btn-primary\"\n    type=\"button\"\n    title=\"{{ 'Duplicate' | translate }}\"\n  >\n    {{ 'Duplicate' | translate }}\n  </button>\n</c8y-wizard-footer>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ApplicationPropertiesFormComponent, selector: "c8y-application-properties-form", inputs: ["application", "disabled"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: WizardFooterComponent, selector: "c8y-wizard-footer" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DuplicateApplicationPropertiesComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-duplicate-application-properties', imports: [
                        NgIf,
                        FormsModule,
                        ApplicationPropertiesFormComponent,
                        LoadingComponent,
                        WizardFooterComponent,
                        C8yTranslatePipe,
                        AsyncPipe
                    ], template: "<p\n  class=\"p-16 text-center text-medium separator-bottom sticky-top bg-level-0 fit-w\"\n  *ngIf=\"!inProgress\"\n>\n  {{ 'Provide application details' | translate }}\n</p>\n\n<ng-container *ngIf=\"!inProgress\">\n  <label class=\"c8y-switch\" *ngIf=\"isSubscribedApp$ | async\">\n    <input type=\"checkbox\" [(ngModel)]=\"disableForm\" (change)=\"getAppConfig()\" />\n    <span></span> {{ 'Overrule subscribed application' | translate }}\n  </label>\n\n  <c8y-application-properties-form\n    [application]=\"newAppConfig\"\n    class=\"d-block fit-w\"\n    [disabled]=\"disableForm\"\n  ></c8y-application-properties-form>\n</ng-container>\n<c8y-loading\n  *ngIf=\"inProgress\"\n  [message]=\"'Duplicating\u2026' | translate\"\n  layout=\"application\"\n  class=\"text-center d-block\"\n></c8y-loading>\n\n<c8y-wizard-footer>\n  <button\n    *ngIf=\"!isFirstStep\"\n    (click)=\"back()\"\n    [disabled]=\"inProgress\"\n    class=\"btn btn-default\"\n    type=\"button\"\n    title=\"{{ 'Back' | translate }}\"\n  >\n    {{ 'Back' | translate }}\n  </button>\n  <button (click)=\"cancel()\" class=\"btn btn-default\" title=\"{{ 'Cancel' | translate }}\">\n    {{ 'Cancel' | translate }}\n  </button>\n  <button\n    (click)=\"duplicateApp()\"\n    [disabled]=\"inProgress\"\n    class=\"btn btn-primary\"\n    type=\"button\"\n    title=\"{{ 'Duplicate' | translate }}\"\n  >\n    {{ 'Duplicate' | translate }}\n  </button>\n</c8y-wizard-footer>\n" }]
        }], ctorParameters: () => [{ type: i1$2.BsModalRef }, { type: EcosystemService }, { type: i3$1.ApplicationService }, { type: i1.GainsightService }], propDecorators: { stepper: [{
                type: Input
            }], existingApps: [{
                type: Input
            }], selectedApp: [{
                type: Input
            }], isFirstStep: [{
                type: Input
            }], duplicatedApp: [{
                type: Output
            }], applicationPropertiesForm: [{
                type: ViewChild,
                args: [ApplicationPropertiesFormComponent]
            }] } });

class DuplicateApplicationComponent {
    constructor(ecosystemService, applicationService, wizardComponent) {
        this.ecosystemService = ecosystemService;
        this.applicationService = applicationService;
        this.wizardComponent = wizardComponent;
        this.selectedApp = new BehaviorSubject(null);
        this.existingApps = [];
        this.directlyMoveToSecondStep = false;
        this.noBackButton = false;
    }
    async ngOnInit() {
        this.existingApps = await this.ecosystemService.getWebApplications();
        if (this.selectedApp.value) {
            this.directlyMoveToSecondStep = true;
        }
    }
    onSelectedApp(app) {
        this.selectedApp.next(app);
    }
    getHref(app) {
        return this.applicationService.getHref(app);
    }
    done() {
        this.wizardComponent.close();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DuplicateApplicationComponent, deps: [{ token: EcosystemService }, { token: i3$1.ApplicationService }, { token: i1.WizardComponent }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: DuplicateApplicationComponent, isStandalone: true, selector: "c8y-duplicate-application", viewQueries: [{ propertyName: "stepper", first: true, predicate: C8yStepper, descendants: true, static: true }], ngImport: i0, template: "<c8y-wizard-header>\n  <i [c8yIcon]=\"'copy'\"></i>\n  <h4\n    id=\"modal-title\"\n    translate\n  >\n    Duplicate application\n  </h4>\n</c8y-wizard-header>\n\n<c8y-wizard-body id=\"modal-body\">\n  <c8y-stepper\n    [disableDefaultIcons]=\"{ edit: true, done: false }\"\n    [customClasses]=\"['hidden']\"\n    linear\n  >\n    <!-- 1st step -->\n    <cdk-step *ngIf=\"!directlyMoveToSecondStep\">\n      <p class=\"p-16 text-center text-medium separator-bottom sticky-top bg-level-0\">\n        {{ 'Select application to duplicate' | translate }}\n      </p>\n      <c8y-duplicate-application-list\n        class=\"d-block\"\n        style=\"min-height: 257px\"\n        (onSelectedApp)=\"onSelectedApp($event)\"\n        *ngIf=\"stepper.selectedIndex === 0\"\n        [existingApps]=\"existingApps\"\n        [stepper]=\"stepper\"\n      ></c8y-duplicate-application-list>\n    </cdk-step>\n    <!-- 2nd step -->\n    <cdk-step>\n      <c8y-duplicate-application-properties\n        class=\"d-flex d-col j-c-center a-i-center\"\n        style=\"min-height: 257px\"\n        (duplicatedApp)=\"duplicatedApp = $event\"\n        *ngIf=\"\n          stepper.selectedIndex === 1 || (stepper.selectedIndex === 0 && directlyMoveToSecondStep)\n        \"\n        [existingApps]=\"existingApps\"\n        [selectedApp]=\"selectedApp\"\n        [stepper]=\"stepper\"\n        [isFirstStep]=\"directlyMoveToSecondStep\"\n      ></c8y-duplicate-application-properties>\n    </cdk-step>\n    <!-- Final step -->\n    <cdk-step>\n      <ng-container\n        *ngIf=\"\n          stepper.selectedIndex === 2 || (stepper.selectedIndex === 1 && directlyMoveToSecondStep)\n        \"\n      >\n        <div\n          class=\"d-flex a-i-center j-c-center\"\n          style=\"min-height: 257px\"\n          *ngIf=\"duplicatedApp; else duplicateAppFailed\"\n        >\n          <c8y-operation-result\n            type=\"success\"\n            text=\"{{ 'Application created' | translate }}\"\n            [size]=\"84\"\n            [vertical]=\"true\"\n          ></c8y-operation-result>\n        </div>\n        <ng-template #duplicateAppFailed>\n          <div\n            class=\"d-flex a-i-center j-c-center\"\n            style=\"min-height: 257px\"\n          >\n            <c8y-operation-result\n              type=\"error\"\n              text=\"{{ 'Application creation failed' | translate }}\"\n              [size]=\"84\"\n              [vertical]=\"true\"\n            ></c8y-operation-result>\n          </div>\n        </ng-template>\n      </ng-container>\n    </cdk-step>\n  </c8y-stepper>\n</c8y-wizard-body>\n\n<c8y-wizard-footer *ngIf=\"stepper.selectedIndex === 0 && noBackButton\">\n  <button\n    class=\"btn btn-default\"\n    title=\"{{ 'Cancel' | translate }}\"\n    type=\"button\"\n    (click)=\"done()\"\n  >\n    {{ 'Cancel' | translate }}\n  </button>\n</c8y-wizard-footer>\n\n<c8y-wizard-footer\n  *ngIf=\"stepper.selectedIndex === 2 || (stepper.selectedIndex === 1 && directlyMoveToSecondStep)\"\n>\n  <button\n    class=\"btn btn-default\"\n    title=\"{{ 'Done' | translate }}\"\n    type=\"button\"\n    (click)=\"done()\"\n  >\n    {{ 'Done' | translate }}\n  </button>\n  <a\n    class=\"btn btn-primary\"\n    title=\"{{ 'Open' | translate }}\"\n    target=\"_blank\"\n    (click)=\"$event.stopPropagation()\"\n    [href]=\"getHref(duplicatedApp)\"\n    rel=\"noopener noreferrer\"\n  >\n    <i\n      class=\"m-r-4\"\n      c8yIcon=\"external-link\"\n    ></i>\n    {{ 'Open' | translate }}\n  </a>\n</c8y-wizard-footer>\n", dependencies: [{ kind: "component", type: WizardHeaderComponent, selector: "c8y-wizard-header" }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: WizardBodyComponent, selector: "c8y-wizard-body" }, { kind: "component", type: C8yStepper, selector: "c8y-stepper", inputs: ["disableDefaultIcons", "disableProgressButtons", "customClasses", "hideStepProgress", "useStepLabelsAsTitlesOnly"], outputs: ["onStepChange"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: CdkStep, selector: "cdk-step", inputs: ["stepControl", "label", "errorMessage", "aria-label", "aria-labelledby", "state", "editable", "optional", "completed", "hasError"], outputs: ["interacted"], exportAs: ["cdkStep"] }, { kind: "component", type: DuplicateApplicationListComponent, selector: "c8y-duplicate-application-list", inputs: ["stepper", "existingApps"], outputs: ["onSelectedApp"] }, { kind: "component", type: DuplicateApplicationPropertiesComponent, selector: "c8y-duplicate-application-properties", inputs: ["stepper", "existingApps", "selectedApp", "isFirstStep"], outputs: ["duplicatedApp"] }, { kind: "component", type: OperationResultComponent, selector: "c8y-operation-result", inputs: ["text", "vertical", "size", "type"] }, { kind: "component", type: WizardFooterComponent, selector: "c8y-wizard-footer" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DuplicateApplicationComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-duplicate-application', imports: [
                        WizardHeaderComponent,
                        IconDirective,
                        C8yTranslateDirective,
                        WizardBodyComponent,
                        C8yStepper,
                        NgIf,
                        CdkStep,
                        DuplicateApplicationListComponent,
                        DuplicateApplicationPropertiesComponent,
                        OperationResultComponent,
                        WizardFooterComponent,
                        C8yTranslatePipe
                    ], template: "<c8y-wizard-header>\n  <i [c8yIcon]=\"'copy'\"></i>\n  <h4\n    id=\"modal-title\"\n    translate\n  >\n    Duplicate application\n  </h4>\n</c8y-wizard-header>\n\n<c8y-wizard-body id=\"modal-body\">\n  <c8y-stepper\n    [disableDefaultIcons]=\"{ edit: true, done: false }\"\n    [customClasses]=\"['hidden']\"\n    linear\n  >\n    <!-- 1st step -->\n    <cdk-step *ngIf=\"!directlyMoveToSecondStep\">\n      <p class=\"p-16 text-center text-medium separator-bottom sticky-top bg-level-0\">\n        {{ 'Select application to duplicate' | translate }}\n      </p>\n      <c8y-duplicate-application-list\n        class=\"d-block\"\n        style=\"min-height: 257px\"\n        (onSelectedApp)=\"onSelectedApp($event)\"\n        *ngIf=\"stepper.selectedIndex === 0\"\n        [existingApps]=\"existingApps\"\n        [stepper]=\"stepper\"\n      ></c8y-duplicate-application-list>\n    </cdk-step>\n    <!-- 2nd step -->\n    <cdk-step>\n      <c8y-duplicate-application-properties\n        class=\"d-flex d-col j-c-center a-i-center\"\n        style=\"min-height: 257px\"\n        (duplicatedApp)=\"duplicatedApp = $event\"\n        *ngIf=\"\n          stepper.selectedIndex === 1 || (stepper.selectedIndex === 0 && directlyMoveToSecondStep)\n        \"\n        [existingApps]=\"existingApps\"\n        [selectedApp]=\"selectedApp\"\n        [stepper]=\"stepper\"\n        [isFirstStep]=\"directlyMoveToSecondStep\"\n      ></c8y-duplicate-application-properties>\n    </cdk-step>\n    <!-- Final step -->\n    <cdk-step>\n      <ng-container\n        *ngIf=\"\n          stepper.selectedIndex === 2 || (stepper.selectedIndex === 1 && directlyMoveToSecondStep)\n        \"\n      >\n        <div\n          class=\"d-flex a-i-center j-c-center\"\n          style=\"min-height: 257px\"\n          *ngIf=\"duplicatedApp; else duplicateAppFailed\"\n        >\n          <c8y-operation-result\n            type=\"success\"\n            text=\"{{ 'Application created' | translate }}\"\n            [size]=\"84\"\n            [vertical]=\"true\"\n          ></c8y-operation-result>\n        </div>\n        <ng-template #duplicateAppFailed>\n          <div\n            class=\"d-flex a-i-center j-c-center\"\n            style=\"min-height: 257px\"\n          >\n            <c8y-operation-result\n              type=\"error\"\n              text=\"{{ 'Application creation failed' | translate }}\"\n              [size]=\"84\"\n              [vertical]=\"true\"\n            ></c8y-operation-result>\n          </div>\n        </ng-template>\n      </ng-container>\n    </cdk-step>\n  </c8y-stepper>\n</c8y-wizard-body>\n\n<c8y-wizard-footer *ngIf=\"stepper.selectedIndex === 0 && noBackButton\">\n  <button\n    class=\"btn btn-default\"\n    title=\"{{ 'Cancel' | translate }}\"\n    type=\"button\"\n    (click)=\"done()\"\n  >\n    {{ 'Cancel' | translate }}\n  </button>\n</c8y-wizard-footer>\n\n<c8y-wizard-footer\n  *ngIf=\"stepper.selectedIndex === 2 || (stepper.selectedIndex === 1 && directlyMoveToSecondStep)\"\n>\n  <button\n    class=\"btn btn-default\"\n    title=\"{{ 'Done' | translate }}\"\n    type=\"button\"\n    (click)=\"done()\"\n  >\n    {{ 'Done' | translate }}\n  </button>\n  <a\n    class=\"btn btn-primary\"\n    title=\"{{ 'Open' | translate }}\"\n    target=\"_blank\"\n    (click)=\"$event.stopPropagation()\"\n    [href]=\"getHref(duplicatedApp)\"\n    rel=\"noopener noreferrer\"\n  >\n    <i\n      class=\"m-r-4\"\n      c8yIcon=\"external-link\"\n    ></i>\n    {{ 'Open' | translate }}\n  </a>\n</c8y-wizard-footer>\n" }]
        }], ctorParameters: () => [{ type: EcosystemService }, { type: i3$1.ApplicationService }, { type: i1.WizardComponent }], propDecorators: { stepper: [{
                type: ViewChild,
                args: [C8yStepper, { static: true }]
            }] } });

class PackageVersionSelectComponent {
    constructor(applicationService, pluginsService) {
        this.applicationService = applicationService;
        this.pluginsService = pluginsService;
        this.label = gettext('Use plugin version');
        this.onInput$ = new BehaviorSubject('');
        this.isDisabled = false;
        this.packageContextPath$ = new BehaviorSubject('');
        this.packageId$ = new BehaviorSubject('');
        const packageIdFromContextPath$ = this.packageContextPath$.pipe(filter(path => !!path), switchMap(path => this.getPackageIdForContextPath(path)));
        const packageId$ = merge(packageIdFromContextPath$, this.packageId$.pipe(filter(id => !!id)));
        const packageVersions$ = packageId$.pipe(switchMap(id => this.getPackageVersions(id)), shareReplay(1));
        this.versions$ = combineLatest([packageVersions$, this.onInput$.asObservable()]).pipe(map(([resultList, filterStr]) => this.applyFilterToResultList(resultList, filterStr)));
    }
    writeValue(obj) {
        this.selectedVersion = obj;
    }
    registerOnChange(fn) {
        this.onChange = fn;
    }
    registerOnTouched(fn) {
        this.onTouched = fn;
    }
    setDisabledState(isDisabled) {
        this.isDisabled = isDisabled;
    }
    ngOnChanges(changes) {
        if (changes.packageContextPath) {
            this.packageContextPath$.next(this.packageContextPath);
        }
        if (changes.packageId) {
            this.packageId$.next(this.packageId);
        }
    }
    async getPackageVersions(packageId) {
        return await this.applicationService.listVersions(packageId);
    }
    onVersionSelect(version) {
        this.selectedVersion = version;
        if (this.onChange) {
            this.onChange(version);
        }
        if (this.onTouched) {
            this.onTouched();
        }
    }
    async getPackageIdForContextPath(contextPath) {
        const { data: application } = await this.applicationService.getManifestOfContextPath(contextPath);
        const packageAppId = application.id;
        return packageAppId;
    }
    setInitialValueForInput(versions) {
        if (!this.selectedVersion && versions.length > 0) {
            const latest = versions.find(v => v.tags.includes('latest'));
            this.selectedVersion = latest || versions[0];
            if (this.onChange) {
                this.onChange(this.selectedVersion);
            }
        }
    }
    filterAppVersions(appVersions, filterStr) {
        return filterStr === ''
            ? appVersions
            : appVersions.filter(appVersion => appVersion.version.includes(filterStr) ||
                appVersion.tags?.some(tag => tag.includes(filterStr)));
    }
    applyFilterToResultList(resultList, filterStr) {
        const versionsFilteredByStr = this.filterAppVersions(resultList.data, filterStr);
        const sortedAppVersions = this.pluginsService.sortVersions({
            list: versionsFilteredByStr,
            path: ['version']
        }, 'desc');
        this.setInitialValueForInput(sortedAppVersions);
        return { data: sortedAppVersions, res: resultList.res };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PackageVersionSelectComponent, deps: [{ token: i3$1.ApplicationService }, { token: i1.PluginsService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: PackageVersionSelectComponent, isStandalone: true, selector: "c8y-package-version-select", inputs: { label: "label", packageContextPath: "packageContextPath", packageId: "packageId" }, providers: [
            {
                provide: NG_VALUE_ACCESSOR,
                multi: true,
                useExisting: forwardRef(() => PackageVersionSelectComponent)
            }
        ], usesOnChanges: true, ngImport: i0, template: "<label for=\"packageVersion\">{{ label | translate }}</label>\n<c8y-form-group>\n  <c8y-typeahead\n    [(ngModel)]=\"selectedVersion\"\n    name=\"packageVersion\"\n    (onSearch)=\"onInput$.next($event)\"\n    placeholder=\"{{ 'Select below or start typing' | translate }}\"\n    [displayProperty]=\"'version'\"\n    [required]=\"true\"\n    [disabled]=\"isDisabled\"\n    [hideNew]=\"true\"\n    [container]=\"'body'\"\n  >\n    <c8y-li\n      *c8yFor=\"let appVersion of versions$; loadMore: 'auto'; notFound: notFoundTemplate\"\n      (click)=\"onVersionSelect(appVersion)\"\n      class=\"p-l-8 p-r-8 c8y-list__item--link\"\n      [active]=\"selectedVersion === appVersion\"\n    >\n      <c8y-li-icon icon=\"big-parcel\"></c8y-li-icon>\n      <c8y-highlight\n        [text]=\"appVersion.version || '--'\"\n        [pattern]=\"onInput$ | async\"\n      ></c8y-highlight>\n      <span>\n        <span *ngFor=\"let tag of appVersion.tags\" class=\"label label-info m-l-4\">\n          {{ tag }}\n        </span>\n      </span>\n    </c8y-li>\n    <ng-template #notFoundTemplate>\n      <c8y-li\n        class=\"bg-gray-lighter p-8\"\n        *ngIf=\"(onInput$ | async)?.length > 0 && (versions$ | async)?.data?.length === 0\"\n      >\n        <span translate>No match found.</span>\n      </c8y-li>\n    </ng-template>\n  </c8y-typeahead>\n</c8y-form-group>\n", dependencies: [{ kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { 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: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { 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: ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PackageVersionSelectComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-package-version-select', providers: [
                        {
                            provide: NG_VALUE_ACCESSOR,
                            multi: true,
                            useExisting: forwardRef(() => PackageVersionSelectComponent)
                        }
                    ], imports: [
                        FormGroupComponent,
                        TypeaheadComponent,
                        FormsModule,
                        ForOfDirective,
                        ListItemComponent,
                        ListItemIconComponent,
                        HighlightComponent,
                        NgFor,
                        NgIf,
                        C8yTranslateDirective,
                        C8yTranslatePipe,
                        AsyncPipe
                    ], template: "<label for=\"packageVersion\">{{ label | translate }}</label>\n<c8y-form-group>\n  <c8y-typeahead\n    [(ngModel)]=\"selectedVersion\"\n    name=\"packageVersion\"\n    (onSearch)=\"onInput$.next($event)\"\n    placeholder=\"{{ 'Select below or start typing' | translate }}\"\n    [displayProperty]=\"'version'\"\n    [required]=\"true\"\n    [disabled]=\"isDisabled\"\n    [hideNew]=\"true\"\n    [container]=\"'body'\"\n  >\n    <c8y-li\n      *c8yFor=\"let appVersion of versions$; loadMore: 'auto'; notFound: notFoundTemplate\"\n      (click)=\"onVersionSelect(appVersion)\"\n      class=\"p-l-8 p-r-8 c8y-list__item--link\"\n      [active]=\"selectedVersion === appVersion\"\n    >\n      <c8y-li-icon icon=\"big-parcel\"></c8y-li-icon>\n      <c8y-highlight\n        [text]=\"appVersion.version || '--'\"\n        [pattern]=\"onInput$ | async\"\n      ></c8y-highlight>\n      <span>\n        <span *ngFor=\"let tag of appVersion.tags\" class=\"label label-info m-l-4\">\n          {{ tag }}\n        </span>\n      </span>\n    </c8y-li>\n    <ng-template #notFoundTemplate>\n      <c8y-li\n        class=\"bg-gray-lighter p-8\"\n        *ngIf=\"(onInput$ | async)?.length > 0 && (versions$ | async)?.data?.length === 0\"\n      >\n        <span translate>No match found.</span>\n      </c8y-li>\n    </ng-template>\n  </c8y-typeahead>\n</c8y-form-group>\n" }]
        }], ctorParameters: () => [{ type: i3$1.ApplicationService }, { type: i1.PluginsService }], propDecorators: { label: [{
                type: Input
            }], packageContextPath: [{
                type: Input
            }], packageId: [{
                type: Input
            }] } });

class UploadArchiveComponent {
    constructor(ecosystemService, alertService) {
        this.ecosystemService = ecosystemService;
        this.alertService = alertService;
        this.uploadNewVersion = false;
        this.applicationChange = new EventEmitter();
        this.refresh = new EventEmitter();
        this.archives = [];
        this.uploadInProgress = false;
        this.canReactivate = false;
    }
    get uploadProgress() {
        return this.ecosystemService.progress;
    }
    async onFileDroppedEvent(event) {
        if (this.preUploadCallback) {
            try {
                await this.preUploadCallback();
            }
            catch (e) {
                // do nothing, i.e. when confirm modal cancels and throws undefined
                return;
            }
        }
        if (event && event.length > 0) {
            const file = event[0].file;
            this.onFile(file);
        }
    }
    async onFile(file) {
        try {
            await this.ecosystemService.validateArchiveToAppCompatibility(file, this.application);
            const isCustomMicroservice = this.ecosystemService.isCustomMicroservice(this.application);
            const isPackage = this.ecosystemService.isPackage(this.application);
            this.archives = isCustomMicroservice
                ? []
                : await this.ecosystemService.listArchives(this.application.id);
            this.archives.sort((a, b) => {
                return new Date(b.created) - new Date(a.created);
            });
            this.uploadInProgress = true;
            this.uploadProgress.next(0);
            if (this.archives.length === 6 && !isCustomMicroservice && !isPackage) {
                await this.ecosystemService.removeOldestArchive(this.application, this.archives);
            }
            const app = await this.ecosystemService.uploadArchiveToApp(file, this.application, this.uploadNewVersion);
            this.applicationChange.emit(app);
            this.uploadProgress.next(100);
            this.uploadInProgress = false;
            this.refresh.emit();
            if (this.uploadNewVersion) {
                return;
            }
            this.alertService.success(gettext('Archive uploaded and activated.'));
        }
        catch (ex) {
            this.uploadInProgress = false;
            if (ex === 'cancelled') {
                return;
            }
            this.ecosystemService.alertError(ex);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: UploadArchiveComponent, deps: [{ token: EcosystemService }, { token: i1.AlertService }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: UploadArchiveComponent, isStandalone: true, selector: "c8y-upload-archive", inputs: { application: "application", uploadNewVersion: "uploadNewVersion", preUploadCallback: "preUploadCallback" }, outputs: { applicationChange: "applicationChange", refresh: "refresh" }, ngImport: i0, template: "<c8y-drop-area\n  (dropped)=\"onFileDroppedEvent($event)\"\n  [accept]=\"'.zip'\"\n  [loading]=\"uploadInProgress\"\n  [maxAllowedFiles]=\"1\"\n  [message]=\"'Upload a *.zip file' | translate\"\n  [progress]=\"uploadProgress | async\"\n  [forceHideList]=\"true\"\n  class=\"drop-area-sm\"\n>\n</c8y-drop-area>\n", dependencies: [{ kind: "component", type: DropAreaComponent, selector: "c8y-drop-area", inputs: ["formControl", "title", "message", "icon", "loadingMessage", "forceHideList", "alwaysShow", "clickToOpen", "loading", "progress", "maxAllowedFiles", "files", "maxFileSizeInMegaBytes", "accept"], outputs: ["dropped"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: UploadArchiveComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-upload-archive', imports: [DropAreaComponent, C8yTranslatePipe, AsyncPipe], template: "<c8y-drop-area\n  (dropped)=\"onFileDroppedEvent($event)\"\n  [accept]=\"'.zip'\"\n  [loading]=\"uploadInProgress\"\n  [maxAllowedFiles]=\"1\"\n  [message]=\"'Upload a *.zip file' | translate\"\n  [progress]=\"uploadProgress | async\"\n  [forceHideList]=\"true\"\n  class=\"drop-area-sm\"\n>\n</c8y-drop-area>\n" }]
        }], ctorParameters: () => [{ type: EcosystemService }, { type: i1.AlertService }], propDecorators: { application: [{
                type: Input
            }], uploadNewVersion: [{
                type: Input
            }], preUploadCallback: [{
                type: Input
            }], applicationChange: [{
                type: Output
            }], refresh: [{
                type: Output
            }] } });

class ListFiltersComponent {
    constructor(formBuilder, ui, translateService, gainsightService, router, activatedRoute) {
        this.formBuilder = formBuilder;
        this.ui = ui;
        this.translateService = translateService;
        this.gainsightService = gainsightService;
        this.router = router;
        this.activatedRoute = activatedRoute;
        this.packageTypes = [];
        this.packageAvailabilities = [];
        this.packageContents = [];
        this.filterPipeChange = new EventEmitter();
        this.chips = [];
        this.customFilters = new Map();
        this.CURRENT_LOCATION = location.href;
        this.destroy$ = new Subject();
        this.formGroup = this.initForm();
    }
    ngOnInit() {
        this.currentFiltersState = this.formGroup.value;
        this.predefinedFiltersVisible =
            this.packageTypes?.length > 0 ||
                this.packageAvailabilities?.length > 0 ||
                this.packageContents?.length > 0;
        this.currentLang = this.ui.state.lang;
        this.subscribeToQueryParams();
    }
    setFilterTerm(filterTerm) {
        this.currentFilterTerm = filterTerm;
        this.setPipe();
        this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.FILTER_LIST, {
            component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.LIST_FILTERS,
            action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.SET_FILTER_TERM,
            url: this.CURRENT_LOCATION
        });
    }
    applyPredefinedFilters() {
        this.currentFiltersState = this.formGroup.value;
        this.setChips();
        this.setPipe();
        this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.FILTER_LIST, {
            component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.LIST_FILTERS,
            action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.SET_PREDEFINED_FILTERS,
            url: this.CURRENT_LOCATION,
            filters: this.currentFiltersState
        });
    }
    reset() {
        this.formGroup.reset();
        this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.FILTER_LIST, {
            component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.LIST_FILTERS,
            action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.RESET_FILTER,
            url: this.CURRENT_LOCATION
        });
        this.applyPredefinedFilters();
    }
    resetAllFilters() {
        this.reset();
        this.filterInput.reset();
    }
    toggleDropdown(isOpen) {
        if (!isOpen) {
            this.formGroup.patchValue(this.currentFiltersState);
        }
    }
    deselectChip(chip) {
        chip[1].setValue(false);
        this.applyPredefinedFilters();
    }
    ngOnDestroy() {
        this.destroy$.next();
        this.destroy$.complete();
    }
    subscribeToQueryParams() {
        this.activatedRoute.queryParams
            .pipe(takeUntil(this.destroy$))
            .subscribe((queryParams) => {
            const filters = this.parseQueryParams(queryParams);
            this.currentFilterTerm = queryParams.filterTerm || '';
            this.formGroup.patchValue(filters);
            this.applyPredefinedFilters();
        });
    }
    setQueryParams() {
        if (!this.currentFiltersState) {
            return;
        }
        this.router.navigate([], {
            queryParams: {
                ...this.simplifyFilterObject(this.currentFiltersState),
                filterTerm: this.currentFilterTerm || null
            }
        });
    }
    parseQueryParams(queryParams) {
        const filter = {};
        for (const fullKey in queryParams) {
            const [key, subKey] = fullKey.split('.');
            if (!filter[key]) {
                filter[key] = {};
            }
            filter[key][subKey] = queryParams[fullKey] === 'true';
        }
        return filter;
    }
    simplifyFilterObject(currentFiltersState) {
        const keys = Object.keys(currentFiltersState);
        const result = {};
        for (const key of keys) {
            const subKeys = Object.keys(currentFiltersState[key]);
            for (const subKey of subKeys) {
                if (currentFiltersState[key][subKey]) {
                    result[`${key}.${subKey}`] = currentFiltersState[key][subKey];
                }
            }
        }
        return result;
    }
    initForm() {
        return this.formBuilder.group({
            type: this.formBuilder.group({
                [PackageType.OFFICIAL]: [false],
                [PackageType.COMMUNITY]: [false]
            }),
            availability: this.formBuilder.group({
                [APP_STATE.SUBSCRIBED.label]: [false],
                [APP_STATE.UNPACKED.label]: [false],
                [APP_STATE.EXTERNAL.label]: [false],
                [APP_STATE.CUSTOM.label]: [false]
            }),
            content: this.formBuilder.group({
                [APP_STATE.PACKAGE_BLUEPRINT.label]: [false],
                [APP_STATE.PACKAGE_PLUGIN.label]: [false]
            }),
            custom: this.formBuilder.group({})
        });
    }
    setPipe() {
        this.setQueryParams();
        const filterPipe = pipe(map((data) => {
            this.data = data.filter((app) => {
                let matchesByString;
                if (!this.currentFilterTerm || this.currentFilterTerm.trim().length === 0) {
                    matchesByString = true;
                }
                else {
                    const appName = this.currentLang === 'en' || !app.name?.length || !internalApps[app.name]
                        ? app.name
                        : this.translateService.instant(internalApps[app.name]);
                    matchesByString =
                        this.filterContainString(appName, this.currentFilterTerm) ||
                            this.filterContainString(app.description, this.currentFilterTerm);
                }
                const matchesByPredefinedProperty = this.appMatchesByPredefinedProperty(app, 'type') &&
                    this.appMatchesByPredefinedProperty(app, 'availability') &&
                    this.appMatchesByPredefinedProperty(app, 'content') &&
                    this.appMatchesByPredefinedProperty(app, 'custom');
                return matchesByString && matchesByPredefinedProperty;
            });
            return this.data;
        }));
        this.filterPipeChange.emit(filterPipe);
    }
    filterContainString(name, filterTerm) {
        const term = filterTerm.toLowerCase().trim();
        return name && name.toLowerCase().indexOf(term) > -1;
    }
    appMatchesByPredefinedProperty(app, property) {
        if (property === 'custom' && this.currentFiltersState) {
            return Object.entries(this.currentFiltersState[property]).every(([key, value]) => this.customFilters.get(key)(app, value));
        }
        // if filter object does not contain property filters or all filters are false, filter is inactive
        const filterForPropertyIsActive = this.currentFiltersState?.[property] &&
            !Object.values(this.currentFiltersState[property]).every(v => !v);
        if (!filterForPropertyIsActive) {
            return true;
        }
        else if (!app.filterProps?.[property]) {
            return false;
        }
        else {
            return this.currentFiltersState[property][app.filterProps[property]];
        }
    }
    setChips() {
        this.chips = [];
        Object.values(this.formGroup.controls).forEach((controlsGroup) => {
            Object.entries(controlsGroup.controls).forEach((entry) => {
                if (entry[1].value) {
                    this.chips.push(entry);
                }
            });
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ListFiltersComponent, deps: [{ token: i1$1.FormBuilder }, { token: i1.AppStateService }, { token: i3.TranslateService }, { token: i1.GainsightService }, { token: i4.Router }, { token: i4.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: ListFiltersComponent, isStandalone: true, selector: "c8y-list-filters", inputs: { packageTypes: "packageTypes", packageAvailabilities: "packageAvailabilities", packageContents: "packageContents" }, outputs: { filterPipeChange: "filterPipeChange" }, viewQueries: [{ propertyName: "filterInput", first: true, predicate: FilterInputComponent, descendants: true }], ngImport: i0, template: "<form\n  class=\"d-flex a-i-center\"\n  [formGroup]=\"formGroup\"\n>\n  <c8y-filter\n    [filterTerm]=\"currentFilterTerm\"\n    (onSearch)=\"setFilterTerm($event)\"\n  ></c8y-filter>\n\n  <div\n    class=\"dropdown m-l-8 m-r-4\"\n    *ngIf=\"predefinedFiltersVisible\"\n    dropdown\n    (isOpenChange)=\"toggleDropdown($event)\"\n    #filtersDropdown=\"bs-dropdown\"\n    [cdkTrapFocus]=\"filtersDropdown.isOpen\"\n    [insideClick]=\"true\"\n  >\n    <div class=\"input-group d-inline-flex\">\n      <button\n        class=\"btn-clean form-control p-l-8 p-r-16 a-s-stretch d-flex a-i-center gap-4 w-auto flex-no-shrink\"\n        title=\"{{ 'Filters' | translate }}\"\n        dropdownToggle\n      >\n        <span [ngPlural]=\"chips.length\">\n          <ng-template ngPluralCase=\"=0\">\n            {{ 'Filters' | translate }}\n          </ng-template>\n          <ng-template ngPluralCase=\"=1\">\n            <span class=\"badge badge-info\">{{ chips.length }}</span>\n            {{ 'Filter' | translate }}\n          </ng-template>\n          <ng-template ngPluralCase=\"other\">\n            <span class=\"badge badge-info\">{{ chips.length }}</span>\n            {{ 'Filters' | translate }}\n          </ng-template>\n        </span>\n        <span class=\"caret\"></span>\n      </button>\n      <div\n        class=\"input-group-addon p-t-0 p-b-0 d-flex gap-4 a-i-center inner-scroll\"\n        *ngIf=\"chips.length > 0\"\n      >\n        <ng-container *ngFor=\"let chip of chips\">\n          <span\n            class=\"tag tag--info chip\"\n            *ngIf=\"chip[1].value\"\n          >\n            <button\n              class=\"btn btn-xs btn-clean text-10\"\n              title=\"{{ 'Remove' | translate }}\"\n              type=\"button\"\n              (click)=\"deselectChip(chip)\"\n            >\n              <i c8yIcon=\"times\"></i>\n            </button>\n            {{ chip[0] | translate | titlecase }}\n          </span>\n        </ng-container>\n      </div>\n    </div>\n    <div\n      class=\"dropdown-menu\"\n      *dropdownMenu\n    >\n      <div class=\"dropdown-form\">\n        <c8y-form-group\n          *ngIf=\"packageTypes.length\"\n          formGroupName=\"type\"\n        >\n          <label class=\"m-b-16\">\n            {{ 'Type' | translate }}\n          </label>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"type | translate\"\n            *ngFor=\"let type of packageTypes\"\n          >\n            <input\n              type=\"checkbox\"\n              [formControlName]=\"type\"\n              [value]=\"type\"\n            />\n            <span></span>\n            <span>{{ type | translate | titlecase }}</span>\n          </label>\n        </c8y-form-group>\n\n        <c8y-form-group\n          *ngIf=\"packageAvailabilities.length\"\n          formGroupName=\"availability\"\n        >\n          <label class=\"m-b-16\">\n            {{ 'Availability`of package based on app state`' | translate }}\n          </label>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"availability | translate\"\n            *ngFor=\"let availability of packageAvailabilities\"\n          >\n            <input\n              type=\"checkbox\"\n              [formControlName]=\"availability\"\n              [value]=\"availability\"\n            />\n            <span></span>\n            <span>{{ availability | translate }}</span>\n          </label>\n        </c8y-form-group>\n\n        <c8y-form-group\n          *ngIf=\"packageContents.length\"\n          formGroupName=\"content\"\n        >\n          <label class=\"m-b-16\">\n            {{ 'Content' | translate }}\n          </label>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"content | translate\"\n            *ngFor=\"let content of packageContents\"\n          >\n            <input\n              type=\"checkbox\"\n              [formControlName]=\"content\"\n              [value]=\"content\"\n            />\n            <span></span>\n            <span>{{ content | translate }}</span>\n          </label>\n        </c8y-form-group>\n        <c8y-form-group formGroupName=\"custom\">\n          <ng-content></ng-content>\n        </c8y-form-group>\n      </div>\n      <div class=\"p-16 d-flex gap-8 separator-top\">\n        <button\n          class=\"btn btn-default btn-sm flex-grow\"\n          title=\"{{ 'Reset' | translate }}\"\n          type=\"button\"\n          (click)=\"reset(); filtersDropdown.isOpen = false\"\n        >\n          {{ 'Reset' | translate }}\n        </button>\n\n        <button\n          class=\"btn btn-primary btn-sm flex-grow\"\n          title=\"{{ 'Apply' | translate }}\"\n          type=\"button\"\n          (click)=\"applyPredefinedFilters(); filtersDropdown.isOpen = false\"\n          [disabled]=\"formGroup.pristine && formGroup.untouched\"\n        >\n          {{ 'Apply' | translate }}\n        </button>\n      </div>\n    </div>\n  </div>\n</form>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$1.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "component", type: FilterInputComponent, selector: "c8y-filter", inputs: ["icon", "filterTerm"], outputs: ["onSearch"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: BsDropdownDirective, selector: "[bsDropdown], [dropdown]", inputs: ["placement", "triggers", "container", "dropup", "autoClose", "isAnimated", "insideClick", "isDisabled", "isOpen"], outputs: ["isOpenChange", "onShown", "onHidden"], exportAs: ["bs-dropdown"] }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "directive", type: BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: NgPlural, selector: "[ngPlural]", inputs: ["ngPlural"] }, { kind: "directive", type: NgPluralCase, selector: "[ngPluralCase]" }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: TitleCasePipe, name: "titlecase" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ListFiltersComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-list-filters', imports: [
                        FormsModule,
                        ReactiveFormsModule,
                        FilterInputComponent,
                        NgIf,
                        BsDropdownDirective,
                        CdkTrapFocus,
                        BsDropdownToggleDirective,
                        NgPlural,
                        NgPluralCase,
                        NgFor,
                        IconDirective,
                        BsDropdownMenuDirective,
                        FormGroupComponent,
                        RequiredInputPlaceholderDirective,
                        C8yTranslatePipe,
                        TitleCasePipe
                    ], template: "<form\n  class=\"d-flex a-i-center\"\n  [formGroup]=\"formGroup\"\n>\n  <c8y-filter\n    [filterTerm]=\"currentFilterTerm\"\n    (onSearch)=\"setFilterTerm($event)\"\n  ></c8y-filter>\n\n  <div\n    class=\"dropdown m-l-8 m-r-4\"\n    *ngIf=\"predefinedFiltersVisible\"\n    dropdown\n    (isOpenChange)=\"toggleDropdown($event)\"\n    #filtersDropdown=\"bs-dropdown\"\n    [cdkTrapFocus]=\"filtersDropdown.isOpen\"\n    [insideClick]=\"true\"\n  >\n    <div class=\"input-group d-inline-flex\">\n      <button\n        class=\"btn-clean form-control p-l-8 p-r-16 a-s-stretch d-flex a-i-center gap-4 w-auto flex-no-shrink\"\n        title=\"{{ 'Filters' | translate }}\"\n        dropdownToggle\n      >\n        <span [ngPlural]=\"chips.length\">\n          <ng-template ngPluralCase=\"=0\">\n            {{ 'Filters' | translate }}\n          </ng-template>\n          <ng-template ngPluralCase=\"=1\">\n            <span class=\"badge badge-info\">{{ chips.length }}</span>\n            {{ 'Filter' | translate }}\n          </ng-template>\n          <ng-template ngPluralCase=\"other\">\n            <span class=\"badge badge-info\">{{ chips.length }}</span>\n            {{ 'Filters' | translate }}\n          </ng-template>\n        </span>\n        <span class=\"caret\"></span>\n      </button>\n      <div\n        class=\"input-group-addon p-t-0 p-b-0 d-flex gap-4 a-i-center inner-scroll\"\n        *ngIf=\"chips.length > 0\"\n      >\n        <ng-container *ngFor=\"let chip of chips\">\n          <span\n            class=\"tag tag--info chip\"\n            *ngIf=\"chip[1].value\"\n          >\n            <button\n              class=\"btn btn-xs btn-clean text-10\"\n              title=\"{{ 'Remove' | translate }}\"\n              type=\"button\"\n              (click)=\"deselectChip(chip)\"\n            >\n              <i c8yIcon=\"times\"></i>\n            </button>\n            {{ chip[0] | translate | titlecase }}\n          </span>\n        </ng-container>\n      </div>\n    </div>\n    <div\n      class=\"dropdown-menu\"\n      *dropdownMenu\n    >\n      <div class=\"dropdown-form\">\n        <c8y-form-group\n          *ngIf=\"packageTypes.length\"\n          formGroupName=\"type\"\n        >\n          <label class=\"m-b-16\">\n            {{ 'Type' | translate }}\n          </label>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"type | translate\"\n            *ngFor=\"let type of packageTypes\"\n          >\n            <input\n              type=\"checkbox\"\n              [formControlName]=\"type\"\n              [value]=\"type\"\n            />\n            <span></span>\n            <span>{{ type | translate | titlecase }}</span>\n          </label>\n        </c8y-form-group>\n\n        <c8y-form-group\n          *ngIf=\"packageAvailabilities.length\"\n          formGroupName=\"availability\"\n        >\n          <label class=\"m-b-16\">\n            {{ 'Availability`of package based on app state`' | translate }}\n          </label>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"availability | translate\"\n            *ngFor=\"let availability of packageAvailabilities\"\n          >\n            <input\n              type=\"checkbox\"\n              [formControlName]=\"availability\"\n              [value]=\"availability\"\n            />\n            <span></span>\n            <span>{{ availability | translate }}</span>\n          </label>\n        </c8y-form-group>\n\n        <c8y-form-group\n          *ngIf=\"packageContents.length\"\n          formGroupName=\"content\"\n        >\n          <label class=\"m-b-16\">\n            {{ 'Content' | translate }}\n          </label>\n          <label\n            class=\"c8y-checkbox\"\n            [title]=\"content | translate\"\n            *ngFor=\"let content of packageContents\"\n          >\n            <input\n              type=\"checkbox\"\n              [formControlName]=\"content\"\n              [value]=\"content\"\n            />\n            <span></span>\n            <span>{{ content | translate }}</span>\n          </label>\n        </c8y-form-group>\n        <c8y-form-group formGroupName=\"custom\">\n          <ng-content></ng-content>\n        </c8y-form-group>\n      </div>\n      <div class=\"p-16 d-flex gap-8 separator-top\">\n        <button\n          class=\"btn btn-default btn-sm flex-grow\"\n          title=\"{{ 'Reset' | translate }}\"\n          type=\"button\"\n          (click)=\"reset(); filtersDropdown.isOpen = false\"\n        >\n          {{ 'Reset' | translate }}\n        </button>\n\n        <button\n          class=\"btn btn-primary btn-sm flex-grow\"\n          title=\"{{ 'Apply' | translate }}\"\n          type=\"button\"\n          (click)=\"applyPredefinedFilters(); filtersDropdown.isOpen = false\"\n          [disabled]=\"formGroup.pristine && formGroup.untouched\"\n        >\n          {{ 'Apply' | translate }}\n        </button>\n      </div>\n    </div>\n  </div>\n</form>\n" }]
        }], ctorParameters: () => [{ type: i1$1.FormBuilder }, { type: i1.AppStateService }, { type: i3.TranslateService }, { type: i1.GainsightService }, { type: i4.Router }, { type: i4.ActivatedRoute }], propDecorators: { packageTypes: [{
                type: Input
            }], packageAvailabilities: [{
                type: Input
            }], packageContents: [{
                type: Input
            }], filterPipeChange: [{
                type: Output
            }], filterInput: [{
                type: ViewChild,
                args: [FilterInputComponent]
            }] } });

class ArchivedFilterComponent {
    constructor(filterComponent) {
        this.filterComponent = filterComponent;
        this.filterLabel = gettext('Show archived packages');
        this.archivedFormControl = new FormControl();
        this.filterComponent.formGroup.controls.custom.addControl(this.filterLabel, this.archivedFormControl);
        filterComponent.customFilters.set(this.filterLabel, (appOrPlugin, enabled) => {
            return (appOrPlugin.filterProps.type !== PackageType.ARCHIVED ||
                (appOrPlugin.filterProps.type === PackageType.ARCHIVED && enabled));
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ArchivedFilterComponent, deps: [{ token: ListFiltersComponent }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: ArchivedFilterComponent, isStandalone: true, selector: "c8y-archived-filter", ngImport: i0, template: "<label class=\"c8y-switch\">\n  <input\n    type=\"checkbox\"\n    checked=\"checked\"\n    [formControl]=\"archivedFormControl\"\n  />\n  <span></span>\n  {{ 'Show archived packages' | translate }}\n</label>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: ArchivedFilterComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-archived-filter', imports: [FormsModule, ReactiveFormsModule, C8yTranslatePipe], template: "<label class=\"c8y-switch\">\n  <input\n    type=\"checkbox\"\n    checked=\"checked\"\n    [formControl]=\"archivedFormControl\"\n  />\n  <span></span>\n  {{ 'Show archived packages' | translate }}\n</label>\n" }]
        }], ctorParameters: () => [{ type: ListFiltersComponent }] });

/**
 * Component to display the change log of a package.
 * It fetches the change log file from the package's repository and displays it.
 * It can fetch the change log for the latest version or a specific version if provided.
 * It can also compare the change log with the previous version if provided and display the difference between the two versions.
 */
class PackageChangelogComponent {
    constructor() {
        this.selectedVersion = 'latest';
        this.previousVersion = null;
        this.isLoading = true;
        this.pluginsService = inject(PluginsService);
    }
    async ngOnChanges() {
        if (!this.package) {
            this.changelog = '';
            this.isLoading = false;
            return;
        }
        this.isLoading = true;
        this.changelog = await this.getChangeLog();
        this.isLoading = false;
    }
    async getChangeLog() {
        if (this.selectedVersion === this.previousVersion || !this.selectedVersion) {
            return '';
        }
        const selectedVersionChangelogUrl = this.baseUrlForVersion(this.selectedVersion);
        this.baseUrl = selectedVersionChangelogUrl;
        if (!this.previousVersion) {
            return await this.pluginsService.getChangelogFileContent(selectedVersionChangelogUrl);
        }
        const previousVersionChangelogUrl = this.baseUrlForVersion(this.previousVersion);
        const changelogsPromises = [
            this.pluginsService.getChangelogFileContent(previousVersionChangelogUrl),
            this.pluginsService.getChangelogFileContent(selectedVersionChangelogUrl)
        ];
        const [previousVersionChangelog, selectedVersionChangelog] = await Promise.all(changelogsPromises);
        // Determine if this is a downgrade using semver comparison
        let isDowngrade;
        try {
            isDowngrade = lt(this.selectedVersion, this.previousVersion);
        }
        catch {
            isDowngrade = false;
        }
        if (isDowngrade) {
            return previousVersionChangelog.replace(selectedVersionChangelog, '');
        }
        else {
            return selectedVersionChangelog.replace(previousVersionChangelog, '');
        }
    }
    baseUrlForVersion(version) {
        return `/apps/${this.package.contextPath}@${version}/`;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PackageChangelogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: PackageChangelogComponent, isStandalone: true, selector: "c8y-contents-changelog", inputs: { package: "package", selectedVersion: "selectedVersion", previousVersion: "previousVersion" }, usesOnChanges: true, ngImport: i0, template: "<c8y-loading *ngIf=\"isLoading\"></c8y-loading>\n\n<ng-container *ngIf=\"!isLoading\">\n  <div\n    *ngIf=\"changelog\"\n    class=\"markdown-content markdown-content--to-h3\"\n    [innerHTML]=\"changelog | markdownToHtml: { baseUrl } | async\"\n  ></div>\n\n  <c8y-ui-empty-state\n    [icon]=\"'user-manual'\"\n    [title]=\"'No CHANGELOG.md found for package version' | translate\"\n    [subtitle]=\"\n      'To view the contents of &quot;CHANGELOG&quot;, add the file &quot;CHANGELOG.md&quot; to the package.'\n        | translate\n    \"\n    *ngIf=\"!changelog\"\n    [horizontal]=\"true\"\n  ></c8y-ui-empty-state>\n</ng-container>\n", dependencies: [{ kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: MarkdownToHtmlPipe, name: "markdownToHtml" }, { 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: PackageChangelogComponent, decorators: [{
            type: Component,
            args: [{ selector: 'c8y-contents-changelog', standalone: true, imports: [
                        LoadingComponent,
                        MarkdownToHtmlPipe,
                        EmptyStateComponent,
                        AsyncPipe,
                        C8yTranslatePipe,
                        NgIf
                    ], template: "<c8y-loading *ngIf=\"isLoading\"></c8y-loading>\n\n<ng-container *ngIf=\"!isLoading\">\n  <div\n    *ngIf=\"changelog\"\n    class=\"markdown-content markdown-content--to-h3\"\n    [innerHTML]=\"changelog | markdownToHtml: { baseUrl } | async\"\n  ></div>\n\n  <c8y-ui-empty-state\n    [icon]=\"'user-manual'\"\n    [title]=\"'No CHANGELOG.md found for package version' | translate\"\n    [subtitle]=\"\n      'To view the contents of &quot;CHANGELOG&quot;, add the file &quot;CHANGELOG.md&quot; to the package.'\n        | translate\n    \"\n    *ngIf=\"!changelog\"\n    [horizontal]=\"true\"\n  ></c8y-ui-empty-state>\n</ng-container>\n" }]
        }], propDecorators: { package: [{
                type: Input
            }], selectedVersion: [{
                type: Input
            }], previousVersion: [{
                type: Input
            }] } });

class SharedEcosystemModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SharedEcosystemModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: SharedEcosystemModule, imports: [CoreModule,
            BsDropdownModule,
            TooltipModule,
            A11yModule,
            FormsModule,
            PopoverModule,
            ReactiveFormsModule,
            IconSelectorModule,
            PackageChangelogComponent,
            AddApplicationComponent,
            ApplicationPropertiesFormComponent,
            UploadArchiveComponent,
            ApplicationCardComponent,
            DuplicateApplicationListComponent,
            DuplicateApplicationPropertiesComponent,
            DuplicateApplicationComponent,
            PackageVersionSelectComponent,
            TranslatePackageLabelPipe,
            ListFiltersComponent,
            ArchivedFilterComponent], exports: [AddApplicationComponent,
            ApplicationPropertiesFormComponent,
            UploadArchiveComponent,
            ApplicationCardComponent,
            DuplicateApplicationListComponent,
            DuplicateApplicationPropertiesComponent,
            DuplicateApplicationComponent,
            PackageVersionSelectComponent,
            TranslatePackageLabelPipe,
            ListFiltersComponent,
            ArchivedFilterComponent,
            PackageChangelogComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SharedEcosystemModule, providers: [
            hookWizard({
                wizardId: EcosystemWizards.APPLICATION_UPLOAD,
                component: DuplicateApplicationComponent,
                name: 'Duplicate existing application',
                c8yIcon: 'copy'
            }),
            hookWizard({
                wizardId: 'duplicateApplication',
                component: DuplicateApplicationComponent,
                name: 'Duplicate existing application',
                c8yIcon: 'copy'
            })
        ], imports: [CoreModule,
            BsDropdownModule,
            TooltipModule,
            A11yModule,
            FormsModule,
            PopoverModule,
            ReactiveFormsModule,
            IconSelectorModule,
            PackageChangelogComponent,
            AddApplicationComponent,
            ApplicationPropertiesFormComponent,
            UploadArchiveComponent,
            ApplicationCardComponent,
            DuplicateApplicationListComponent,
            DuplicateApplicationPropertiesComponent,
            DuplicateApplicationComponent,
            PackageVersionSelectComponent,
            ListFiltersComponent,
            ArchivedFilterComponent] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: SharedEcosystemModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [
                        CoreModule,
                        BsDropdownModule,
                        TooltipModule,
                        A11yModule,
                        FormsModule,
                        PopoverModule,
                        ReactiveFormsModule,
                        IconSelectorModule,
                        PackageChangelogComponent,
                        AddApplicationComponent,
                        ApplicationPropertiesFormComponent,
                        UploadArchiveComponent,
                        ApplicationCardComponent,
                        DuplicateApplicationListComponent,
                        DuplicateApplicationPropertiesComponent,
                        DuplicateApplicationComponent,
                        PackageVersionSelectComponent,
                        TranslatePackageLabelPipe,
                        ListFiltersComponent,
                        ArchivedFilterComponent
                    ],
                    exports: [
                        AddApplicationComponent,
                        ApplicationPropertiesFormComponent,
                        UploadArchiveComponent,
                        ApplicationCardComponent,
                        DuplicateApplicationListComponent,
                        DuplicateApplicationPropertiesComponent,
                        DuplicateApplicationComponent,
                        PackageVersionSelectComponent,
                        TranslatePackageLabelPipe,
                        ListFiltersComponent,
                        ArchivedFilterComponent,
                        PackageChangelogComponent
                    ],
                    providers: [
                        hookWizard({
                            wizardId: EcosystemWizards.APPLICATION_UPLOAD,
                            component: DuplicateApplicationComponent,
                            name: 'Duplicate existing application',
                            c8yIcon: 'copy'
                        }),
                        hookWizard({
                            wizardId: 'duplicateApplication',
                            component: DuplicateApplicationComponent,
                            name: 'Duplicate existing application',
                            c8yIcon: 'copy'
                        })
                    ]
                }]
        }] });

const defaultPackageTypes = [
    PackageType.OFFICIAL,
    PackageType.COMMUNITY
];
const defaultPackageAvailabilities = [
    APP_STATE.SUBSCRIBED.label,
    APP_STATE.UNPACKED.label,
    APP_STATE.EXTERNAL.label,
    APP_STATE.CUSTOM.label
];
const defaultPackageContents = [
    APP_STATE.PACKAGE_BLUEPRINT.label,
    APP_STATE.PACKAGE_PLUGIN.label
];

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

export { APP_STATE, AddApplicationComponent, ApplicationCardComponent, ApplicationPropertiesFormComponent, ArchivedFilterComponent, DuplicateApplicationComponent, DuplicateApplicationListComponent, DuplicateApplicationPropertiesComponent, ERROR_MESSAGES, ERROR_TYPE, EcosystemService, EcosystemWizards, ListFiltersComponent, PACKAGE_TYPE_LABELS, PRODUCT_EXPERIENCE_ECOSYSTEM, PackageAvailabilityService, PackageChangelogComponent, PackageVersionSelectComponent, SharedEcosystemModule, TranslatePackageLabelPipe, UploadArchiveComponent, defaultPackageAvailabilities, defaultPackageContents, defaultPackageTypes, packageProperties };
//# sourceMappingURL=c8y-ngx-components-ecosystem-shared.mjs.map