UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

501 lines 88.1 kB
import { Component, Input, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { AlertService, ApplicationPluginStatus, DataGridComponent, GainsightService, gettext, PluginsService, PluginsExportScopes, BottomDrawerService } from '@c8y/ngx-components'; import { EcosystemService, PRODUCT_EXPERIENCE_ECOSYSTEM } from '@c8y/ngx-components/ecosystem/shared'; import { pick } from 'lodash-es'; import { BsModalService } from 'ngx-bootstrap/modal'; import { BehaviorSubject, combineLatest, firstValueFrom, Subject } from 'rxjs'; import { map, shareReplay } from 'rxjs/operators'; import { InstallPluginComponent } from './install-plugin.component'; import { LabelCellRendererComponent } from './label-cell-renderer.component'; import { OrphanedStatusCellRendererComponent } from './orphaned-status-cell-renderer.component'; import { UpdatePluginOfAppComponent } from './update-plugin-of-app/update-plugin-of-app.component'; import { ApplicationPluginReadmeComponent } from './application-plugin-readme.component'; import * as i0 from "@angular/core"; import * as i1 from "@angular/router"; import * as i2 from "@c8y/ngx-components/ecosystem/shared"; import * as i3 from "ngx-bootstrap/modal"; import * as i4 from "@c8y/ngx-components"; import * as i5 from "@angular/common"; export class ApplicationPluginsComponent { constructor(activatedRoute, ecosystemService, bsModalService, pluginsService, alertService, gainsightService, bottomDrawerService) { this.activatedRoute = activatedRoute; this.ecosystemService = ecosystemService; this.bsModalService = bsModalService; this.pluginsService = pluginsService; this.alertService = alertService; this.gainsightService = gainsightService; this.bottomDrawerService = bottomDrawerService; this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_ECOSYSTEM; this.CURRENT_LOCATION = location.href; this.remotePlugins$ = new BehaviorSubject({}); this.allAvailablePlugins$ = new BehaviorSubject([]); this.selfPlugins$ = new BehaviorSubject([]); this.installedPlugins$ = combineLatest([ this.remotePlugins$.pipe(map(remotes => PluginsService.convertInstalledRemotesToIds(remotes))), this.allAvailablePlugins$ ]).pipe(map(([remotePlugins, allPlugins]) => this.getInstalledPlugins(allPlugins, remotePlugins)), shareReplay(1)); this.orphanedPlugins$ = this.installedPlugins$.pipe(map(plugins => plugins.filter(p => p.status === ApplicationPluginStatus.ORPHANED))); this.isStandard$ = combineLatest([this.installedPlugins$, this.selfPlugins$]).pipe(map(([installedPlugins, selfPlugins]) => { const manifestRemotes = this.app?.manifest?.remotes || {}; // ensure that every installed plugin is a self plugin or a plugin from the manifest const allInstalledPluginsAreSelf = installedPlugins.every(p => selfPlugins.some(selfPlugin => selfPlugin.id === p.id) || (Array.isArray(manifestRemotes[p.contextPath]) && manifestRemotes[p.contextPath].includes(p.module))); // ensure that every self plugin is installed const allSelfPluginsAreInstalled = selfPlugins.every(selfPlugin => installedPlugins.some(p => p.id === selfPlugin.id)); const configRemotes = this.app?.config?.remotes || {}; // ensure that every remote from the manifest is in the config // if no config exists we are also all good const everyRemoteFromManifestIsInConfig = !this.app?.config?.remotes || Object.keys(manifestRemotes).every(contextPath => Array.isArray(configRemotes[contextPath]) && Array.isArray(manifestRemotes[contextPath]) && manifestRemotes[contextPath].every(module => configRemotes[contextPath].includes(module))); return (allInstalledPluginsAreSelf && allSelfPluginsAreInstalled && everyRemoteFromManifestIsInConfig); })); this.title = gettext('Installed plugins'); this.loadMoreItemsLabel = gettext('Load more packages'); this.loadingItemsLabel = gettext('Loading packages…'); this.actionControls = this.getActionControls(); this.bulkActionControls = this.getBulkActionControls(); this.headerActionControls = []; this.noResultsMessage = gettext('No plugins to display.'); this.noDataMessage = gettext('No plugins installed.'); this.noResultsSubtitle = gettext('Refine your search terms or check your spelling.'); this.noDataSubtitle = gettext("This application doesn't have any plugin. Click below to install."); this.pagination = { pageSize: 10, currentPage: 1 }; this.displayOptions = { bordered: false, striped: true, filter: true, gridHeader: true, hover: true }; this.columns = [ { name: 'name', header: gettext('Plugin name'), path: 'name', filterable: true }, { name: 'Version', header: gettext('Version'), path: 'version', filterable: false }, { name: 'Tag', header: gettext('Tag`noun`'), path: 'installedViaTag', filterable: false, cellRendererComponent: LabelCellRendererComponent }, { name: 'description', header: gettext('Description'), path: 'description', filterable: false, cellCSSClassName: 'small' }, { name: 'contextPath', header: gettext('Source'), path: 'contextPath', filterable: false, cellRendererComponent: LabelCellRendererComponent }, { name: 'scope', header: gettext('Scope'), path: 'scope', filterable: false, visible: false, cellRendererComponent: LabelCellRendererComponent }, { name: 'status', header: gettext('Status'), path: 'status', filterable: false, cellRendererComponent: OrphanedStatusCellRendererComponent } ]; this.destroy$ = new Subject(); } ngOnInit() { this.addInstallButtonToHeaderActionControls(); this.loadData(); } async loadData() { this.isLoading = true; await this.getApplicationMO(); await this.getApplicationMFRemotes(this.app); await this.getAllApplicationsMFExports(this.app); await this.getAllSelfMFExports(this.app); this.isLoading = false; } async resetToDefault() { this.isLoading = true; await this.pluginsService.resetRemotes(this.app); await this.loadData(); this.alertService.success(gettext('The application was reset to its default plugins.')); } async installPlugins() { let currentPlugin = null; try { this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.INSTALLED_PLUGINS, { component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.APPLICATION_PLUGINS, action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.INSTALL_PLUGINS_INITIATED, url: this.CURRENT_LOCATION, targetApplicationName: this.app.name, targetApplicationContextPath: this.app.contextPath }); const drawer = this.bottomDrawerService.openDrawer(InstallPluginComponent, { initialState: this.getInstallModalInitState(), closeOnNavigation: true }); const pluginsToAdd = await drawer.instance.result; const isArchived = await this.ecosystemService.verifyArchived(pluginsToAdd); if (!isArchived) { return; } const licensesVerifiedByUser = await this.ecosystemService.verifyLicenses(pluginsToAdd); if (!licensesVerifiedByUser) { return; } const verifyVersionCompatibility = await this.ecosystemService.verifyPluginVersionsCompatibility(pluginsToAdd, this.app); if (!verifyVersionCompatibility) { return; } this.isLoading = true; await this.handleRemotesInstallation(pluginsToAdd); this.alertService.success(gettext('Plugins installed.')); pluginsToAdd.forEach(plugin => { currentPlugin = plugin; this.triggerPluginEvent(plugin, PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.PLUGIN_INSTALLED); }); } catch (ex) { if (ex) { this.alertService.addServerFailure(ex); this.triggerPluginEvent(currentPlugin, PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE); } } finally { this.isLoading = false; } } async removePlugins(plugins) { let currentPlugin = null; try { this.isLoading = true; const installedPlugins = await firstValueFrom(this.installedPlugins$); const pluginsToRemove = installedPlugins.filter(p => plugins.includes(p.id)); const updatedRemotes = await this.pluginsService.removeRemotes(this.app, plugins.map(id => installedPlugins.find(p => p.id === id))); this.emitRemotes(updatedRemotes); this.isLoading = false; this.dataGrid.cancel(); this.alertService.success(gettext('Plugins removed.')); pluginsToRemove.forEach(plugin => { currentPlugin = plugin; this.triggerPluginEvent(plugin, PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.PLUGIN_REMOVED); }); } catch (ex) { if (ex) { this.alertService.addServerFailure(ex); this.triggerPluginEvent(currentPlugin, PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE); } } finally { this.isLoading = false; } } async cleanupOrphanedPlugins(plugins) { const pluginIds = plugins.map(p => p.id); await this.removePlugins(pluginIds); } getActionControls() { return [ { type: 'showReadme', text: gettext('Show readme'), icon: 'documents', showIf: (plugin) => { return !!plugin.readmePath; }, callback: plugin => this.showPluginReadme(plugin) }, { type: 'customUpdate', text: gettext('Update'), icon: 'installing-updates', showIf: plugin => { return (plugin.status === ApplicationPluginStatus.OUTDATED || plugin.status === ApplicationPluginStatus.REVOKED); }, callback: plugin => this.updatePlugin(this.app, plugin) }, { type: 'customDowngrade', text: gettext('Downgrade'), icon: 'installing-updates', showIf: (plugin) => { if (plugin.scope === PluginsExportScopes.SELF || plugin.scope === PluginsExportScopes.SELF_OPTIONAL) { return false; } return plugin.status === ApplicationPluginStatus.LATEST; }, callback: plugin => this.updatePlugin(this.app, plugin, true) } ]; } showPluginReadme(plugin) { this.bottomDrawerService.openDrawer(ApplicationPluginReadmeComponent, { initialState: { plugin }, closeOnNavigation: true }); } getBulkActionControls() { return [ { type: 'customDelete', text: gettext('Remove'), icon: 'trash', callback: plugins => this.removePlugins(plugins) } ]; } async updatePlugin(app, plugin, downgrade = false) { try { await this.bsModalService.show(UpdatePluginOfAppComponent, { class: 'modal-md', ariaDescribedby: 'modal-body', ariaLabelledBy: 'modal-title', initialState: { app, plugin, downgrade }, ignoreBackdropClick: true }).content.result; this.refresh(); } catch (er) { return; } } refresh() { this.loadData(); } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } addInstallButtonToHeaderActionControls() { if (this.appId) { this.headerActionControls = [ { text: gettext('Install plugins'), callback: () => { this.installPlugins(); }, icon: 'plus-circle', type: 'custom' } ]; } } async handleRemotesInstallation(plugins) { const updatedRemotes = await this.pluginsService.addRemotes(this.app, plugins); return this.emitRemotes(updatedRemotes); } emitRemotes(pluginsConfig) { const { remotes, excludedRemotes } = pluginsConfig; // needed for first time adding/removing a plugin if (!this.app.config) { this.app.config = {}; } this.app.config.remotes = remotes; this.app.config.excludedRemotes = excludedRemotes; const actualRemotes = this.pluginsService.getMFRemotes(this.app); this.remotePlugins$.next(actualRemotes); return { ...this.remotePlugins$.value }; } async getApplicationMO() { let id = this.appId; if (!id) { const { id: routeId } = this.activatedRoute.snapshot.parent.data.contextData; id = routeId; } try { this.app = await this.ecosystemService.getApplication(id); } catch (er) { if (er) { this.alertService.addServerFailure(er); } } return this.app; } async getApplicationMFExports(app) { const exports = this.pluginsService.getMFExports(app, [], true); return exports; } async getApplicationMFRemotes(app) { const appConfigRemotes = this.pluginsService.getMFRemotes(app); this.remotePlugins$.next(appConfigRemotes || {}); } async getAllApplicationsMFExports(app) { const exportedByCurrentApp = await this.getApplicationMFExports(app); const allAppsMFExports = await this.pluginsService.getAllMFExports(true); this.allAvailablePlugins$.next([...allAppsMFExports, ...exportedByCurrentApp]); } async getAllSelfMFExports(app) { const exportedByCurrentApp = await this.getApplicationMFExports(app); this.selfPlugins$.next(exportedByCurrentApp.filter(({ scope }) => scope === 'self')); } getInstallModalInitState() { return { plugins$: combineLatest([this.allAvailablePlugins$, this.installedPlugins$]).pipe(map(([allPlugins, installedPlugins]) => { // to not mutate the original array and objects contained in it const allPluginsAsNewObjects = allPlugins.map(p => ({ ...p })); for (const plugin of installedPlugins) { let installedPlugin = allPluginsAsNewObjects.find(p => p.id === plugin.id); if (!installedPlugin && plugin.installedViaTag) { installedPlugin = allPluginsAsNewObjects.find(p => p.contextPath === plugin.contextPath && p.module === plugin.module && p.tags?.includes(plugin.installedViaTag)); } if (installedPlugin) { installedPlugin.installed = true; continue; } } return allPluginsAsNewObjects.map(p => ({ ...p, installed: !!p.installed })); }), shareReplay(1)) }; } getOrphanedPlugins(orphanedPluginIds, allPlugins) { const orphanedPlugins = orphanedPluginIds.map(p => this.extractDetails(p)); const orphanedPluginsUpdated = orphanedPlugins.map(p => { const pluginWithMatchingTag = allPlugins.find(tmp => tmp.contextPath === p.contextPath && tmp.module === p.module && tmp.tags?.includes(p.version || 'latest')); if (pluginWithMatchingTag) { return { ...pluginWithMatchingTag, id: p.id, status: ApplicationPluginStatus.AUTO, installedViaTag: p.version || 'latest' }; } const pluginInDifferentVersion = allPlugins.find(tmp => tmp.contextPath === p.contextPath && tmp.module === p.module); if (pluginInDifferentVersion) { return { ...pluginInDifferentVersion, version: p.version, id: p.id, status: ApplicationPluginStatus.OUTDATED }; } return p; }); return orphanedPluginsUpdated; } splitOrphanedPluginsIntoOrphanedAndRevokedPlugins(allPlugins, orphanedPlugins) { const revokedPlugins = new Array(); const actuallyOrphanedPlugins = new Array(); for (const plugin of orphanedPlugins) { const foundFamiliarPlugin = allPlugins.find(plugin1 => plugin.contextPath === plugin1.contextPath && plugin.module === plugin1.module); if (foundFamiliarPlugin) { revokedPlugins.push(Object.assign({}, foundFamiliarPlugin, plugin, { status: ApplicationPluginStatus.REVOKED })); } else { actuallyOrphanedPlugins.push(plugin); } } return { revokedPlugins, actuallyOrphanedPlugins }; } getInstalledPlugins(allPlugins, remotePlugins) { const availablePlugins = allPlugins .filter(plugin => remotePlugins.includes(plugin.id)) .map(plugin => Object.assign(plugin, { status: plugin.tags?.includes('latest') ? ApplicationPluginStatus.LATEST : ApplicationPluginStatus.OUTDATED })); const orphanedPluginIds = remotePlugins.filter(r => !availablePlugins.find(plugin => plugin.id === r)); const orphanedPlugins = this.getOrphanedPlugins(orphanedPluginIds, allPlugins); const notActuallyOrphanedPlugins = orphanedPlugins.filter(p => p.status === ApplicationPluginStatus.AUTO); const orphanedOrRevokedPlugins = orphanedPlugins.filter(p => p.status !== ApplicationPluginStatus.AUTO); const { actuallyOrphanedPlugins, revokedPlugins } = this.splitOrphanedPluginsIntoOrphanedAndRevokedPlugins(allPlugins, orphanedOrRevokedPlugins); return [ ...availablePlugins, ...notActuallyOrphanedPlugins, ...revokedPlugins, ...actuallyOrphanedPlugins ]; } extractDetails(pluginId) { const contextPath = this.getStringMatchingRegex(pluginId, /^[^@]*(@|\/)/); const version = this.getStringMatchingRegex(pluginId, /@.*\//); const module = this.getStringMatchingRegex(pluginId, /\/.*$/); const unavailable = gettext('unavailable`plugin`'); return { id: pluginId, idLatest: `${contextPath}/${module}`, path: '', module, name: module, status: ApplicationPluginStatus.ORPHANED, contextPath: contextPath, description: unavailable, version: version }; } getStringMatchingRegex(str, regex) { const matches = str.match(regex); const value = matches ? matches[0] : ''; return value.replace(/(@|\/)/g, ''); } triggerPluginEvent(plugin, result) { const pluginInfo = pick(plugin, [ 'name', 'contextPath', 'module', 'version', 'type', 'id' ]); this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.INSTALLED_PLUGINS, { component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.APPLICATION_PLUGINS, result, url: this.CURRENT_LOCATION, ...pluginInfo, targetApplicationName: this.app.name, targetApplicationContextPath: this.app.contextPath }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ApplicationPluginsComponent, deps: [{ token: i1.ActivatedRoute }, { token: i2.EcosystemService }, { token: i3.BsModalService }, { token: i4.PluginsService }, { token: i4.AlertService }, { token: i4.GainsightService }, { token: i4.BottomDrawerService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: ApplicationPluginsComponent, selector: "c8y-app-plugins", inputs: { appId: "appId" }, viewQueries: [{ propertyName: "dataGrid", first: true, predicate: DataGridComponent, descendants: true }], ngImport: i0, template: "<c8y-title>{{ app | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-modules'\"\n [label]=\"'Applications' | translate\"\n [path]=\"'ecosystem/application/applications'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"app | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Plugins' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n *ngIf=\"!(isStandard$ | async)\"\n>\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reset to default plugins' | translate }}\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n (click)=\"resetToDefault()\"\n >\n <i c8yIcon=\"undo\"></i>\n {{ 'Reset to default' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Install plugins' | translate }}\"\n (click)=\"installPlugins()\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Install plugins' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<ng-container *ngIf=\"orphanedPlugins$ | async as orphanedPlugins\">\n <c8y-action-bar-item\n *ngIf=\"orphanedPlugins?.length\"\n [placement]=\"'right'\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Clean up orphaned plugins' | translate }}\"\n (click)=\"cleanupOrphanedPlugins(orphanedPlugins)\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n >\n <i c8yIcon=\"erase\"></i>\n {{ 'Clean up orphaned plugins' | translate }}\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<div class=\"content-fullpage d-flex d-col border-top\">\n <c8y-data-grid\n class=\"d-contents\"\n [title]=\"title\"\n [loadMoreItemsLabel]=\"loadMoreItemsLabel\"\n [loadingItemsLabel]=\"loadingItemsLabel\"\n [displayOptions]=\"displayOptions\"\n [columns]=\"columns\"\n [rows]=\"installedPlugins$ | async\"\n [pagination]=\"pagination\"\n [selectable]=\"true\"\n [actionControls]=\"actionControls\"\n [bulkActionControls]=\"bulkActionControls\"\n [headerActionControls]=\"headerActionControls\"\n (onReload)=\"refresh()\"\n >\n <c8y-ui-empty-state\n [icon]=\"stats?.size > 0 ? 'search' : 'plugin'\"\n [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : (noDataSubtitle | translate)\"\n *emptyStateContext=\"let stats\"\n [horizontal]=\"stats?.size > 0\"\n >\n <p *ngIf=\"stats?.size === 0\">\n <button\n class=\"btn btn-primary btn-sm\"\n title=\"{{ 'Install plugins' | translate }}\"\n (click)=\"installPlugins()\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n translate\n >\n Install plugins\n </button>\n </p>\n </c8y-ui-empty-state>\n </c8y-data-grid>\n</div>\n", dependencies: [{ kind: "component", type: i4.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "component", type: i4.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i4.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i4.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i4.EmptyStateContextDirective, selector: "[emptyStateContext]" }, { kind: "directive", type: i4.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i4.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4.DataGridComponent, selector: "c8y-data-grid", inputs: ["title", "loadMoreItemsLabel", "loadingItemsLabel", "showSearch", "refresh", "columns", "rows", "pagination", "infiniteScroll", "serverSideDataCallback", "selectable", "singleSelection", "selectionPrimaryKey", "displayOptions", "actionControls", "bulkActionControls", "headerActionControls", "searchText", "configureColumnsEnabled", "showCounterWarning", "activeClassName", "expandableRows", "hideReload"], outputs: ["rowMouseOver", "rowMouseLeave", "rowClick", "onConfigChange", "onBeforeFilter", "onBeforeSearch", "onFilter", "itemsSelect", "onReload", "onAddCustomColumn", "onRemoveCustomColumn", "onColumnFilterReset", "onSort", "onPageSizeChange", "onColumnReordered", "onColumnVisibilityChange"] }, { kind: "component", type: i4.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }, { kind: "pipe", type: i4.HumanizeAppNamePipe, name: "humanizeAppName" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ApplicationPluginsComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-app-plugins', template: "<c8y-title>{{ app | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-modules'\"\n [label]=\"'Applications' | translate\"\n [path]=\"'ecosystem/application/applications'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"app | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Plugins' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n *ngIf=\"!(isStandard$ | async)\"\n>\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reset to default plugins' | translate }}\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n (click)=\"resetToDefault()\"\n >\n <i c8yIcon=\"undo\"></i>\n {{ 'Reset to default' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Install plugins' | translate }}\"\n (click)=\"installPlugins()\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Install plugins' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<ng-container *ngIf=\"orphanedPlugins$ | async as orphanedPlugins\">\n <c8y-action-bar-item\n *ngIf=\"orphanedPlugins?.length\"\n [placement]=\"'right'\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Clean up orphaned plugins' | translate }}\"\n (click)=\"cleanupOrphanedPlugins(orphanedPlugins)\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n >\n <i c8yIcon=\"erase\"></i>\n {{ 'Clean up orphaned plugins' | translate }}\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<div class=\"content-fullpage d-flex d-col border-top\">\n <c8y-data-grid\n class=\"d-contents\"\n [title]=\"title\"\n [loadMoreItemsLabel]=\"loadMoreItemsLabel\"\n [loadingItemsLabel]=\"loadingItemsLabel\"\n [displayOptions]=\"displayOptions\"\n [columns]=\"columns\"\n [rows]=\"installedPlugins$ | async\"\n [pagination]=\"pagination\"\n [selectable]=\"true\"\n [actionControls]=\"actionControls\"\n [bulkActionControls]=\"bulkActionControls\"\n [headerActionControls]=\"headerActionControls\"\n (onReload)=\"refresh()\"\n >\n <c8y-ui-empty-state\n [icon]=\"stats?.size > 0 ? 'search' : 'plugin'\"\n [title]=\"stats?.size > 0 ? (noResultsMessage | translate) : (noDataMessage | translate)\"\n [subtitle]=\"stats?.size > 0 ? (noResultsSubtitle | translate) : (noDataSubtitle | translate)\"\n *emptyStateContext=\"let stats\"\n [horizontal]=\"stats?.size > 0\"\n >\n <p *ngIf=\"stats?.size === 0\">\n <button\n class=\"btn btn-primary btn-sm\"\n title=\"{{ 'Install plugins' | translate }}\"\n (click)=\"installPlugins()\"\n [ngClass]=\"{ 'btn-pending': isLoading }\"\n translate\n >\n Install plugins\n </button>\n </p>\n </c8y-ui-empty-state>\n </c8y-data-grid>\n</div>\n" }] }], ctorParameters: () => [{ type: i1.ActivatedRoute }, { type: i2.EcosystemService }, { type: i3.BsModalService }, { type: i4.PluginsService }, { type: i4.AlertService }, { type: i4.GainsightService }, { type: i4.BottomDrawerService }], propDecorators: { appId: [{ type: Input }], dataGrid: [{ type: ViewChild, args: [DataGridComponent, { static: false }] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwbGljYXRpb24tcGx1Z2lucy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9lY29zeXN0ZW0vYXBwbGljYXRpb24tcGx1Z2lucy9hcHBsaWNhdGlvbi1wbHVnaW5zLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uL2Vjb3N5c3RlbS9hcHBsaWNhdGlvbi1wbHVnaW5zL2FwcGxpY2F0aW9uLXBsdWdpbnMuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQXFCLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMvRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFakQsT0FBTyxFQUVMLFlBQVksRUFFWix1QkFBdUIsRUFHdkIsaUJBQWlCLEVBRWpCLGdCQUFnQixFQUNoQixPQUFPLEVBSVAsY0FBYyxFQUNkLG1CQUFtQixFQUNuQixtQkFBbUIsRUFDcEIsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQ0wsZ0JBQWdCLEVBQ2hCLDRCQUE0QixFQUM3QixNQUFNLHNDQUFzQyxDQUFDO0FBQzlDLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDakMsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxlQUFlLEVBQUUsYUFBYSxFQUFFLGNBQWMsRUFBYyxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDM0YsT0FBTyxFQUFFLEdBQUcsRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNwRSxPQUFPLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSxpQ0FBaUMsQ0FBQztBQUM3RSxPQUFPLEVBQUUsbUNBQW1DLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUNo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