@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
2,367 lines • 302 kB
JavaScript
import * as i0 from '@angular/core';
import { Input, Component, ViewChild, Injectable, EventEmitter, Output, inject, NgModule } from '@angular/core';
import * as i2 from '@c8y/ngx-components';
import { ListGroupComponent, ListItemTimelineComponent, ListItemComponent, ListItemIconComponent, ListItemBodyComponent, IconDirective, ListItemActionComponent, FormGroupComponent, C8yTranslatePipe, DatePipe, gettext, Status, LoadingComponent, PluginsService, PluginsExportScopes, ModalComponent, C8yTranslateDirective, ListItemFooterComponent, ListItemCollapseComponent, OperationResultComponent, Permissions, ViewContext, TitleComponent, BreadcrumbComponent, BreadcrumbItemComponent, AppIconComponent, TextareaAutoresizeDirective, PropertiesListComponent, RequiredInputPlaceholderDirective, MessagesComponent, MessageDirective, HumanizeAppNamePipe, WizardHeaderComponent, WizardBodyComponent, WizardFooterComponent, IfAllowedDirective, ActionBarItemComponent, ListDisplaySwitchComponent, HelpComponent, EmptyStateComponent, TypeaheadComponent, ForOfDirective, HighlightComponent, C8yStepper, PackageType, MarkdownToHtmlPipe, CoreModule, FormsModule as FormsModule$1, hookTab, hookRoute, hookWizard } from '@c8y/ngx-components';
import * as i1 from '@c8y/ngx-components/ecosystem/shared';
import { UploadArchiveComponent, packageProperties, PRODUCT_EXPERIENCE_ECOSYSTEM, AddApplicationComponent, defaultPackageAvailabilities, EcosystemWizards, ListFiltersComponent, ApplicationCardComponent, ApplicationPropertiesFormComponent, ERROR_TYPE, APP_STATE, PackageVersionSelectComponent, PACKAGE_TYPE_LABELS, TranslatePackageLabelPipe, defaultPackageTypes, defaultPackageContents, ArchivedFilterComponent, PackageChangelogComponent, SharedEcosystemModule } from '@c8y/ngx-components/ecosystem/shared';
import { NgFor, NgClass, NgIf, AsyncPipe, NgSwitch, NgSwitchCase, NgStyle } from '@angular/common';
import * as i3 from '@angular/forms';
import { Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
import * as i1$2 from '@angular/router';
import { Router, RouterModule } from '@angular/router';
import * as i4 from '@c8y/client';
import { Isolation, BillingMode, ApplicationType } from '@c8y/client';
import * as i6 from '@ngx-translate/core';
import * as i1$1 from 'ngx-bootstrap/modal';
import { isEmpty } from 'lodash';
import { BehaviorSubject, Subject, combineLatest, of, from } from 'rxjs';
import { PluginListComponent, ApplicationPluginsModule } from '@c8y/ngx-components/ecosystem/application-plugins';
import { TooltipDirective, TooltipModule } from 'ngx-bootstrap/tooltip';
import { IconSelectorWrapperComponent, IconSelectorModule } from '@c8y/ngx-components/icon-selector';
import { tap, switchMap, shareReplay, takeUntil, map } from 'rxjs/operators';
import { A11yModule } from '@angular/cdk/a11y';
import { ArchivedConfirmModule } from '@c8y/ngx-components/ecosystem/archived-confirm';
import { LicenseConfirmModule } from '@c8y/ngx-components/ecosystem/license-confirm';
import { BsDropdownDirective, BsDropdownToggleDirective, BsDropdownMenuDirective, BsDropdownModule } from 'ngx-bootstrap/dropdown';
import { PopoverModule } from 'ngx-bootstrap/popover';
import { pick } from 'lodash-es';
class ActivityLogComponent {
constructor(ecosystemService, alertService) {
this.ecosystemService = ecosystemService;
this.alertService = alertService;
this.hasAdminPermissions = false;
this.archives = [];
this.canReactivate = false;
}
get uploadProgress() {
return this.ecosystemService.progress;
}
async ngOnInit() {
this.canReactivate = this.showReactivate();
this.refresh();
}
isActive(archive) {
return this.application.activeVersionId === archive.id;
}
toActivate(archive) {
return this.toActivateVersionId === archive.id;
}
checkIfLast(archive) {
return archive.id === this.last.id;
}
showReactivate() {
return this.ecosystemService.isApplication(this.application);
}
async setActive(archive) {
const id = archive.id || archive;
this.toActivateVersionId = id;
this.isLoading = true;
try {
this.application = (await this.ecosystemService.setAppActiveVersion(this.application, id)).data;
}
catch (ex) {
this.alertService.addServerFailure(ex);
}
this.isLoading = false;
this.refresh();
}
async deleteArchive(archive) {
await this.ecosystemService.deleteArchive(archive, this.application);
this.refresh();
}
async downloadArchive(archive) {
await this.ecosystemService.downloadArchive(this.application, archive);
}
async reactivateArchive() {
await this.ecosystemService.reactivateArchive(this.application);
}
async onRefresh() {
await this.refresh();
}
async refresh() {
this.isLoading = true;
this.archives = await this.ecosystemService.listArchives(this.application.id);
if (this.application.manifest?.package === 'blueprint') {
// filter out entries without description because using them as active may break application's
// manifest (changing isPackage property of deployed app to 'true')
this.archives = this.archives.filter((archive) => !!archive.description);
}
this.archives.sort((a, b) => {
return new Date(b.created) - new Date(a.created);
});
this.last = this.archives[this.archives.length - 1];
this.isLoading = false;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ActivityLogComponent, deps: [{ token: i1.EcosystemService }, { token: i2.AlertService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: ActivityLogComponent, isStandalone: true, selector: "c8y-activity-log", inputs: { application: "application", hasAdminPermissions: "hasAdminPermissions" }, ngImport: i0, template: "<div class=\"inner-scroll bg-level-1 flex-grow inner-scroll--md overflow-visible-sm overflow-visible-xs\">\n <div class=\"card-block overflow-visible\">\n <c8y-list-group>\n <c8y-li-timeline *ngFor=\"let archive of archives\" [ngClass]=\"{ active: isActive(archive) }\">\n {{ archive.created | c8yDate: 'd MMM YYYY' }}\n {{ archive.created | c8yDate: 'shortTime' }}\n <c8y-li>\n <c8y-li-icon\n [icon]=\"checkIfLast(archive) ? 'flag-checkered' : 'file-zip-o'\"\n ></c8y-li-icon>\n <c8y-li-body>\n <div class=\"d-flex a-i-start\">\n <div style=\"min-width: 0; flex: 1\">\n <span class=\"text-truncate-wrap\" title=\" {{ archive.description || archive.name }}\">\n {{ archive.description || archive.name }}\n </span>\n <small *ngIf=\"archive.description\" class=\"text-muted\">{{\n archive.description\n }}</small>\n </div>\n <i\n *ngIf=\"isLoading && toActivate(archive)\"\n [c8yIcon]=\"'circle-o-notch'\"\n class=\"icon-spin\"\n title=\"{{ 'Activating' | translate }}\"\n ></i>\n\n <span *ngIf=\"isActive(archive)\" class=\"label label-primary m-l-auto m-t-4\">{{\n 'Active' | translate\n }}</span>\n </div>\n </c8y-li-body>\n <c8y-li-action\n (click)=\"setActive(archive)\"\n *ngIf=\"hasAdminPermissions && !isLoading && !isActive(archive)\"\n icon=\"check-square-o\"\n >\n {{ 'Set as active`archive`' | translate }}\n </c8y-li-action>\n <c8y-li-action (click)=\"downloadArchive(archive)\" icon=\"download\">\n {{ 'Download`archive`' | translate }}\n </c8y-li-action>\n <c8y-li-action\n (click)=\"deleteArchive(archive)\"\n *ngIf=\"\n hasAdminPermissions &&\n archives.length > 1 &&\n !checkIfLast(archive) &&\n !isActive(archive)\n \"\n icon=\"delete\"\n >\n {{ 'Delete`archive`' | translate }}\n </c8y-li-action>\n <c8y-li-action\n (click)=\"reactivateArchive()\"\n *ngIf=\"hasAdminPermissions && canReactivate && isActive(archive)\"\n icon=\"undo\"\n >\n {{ 'Reactivate archive' | translate }}\n </c8y-li-action>\n </c8y-li>\n </c8y-li-timeline>\n </c8y-list-group>\n </div>\n</div>\n<div class=\"card-footer\" *ngIf=\"!isLoading && hasAdminPermissions\">\n <c8y-form-group class=\"m-auto\">\n <c8y-upload-archive [(application)]=\"application\" (refresh)=\"onRefresh()\"></c8y-upload-archive>\n </c8y-form-group>\n</div>\n", dependencies: [{ kind: "component", type: ListGroupComponent, selector: "c8y-list-group" }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ListItemTimelineComponent, selector: "c8y-list-item-timeline, c8y-li-timeline" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: ListItemActionComponent, selector: "c8y-list-item-action, c8y-li-action", inputs: ["label", "icon", "disabled"], outputs: ["click"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: UploadArchiveComponent, selector: "c8y-upload-archive", inputs: ["application", "uploadNewVersion", "preUploadCallback"], outputs: ["applicationChange", "refresh"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: DatePipe, name: "c8yDate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ActivityLogComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-activity-log', imports: [
ListGroupComponent,
NgFor,
ListItemTimelineComponent,
NgClass,
ListItemComponent,
ListItemIconComponent,
ListItemBodyComponent,
NgIf,
IconDirective,
ListItemActionComponent,
FormGroupComponent,
UploadArchiveComponent,
C8yTranslatePipe,
DatePipe
], template: "<div class=\"inner-scroll bg-level-1 flex-grow inner-scroll--md overflow-visible-sm overflow-visible-xs\">\n <div class=\"card-block overflow-visible\">\n <c8y-list-group>\n <c8y-li-timeline *ngFor=\"let archive of archives\" [ngClass]=\"{ active: isActive(archive) }\">\n {{ archive.created | c8yDate: 'd MMM YYYY' }}\n {{ archive.created | c8yDate: 'shortTime' }}\n <c8y-li>\n <c8y-li-icon\n [icon]=\"checkIfLast(archive) ? 'flag-checkered' : 'file-zip-o'\"\n ></c8y-li-icon>\n <c8y-li-body>\n <div class=\"d-flex a-i-start\">\n <div style=\"min-width: 0; flex: 1\">\n <span class=\"text-truncate-wrap\" title=\" {{ archive.description || archive.name }}\">\n {{ archive.description || archive.name }}\n </span>\n <small *ngIf=\"archive.description\" class=\"text-muted\">{{\n archive.description\n }}</small>\n </div>\n <i\n *ngIf=\"isLoading && toActivate(archive)\"\n [c8yIcon]=\"'circle-o-notch'\"\n class=\"icon-spin\"\n title=\"{{ 'Activating' | translate }}\"\n ></i>\n\n <span *ngIf=\"isActive(archive)\" class=\"label label-primary m-l-auto m-t-4\">{{\n 'Active' | translate\n }}</span>\n </div>\n </c8y-li-body>\n <c8y-li-action\n (click)=\"setActive(archive)\"\n *ngIf=\"hasAdminPermissions && !isLoading && !isActive(archive)\"\n icon=\"check-square-o\"\n >\n {{ 'Set as active`archive`' | translate }}\n </c8y-li-action>\n <c8y-li-action (click)=\"downloadArchive(archive)\" icon=\"download\">\n {{ 'Download`archive`' | translate }}\n </c8y-li-action>\n <c8y-li-action\n (click)=\"deleteArchive(archive)\"\n *ngIf=\"\n hasAdminPermissions &&\n archives.length > 1 &&\n !checkIfLast(archive) &&\n !isActive(archive)\n \"\n icon=\"delete\"\n >\n {{ 'Delete`archive`' | translate }}\n </c8y-li-action>\n <c8y-li-action\n (click)=\"reactivateArchive()\"\n *ngIf=\"hasAdminPermissions && canReactivate && isActive(archive)\"\n icon=\"undo\"\n >\n {{ 'Reactivate archive' | translate }}\n </c8y-li-action>\n </c8y-li>\n </c8y-li-timeline>\n </c8y-list-group>\n </div>\n</div>\n<div class=\"card-footer\" *ngIf=\"!isLoading && hasAdminPermissions\">\n <c8y-form-group class=\"m-auto\">\n <c8y-upload-archive [(application)]=\"application\" (refresh)=\"onRefresh()\"></c8y-upload-archive>\n </c8y-form-group>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.AlertService }], propDecorators: { application: [{
type: Input
}], hasAdminPermissions: [{
type: Input
}] } });
class SubscriptionModalComponent {
constructor(bsModalRef, ecosystemService, tabsService, modal, applicationService, alertService, contextRouteService) {
this.bsModalRef = bsModalRef;
this.ecosystemService = ecosystemService;
this.tabsService = tabsService;
this.modal = modal;
this.applicationService = applicationService;
this.alertService = alertService;
this.contextRouteService = contextRouteService;
this.RETRY_TIMEOUT = 3000;
this.isLoading = false;
this.result = new Promise(resolve => {
this._resolve = resolve;
});
this.retryCounter = 0;
this.TABS = ['Logs', 'Status'];
}
ngOnInit() {
if (this.isSubscribed) {
this.unsubscribe();
}
else {
this.subscribe();
}
}
async subscribe() {
this.retryCounter = 0;
this.isLoading = true;
this.message = gettext('Subscribing…');
await this.ecosystemService.subscribeApp(this.application);
this.getStatusDetails('subscribe');
}
async unsubscribe() {
this.retryCounter = 0;
this.isLoading = true;
this.message = gettext('Unsubscribing…');
await this.ecosystemService.unsubscribeApp(this.application);
this.getStatusDetails('unsubscribe');
}
async getStatusDetails(action) {
this.contextRouteService.refreshContext();
const actionSuccessful = action === 'subscribe' ? await this.onSubscribe() : this.onUnsubscribe();
if (actionSuccessful) {
return this.hideSubscriptionModal();
}
if (this.retryCounter === 4) {
this.showWarningModal(action);
return this.hideSubscriptionModal();
}
this.retryCounter += 1;
setTimeout(async () => {
this.getStatusDetails(action);
}, this.RETRY_TIMEOUT);
}
async onSubscribe() {
try {
if (!this.application.activeVersionId) {
return true;
}
const res = (await this.applicationService.getStatusDetails(this.application)).data[0];
return this.shouldShowMSSpecificTabs(res);
}
catch (er) {
this.alertService.addServerFailure(er);
}
}
// Checks if the UI should show tabs with logs and status
shouldShowMSSpecificTabs(mo) {
return !isEmpty(mo.c8y_Status?.instances) && !!mo.c8y_SupportedLogs;
}
onUnsubscribe() {
return !this.tabsService.areAvailable(this.TABS);
}
hideSubscriptionModal() {
this._resolve();
this.bsModalRef.hide();
this.isLoading = false;
}
showWarningModal(action) {
const title = gettext('Warning');
const body = action === 'subscribe'
? gettext('Something went wrong, please refresh the page or resubscribe the application.')
: gettext('Something went wrong, please refresh the page or retry to unsubscribe from the application.');
this.modal.acknowledge(title, body, Status.WARNING, gettext('Close'));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SubscriptionModalComponent, deps: [{ token: i1$1.BsModalRef }, { token: i1.EcosystemService }, { token: i2.TabsService }, { token: i2.ModalService }, { token: i4.ApplicationService }, { token: i2.AlertService }, { token: i2.ContextRouteService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: SubscriptionModalComponent, isStandalone: true, selector: "c8y-subscription-modal", ngImport: i0, template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i c8yIcon=\"c8y-atom\"></i>\n <h4 id=\"modal-title\">{{ message | translate }}</h4>\n </div>\n <div class=\"modal-body\" id=\"modal-body\" *ngIf=\"isLoading\">\n <div class=\"p-16 text-center\">\n <c8y-loading></c8y-loading>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SubscriptionModalComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-subscription-modal', imports: [IconDirective, NgIf, LoadingComponent, C8yTranslatePipe], template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i c8yIcon=\"c8y-atom\"></i>\n <h4 id=\"modal-title\">{{ message | translate }}</h4>\n </div>\n <div class=\"modal-body\" id=\"modal-body\" *ngIf=\"isLoading\">\n <div class=\"p-16 text-center\">\n <c8y-loading></c8y-loading>\n </div>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1$1.BsModalRef }, { type: i1.EcosystemService }, { type: i2.TabsService }, { type: i2.ModalService }, { type: i4.ApplicationService }, { type: i2.AlertService }, { type: i2.ContextRouteService }] });
class UpdateApplicationModalComponent {
constructor(inventoryService, ecosystemService, pluginsService) {
this.inventoryService = inventoryService;
this.ecosystemService = ecosystemService;
this.pluginsService = pluginsService;
this.isUpdateOngoing = false;
this.updateFailure = false;
this.result = new Promise((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});
this.orphanedPlugins$ = new BehaviorSubject([]);
this.newPlugins$ = new BehaviorSubject([]);
}
ngOnInit() {
const hasDelta = this.getRemoteDelta();
if (!hasDelta) {
// start update directly if no remote delta detected
this.updateApplication();
}
}
/**
* Checks if there is a delta between the current application and the source package remotes.
* @returns {boolean} true if there is a delta between the current application and the source package remotes.
*/
getRemoteDelta() {
const currentRemotes = this.pluginsService.getMFExports(this.application, []);
const possibleNewRemotes = this.pluginsService.getMFExports(this.sourcePackage, []);
const installedRemotes = this.pluginsService.getMFRemotes(this.application);
const installedRemotesIds = PluginsService.convertInstalledRemotesToIds(installedRemotes);
const allRemotesToRemove = this.getAllRemotesToRemove(currentRemotes, possibleNewRemotes, installedRemotesIds);
const allRemotesToAdd = this.getAllRemotesToAdd(possibleNewRemotes, currentRemotes);
this.orphanedPlugins$.next(allRemotesToRemove);
this.newPlugins$.next(allRemotesToAdd);
return allRemotesToRemove.length !== 0 || allRemotesToAdd.length !== 0;
}
close() {
this._reject();
this.modal._dismiss();
}
done() {
if (!this.updateFailure) {
this._resolve();
this.modal._dismiss();
return;
}
this._reject();
this.modal._dismiss();
}
async updateApplication() {
try {
this.isUpdateOngoing = true;
const toInstallPlugins = this.newPlugins$.value.filter(({ selected }) => selected === true);
const toRemovePlugins = this.orphanedPlugins$.value;
this.orphanedPlugins$.next([]);
this.newPlugins$.next([]);
if (toRemovePlugins.length > 0) {
const remotes = await this.pluginsService.removeRemotes(this.application, toRemovePlugins);
this.application.config.remotes = remotes;
}
if (toInstallPlugins.length > 0) {
const remotes = await this.pluginsService.addRemotes(this.application, toInstallPlugins);
this.application.config.remotes = remotes;
}
const binaryMoId = this.sourcePackage.activeVersionId;
await this.inventoryService.detail(binaryMoId); // only trying if we can access it
await this.ecosystemService.uploadBinaryFromOtherPackage(this.sourcePackage, this.application, this.sourcePackage.activeVersionId);
}
catch (e) {
if (e.res?.status === 404) {
try {
this.updateFailure = !(await this.ecosystemService.fallbackToClone(this.application, this.sourcePackage));
}
catch (ex) {
this.updateFailure = true;
this.ecosystemService.alertError(e);
}
}
else {
this.updateFailure = true;
this.ecosystemService.alertError(e);
}
}
finally {
this.isUpdateOngoing = false;
}
}
getAllRemotesToAdd(possibleNewRemotes, currentRemotes) {
return possibleNewRemotes
.filter(possibleNewRemote => {
const isUnchanged = !!currentRemotes.some(currentRemote => PluginsService.createPluginId(this.application.contextPath, possibleNewRemote.module, '', true) === currentRemote.idLatest);
const isSelf = possibleNewRemote.scope === PluginsExportScopes.SELF ||
possibleNewRemote.scope === PluginsExportScopes.SELF_OPTIONAL;
return !isUnchanged && isSelf;
})
.map(newRemote => {
newRemote.contextPath = this.application.contextPath;
newRemote.id = `${newRemote.contextPath}/${newRemote.module}`;
newRemote.selected = newRemote.scope === PluginsExportScopes.SELF;
return newRemote;
});
}
getAllRemotesToRemove(currentRemotes, possibleNewRemotes, installedRemotesIds) {
return currentRemotes
.filter(currentRemote => {
const isUnchanged = !!possibleNewRemotes.some(newRemote => PluginsService.createPluginId(this.application.contextPath, newRemote.module, '', true) === currentRemote.idLatest);
const isInstalled = installedRemotesIds
? !!installedRemotesIds.some(currentInstalled => currentRemote.id === currentInstalled || currentRemote.idLatest === currentInstalled)
: false;
const isSelf = currentRemote.scope === PluginsExportScopes.SELF ||
currentRemote.scope === PluginsExportScopes.SELF_OPTIONAL;
return !isUnchanged && isInstalled && isSelf;
})
.map(toRemoveRemote => {
toRemoveRemote.contextPath = this.application.contextPath;
toRemoveRemote.id = `${toRemoveRemote.contextPath}/${toRemoveRemote.module}`;
toRemoveRemote.selected = true;
return toRemoveRemote;
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UpdateApplicationModalComponent, deps: [{ token: i4.InventoryService }, { token: i1.EcosystemService }, { token: i2.PluginsService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: UpdateApplicationModalComponent, isStandalone: true, selector: "c8y-update-application-modal", viewQueries: [{ propertyName: "modal", first: true, predicate: ["modal"], descendants: true }], ngImport: i0, template: "<c8y-modal\n [title]=\"'Update application' | translate\"\n [headerClasses]=\"'dialog-header'\"\n [customFooter]=\"true\"\n #modal\n>\n <ng-container c8y-modal-title>\n <span class=\"dlt-c8y-icon-installing-updates\"></span>\n </ng-container>\n\n <ng-container\n *ngIf=\"\n (orphanedPlugins$ | async).length > 0 || (newPlugins$ | async).length > 0;\n else updateProgress\n \"\n >\n <p\n class=\"text-center text-break-word p-24 text-14\"\n translate\n >\n Updating this blueprint will change the default plugins. Review the plugin changes before\n proceeding.\n </p>\n <c8y-list-group *ngIf=\"(orphanedPlugins$ | async).length > 0\">\n <c8y-li [collapsed]=\"true\">\n <c8y-li-icon>\n <span class=\"badge badge-danger\">{{ (orphanedPlugins$ | async).length }}</span>\n </c8y-li-icon>\n <c8y-li-body>\n <div translate>Orphaned plugins</div>\n </c8y-li-body>\n <c8y-li-footer translate>\n Some plugins are not contained in the new version of this blueprint and will therefore get\n removed.\n </c8y-li-footer>\n <c8y-li-collapse>\n <c8y-plugin-list\n class=\"m-t-16\"\n [emptyListText]=\"'No plugins available' | translate\"\n [plugins$]=\"orphanedPlugins$\"\n [selectable]=\"false\"\n [hideSource]=\"true\"\n ></c8y-plugin-list>\n </c8y-li-collapse>\n </c8y-li>\n </c8y-list-group>\n\n <c8y-list-group *ngIf=\"(newPlugins$ | async).length > 0\">\n <c8y-li [collapsed]=\"false\">\n <c8y-li-icon>\n <span class=\"badge badge-success\">{{ (newPlugins$ | async).length }}</span>\n </c8y-li-icon>\n <c8y-li-body>\n <div translate>New plugins added</div>\n </c8y-li-body>\n <c8y-li-footer translate>\n This blueprint will add new plugins. Please choose which you want to install.\n </c8y-li-footer>\n <c8y-li-collapse>\n <c8y-plugin-list\n class=\"m-t-16\"\n [emptyListText]=\"'No plugins available' | translate\"\n [plugins$]=\"newPlugins$\"\n [selectable]=\"true\"\n [hideSource]=\"false\"\n ></c8y-plugin-list>\n </c8y-li-collapse>\n </c8y-li>\n </c8y-list-group>\n </ng-container>\n\n <ng-container c8y-modal-footer-custom>\n <div\n class=\"modal-footer\"\n *ngIf=\"\n (orphanedPlugins$ | async).length > 0 || (newPlugins$ | async).length > 0;\n else updateProgressButtons\n \"\n >\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Close' | translate }}\"\n (click)=\"close()\"\n [disabled]=\"isUpdateOngoing\"\n >\n {{ 'Close' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Continue' | translate }}\"\n (click)=\"updateApplication()\"\n *ngIf=\"(orphanedPlugins$ | async).length > 0 || (newPlugins$ | async).length > 0\"\n [disabled]=\"isUpdateOngoing\"\n >\n {{ 'Continue' | translate }}\n </button>\n </div>\n </ng-container>\n\n <ng-template #updateProgressButtons>\n <ng-container c8y-modal-footer-custom>\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Close' | translate }}\"\n (click)=\"done()\"\n [disabled]=\"isUpdateOngoing\"\n >\n {{ 'Close' | translate }}\n </button>\n </div>\n </ng-container>\n </ng-template>\n\n <ng-template #updateProgress>\n <c8y-loading\n class=\"text-center d-block p-t-56 p-b-56 m-t-4 m-b-4\"\n style=\"min-height: 180px\"\n layout=\"application\"\n *ngIf=\"isUpdateOngoing\"\n [message]=\"'Updating\u2026' | translate\"\n ></c8y-loading>\n\n <c8y-operation-result\n type=\"success\"\n *ngIf=\"!isUpdateOngoing && !updateFailure\"\n text=\"{{ 'Update completed' | translate }}\"\n [size]=\"120\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n <c8y-operation-result\n type=\"error\"\n *ngIf=\"!isUpdateOngoing && updateFailure\"\n text=\"{{ 'Failed to update application.' | translate }}\"\n [size]=\"120\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </ng-template>\n</c8y-modal>\n", dependencies: [{ kind: "component", type: ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: ListGroupComponent, selector: "c8y-list-group" }, { 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: ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "component", type: ListItemFooterComponent, selector: "c8y-list-item-footer, c8y-li-footer", inputs: ["footer"] }, { kind: "component", type: ListItemCollapseComponent, selector: "c8y-list-item-collapse, c8y-li-collapse", inputs: ["collapseWay"] }, { kind: "component", type: PluginListComponent, selector: "c8y-plugin-list", inputs: ["plugins$", "emptyListText", "selectable", "hideSource", "installable", "package", "selectedPlugin"], outputs: ["selectedItems", "showOverview"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: OperationResultComponent, selector: "c8y-operation-result", inputs: ["text", "vertical", "size", "type"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UpdateApplicationModalComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-update-application-modal', imports: [
ModalComponent,
NgIf,
C8yTranslateDirective,
ListGroupComponent,
ListItemComponent,
ListItemIconComponent,
ListItemBodyComponent,
ListItemFooterComponent,
ListItemCollapseComponent,
PluginListComponent,
LoadingComponent,
OperationResultComponent,
C8yTranslatePipe,
AsyncPipe
], template: "<c8y-modal\n [title]=\"'Update application' | translate\"\n [headerClasses]=\"'dialog-header'\"\n [customFooter]=\"true\"\n #modal\n>\n <ng-container c8y-modal-title>\n <span class=\"dlt-c8y-icon-installing-updates\"></span>\n </ng-container>\n\n <ng-container\n *ngIf=\"\n (orphanedPlugins$ | async).length > 0 || (newPlugins$ | async).length > 0;\n else updateProgress\n \"\n >\n <p\n class=\"text-center text-break-word p-24 text-14\"\n translate\n >\n Updating this blueprint will change the default plugins. Review the plugin changes before\n proceeding.\n </p>\n <c8y-list-group *ngIf=\"(orphanedPlugins$ | async).length > 0\">\n <c8y-li [collapsed]=\"true\">\n <c8y-li-icon>\n <span class=\"badge badge-danger\">{{ (orphanedPlugins$ | async).length }}</span>\n </c8y-li-icon>\n <c8y-li-body>\n <div translate>Orphaned plugins</div>\n </c8y-li-body>\n <c8y-li-footer translate>\n Some plugins are not contained in the new version of this blueprint and will therefore get\n removed.\n </c8y-li-footer>\n <c8y-li-collapse>\n <c8y-plugin-list\n class=\"m-t-16\"\n [emptyListText]=\"'No plugins available' | translate\"\n [plugins$]=\"orphanedPlugins$\"\n [selectable]=\"false\"\n [hideSource]=\"true\"\n ></c8y-plugin-list>\n </c8y-li-collapse>\n </c8y-li>\n </c8y-list-group>\n\n <c8y-list-group *ngIf=\"(newPlugins$ | async).length > 0\">\n <c8y-li [collapsed]=\"false\">\n <c8y-li-icon>\n <span class=\"badge badge-success\">{{ (newPlugins$ | async).length }}</span>\n </c8y-li-icon>\n <c8y-li-body>\n <div translate>New plugins added</div>\n </c8y-li-body>\n <c8y-li-footer translate>\n This blueprint will add new plugins. Please choose which you want to install.\n </c8y-li-footer>\n <c8y-li-collapse>\n <c8y-plugin-list\n class=\"m-t-16\"\n [emptyListText]=\"'No plugins available' | translate\"\n [plugins$]=\"newPlugins$\"\n [selectable]=\"true\"\n [hideSource]=\"false\"\n ></c8y-plugin-list>\n </c8y-li-collapse>\n </c8y-li>\n </c8y-list-group>\n </ng-container>\n\n <ng-container c8y-modal-footer-custom>\n <div\n class=\"modal-footer\"\n *ngIf=\"\n (orphanedPlugins$ | async).length > 0 || (newPlugins$ | async).length > 0;\n else updateProgressButtons\n \"\n >\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Close' | translate }}\"\n (click)=\"close()\"\n [disabled]=\"isUpdateOngoing\"\n >\n {{ 'Close' | translate }}\n </button>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Continue' | translate }}\"\n (click)=\"updateApplication()\"\n *ngIf=\"(orphanedPlugins$ | async).length > 0 || (newPlugins$ | async).length > 0\"\n [disabled]=\"isUpdateOngoing\"\n >\n {{ 'Continue' | translate }}\n </button>\n </div>\n </ng-container>\n\n <ng-template #updateProgressButtons>\n <ng-container c8y-modal-footer-custom>\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Close' | translate }}\"\n (click)=\"done()\"\n [disabled]=\"isUpdateOngoing\"\n >\n {{ 'Close' | translate }}\n </button>\n </div>\n </ng-container>\n </ng-template>\n\n <ng-template #updateProgress>\n <c8y-loading\n class=\"text-center d-block p-t-56 p-b-56 m-t-4 m-b-4\"\n style=\"min-height: 180px\"\n layout=\"application\"\n *ngIf=\"isUpdateOngoing\"\n [message]=\"'Updating\u2026' | translate\"\n ></c8y-loading>\n\n <c8y-operation-result\n type=\"success\"\n *ngIf=\"!isUpdateOngoing && !updateFailure\"\n text=\"{{ 'Update completed' | translate }}\"\n [size]=\"120\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n <c8y-operation-result\n type=\"error\"\n *ngIf=\"!isUpdateOngoing && updateFailure\"\n text=\"{{ 'Failed to update application.' | translate }}\"\n [size]=\"120\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </ng-template>\n</c8y-modal>\n" }]
}], ctorParameters: () => [{ type: i4.InventoryService }, { type: i1.EcosystemService }, { type: i2.PluginsService }], propDecorators: { modal: [{
type: ViewChild,
args: ['modal', { static: false }]
}] } });
const MICROSERVICES_BASE_PATH = '/ecosystem/microservice/microservices';
const APPLICATIONS_BASE_PATH = '/ecosystem/application/applications';
class ApplicationPropertiesComponent {
constructor(activatedRoute, ecosystemService, router, formBuilder, applicationService, alertService, inventoryService, permissions, modalService, translate, bsModalService, gainsightService) {
this.activatedRoute = activatedRoute;
this.ecosystemService = ecosystemService;
this.router = router;
this.formBuilder = formBuilder;
this.applicationService = applicationService;
this.alertService = alertService;
this.inventoryService = inventoryService;
this.permissions = permissions;
this.modalService = modalService;
this.translate = translate;
this.bsModalService = bsModalService;
this.gainsightService = gainsightService;
this.CURRENT_LOCATION = location.href;
this.singleTenant = false;
this.subscription = false;
this.iconMap = {
HOSTED: 'cloud',
EXTERNAL: 'external-link-square',
MICROSERVICE: 'microchip'
};
this.isLoading = true;
this.hasAdminPermissions = false;
this.noDescriptionLabel = gettext('No description available.');
this.packageProperties = [...packageProperties];
this.isUpdateAvailable = false;
}
async ngOnInit() {
this.hasAdminPermissions = this.permissions.hasRole(Permissions.ROLE_APPLICATION_MANAGEMENT_ADMIN);
await this.refresh();
}
async refresh() {
await this.load();
this.isUnpacked = this.ecosystemService.isUnpacked(this.application);
this.isPackage = this.ecosystemService.isPackage(this.application);
this.isFeature = this.ecosystemService.isFeature(this.application);
this.isExternal = this.ecosystemService.isExternal(this.application);
this.isMicroservice = this.ecosystemService.isMicroservice(this.application);
this.appState = this.ecosystemService.getAppState(this.application);
if (this.isUnpacked) {
await this.resolveSourcePackageDetails();
}
this.setBreadcrumbConfig();
if (this.isCustomMicroservice) {
this.loadBinaryMo();
}
}
async load() {
this.isLoading = true;
this.initForm();
await this.loadApplication();
this.isLoading = false;
}
onApplication(app) {
if (app.manifest) {
this.singleTenant = app.manifest.isolation === Isolation.PER_TENANT;
this.subscription = app.manifest.billingMode === BillingMode.SUBSCRIPTION;
}
}
cancel() {
if (this.application.type === ApplicationType.MICROSERVICE) {
this.router.navigateByUrl(MICROSERVICES_BASE_PATH);
}
else {
this.router.navigateByUrl(APPLICATIONS_BASE_PATH);
}
}
openApp(app) {
this.ecosystemService.openApp(app);
}
getPackage(entityOrId) {
return this.applicationService.detail(entityOrId);
}
async delete() {
try {
await this.ecosystemService.deleteApp(this.application);
if (this.application.type === ApplicationType.MICROSERVICE) {
this.router.navigateByUrl(MICROSERVICES_BASE_PATH);
}
else {
this.router.navigateByUrl(APPLICATIONS_BASE_PATH);
}
}
catch (ex) {
if (ex) {
this.alertService.addServerFailure(ex);
}
}
}
async subscribe() {
const initialState = { application: this.application, isSubscribed: false };
await this.confirmSubscriptionChange(initialState);
this.loadApplication();
}
async unsubscribe() {
const initialState = { application: this.application, isSubscribed: true };
await this.confirmSubscriptionChange(initialState);
this.loadApplication();
}
async loadApplication() {
const { id } = this.activatedRoute.snapshot.parent.data.contextData;
this.application = await this.ecosystemService.getApplication(id);
if (this.application.type === ApplicationType.MICROSERVICE) {
this.formGroup.get('name').disable();
}
const updatedApplication = {
...this.application,
description: this.getDescription(this.application),
icon: this.application.config?.icon?.class || this.application.manifest?.icon?.class
};
this.formGroup.patchValue(updatedApplication);
this.canOpenInBrowser = this.ecosystemService.canOpenAppInBrowser(this.application);
this.disableOpenInBrowser =
this.canOpenInBrowser &&
(await this.ecosystemService.isOverwrittenByCustomApp(this.application));
this.canDelete = await this.ecosystemService.canDeleteApp(this.application);
this.isOwner = this.ecosystemService.isOwner(this.application);
this.isActivityLogSupported = this.isActivityLogSupportedByApp(this.application);
this.isCustomMicroservice = this.ecosystemService.isCustomMicroservice(this.application);
this.isSubscribed = await this.ecosystemService.checkIfSubscribed(this.application);
this.onApplication(this.application);
}
async save(app) {
const icon = this.formGroup.controls['icon'].value;
const name = this.formGroup.controls['name'].value;
if (icon) {
app = {
...app,
config: { ...this.application.config, icon: { class: icon }, appTitle: name }
};
}
else if (this.application.config) {
app = {
...app,
config: { ...this.application.config, appTitle: name }
};
}
app.id = this.application.id;
try {
const { data } = await this.ecosystemService.updateApp(app);
this.formGroup.reset();
this.loadApplication();
if (data) {
this.alertService.success(gettext('Application saved.'));
}
}
catch (ex) {
// do nothing
}
}
onNewArchive() {
this.loadBinaryMo();
}
async updateToLatestVersion() {
this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.APPLICATION_PROPERTIES, {
component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.APPLICATION_PROPERTIES,
action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.UPDATE_AVAILABLE,
url: this.CURRENT_LOCATION
});
try {
const translatedBody = this.translate.instant(gettext(`You're using the version {{ currentVersion }} of the {{ packageName }} package, the latest version available is {{ latestVersion }}, do you want to update? You can always revert to a previous version in the Activity log panel.`), {
currentVersion: this.application.manifest?.version,
latestVersion: this.blueprintApplicationVersion,
packageName: this.sourcePackage.name
});
await this.modalService.confirm(gettext('Update application'), translatedBody, 'warning', {
ok: gettext('Update'),
cancel: gettext('Cancel')
});
}
catch {
// modal canceled
return;
}
try {
await this.bsModalService.show(UpdateApplicationModalComponent, {
ariaDescribedby: 'modal-body',
ariaLabelledBy: 'modal-title',
class: 'modal-sm',
ignoreBackdropClick: true,
initialState: {
sourcePackage: this.sourcePackage,
application: this.application
}
}).content.result;
}
catch {
// modal canceled
return;
}
await this.refresh();
this.alertService.success(gettext('Application updated.'));
}
getDescription(application) {
if (!application) {
return;
}
return application.description || application.manifest?.description;
}
async confirmSubscriptionChange(initialState) {
await this.bsModalService.show(SubscriptionModalComponent, {
class: 'modal-sm',
ariaDescribedby: 'modal-body',
ariaLabelledBy: 'modal-title',
initialState,
ignoreBackdropClick: true
}).content.result;
}
async resolveSourcePackageDetails() {
try {
this.sourcePackage = (await this.getPackage(this.application.manifest?.source)).data;
if (this.sourcePackage) {
this.packageProperties.push({
label: gettext('Source package'),
value: this.sourcePackage.name,
type: 'link',
action: () => this.router.navigateByUrl(ViewContext.Extension.replace(':id', this.sourcePackage.id.toString()))
});
}
}
catch {
this.alertService.warning(gettext('Unable to resolve source package.'));
return;
}
await this.extractVersionInformation(this.application);
}
initForm() {
this.formGroup = this.formBuilder.group({
id: [{ value: '' }],
name: [Validators.required, Validators.maxLength(120)],
key: [Validators.required, Validators.maxLength(120)],
contextPath: [Validators.required, Validators.maxLength(120)],
description: ['', Validators.maxLength(200)],
username: [Validators.required],
password: [Validators.required],
externalUrl: [Validators.required],
icon: [undefined, [Validators.minLength(1)]]
});
if (!this.hasAdminPermissions) {
this.formGroup.disable();
}
}
isActivityLogSupportedByApp(app) {
return (this.ecosystemService.isOwner(app) &&
app.type !== ApplicationType.MICROSERVICE &&
app.type !== ApplicationType.EXTERNAL);
}
setBreadcrumbConfig() {
this.breadcrumbConfig = {
icon: this.isMicroservice ? 'microchip' : this.isFeature ? 'tab' : 'c8y-modules',
label: this.isMicroservice
? gettext('Microservices')
: this.isFeature
? gettext('Features')
: gettext('Applications'),
path: this.isMicroservice
? '/ecosystem/microservice/microservices'
: this.isFeature
? 'ecosystem/application/features'
: 'ecosystem/application/applications'
};
}
async loadBinaryMo() {
this.binaryMo = (await this.inventoryService.detail(this.application.activeVersionId)).data;
}
async extractVersionInformation(application) {
if (!application.manifest.isPackage && !application.manifest.source) {
return;
}
const blueprintApplicationId = application.manifest?.source;
const currentVersion = application.manifest?.version;
try {
const { data: blueprintApplicationVersions } = await this.applicationService.listVersions(blueprintApplicationId);
const blueprintLatestVersion = this.ecosystemService.getApplicationVersionObjectByTag(blueprintApplicationVersions, 'latest');
this.blueprintApplicationVersion = blueprintLatestVersion.version;
this.isUpdateAvailable = this.ecosystemService.shouldUpgradePackage(currentVersion, blueprintLatestVersion);
}
catch {
this.alertService.warning(gettext('Unable to resolve versions of source package.'));
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ApplicationPropertiesComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i1.EcosystemService }, { token: i1$2.Router }, { token: i3.FormBuilder }, { token: i4.ApplicationService }, { token: i2.AlertService }, { token: i4.InventoryService }, { token: i2.Permissions }, { token: i2.ModalService }, { token: i6.TranslateService }, { token: i1$1.BsModalService }, { token: i2.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: ApplicationPropertiesComponent, isStandalone: true, selector: "c8y-application-properties", ngImport: i0, template: "<c8y-title>{{ application | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb *ngIf=\"!isMicroservice\">\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\n [icon]=\"breadcrumbConfig?.icon\"\n *ngIf=\"isFeature\"\n [label]=\"breadcrumbConfig?.label\"\n [path]=\"breadcrumbConfig?.path\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"application | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Properties' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-breadcrumb *ngIf=\"isMicroservice\">\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"breadcrumbConfig?.icon\"\n [label]=\"breadcrumbConfig?.label\"\n [path]=\"breadcrumbConfig?.path\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"application | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Properties' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<div class=\"row\">\n <div [ngClass]=\"{ 'col-md-8': !isActivityLogSupported, 'col-md-12': isActivityLogSupported }\">\n <div\n class=\"card content-fullpage\"\n *ngIf=\"application\"\n [ngClass]=\"{ 'd-grid grid__col--7-5--md': isActivityLogSupported }\"\n >\n <form\n class=\"d-flex d-col content-fullpage\"\n (ngSubmit)=\"formGroup.valid && save(formGroup.value)\"\n [formGroup]=\"formGroup\"\n novalidate\n >\n <div\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n >\n <div class=\"card-block separator-bottom large-padding flex-no-shrink\">\n <div class=\"d-flex-md a-i-start text-center text-left-md\">\n <c8y-app-icon\n class=\"icon-48\"\n *ngIf=\"!isPackage && !isFeature && !isMicroservice && !isExternal\"\n [app]=\"application\"\n [contextPath]=\"application.contextPath\"\n [name]=\"application.name\"\n ></c8y-app-icon>\n <i\n class=\"icon-48\"\n c8yIcon=\"big-parcel\"\n *ngIf=\"isPackage\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"tab\"\n *ngIf=\"isFeature\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"microchip\"\n *ngIf=\"isMicroservice\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"globe1\"\n *ngIf=\"isExternal\"\n ></i>\n\n <div class=\"p-t-md-16 p-l-md-16 p-r-md-32 flex-grow\">\n <p class=\"h4 text-medium m-b-8\">{{ application | humanizeAppName | async }}</p>\n <p *ngIf=\"!isOwner\">\n <em class=\"text-muted\">\n {{\n formGroup?.controls?.description?.value || (noDescriptionLabel | translate)\n }}\n </em>\n </p>\n <div\n class=\"form-group m-b-0\"\n *ngIf=\"isOwner\"\n >\n <label\n class=\"editable\"\n [ngClass]=\"{ updated: formGroup?.controls?.description?.dirty }\"\n >\n <textarea\n class=\"form-control no-resize\"\n placeholder=\"{{ noDescriptionLabel | translate }}\"\n name=\"description\"\n c8y-textarea-autoresize\n formControlName=\"description\"\n ></textarea>\n </label>\n </div>\n </div>\n <div class=\"text-right-md m-t-4\">\n <span\n class=\"label\"\n [ngClass]=\"appState?.class\"\n >\n {{ appState?.label | translate }}\n </span>\n <div\n class=\"fit-w m-t-2\"\n *ngIf=\"application.manifest?.version\"\n data-cy=\"application-detail--version\"\n >\n <label\n class=\"text-label-small\"\n translate\n >\n Version:\n </label>\n <small class=\"p-l-4 text-bold\">{{ application.manifest?.version }}</small>\n </div>\n <div\n class=\"fit-w m-t-2\"\n *ngIf=\"!isUnpacked\"\n >\n <label\n class=\"text-label-small\"\n translate\n >\n Creation time:\n </label>\n <small class=\"p-l-4 text-bold\">\n {{ (binaryMo?.creationTime | c8yDate) || '---' }}\n </small>\n </div>\n <div class=\"m-t-8\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.aria-label]=\"\n 'There\\'s a newer version available, click to update' | translate\n \"\n tooltip=\"{{\n 'There\\'s a newer version available, click to update' | translate\n }}\"\n placement=\"top\"\n type=\"button\"\n *ngIf=\"isUpdateAvailable\"\n (click)=\"updateToLatestVersion()\"\n [delay]=\"300\"\n >\n <i [c8yIcon]=\"'installing-updates'\"></i>\n {{ 'Update available' | translate }}\n </button>\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Open' | translate }}\"\n type=\"button\"\n (click)=\"openApp(application)\"\n [disabled]=\"disableOpenInBrowser\"\n *ngIf=\"canOpenInBrowser\"\n >\n <i [c8yIcon]=\"'external-link'\"></i>\n {{ 'Open' | translate }}\n </button>\n <div *ngIf=\"canOpenInBrowser && disableOpenInBrowser\">\n <small\n class=\"text-muted\"\n translate\n >\n The application is overwritten by a custom application sharing the same path\n </small>\n </div>\n <span *ngIf=\"isCustomMicroservice\">\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Subscribe' | translate }}\"\n type=\"button\"\n (click)=\"subscribe()\"\n *ngIf=\"!isSubscribed\"\n >\n <i [c8yIcon]=\"'check-circle-o'\"></i>\n {{ 'Subscribe' | translate }}\n </button>\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Unsubscribe' | translate }}\"\n type=\"button\"\n (click)=\"unsubscribe()\"\n *ngIf=\"isSubscribed\"\n >\n <i [c8yIcon]=\"'minus-circle'\"></i>\n {{ 'Unsubscribe' | translate }}\n </button>\n </span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"inner-scroll bg-level-0 flex-grow\">\n <div class=\"card-block large-padding\">\n <div\n class=\"row p-16\"\n *ngIf=\"isPackage\"\n >\n <c8y-properties-list\n icon=\"info\"\n [title]=\"'Package details' | translate\"\n [data]=\"application.manifest\"\n [properties]=\"packageProperties\"\n [emptyLabel]=\"'---'\"\n ></c8y-properties-list>\n </div>\n <div\n class=\"row p-16\"\n *ngIf=\"sourcePackage\"\n >\n <c8y-properties-list\n icon=\"info\"\n [title]=\"'Source package information' | translate\"\n [data]=\"sourcePackage.manifest\"\n [properties]=\"packageProperties\"\n [emptyLabel]=\"'---'\"\n ></c8y-properties-list>\n </div>\n <div class=\"row\">\n <div class=\"col-sm-5\">\n <c8y-form-group>\n <label for=\"appId\">ID</label>\n <input\n class=\"form-control\"\n id=\"appId\"\n name=\"id\"\n type=\"text\"\n autocomplete=\"off\"\n [readonly]=\"true\"\n formControlName=\"id\"\n />\n </c8y-form-group>\n </div>\n <div class=\"col-sm-7\">\n <c8y-form-group>\n <label>{{ 'Name' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. My application' | translate }}\"\n name=\"name\"\n type=\"text\"\n required\n [readonly]=\"!isOwner\"\n formControlName=\"name\"\n />\n </c8y-form-group>\n </div>\n </div>\n\n <div class=\"row\">\n <div class=\"col-sm-5\">\n <c8y-form-group>\n <label>{{ 'Application key' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. my-application-key' | translate }}\"\n name=\"key\"\n type=\"text\"\n required\n [readonly]=\"application.id || !isOwner\"\n formControlName=\"key\"\n />\n </c8y-form-group>\n </div>\n\n <div class=\"col-sm-7\" data-cy=\"application-detail--type\">\n <c8y-form-group>\n <label>{{ 'Type' | translate }}</label>\n <div>\n <div *ngIf=\"application.id\">\n <p class=\"form-control-static\">\n <i [c8yIcon]=\"iconMap[application.type]\"></i>\n <span>\n {{ application.type | translate }}\n </span>\n </p>\n </div>\n </div>\n </c8y-form-group>\n </div>\n </div>\n\n <div [ngSwitch]=\"application.type\">\n <div *ngSwitchCase=\"'HOSTED'\">\n <c8y-form-group>\n <label>{{ 'Path' | translate }}</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`used in URL`' | translate }}\"\n name=\"contextPath\"\n type=\"text\"\n required\n [readOnly]=\"application.id || !isOwner\"\n formControlName=\"contextPath\"\n />\n </div>\n </c8y-form-group>\n </div>\n\n <div *ngSwitchCase=\"'MICROSERVICE'\">\n <c8y-form-group>\n <label>{{ 'Path' | translate }}</label>\n <div class=\"input-group\">\n <span class=\"input-group-addon\">/service/</span>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. my-microservice`used in URL`' | translate }}\"\n name=\"contextPath\"\n type=\"text\"\n required\n [readOnly]=\"application.id || !isOwner\"\n formControlName=\"contextPath\"\n />\n </div>\n </c8y-form-group>\n <div class=\"row\">\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.version\"\n data-cy=\"application-detail--version\"\n >\n <label>{{ 'Version' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.version }}\n </p>\n </div>\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.isolation\"\n data-cy=\"application-detail--isolation\"\n >\n <label>{{ 'Isolation' | translate }}</label>\n <p class=\"form-control-static\">\n <span *ngIf=\"singleTenant\">\n <i\n class=\"c8y-icon-duocolor h4\"\n [c8yIcon]=\"'c8y-enterprise'\"\n ></i>\n {{ 'Single tenant' | translate }}\n </span>\n <span *ngIf=\"!singleTenant\">\n <i\n class=\"c8y-icon-duocolor icon-32\"\n [c8yIcon]=\"'c8y-sub-tenants'\"\n ></i>\n {{ 'Multi tenant' | translate }}\n </span>\n </p>\n </div>\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.isolation\"\n data-cy=\"application-detail--billing-mode\"\n >\n <label>{{ 'Billing mode' | translate }}</label>\n <p class=\"form-control-static\">\n <span\n [tooltip]=\"'Resources usage assigned to: Owner' | translate\"\n *ngIf=\"subscription\"\n >\n {{ 'Subscription' | translate }}\n </span>\n <span\n [tooltip]=\"'Resources usage assigned to: Subscriber | translate'\"\n *ngIf=\"!subscription && singleTenant\"\n >\n {{ 'Resources' | translate }}\n </span>\n <span\n [tooltip]=\"'Resources usage assigned to: Owner' | translate\"\n *ngIf=\"!subscription && !singleTenant\"\n >\n {{ 'Resources' | translate }}\n </span>\n </p>\n </div>\n </div>\n\n <div\n class=\"legend form-block m-t-40\"\n *ngIf=\"application.manifest.provider\"\n >\n {{ 'Provider' | translate }}\n </div>\n <div\n class=\"list-inline\"\n *ngIf=\"application.manifest.provider\"\n data-cy=\"application-detail--provider\"\n >\n <div *ngIf=\"application.manifest.provider.name\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Name' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.name }}\n </p>\n </div>\n </div>\n <div *ngIf=\"application.manifest.provider.domain\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Domain' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.domain }}\n </p>\n </div>\n </div>\n <div *ngIf=\"application.manifest.provider.support\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Support' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.support }}\n </p>\n </div>\n </div>\n </div>\n </div>\n\n <div *ngSwitchCase=\"'EXTERNAL'\">\n <c8y-form-group>\n <label>{{ 'External URL' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} http://www.example.com/\"\n name=\"externalUrl\"\n type=\"url\"\n required\n [pattern]=\"'^(?!javascript:).+'\"\n [readOnly]=\"!isOwner\"\n formControlName=\"externalUrl\"\n />\n <c8y-messages>\n <c8y-message\n [name]=\"'pattern'\"\n [text]=\"'Valid URL required.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </div>\n\n <div *ngIf=\"isOwner && !isCustomMicroservice\">\n <label>{{ 'Select icon' | translate }}</label>\n <c8y-icon-selector-wrapper\n name=\"icon\"\n formControlName=\"icon\"\n ></c8y-icon-selector-wrapper>\n </div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"isCustomMicroservice\">\n <div\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n >\n <c8y-upload-archive\n [(application)]=\"application\"\n (refresh)=\"onNewArchive()\"\n ></c8y-upload-archive>\n </div>\n </ng-container>\n <div\n class=\"card-footer separator\"\n *ngIf=\"application && !!isOwner && hasAdminPermissions\"\n >\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-danger\"\n title=\"{{ 'Delete' | translate }}\"\n type=\"button\"\n (click)=\"delete()\"\n *ngIf=\"canDelete\"\n >\n {{ 'Delete' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-form\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n [disabled]=\"!application.type || formGroup.invalid || formGroup.pristine\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </form>\n\n <div\n class=\"content-fullpage d-flex d-col bg-level-1\"\n *ngIf=\"isActivityLogSupported\"\n >\n <div class=\"card-header separator\">\n <div\n class=\"card-title\"\n translate\n >\n Activity log\n </div>\n <div class=\"m-l-auto\">\n <button\n class=\"btn btn-link btn-sm\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"load()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': isLoading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n </div>\n </div>\n <div\n class=\"p-16 text-center\"\n *ngIf=\"isLoading\"\n >\n <c8y-loading></c8y-loading>\n </div>\n <c8y-activity-log\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n [hasAdminPermissions]=\"hasAdminPermissions\"\n [application]=\"application\"\n ></c8y-activity-log>\n </div>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.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: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: AppIconComponent, selector: "c8y-app-icon", inputs: ["contextPath", "name", "app"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: TextareaAutoresizeDirective, selector: "[c8y-textarea-autoresize]" }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { 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: "component", type: PropertiesListComponent, selector: "c8y-properties-list", inputs: ["properties", "title", "icon", "data", "groups", "noParse", "emptyLabel"] }, { kind: "component", type: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "component", type: MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: IconSelectorWrapperComponent, selector: "c8y-icon-selector-wrapper", inputs: ["canRemoveIcon", "selectedIcon", "iconSize"], outputs: ["onSelect"] }, { kind: "component", type: UploadArchiveComponent, selector: "c8y-upload-archive", inputs: ["application", "uploadNewVersion", "preUploadCallback"], outputs: ["applicationChange", "refresh"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: ActivityLogComponent, selector: "c8y-activity-log", inputs: ["application", "hasAdminPermissions"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: HumanizeAppNamePipe, name: "humanizeAppName" }, { kind: "pipe", type: DatePipe, name: "c8yDate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ApplicationPropertiesComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-application-properties', imports: [
TitleComponent,
NgIf,
BreadcrumbComponent,
BreadcrumbItemComponent,
NgClass,
FormsModule,
ReactiveFormsModule,
AppIconComponent,
IconDirective,
TextareaAutoresizeDirective,
C8yTranslateDirective,
TooltipDirective,
PropertiesListComponent,
FormGroupComponent,
RequiredInputPlaceholderDirective,
NgSwitch,
NgSwitchCase,
MessagesComponent,
MessageDirective,
IconSelectorWrapperComponent,
UploadArchiveComponent,
LoadingComponent,
ActivityLogComponent,
C8yTranslatePipe,
AsyncPipe,
HumanizeAppNamePipe,
DatePipe
], template: "<c8y-title>{{ application | humanizeAppName | async }}</c8y-title>\n\n<c8y-breadcrumb *ngIf=\"!isMicroservice\">\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\n [icon]=\"breadcrumbConfig?.icon\"\n *ngIf=\"isFeature\"\n [label]=\"breadcrumbConfig?.label\"\n [path]=\"breadcrumbConfig?.path\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"application | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Properties' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-breadcrumb *ngIf=\"isMicroservice\">\n <c8y-breadcrumb-item\n [icon]=\"'c8y-atom'\"\n [label]=\"'Ecosystem' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"breadcrumbConfig?.icon\"\n [label]=\"breadcrumbConfig?.label\"\n [path]=\"breadcrumbConfig?.path\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"application | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Properties' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<div class=\"row\">\n <div [ngClass]=\"{ 'col-md-8': !isActivityLogSupported, 'col-md-12': isActivityLogSupported }\">\n <div\n class=\"card content-fullpage\"\n *ngIf=\"application\"\n [ngClass]=\"{ 'd-grid grid__col--7-5--md': isActivityLogSupported }\"\n >\n <form\n class=\"d-flex d-col content-fullpage\"\n (ngSubmit)=\"formGroup.valid && save(formGroup.value)\"\n [formGroup]=\"formGroup\"\n novalidate\n >\n <div\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n >\n <div class=\"card-block separator-bottom large-padding flex-no-shrink\">\n <div class=\"d-flex-md a-i-start text-center text-left-md\">\n <c8y-app-icon\n class=\"icon-48\"\n *ngIf=\"!isPackage && !isFeature && !isMicroservice && !isExternal\"\n [app]=\"application\"\n [contextPath]=\"application.contextPath\"\n [name]=\"application.name\"\n ></c8y-app-icon>\n <i\n class=\"icon-48\"\n c8yIcon=\"big-parcel\"\n *ngIf=\"isPackage\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"tab\"\n *ngIf=\"isFeature\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"microchip\"\n *ngIf=\"isMicroservice\"\n ></i>\n <i\n class=\"icon-48\"\n c8yIcon=\"globe1\"\n *ngIf=\"isExternal\"\n ></i>\n\n <div class=\"p-t-md-16 p-l-md-16 p-r-md-32 flex-grow\">\n <p class=\"h4 text-medium m-b-8\">{{ application | humanizeAppName | async }}</p>\n <p *ngIf=\"!isOwner\">\n <em class=\"text-muted\">\n {{\n formGroup?.controls?.description?.value || (noDescriptionLabel | translate)\n }}\n </em>\n </p>\n <div\n class=\"form-group m-b-0\"\n *ngIf=\"isOwner\"\n >\n <label\n class=\"editable\"\n [ngClass]=\"{ updated: formGroup?.controls?.description?.dirty }\"\n >\n <textarea\n class=\"form-control no-resize\"\n placeholder=\"{{ noDescriptionLabel | translate }}\"\n name=\"description\"\n c8y-textarea-autoresize\n formControlName=\"description\"\n ></textarea>\n </label>\n </div>\n </div>\n <div class=\"text-right-md m-t-4\">\n <span\n class=\"label\"\n [ngClass]=\"appState?.class\"\n >\n {{ appState?.label | translate }}\n </span>\n <div\n class=\"fit-w m-t-2\"\n *ngIf=\"application.manifest?.version\"\n data-cy=\"application-detail--version\"\n >\n <label\n class=\"text-label-small\"\n translate\n >\n Version:\n </label>\n <small class=\"p-l-4 text-bold\">{{ application.manifest?.version }}</small>\n </div>\n <div\n class=\"fit-w m-t-2\"\n *ngIf=\"!isUnpacked\"\n >\n <label\n class=\"text-label-small\"\n translate\n >\n Creation time:\n </label>\n <small class=\"p-l-4 text-bold\">\n {{ (binaryMo?.creationTime | c8yDate) || '---' }}\n </small>\n </div>\n <div class=\"m-t-8\">\n <button\n class=\"btn btn-default btn-sm\"\n [attr.aria-label]=\"\n 'There\\'s a newer version available, click to update' | translate\n \"\n tooltip=\"{{\n 'There\\'s a newer version available, click to update' | translate\n }}\"\n placement=\"top\"\n type=\"button\"\n *ngIf=\"isUpdateAvailable\"\n (click)=\"updateToLatestVersion()\"\n [delay]=\"300\"\n >\n <i [c8yIcon]=\"'installing-updates'\"></i>\n {{ 'Update available' | translate }}\n </button>\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Open' | translate }}\"\n type=\"button\"\n (click)=\"openApp(application)\"\n [disabled]=\"disableOpenInBrowser\"\n *ngIf=\"canOpenInBrowser\"\n >\n <i [c8yIcon]=\"'external-link'\"></i>\n {{ 'Open' | translate }}\n </button>\n <div *ngIf=\"canOpenInBrowser && disableOpenInBrowser\">\n <small\n class=\"text-muted\"\n translate\n >\n The application is overwritten by a custom application sharing the same path\n </small>\n </div>\n <span *ngIf=\"isCustomMicroservice\">\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Subscribe' | translate }}\"\n type=\"button\"\n (click)=\"subscribe()\"\n *ngIf=\"!isSubscribed\"\n >\n <i [c8yIcon]=\"'check-circle-o'\"></i>\n {{ 'Subscribe' | translate }}\n </button>\n <button\n class=\"btn btn-default btn-sm\"\n title=\"{{ 'Unsubscribe' | translate }}\"\n type=\"button\"\n (click)=\"unsubscribe()\"\n *ngIf=\"isSubscribed\"\n >\n <i [c8yIcon]=\"'minus-circle'\"></i>\n {{ 'Unsubscribe' | translate }}\n </button>\n </span>\n </div>\n </div>\n </div>\n </div>\n <div class=\"inner-scroll bg-level-0 flex-grow\">\n <div class=\"card-block large-padding\">\n <div\n class=\"row p-16\"\n *ngIf=\"isPackage\"\n >\n <c8y-properties-list\n icon=\"info\"\n [title]=\"'Package details' | translate\"\n [data]=\"application.manifest\"\n [properties]=\"packageProperties\"\n [emptyLabel]=\"'---'\"\n ></c8y-properties-list>\n </div>\n <div\n class=\"row p-16\"\n *ngIf=\"sourcePackage\"\n >\n <c8y-properties-list\n icon=\"info\"\n [title]=\"'Source package information' | translate\"\n [data]=\"sourcePackage.manifest\"\n [properties]=\"packageProperties\"\n [emptyLabel]=\"'---'\"\n ></c8y-properties-list>\n </div>\n <div class=\"row\">\n <div class=\"col-sm-5\">\n <c8y-form-group>\n <label for=\"appId\">ID</label>\n <input\n class=\"form-control\"\n id=\"appId\"\n name=\"id\"\n type=\"text\"\n autocomplete=\"off\"\n [readonly]=\"true\"\n formControlName=\"id\"\n />\n </c8y-form-group>\n </div>\n <div class=\"col-sm-7\">\n <c8y-form-group>\n <label>{{ 'Name' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. My application' | translate }}\"\n name=\"name\"\n type=\"text\"\n required\n [readonly]=\"!isOwner\"\n formControlName=\"name\"\n />\n </c8y-form-group>\n </div>\n </div>\n\n <div class=\"row\">\n <div class=\"col-sm-5\">\n <c8y-form-group>\n <label>{{ 'Application key' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. my-application-key' | translate }}\"\n name=\"key\"\n type=\"text\"\n required\n [readonly]=\"application.id || !isOwner\"\n formControlName=\"key\"\n />\n </c8y-form-group>\n </div>\n\n <div class=\"col-sm-7\" data-cy=\"application-detail--type\">\n <c8y-form-group>\n <label>{{ 'Type' | translate }}</label>\n <div>\n <div *ngIf=\"application.id\">\n <p class=\"form-control-static\">\n <i [c8yIcon]=\"iconMap[application.type]\"></i>\n <span>\n {{ application.type | translate }}\n </span>\n </p>\n </div>\n </div>\n </c8y-form-group>\n </div>\n </div>\n\n <div [ngSwitch]=\"application.type\">\n <div *ngSwitchCase=\"'HOSTED'\">\n <c8y-form-group>\n <label>{{ 'Path' | translate }}</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`used in URL`' | translate }}\"\n name=\"contextPath\"\n type=\"text\"\n required\n [readOnly]=\"application.id || !isOwner\"\n formControlName=\"contextPath\"\n />\n </div>\n </c8y-form-group>\n </div>\n\n <div *ngSwitchCase=\"'MICROSERVICE'\">\n <c8y-form-group>\n <label>{{ 'Path' | translate }}</label>\n <div class=\"input-group\">\n <span class=\"input-group-addon\">/service/</span>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g. my-microservice`used in URL`' | translate }}\"\n name=\"contextPath\"\n type=\"text\"\n required\n [readOnly]=\"application.id || !isOwner\"\n formControlName=\"contextPath\"\n />\n </div>\n </c8y-form-group>\n <div class=\"row\">\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.version\"\n data-cy=\"application-detail--version\"\n >\n <label>{{ 'Version' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.version }}\n </p>\n </div>\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.isolation\"\n data-cy=\"application-detail--isolation\"\n >\n <label>{{ 'Isolation' | translate }}</label>\n <p class=\"form-control-static\">\n <span *ngIf=\"singleTenant\">\n <i\n class=\"c8y-icon-duocolor h4\"\n [c8yIcon]=\"'c8y-enterprise'\"\n ></i>\n {{ 'Single tenant' | translate }}\n </span>\n <span *ngIf=\"!singleTenant\">\n <i\n class=\"c8y-icon-duocolor icon-32\"\n [c8yIcon]=\"'c8y-sub-tenants'\"\n ></i>\n {{ 'Multi tenant' | translate }}\n </span>\n </p>\n </div>\n <div\n class=\"col-sm-4 m-b-16 flex-auto\"\n *ngIf=\"application.manifest.isolation\"\n data-cy=\"application-detail--billing-mode\"\n >\n <label>{{ 'Billing mode' | translate }}</label>\n <p class=\"form-control-static\">\n <span\n [tooltip]=\"'Resources usage assigned to: Owner' | translate\"\n *ngIf=\"subscription\"\n >\n {{ 'Subscription' | translate }}\n </span>\n <span\n [tooltip]=\"'Resources usage assigned to: Subscriber | translate'\"\n *ngIf=\"!subscription && singleTenant\"\n >\n {{ 'Resources' | translate }}\n </span>\n <span\n [tooltip]=\"'Resources usage assigned to: Owner' | translate\"\n *ngIf=\"!subscription && !singleTenant\"\n >\n {{ 'Resources' | translate }}\n </span>\n </p>\n </div>\n </div>\n\n <div\n class=\"legend form-block m-t-40\"\n *ngIf=\"application.manifest.provider\"\n >\n {{ 'Provider' | translate }}\n </div>\n <div\n class=\"list-inline\"\n *ngIf=\"application.manifest.provider\"\n data-cy=\"application-detail--provider\"\n >\n <div *ngIf=\"application.manifest.provider.name\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Name' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.name }}\n </p>\n </div>\n </div>\n <div *ngIf=\"application.manifest.provider.domain\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Domain' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.domain }}\n </p>\n </div>\n </div>\n <div *ngIf=\"application.manifest.provider.support\">\n <div class=\"col-sm-4 m-b-16\">\n <label>{{ 'Support' | translate }}</label>\n <p class=\"form-control-static\">\n {{ application.manifest.provider.support }}\n </p>\n </div>\n </div>\n </div>\n </div>\n\n <div *ngSwitchCase=\"'EXTERNAL'\">\n <c8y-form-group>\n <label>{{ 'External URL' | translate }}</label>\n <input\n class=\"form-control\"\n placeholder=\"{{ 'e.g.' | translate }} http://www.example.com/\"\n name=\"externalUrl\"\n type=\"url\"\n required\n [pattern]=\"'^(?!javascript:).+'\"\n [readOnly]=\"!isOwner\"\n formControlName=\"externalUrl\"\n />\n <c8y-messages>\n <c8y-message\n [name]=\"'pattern'\"\n [text]=\"'Valid URL required.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </div>\n\n <div *ngIf=\"isOwner && !isCustomMicroservice\">\n <label>{{ 'Select icon' | translate }}</label>\n <c8y-icon-selector-wrapper\n name=\"icon\"\n formControlName=\"icon\"\n ></c8y-icon-selector-wrapper>\n </div>\n </div>\n </div>\n </div>\n <ng-container *ngIf=\"isCustomMicroservice\">\n <div\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n >\n <c8y-upload-archive\n [(application)]=\"application\"\n (refresh)=\"onNewArchive()\"\n ></c8y-upload-archive>\n </div>\n </ng-container>\n <div\n class=\"card-footer separator\"\n *ngIf=\"application && !!isOwner && hasAdminPermissions\"\n >\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Cancel' | translate }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ 'Cancel' | translate }}\n </button>\n <button\n class=\"btn btn-danger\"\n title=\"{{ 'Delete' | translate }}\"\n type=\"button\"\n (click)=\"delete()\"\n *ngIf=\"canDelete\"\n >\n {{ 'Delete' | translate }}\n </button>\n <button\n class=\"btn btn-primary btn-form\"\n title=\"{{ 'Save' | translate }}\"\n type=\"submit\"\n [disabled]=\"!application.type || formGroup.invalid || formGroup.pristine\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </form>\n\n <div\n class=\"content-fullpage d-flex d-col bg-level-1\"\n *ngIf=\"isActivityLogSupported\"\n >\n <div class=\"card-header separator\">\n <div\n class=\"card-title\"\n translate\n >\n Activity log\n </div>\n <div class=\"m-l-auto\">\n <button\n class=\"btn btn-link btn-sm\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"load()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': isLoading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n </div>\n </div>\n <div\n class=\"p-16 text-center\"\n *ngIf=\"isLoading\"\n >\n <c8y-loading></c8y-loading>\n </div>\n <c8y-activity-log\n class=\"d-contents\"\n *ngIf=\"!isLoading\"\n [hasAdminPermissions]=\"hasAdminPermissions\"\n [application]=\"application\"\n ></c8y-activity-log>\n </div>\n </div>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i1.EcosystemService }, { type: i1$2.Router }, { type: i3.FormBuilder }, { type: i4.ApplicationService }, { type: i2.AlertService }, { type: i4.InventoryService }, { type: i2.Permissions }, { type: i2.ModalService }, { type: i6.TranslateService }, { type: i1$1.BsModalService }, { type: i2.GainsightService }] });
class ApplicationPropertiesGuard {
constructor(ecosystemService) {
this.ecosystemService = ecosystemService;
}
canActivate(route) {
const app = route.data.contextData || route.parent.data.contextData;
if (!app) {
return false;
}
return !this.ecosystemService.isPackage(app);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ApplicationPropertiesGuard, deps: [{ token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ApplicationPropertiesGuard }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ApplicationPropertiesGuard, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: i1.EcosystemService }] });
class AddExternalApplicationComponent {
constructor(applicationService, formBuilder, alertService, wizardComponent) {
this.applicationService = applicationService;
this.formBuilder = formBuilder;
this.alertService = alertService;
this.wizardComponent = wizardComponent;
}
ngOnInit() {
this.initForm();
}
back() {
this.wizardComponent.reset();
}
cancel() {
this.wizardComponent.close();
}
done() {
this.wizardComponent.close();
}
async save(app) {
const appToSave = {
manifest: {},
externalUrl: app.externalUrl,
type: ApplicationType.EXTERNAL,
name: app.name,
key: app.key
};
try {
this.createdApp = await this.applicationService.create(appToSave);
}
catch (ex) {
this.alertService.addServerFailure(ex);
}
}
initForm() {
this.formGroup = this.formBuilder.group({
name: ['', [Validators.required, Validators.maxLength(120)]],
key: ['', [Validators.required, Validators.maxLength(120)]],
externalUrl: ['', Validators.required]
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AddExternalApplicationComponent, deps: [{ token: i4.ApplicationService }, { token: i3.FormBuilder }, { token: i2.AlertService }, { token: i2.WizardComponent }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: AddExternalApplicationComponent, isStandalone: true, selector: "c8y-add-external-application", ngImport: i0, template: "<form *ngIf=\"!createdApp; else appCreated\" [formGroup]=\"formGroup\" novalidate>\n <c8y-wizard-header>\n <i [c8yIcon]=\"'cloud-link'\"></i>\n <h4 translate id=\"modal-title\">Add external application</h4>\n </c8y-wizard-header>\n\n <c8y-wizard-body>\n <p class=\"p-16 text-medium text-center bg-level-0 separator-bottom sticky-top\">\n {{ 'Provide external application details' | translate }}\n </p>\n <div class=\"modal-body p-t-8\" id=\"modal-body\">\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'Name' | translate }}</label>\n <input\n class=\"form-control\"\n formControlName=\"name\"\n name=\"name\"\n placeholder=\"{{ 'e.g. My application' | translate }}\"\n required\n type=\"text\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'Application key' | translate }}</label>\n <input\n class=\"form-control\"\n formControlName=\"key\"\n name=\"key\"\n placeholder=\"{{ 'e.g. my-external-application-key' | translate }}\"\n required\n type=\"text\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'External URL' | translate }}</label>\n <input\n [pattern]=\"'^(?!javascript:).+'\"\n class=\"form-control\"\n formControlName=\"externalUrl\"\n name=\"externalUrl\"\n placeholder=\"{{ 'e.g.' | translate }} https://www.example.com\"\n required\n type=\"url\"\n />\n </c8y-form-group>\n </div>\n </c8y-wizard-body>\n\n <c8y-wizard-footer>\n <button\n (click)=\"back()\"\n class=\"btn btn-default\"\n title=\"{{ 'Back' | translate }}\"\n translate\n type=\"button\"\n >\n Back\n </button>\n <button (click)=\"cancel()\" class=\"btn btn-default\" title=\"{{ 'Cancel' | translate }}\" translate>\n Cancel\n </button>\n <button\n (click)=\"save(formGroup.value)\"\n [disabled]=\"formGroup.invalid || formGroup.pristine\"\n class=\"btn btn-primary btn-form\"\n title=\"{{ 'Add application' | translate }}\"\n type=\"button\"\n >\n {{ 'Add application' | translate }}\n </button>\n </c8y-wizard-footer>\n</form>\n<ng-template #appCreated>\n <c8y-wizard-body>\n <div class=\"d-flex d-col j-c-center a-i-center\" style=\"min-height: 324px\">\n <c8y-operation-result\n text=\"{{ 'Application created' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n type=\"success\"\n class=\"lead\"\n ></c8y-operation-result>\n </div>\n </c8y-wizard-body>\n <c8y-wizard-footer>\n <button (click)=\"done()\" class=\"btn btn-default\" title=\"{{ 'Done' | translate }}\" translate>\n Done\n </button>\n <a\n (click)=\"$event.stopPropagation()\"\n [href]=\"formGroup.value.externalUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"btn btn-primary\"\n title=\"{{ 'Open' | translate }}\"\n >\n <i c8yIcon=\"external-link\" class=\"m-r-4\"></i>\n {{ 'Open' | translate }}\n </a>\n </c8y-wizard-footer>\n</ng-template>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.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: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i3.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i3.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { 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: FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: WizardFooterComponent, selector: "c8y-wizard-footer" }, { kind: "component", type: OperationResultComponent, selector: "c8y-operation-result", inputs: ["text", "vertical", "size", "type"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AddExternalApplicationComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-add-external-application', imports: [
NgIf,
FormsModule,
ReactiveFormsModule,
WizardHeaderComponent,
IconDirective,
C8yTranslateDirective,
WizardBodyComponent,
FormGroupComponent,
RequiredInputPlaceholderDirective,
WizardFooterComponent,
OperationResultComponent,
C8yTranslatePipe
], template: "<form *ngIf=\"!createdApp; else appCreated\" [formGroup]=\"formGroup\" novalidate>\n <c8y-wizard-header>\n <i [c8yIcon]=\"'cloud-link'\"></i>\n <h4 translate id=\"modal-title\">Add external application</h4>\n </c8y-wizard-header>\n\n <c8y-wizard-body>\n <p class=\"p-16 text-medium text-center bg-level-0 separator-bottom sticky-top\">\n {{ 'Provide external application details' | translate }}\n </p>\n <div class=\"modal-body p-t-8\" id=\"modal-body\">\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'Name' | translate }}</label>\n <input\n class=\"form-control\"\n formControlName=\"name\"\n name=\"name\"\n placeholder=\"{{ 'e.g. My application' | translate }}\"\n required\n type=\"text\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'Application key' | translate }}</label>\n <input\n class=\"form-control\"\n formControlName=\"key\"\n name=\"key\"\n placeholder=\"{{ 'e.g. my-external-application-key' | translate }}\"\n required\n type=\"text\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label style=\"text-align: left\">{{ 'External URL' | translate }}</label>\n <input\n [pattern]=\"'^(?!javascript:).+'\"\n class=\"form-control\"\n formControlName=\"externalUrl\"\n name=\"externalUrl\"\n placeholder=\"{{ 'e.g.' | translate }} https://www.example.com\"\n required\n type=\"url\"\n />\n </c8y-form-group>\n </div>\n </c8y-wizard-body>\n\n <c8y-wizard-footer>\n <button\n (click)=\"back()\"\n class=\"btn btn-default\"\n title=\"{{ 'Back' | translate }}\"\n translate\n type=\"button\"\n >\n Back\n </button>\n <button (click)=\"cancel()\" class=\"btn btn-default\" title=\"{{ 'Cancel' | translate }}\" translate>\n Cancel\n </button>\n <button\n (click)=\"save(formGroup.value)\"\n [disabled]=\"formGroup.invalid || formGroup.pristine\"\n class=\"btn btn-primary btn-form\"\n title=\"{{ 'Add application' | translate }}\"\n type=\"button\"\n >\n {{ 'Add application' | translate }}\n </button>\n </c8y-wizard-footer>\n</form>\n<ng-template #appCreated>\n <c8y-wizard-body>\n <div class=\"d-flex d-col j-c-center a-i-center\" style=\"min-height: 324px\">\n <c8y-operation-result\n text=\"{{ 'Application created' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n type=\"success\"\n class=\"lead\"\n ></c8y-operation-result>\n </div>\n </c8y-wizard-body>\n <c8y-wizard-footer>\n <button (click)=\"done()\" class=\"btn btn-default\" title=\"{{ 'Done' | translate }}\" translate>\n Done\n </button>\n <a\n (click)=\"$event.stopPropagation()\"\n [href]=\"formGroup.value.externalUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"btn btn-primary\"\n title=\"{{ 'Open' | translate }}\"\n >\n <i c8yIcon=\"external-link\" class=\"m-r-4\"></i>\n {{ 'Open' | translate }}\n </a>\n </c8y-wizard-footer>\n</ng-template>\n" }]
}], ctorParameters: () => [{ type: i4.ApplicationService }, { type: i3.FormBuilder }, { type: i2.AlertService }, { type: i2.WizardComponent }] });
class AddWebApplicationComponent {
constructor(ecosystemService) {
this.ecosystemService = ecosystemService;
this.headerText = gettext('Upload web application');
this.successText = gettext('Application created');
this.createApplicationHandler = (f) => this.createApplication(f);
this.uploadApplicationHandler = (f, app) => this.uploadApplication(f, app);
}
async createApplication(file) {
await this.ecosystemService.isValidAppType(file, ApplicationType.HOSTED);
return this.ecosystemService.createAppForArchive(file);
}
async uploadApplication(file, app) {
return this.ecosystemService.uploadArchiveToApp(file, app);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AddWebApplicationComponent, deps: [{ token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: AddWebApplicationComponent, isStandalone: true, selector: "c8y-add-web-application", ngImport: i0, template: `<c8y-add-application
[headerIcon]="'upload'"
[headerText]="headerText"
[successText]="successText"
[createApplicationHandler]="createApplicationHandler"
[uploadApplicationHandler]="uploadApplicationHandler"
[canGoBack]="true"
></c8y-add-application>`, isInline: true, dependencies: [{ kind: "component", type: AddApplicationComponent, selector: "c8y-add-application", inputs: ["headerText", "headerIcon", "successText", "createApplicationHandler", "uploadApplicationHandler", "canGoBack", "applicationType"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AddWebApplicationComponent, decorators: [{
type: Component,
args: [{
selector: 'c8y-add-web-application',
template: `<c8y-add-application
[headerIcon]="'upload'"
[headerText]="headerText"
[successText]="successText"
[createApplicationHandler]="createApplicationHandler"
[uploadApplicationHandler]="uploadApplicationHandler"
[canGoBack]="true"
></c8y-add-application>`,
imports: [AddApplicationComponent]
}]
}], ctorParameters: () => [{ type: i1.EcosystemService }] });
class ApplicationListComponent {
constructor(ecosystemService, wizardModalService) {
this.ecosystemService = ecosystemService;
this.wizardModalService = wizardModalService;
this.reloading = false;
this.reload$ = new BehaviorSubject(null);
this.apps$ = this.reload$.pipe(tap(() => (this.reloading = true)), switchMap(() => this.ecosystemService.getWebApplications()), tap(apps => {
apps.forEach(app => {
app.filterProps = this.ecosystemService.getAppFilterProps(app);
});
}), tap(() => (this.reloading = false)), shareReplay());
this.packageAvailabilities = defaultPackageAvailabilities;
this.destroy$ = new Subject();
}
ngOnInit() {
this.loadApplications();
}
loadApplications() {
this.reload$.next();
}
addApplication() {
const wizardConfig = {
headerText: 'Add Application',
headerIcon: 'c8y-atom'
};
const initialState = {
wizardConfig,
id: EcosystemWizards.APPLICATION_UPLOAD
};
const modalOptions = { initialState };
const modalRef = this.wizardModalService.show(modalOptions);
modalRef.content.onClose.pipe(takeUntil(this.destroy$)).subscribe(() => {
this.loadApplications();
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
setFilterPipe(pipe) {
this.filteredApps$ = this.apps$.pipe(src => pipe(src));
}
resetFilters() {
this.filtersComponent.resetAllFilters();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ApplicationListComponent, deps: [{ token: i1.EcosystemService }, { token: i2.WizardModalService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: ApplicationListComponent, isStandalone: true, selector: "c8y-application-list", viewQueries: [{ propertyName: "filtersComponent", first: true, predicate: ListFiltersComponent, descendants: true }], ngImport: i0, template: "<c8y-title>{{ 'Applications' | translate }}</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>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n *c8yIfAllowed=\"['ROLE_APPLICATION_MANAGEMENT_ADMIN']\"\n>\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add application' | translate }}\"\n (click)=\"addApplication()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add application' | 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=\"{{ 'Reload' | translate }}\"\n (click)=\"loadApplications()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n <c8y-list-filters\n *ngIf=\"apps$ | async\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n [packageAvailabilities]=\"packageAvailabilities\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(apps$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<c8y-help src=\"/docs/standard-tenant/ecosystem/#managing-applications\"></c8y-help>\n\n<div\n class=\"c8y-empty-state text-center\"\n *ngIf=\"(apps$ | async)?.length === 0\"\n>\n <h1 class=\"c8y-icon c8y-icon-modules c8y-icon-duocolor\"></h1>\n <h3 translate>No applications to display.</h3>\n <p translate>Add your first application by clicking below.</p>\n <p>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add application' | translate }}\"\n (click)=\"addApplication()\"\n >\n {{ 'Add application' | translate }}\n </button>\n </p>\n</div>\n\n<div\n class=\"card-group\"\n [ngClass]=\"listClass\"\n>\n <div\n class=\"page-sticky-header hidden-xs d-flex\"\n *ngIf=\"(apps$ | async)?.length > 0\"\n >\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Application' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80 m-r-40\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n <div class=\"card-block card-column-20\"></div>\n </div>\n </div>\n <div\n class=\"col-xs-12 col-sm-4 col-md-3\"\n *ngFor=\"let app of filteredApps$ | async\"\n >\n <c8y-application-card\n class=\"d-contents\"\n (onAppDeleted)=\"loadApplications()\"\n (onAppCloned)=\"loadApplications()\"\n [app]=\"app\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No matching applications.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n *ngIf=\"(apps$ | async)?.length > 0 && (filteredApps$ | async)?.length === 0\"\n>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset filters' | translate }}\"\n type=\"button\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n", dependencies: [{ kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "directive", type: IfAllowedDirective, selector: "[c8yIfAllowed]", inputs: ["c8yIfAllowed", "c8yIfAllowedAllowAny"] }, { kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ListFiltersComponent, selector: "c8y-list-filters", inputs: ["packageTypes", "packageAvailabilities", "packageContents"], outputs: ["filterPipeChange"] }, { kind: "component", type: ListDisplaySwitchComponent, selector: "c8y-list-display-switch", inputs: ["listKey", "listLength", "filterPipe"], outputs: ["onListClassChange"] }, { kind: "component", type: HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ApplicationCardComponent, selector: "c8y-application-card", inputs: ["app", "canEdit"], outputs: ["onAppDeleted", "onAppCloned"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ApplicationListComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-application-list', imports: [
TitleComponent,
BreadcrumbComponent,
BreadcrumbItemComponent,
IfAllowedDirective,
ActionBarItemComponent,
IconDirective,
NgClass,
NgIf,
ListFiltersComponent,
ListDisplaySwitchComponent,
HelpComponent,
C8yTranslateDirective,
NgFor,
ApplicationCardComponent,
EmptyStateComponent,
C8yTranslatePipe,
AsyncPipe
], template: "<c8y-title>{{ 'Applications' | translate }}</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>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n *c8yIfAllowed=\"['ROLE_APPLICATION_MANAGEMENT_ADMIN']\"\n>\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add application' | translate }}\"\n (click)=\"addApplication()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add application' | 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=\"{{ 'Reload' | translate }}\"\n (click)=\"loadApplications()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n <c8y-list-filters\n *ngIf=\"apps$ | async\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n [packageAvailabilities]=\"packageAvailabilities\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(apps$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<c8y-help src=\"/docs/standard-tenant/ecosystem/#managing-applications\"></c8y-help>\n\n<div\n class=\"c8y-empty-state text-center\"\n *ngIf=\"(apps$ | async)?.length === 0\"\n>\n <h1 class=\"c8y-icon c8y-icon-modules c8y-icon-duocolor\"></h1>\n <h3 translate>No applications to display.</h3>\n <p translate>Add your first application by clicking below.</p>\n <p>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add application' | translate }}\"\n (click)=\"addApplication()\"\n >\n {{ 'Add application' | translate }}\n </button>\n </p>\n</div>\n\n<div\n class=\"card-group\"\n [ngClass]=\"listClass\"\n>\n <div\n class=\"page-sticky-header hidden-xs d-flex\"\n *ngIf=\"(apps$ | async)?.length > 0\"\n >\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Application' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80 m-r-40\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n <div class=\"card-block card-column-20\"></div>\n </div>\n </div>\n <div\n class=\"col-xs-12 col-sm-4 col-md-3\"\n *ngFor=\"let app of filteredApps$ | async\"\n >\n <c8y-application-card\n class=\"d-contents\"\n (onAppDeleted)=\"loadApplications()\"\n (onAppCloned)=\"loadApplications()\"\n [app]=\"app\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No matching applications.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n *ngIf=\"(apps$ | async)?.length > 0 && (filteredApps$ | async)?.length === 0\"\n>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset filters' | translate }}\"\n type=\"button\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n" }]
}], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.WizardModalService }], propDecorators: { filtersComponent: [{
type: ViewChild,
args: [ListFiltersComponent]
}] } });
class InstallFromPackageComponent {
constructor(ecosystemService, applicationService, wizardComponent, pluginsService) {
this.ecosystemService = ecosystemService;
this.applicationService = applicationService;
this.wizardComponent = wizardComponent;
this.pluginsService = pluginsService;
this.deployedWithSuccess = false;
this.isDeployed = false;
this.model = {
selected: undefined,
binary: {
id: undefined
}
};
this.canDeploy = false;
this.onInput = new BehaviorSubject('');
}
async ngOnInit() {
this.loadPackages();
}
back() {
this.wizardComponent.reset();
}
clean() {
this.selectedPackage = undefined;
this.versions$ = undefined;
this.model = {
selected: undefined,
binary: {
id: undefined
}
};
}
cancel() {
this.wizardComponent.close();
}
async deployApp() {
this.inProgress = true;
const formGroupValue = this.applicationPropertiesForm.formGroup.getRawValue();
const { contextPath, license, name } = this.selectedPackage;
const type = this.pluginsService.getPackageType(this.selectedPackage);
const licensedApp = {
contextPath,
license,
name,
type,
version: this.model.selected.version
};
const isArchived = await this.ecosystemService.verifyArchived([licensedApp]);
if (!isArchived) {
this.cancel();
return;
}
const licensesVerifiedByUser = await this.ecosystemService.verifyLicenses([licensedApp]);
if (!licensesVerifiedByUser) {
this.cancel();
return;
}
// Verify if selected package version is compatible with current platform versions.
this.selectedPackage.manifest.version = this.model.selected.version;
const verifyVersionCompatibility = await this.ecosystemService.verifyBlueprintVersionsCompatibility(this.selectedPackage.manifest);
if (!verifyVersionCompatibility) {
this.cancel();
return;
}
try {
await this.ecosystemService.deployApp(this.selectedPackage, formGroupValue, this.model);
this.deployedWithSuccess = true;
}
catch (error) {
this.ecosystemService.alertError(error);
}
finally {
this.markAsDeployed();
}
}
onAppVersionSelect(appVersion) {
Object.assign(this.model, {
selected: appVersion
});
this.canDeploy = true;
}
async selectPackage(selectedPackage) {
const apps = await this.ecosystemService.getHostedAndPackageApplications();
this.newAppConfig = this.ecosystemService.getUniqueAppConfig(selectedPackage, apps);
this.selectedPackage = selectedPackage;
this.loadSelectedPackageVersions();
}
loadSelectedPackageVersions() {
this.versions$ = combineLatest([
this.getAppVersions(this.selectPackage),
this.onInput.asObservable()
]).pipe(map(([resultList, filterStr]) => {
this.canDeploy = false;
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 };
}));
}
getAppVersions(mo) {
const versions = mo?.applicationVersions;
return versions && versions.length > 0
? of({ data: versions, res: undefined })
: from(this.applicationService.listVersions(this.selectedPackage.id));
}
setInitialValueForInput(versions) {
if (!this.model.selected && versions.length > 0) {
const latest = versions.find(v => v.tags.includes('latest'));
this.model.selected = latest || versions[0];
this.canDeploy = true;
}
}
filterAppVersions(appVersions, filterStr) {
return filterStr === ''
? appVersions
: appVersions.filter(appVersion => appVersion.version.includes(filterStr));
}
markAsDeployed() {
this.isDeployed = true;
this.inProgress = false;
}
async loadPackages() {
const applications = await this.ecosystemService.getPackageApplications();
this.packages = applications.filter(app => this.ecosystemService.isPackageBlueprint(app));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: InstallFromPackageComponent, deps: [{ token: i1.EcosystemService }, { token: i4.ApplicationService }, { token: i2.WizardComponent }, { token: i2.PluginsService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: InstallFromPackageComponent, isStandalone: true, selector: "c8y-install-from-package", viewQueries: [{ propertyName: "applicationPropertiesForm", first: true, predicate: ApplicationPropertiesFormComponent, descendants: true }], ngImport: i0, template: "<c8y-wizard-header>\n <i [c8yIcon]=\"'big-parcel'\"></i>\n <h4\n id=\"modal-title\"\n translate\n >\n Install from extension package\n </h4>\n</c8y-wizard-header>\n<c8y-wizard-body>\n <ng-container *ngIf=\"!selectedPackage\">\n <div\n class=\"modal-inner-scroll\"\n id=\"modal-body\"\n >\n <p class=\"p-16 text-medium text-center separator-bottom sticky-top bg-level-0\">\n {{ 'Select from available extension packages' | translate }}\n </p>\n\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [title]=\"'No extension packages to display.' | translate\"\n *ngIf=\"!packages?.length\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n\n <div\n class=\"c8y-wizard-list-nav\"\n style=\"min-height: 257px\"\n *ngIf=\"packages?.length\"\n >\n <button\n class=\"list-group-item text-truncate bg-component\"\n title=\"{{ package.name }}\"\n type=\"button\"\n *ngFor=\"let package of packages\"\n (click)=\"selectPackage(package)\"\n >\n <i\n class=\"list-group-icon\"\n c8yIcon=\"big-parcel\"\n ></i>\n <span [innerText]=\"package.name\"></span>\n </button>\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"!isDeployed && selectedPackage\">\n <p class=\"p-16 text-center text-medium separator-bottom sticky-top bg-level-0\">\n {{ 'Provide application details' | translate }}\n </p>\n <div\n class=\"d-flex d-col a-i-center j-c-center\"\n style=\"min-height: 257px\"\n >\n <c8y-application-properties-form\n class=\"d-block fit-w\"\n *ngIf=\"!inProgress\"\n [application]=\"newAppConfig\"\n ></c8y-application-properties-form>\n\n <ng-container *ngIf=\"!inProgress\">\n <div\n class=\"d-block fit-w bg-gray-white\"\n [ngStyle]=\"{ padding: '0 16px' }\"\n >\n <label\n for=\"packageVersion\"\n translate\n >\n Use extension package version\n </label>\n <c8y-form-group>\n <c8y-typeahead\n placeholder=\"{{ 'Select or enter' | translate }}\"\n name=\"packageVersion\"\n [(ngModel)]=\"model.selected\"\n (onSearch)=\"onInput.next($event)\"\n [displayProperty]=\"'version'\"\n [required]=\"true\"\n [hideNew]=\"true\"\n [container]=\"'body'\"\n >\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n *c8yFor=\"let version of versions$; loadMore: 'auto'; notFound: notFoundTemplate\"\n (click)=\"onAppVersionSelect(version)\"\n [active]=\"model.selected === version\"\n >\n <c8y-li-icon icon=\"big-parcel\"></c8y-li-icon>\n <span\n [ngStyle]=\"{\n display: 'flex',\n 'flex-direction': 'row',\n 'align-content': 'center',\n 'justify-content': 'space-between',\n 'align-items': 'center'\n }\"\n >\n <c8y-highlight\n [text]=\"version.version || '--'\"\n [pattern]=\"onInput | async\"\n ></c8y-highlight>\n\n <span>\n <span\n class=\"label label-info m-l-4\"\n *ngFor=\"let tag of version.tags\"\n >\n {{ tag }}\n </span>\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 </div>\n </ng-container>\n\n <c8y-loading\n class=\"text-center d-block\"\n [message]=\"'Installing\u2026' | translate\"\n *ngIf=\"inProgress\"\n layout=\"application\"\n ></c8y-loading>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isDeployed\">\n <div\n class=\"d-flex a-i-center j-c-center\"\n style=\"min-height: 257px\"\n *ngIf=\"deployedWithSuccess; else failedDeploy\"\n >\n <c8y-operation-result\n class=\"lead\"\n type=\"success\"\n text=\"{{ 'Application created' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </div>\n <ng-template #failedDeploy>\n <div\n class=\"d-flex a-i-center j-c-center\"\n style=\"min-height: 257px\"\n >\n <c8y-operation-result\n class=\"lead\"\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</c8y-wizard-body>\n\n<c8y-wizard-footer>\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Back' | translate }}\"\n type=\"button\"\n *ngIf=\"!isDeployed\"\n (click)=\"selectedPackage ? clean() : back()\"\n [disabled]=\"inProgress\"\n >\n {{ 'Back' | translate }}\n </button>\n <button\n class=\"btn btn-default\"\n title=\"{{ isDeployed && deployedWithSuccess ? ('Close' | translate) : ('Cancel' | translate) }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ isDeployed && deployedWithSuccess ? ('Close' | translate) : ('Cancel' | translate) }}\n </button>\n\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Install' | translate }}\"\n type=\"button\"\n (click)=\"deployApp()\"\n [disabled]=\"inProgress || !packages?.length\"\n *ngIf=\"!isDeployed\"\n >\n {{ 'Install' | translate }}\n </button>\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: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ApplicationPropertiesFormComponent, selector: "c8y-application-properties-form", inputs: ["application", "disabled"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { 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", "highlightFirstItem"], outputs: ["onSearch", "onIconClick"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.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: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { 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" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: InstallFromPackageComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-install-from-package', imports: [
WizardHeaderComponent,
IconDirective,
C8yTranslateDirective,
WizardBodyComponent,
NgIf,
EmptyStateComponent,
NgFor,
ApplicationPropertiesFormComponent,
NgStyle,
FormGroupComponent,
TypeaheadComponent,
FormsModule,
ForOfDirective,
ListItemComponent,
ListItemIconComponent,
HighlightComponent,
LoadingComponent,
OperationResultComponent,
WizardFooterComponent,
C8yTranslatePipe,
AsyncPipe
], template: "<c8y-wizard-header>\n <i [c8yIcon]=\"'big-parcel'\"></i>\n <h4\n id=\"modal-title\"\n translate\n >\n Install from extension package\n </h4>\n</c8y-wizard-header>\n<c8y-wizard-body>\n <ng-container *ngIf=\"!selectedPackage\">\n <div\n class=\"modal-inner-scroll\"\n id=\"modal-body\"\n >\n <p class=\"p-16 text-medium text-center separator-bottom sticky-top bg-level-0\">\n {{ 'Select from available extension packages' | translate }}\n </p>\n\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [title]=\"'No extension packages to display.' | translate\"\n *ngIf=\"!packages?.length\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n\n <div\n class=\"c8y-wizard-list-nav\"\n style=\"min-height: 257px\"\n *ngIf=\"packages?.length\"\n >\n <button\n class=\"list-group-item text-truncate bg-component\"\n title=\"{{ package.name }}\"\n type=\"button\"\n *ngFor=\"let package of packages\"\n (click)=\"selectPackage(package)\"\n >\n <i\n class=\"list-group-icon\"\n c8yIcon=\"big-parcel\"\n ></i>\n <span [innerText]=\"package.name\"></span>\n </button>\n </div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"!isDeployed && selectedPackage\">\n <p class=\"p-16 text-center text-medium separator-bottom sticky-top bg-level-0\">\n {{ 'Provide application details' | translate }}\n </p>\n <div\n class=\"d-flex d-col a-i-center j-c-center\"\n style=\"min-height: 257px\"\n >\n <c8y-application-properties-form\n class=\"d-block fit-w\"\n *ngIf=\"!inProgress\"\n [application]=\"newAppConfig\"\n ></c8y-application-properties-form>\n\n <ng-container *ngIf=\"!inProgress\">\n <div\n class=\"d-block fit-w bg-gray-white\"\n [ngStyle]=\"{ padding: '0 16px' }\"\n >\n <label\n for=\"packageVersion\"\n translate\n >\n Use extension package version\n </label>\n <c8y-form-group>\n <c8y-typeahead\n placeholder=\"{{ 'Select or enter' | translate }}\"\n name=\"packageVersion\"\n [(ngModel)]=\"model.selected\"\n (onSearch)=\"onInput.next($event)\"\n [displayProperty]=\"'version'\"\n [required]=\"true\"\n [hideNew]=\"true\"\n [container]=\"'body'\"\n >\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n *c8yFor=\"let version of versions$; loadMore: 'auto'; notFound: notFoundTemplate\"\n (click)=\"onAppVersionSelect(version)\"\n [active]=\"model.selected === version\"\n >\n <c8y-li-icon icon=\"big-parcel\"></c8y-li-icon>\n <span\n [ngStyle]=\"{\n display: 'flex',\n 'flex-direction': 'row',\n 'align-content': 'center',\n 'justify-content': 'space-between',\n 'align-items': 'center'\n }\"\n >\n <c8y-highlight\n [text]=\"version.version || '--'\"\n [pattern]=\"onInput | async\"\n ></c8y-highlight>\n\n <span>\n <span\n class=\"label label-info m-l-4\"\n *ngFor=\"let tag of version.tags\"\n >\n {{ tag }}\n </span>\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 </div>\n </ng-container>\n\n <c8y-loading\n class=\"text-center d-block\"\n [message]=\"'Installing\u2026' | translate\"\n *ngIf=\"inProgress\"\n layout=\"application\"\n ></c8y-loading>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isDeployed\">\n <div\n class=\"d-flex a-i-center j-c-center\"\n style=\"min-height: 257px\"\n *ngIf=\"deployedWithSuccess; else failedDeploy\"\n >\n <c8y-operation-result\n class=\"lead\"\n type=\"success\"\n text=\"{{ 'Application created' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </div>\n <ng-template #failedDeploy>\n <div\n class=\"d-flex a-i-center j-c-center\"\n style=\"min-height: 257px\"\n >\n <c8y-operation-result\n class=\"lead\"\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</c8y-wizard-body>\n\n<c8y-wizard-footer>\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Back' | translate }}\"\n type=\"button\"\n *ngIf=\"!isDeployed\"\n (click)=\"selectedPackage ? clean() : back()\"\n [disabled]=\"inProgress\"\n >\n {{ 'Back' | translate }}\n </button>\n <button\n class=\"btn btn-default\"\n title=\"{{ isDeployed && deployedWithSuccess ? ('Close' | translate) : ('Cancel' | translate) }}\"\n type=\"button\"\n (click)=\"cancel()\"\n >\n {{ isDeployed && deployedWithSuccess ? ('Close' | translate) : ('Cancel' | translate) }}\n </button>\n\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Install' | translate }}\"\n type=\"button\"\n (click)=\"deployApp()\"\n [disabled]=\"inProgress || !packages?.length\"\n *ngIf=\"!isDeployed\"\n >\n {{ 'Install' | translate }}\n </button>\n</c8y-wizard-footer>\n" }]
}], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i4.ApplicationService }, { type: i2.WizardComponent }, { type: i2.PluginsService }], propDecorators: { applicationPropertiesForm: [{
type: ViewChild,
args: [ApplicationPropertiesFormComponent]
}] } });
class EcosystemTabs {
constructor(router) {
this.router = router;
this.ecosystemTabs = [
{
icon: 'c8y-modules',
priority: 1000,
label: gettext('Applications'),
path: 'ecosystem/application/applications'
},
{
icon: 'tab',
priority: 998,
label: gettext('Features'),
path: 'ecosystem/application/features'
}
];
}
get() {
if (this.router.url === '/ecosystem/application/applications' ||
this.router.url === '/ecosystem/application/features') {
return this.ecosystemTabs;
}
return [];
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: EcosystemTabs, deps: [{ token: i1$2.Router }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: EcosystemTabs }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: EcosystemTabs, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: i1$2.Router }] });
class FeatureListComponent {
constructor(ecosystemService) {
this.ecosystemService = ecosystemService;
this.reloading = false;
this.reload$ = new BehaviorSubject(null);
this.features$ = this.reload$.pipe(tap(() => (this.reloading = true)), switchMap(() => this.ecosystemService.getFeatureApplications()), tap(() => (this.reloading = false)), shareReplay());
}
ngOnInit() {
this.loadFeatures();
}
loadFeatures() {
this.reload$.next();
}
setFilterPipe(pipe) {
this.filteredFeatures$ = this.features$.pipe(src => pipe(src));
}
resetFilters() {
this.filtersComponent?.resetAllFilters();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FeatureListComponent, deps: [{ token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: FeatureListComponent, isStandalone: true, selector: "c8y-feature-list", viewQueries: [{ propertyName: "filtersComponent", first: true, predicate: ListFiltersComponent, descendants: true }], ngImport: i0, template: "<c8y-title>{{ 'Features' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item [icon]=\"'c8y-atom'\" [label]=\"'Ecosystem' | translate\"></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 [icon]=\"'tab'\" [label]=\"'Features' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button (click)=\"reload$.next()\" class=\"btn btn-link\" title=\"{{ 'Reload' | translate }}\">\n <i [ngClass]=\"{ 'icon-spin': reloading }\" c8yIcon=\"refresh\"></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n <c8y-list-filters\n *ngIf=\"features$ | async\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\" itemClass=\"navbar-form hidden-xs\">\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(features$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<div *ngIf=\"(features$ | async)?.length === 0\" class=\"c8y-empty-state text-center\">\n <h1 class=\"c8y-icon c8y-icon-modules c8y-icon-duocolor\"></h1>\n <h3 translate>No features to display.</h3>\n <p translate>No additional features are subscribed to the tenant.</p>\n</div>\n\n<div [ngClass]=\"listClass\" class=\"card-group\">\n <div class=\"page-sticky-header hidden-xs d-flex\" *ngIf=\"(features$ | async)?.length > 0\">\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Feature' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n </div>\n </div>\n <div *ngFor=\"let feature of filteredFeatures$ | async\" class=\"col-xs-12 col-sm-4 col-md-3\">\n <c8y-application-card\n [app]=\"feature\"\n [canEdit]=\"false\"\n class=\"d-contents\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n *ngIf=\"(features$ | async)?.length > 0 && (filteredFeatures$ | async)?.length === 0\"\n [icon]=\"'search'\"\n [title]=\"'No matching features.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n>\n <button\n class=\"btn btn-primary\"\n type=\"button\"\n title=\"{{ 'Reset filters' | translate }}\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n", dependencies: [{ kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ListFiltersComponent, selector: "c8y-list-filters", inputs: ["packageTypes", "packageAvailabilities", "packageContents"], outputs: ["filterPipeChange"] }, { kind: "component", type: ListDisplaySwitchComponent, selector: "c8y-list-display-switch", inputs: ["listKey", "listLength", "filterPipe"], outputs: ["onListClassChange"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ApplicationCardComponent, selector: "c8y-application-card", inputs: ["app", "canEdit"], outputs: ["onAppDeleted", "onAppCloned"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FeatureListComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-feature-list', imports: [
TitleComponent,
BreadcrumbComponent,
BreadcrumbItemComponent,
ActionBarItemComponent,
IconDirective,
NgClass,
NgIf,
ListFiltersComponent,
ListDisplaySwitchComponent,
C8yTranslateDirective,
NgFor,
ApplicationCardComponent,
EmptyStateComponent,
C8yTranslatePipe,
AsyncPipe
], template: "<c8y-title>{{ 'Features' | translate }}</c8y-title>\n\n<c8y-breadcrumb>\n <c8y-breadcrumb-item [icon]=\"'c8y-atom'\" [label]=\"'Ecosystem' | translate\"></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 [icon]=\"'tab'\" [label]=\"'Features' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button (click)=\"reload$.next()\" class=\"btn btn-link\" title=\"{{ 'Reload' | translate }}\">\n <i [ngClass]=\"{ 'icon-spin': reloading }\" c8yIcon=\"refresh\"></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n <c8y-list-filters\n *ngIf=\"features$ | async\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\" itemClass=\"navbar-form hidden-xs\">\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(features$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<div *ngIf=\"(features$ | async)?.length === 0\" class=\"c8y-empty-state text-center\">\n <h1 class=\"c8y-icon c8y-icon-modules c8y-icon-duocolor\"></h1>\n <h3 translate>No features to display.</h3>\n <p translate>No additional features are subscribed to the tenant.</p>\n</div>\n\n<div [ngClass]=\"listClass\" class=\"card-group\">\n <div class=\"page-sticky-header hidden-xs d-flex\" *ngIf=\"(features$ | async)?.length > 0\">\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Feature' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n </div>\n </div>\n <div *ngFor=\"let feature of filteredFeatures$ | async\" class=\"col-xs-12 col-sm-4 col-md-3\">\n <c8y-application-card\n [app]=\"feature\"\n [canEdit]=\"false\"\n class=\"d-contents\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n *ngIf=\"(features$ | async)?.length > 0 && (filteredFeatures$ | async)?.length === 0\"\n [icon]=\"'search'\"\n [title]=\"'No matching features.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n>\n <button\n class=\"btn btn-primary\"\n type=\"button\"\n title=\"{{ 'Reset filters' | translate }}\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n" }]
}], ctorParameters: () => [{ type: i1.EcosystemService }], propDecorators: { filtersComponent: [{
type: ViewChild,
args: [ListFiltersComponent]
}] } });
class AddMicroserviceComponent {
constructor(ecosystemService, modal, tenantService, docs) {
this.ecosystemService = ecosystemService;
this.modal = modal;
this.tenantService = tenantService;
this.docs = docs;
this.slaHref = this.docs.getUserGuideLink('docs/service-terms/service-level/#microservices-sla');
this.headerText = gettext('Add microservice');
this.successText = gettext('Microservice created');
this.createMicroserviceApplicationHandler = (f) => this.createMicroserviceApplication(f);
this.uploadMicroserviceHandler = (f, app) => this.uploadMicroservice(f, app);
}
async createMicroserviceApplication(file) {
await this.ecosystemService.isValidAppType(file, ApplicationType.MICROSERVICE);
return this.ecosystemService.createAppForArchive(file);
}
async uploadMicroservice(file, microservice) {
const subscribeToCurrentTenant = await this.askIfActivationAfterUploadNeeded();
await this.ecosystemService.uploadArchiveToApp(file, microservice);
await this.subscribeMicroservice(microservice, subscribeToCurrentTenant);
}
async askIfActivationAfterUploadNeeded() {
try {
await this.modal.confirm(gettext('Subscribe to microservice'), gettext('You are about to subscribe to the microservice after upload. Do you want to subscribe to it?'), Status.INFO, { ok: gettext('Subscribe'), cancel: gettext("Don't subscribe") });
return true;
}
catch (ex) {
return false;
}
}
async subscribeMicroservice(app, subscribeToCurrentTenant) {
const tenant = (await this.tenantService.current()).data;
const applications = tenant.applications.references;
const isSubscribed = applications.some(({ application }) => application.id === app.id);
if (!isSubscribed && subscribeToCurrentTenant) {
try {
return await this.tenantService.subscribeApplication(tenant, app);
}
catch (res) {
if (res.status === 409) {
throw Error(ERROR_TYPE.ALREADY_SUBSCRIBED);
}
}
}
else if (isSubscribed && !subscribeToCurrentTenant) {
return this.tenantService.unsubscribeApplication(tenant, app);
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AddMicroserviceComponent, deps: [{ token: i1.EcosystemService }, { token: i2.ModalService }, { token: i4.TenantService }, { token: i2.DocsService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: AddMicroserviceComponent, isStandalone: true, selector: "c8y-add-microservice", ngImport: i0, template: `<div class="p-16" translate [translateParams]="{ slaHref: slaHref }" ngNonBindable>
By uploading a microservice, you agree to the
<a href="{{ slaHref }}" target="_blank" rel="noopener noreferrer"
>Microservice Deployment SLA</a
>
which outlines our microservices hosting terms, conditions, and performance standards.
</div>
<c8y-add-application
[headerIcon]="'microchip'"
[headerText]="headerText"
[successText]="successText"
[createApplicationHandler]="createMicroserviceApplicationHandler"
[uploadApplicationHandler]="uploadMicroserviceHandler"
></c8y-add-application>`, isInline: true, dependencies: [{ kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "component", type: AddApplicationComponent, selector: "c8y-add-application", inputs: ["headerText", "headerIcon", "successText", "createApplicationHandler", "uploadApplicationHandler", "canGoBack", "applicationType"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AddMicroserviceComponent, decorators: [{
type: Component,
args: [{
selector: 'c8y-add-microservice',
template: `<div class="p-16" translate [translateParams]="{ slaHref: slaHref }" ngNonBindable>
By uploading a microservice, you agree to the
<a href="{{ slaHref }}" target="_blank" rel="noopener noreferrer"
>Microservice Deployment SLA</a
>
which outlines our microservices hosting terms, conditions, and performance standards.
</div>
<c8y-add-application
[headerIcon]="'microchip'"
[headerText]="headerText"
[successText]="successText"
[createApplicationHandler]="createMicroserviceApplicationHandler"
[uploadApplicationHandler]="uploadMicroserviceHandler"
></c8y-add-application>`,
imports: [C8yTranslateDirective, AddApplicationComponent]
}]
}], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.ModalService }, { type: i4.TenantService }, { type: i2.DocsService }] });
class MicroserviceListComponent {
constructor(ecosystemService, wizardModalService, cd) {
this.ecosystemService = ecosystemService;
this.wizardModalService = wizardModalService;
this.cd = cd;
this.reloading = false;
this.reload$ = new BehaviorSubject(null);
this.microservices$ = this.reload$.pipe(tap(() => (this.reloading = true)), switchMap(() => this.ecosystemService.getMicroservices()), tap(microservices => {
microservices.forEach(microservice => {
microservice.filterProps = this.ecosystemService.getAppFilterProps(microservice);
});
}), tap(() => (this.reloading = false)), shareReplay());
this.isMicroserviceHostingAllowed$ = this.reload$.pipe(switchMap(() => this.ecosystemService.isMicroserviceHostingAllowed()), shareReplay());
this.packageAvailabilities = [
APP_STATE.SUBSCRIBED.label,
APP_STATE.CUSTOM.label
];
}
ngOnInit() {
this.loadMicroservices();
// manually trigger detection to not have ExpressionChangedAfterItHasBeenChecked error in spec file
this.cd.detectChanges();
}
loadMicroservices() {
this.reload$.next();
}
addMicroservice() {
const initialState = {
id: EcosystemWizards.MICROSERVICE_UPLOAD
};
const modalOptions = { initialState };
const modalRef = this.wizardModalService.show(modalOptions);
modalRef.content.onClose.subscribe(() => {
this.loadMicroservices();
});
}
setFilterPipe(pipe) {
this.filteredMicroservices$ = this.microservices$.pipe(src => pipe(src));
}
resetFilters() {
this.filtersComponent?.resetAllFilters();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MicroserviceListComponent, deps: [{ token: i1.EcosystemService }, { token: i2.WizardModalService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: MicroserviceListComponent, isStandalone: true, selector: "c8y-microservice-list", viewQueries: [{ propertyName: "filtersComponent", first: true, predicate: ListFiltersComponent, descendants: true }], ngImport: i0, template: "<c8y-title>{{ 'Microservices' | translate }}</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]=\"'microchip'\"\n [label]=\"'Microservices' | translate\"\n [path]=\"'ecosystem/microservice/microservices'\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<ng-container *c8yIfAllowed=\"['ROLE_APPLICATION_MANAGEMENT_ADMIN']\">\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"100\"\n *ngIf=\"isMicroserviceHostingAllowed$ | async\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add microservice' | translate }}\"\n (click)=\"addMicroservice()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add microservice' | translate }}\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<c8y-help src=\"/docs/standard-tenant/ecosystem/#managing-microservices\"></c8y-help>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"reload$.next()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n <c8y-list-filters\n *ngIf=\"microservices$ | async\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n [packageAvailabilities]=\"packageAvailabilities\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(microservices$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<div\n class=\"c8y-empty-state text-center\"\n *ngIf=\"(microservices$ | async)?.length === 0\"\n>\n <h1 class=\"c8y-icon c8y-icon-modules c8y-icon-duocolor\"></h1>\n <h3 translate>No microservices to display.</h3>\n <p translate>Add your first microservice by clicking below.</p>\n <p>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add microservice' | translate }}\"\n (click)=\"addMicroservice()\"\n >\n {{ 'Add microservice' | translate }}\n </button>\n </p>\n</div>\n\n<div\n class=\"card-group\"\n [ngClass]=\"listClass\"\n>\n <div\n class=\"page-sticky-header hidden-xs d-flex\"\n *ngIf=\"(microservices$ | async)?.length > 0\"\n >\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Microservice' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80 m-r-40\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n <div class=\"card-block card-column-20\"></div>\n </div>\n </div>\n <div\n class=\"col-xs-12 col-sm-4 col-md-3\"\n *ngFor=\"let microservice of filteredMicroservices$ | async\"\n >\n <c8y-application-card\n class=\"d-contents\"\n (onAppDeleted)=\"loadMicroservices()\"\n [app]=\"microservice\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No matching microservices.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n *ngIf=\"(microservices$ | async)?.length > 0 && (filteredMicroservices$ | async)?.length === 0\"\n>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset filters' | translate }}\"\n type=\"button\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n", dependencies: [{ kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "directive", type: IfAllowedDirective, selector: "[c8yIfAllowed]", inputs: ["c8yIfAllowed", "c8yIfAllowedAllowAny"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ListFiltersComponent, selector: "c8y-list-filters", inputs: ["packageTypes", "packageAvailabilities", "packageContents"], outputs: ["filterPipeChange"] }, { kind: "component", type: ListDisplaySwitchComponent, selector: "c8y-list-display-switch", inputs: ["listKey", "listLength", "filterPipe"], outputs: ["onListClassChange"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ApplicationCardComponent, selector: "c8y-application-card", inputs: ["app", "canEdit"], outputs: ["onAppDeleted", "onAppCloned"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MicroserviceListComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-microservice-list', imports: [
TitleComponent,
BreadcrumbComponent,
BreadcrumbItemComponent,
IfAllowedDirective,
NgIf,
ActionBarItemComponent,
IconDirective,
HelpComponent,
NgClass,
ListFiltersComponent,
ListDisplaySwitchComponent,
C8yTranslateDirective,
NgFor,
ApplicationCardComponent,
EmptyStateComponent,
C8yTranslatePipe,
AsyncPipe
], template: "<c8y-title>{{ 'Microservices' | translate }}</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]=\"'microchip'\"\n [label]=\"'Microservices' | translate\"\n [path]=\"'ecosystem/microservice/microservices'\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<ng-container *c8yIfAllowed=\"['ROLE_APPLICATION_MANAGEMENT_ADMIN']\">\n <c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"100\"\n *ngIf=\"isMicroserviceHostingAllowed$ | async\"\n >\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add microservice' | translate }}\"\n (click)=\"addMicroservice()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add microservice' | translate }}\n </button>\n </c8y-action-bar-item>\n</ng-container>\n\n<c8y-help src=\"/docs/standard-tenant/ecosystem/#managing-microservices\"></c8y-help>\n\n<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n (click)=\"reload$.next()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item [placement]=\"'left'\">\n <c8y-list-filters\n *ngIf=\"microservices$ | async\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n [packageAvailabilities]=\"packageAvailabilities\"\n ></c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(microservices$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<div\n class=\"c8y-empty-state text-center\"\n *ngIf=\"(microservices$ | async)?.length === 0\"\n>\n <h1 class=\"c8y-icon c8y-icon-modules c8y-icon-duocolor\"></h1>\n <h3 translate>No microservices to display.</h3>\n <p translate>Add your first microservice by clicking below.</p>\n <p>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add microservice' | translate }}\"\n (click)=\"addMicroservice()\"\n >\n {{ 'Add microservice' | translate }}\n </button>\n </p>\n</div>\n\n<div\n class=\"card-group\"\n [ngClass]=\"listClass\"\n>\n <div\n class=\"page-sticky-header hidden-xs d-flex\"\n *ngIf=\"(microservices$ | async)?.length > 0\"\n >\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Microservice' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80 m-r-40\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n <div class=\"card-block card-column-20\"></div>\n </div>\n </div>\n <div\n class=\"col-xs-12 col-sm-4 col-md-3\"\n *ngFor=\"let microservice of filteredMicroservices$ | async\"\n >\n <c8y-application-card\n class=\"d-contents\"\n (onAppDeleted)=\"loadMicroservices()\"\n [app]=\"microservice\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No matching microservices.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n *ngIf=\"(microservices$ | async)?.length > 0 && (filteredMicroservices$ | async)?.length === 0\"\n>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset filters' | translate }}\"\n type=\"button\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n" }]
}], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.WizardModalService }, { type: i0.ChangeDetectorRef }], propDecorators: { filtersComponent: [{
type: ViewChild,
args: [ListFiltersComponent]
}] } });
class AddPackageComponent {
constructor(ecosystemService) {
this.ecosystemService = ecosystemService;
this.headerText = gettext('Add extension package');
this.successText = gettext('Extension package created');
this.createPackageAppHandler = (f) => this.createPackageApp(f);
this.uploadPackageHandler = (f, app) => this.uploadPackage(f, app);
}
async createPackageApp(file) {
await this.ecosystemService.isValidAppType(file, ApplicationType.HOSTED);
return await this.ecosystemService.createAppForArchive(file, true);
}
uploadPackage(file, pckg) {
return this.ecosystemService.uploadArchiveToApp(file, pckg, true);
}
next() {
this.stepper.next();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AddPackageComponent, deps: [{ token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: AddPackageComponent, isStandalone: true, selector: "c8y-add-package", viewQueries: [{ propertyName: "stepper", first: true, predicate: C8yStepper, descendants: true, static: true }], ngImport: i0, template: `<c8y-add-application
[headerIcon]="'big-parcel'"
[headerText]="headerText"
[successText]="successText"
[createApplicationHandler]="createPackageAppHandler"
[uploadApplicationHandler]="uploadPackageHandler"
[applicationType]="'package'"
></c8y-add-application>`, isInline: true, dependencies: [{ kind: "component", type: AddApplicationComponent, selector: "c8y-add-application", inputs: ["headerText", "headerIcon", "successText", "createApplicationHandler", "uploadApplicationHandler", "canGoBack", "applicationType"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AddPackageComponent, decorators: [{
type: Component,
args: [{
selector: 'c8y-add-package',
template: `<c8y-add-application
[headerIcon]="'big-parcel'"
[headerText]="headerText"
[successText]="successText"
[createApplicationHandler]="createPackageAppHandler"
[uploadApplicationHandler]="uploadPackageHandler"
[applicationType]="'package'"
></c8y-add-application>`,
imports: [AddApplicationComponent]
}]
}], ctorParameters: () => [{ type: i1.EcosystemService }], propDecorators: { stepper: [{
type: ViewChild,
args: [C8yStepper, { static: true }]
}] } });
class DeployApplicationComponent {
constructor(ecosystemService, wizardComponent, translate, pluginService, gainsightService, router) {
this.ecosystemService = ecosystemService;
this.wizardComponent = wizardComponent;
this.translate = translate;
this.pluginService = pluginService;
this.gainsightService = gainsightService;
this.router = router;
this.CURRENT_LOCATION = location.href;
this.inProgress = true;
this.isDeployed = false;
this.deployedWithSuccess = false;
this.model = {
selected: undefined,
binary: {
id: undefined
}
};
this.canDeploy = false;
this.descriptionTemplate = gettext('Deploy application using "{{ packageName }}" package');
this.successMessageTemplate = gettext('Application "{{ packageName }}" created');
this.doneLabel = gettext('Done');
this.cancelLabel = gettext('Cancel');
this.package = this.wizardComponent.package;
}
async ngOnInit() {
const apps = await this.ecosystemService.getHostedAndPackageApplications();
this.newAppConfig = this.ecosystemService.getUniqueAppConfig(this.package, apps);
this.headerText = this.getHeaderText();
this.inProgress = false;
}
async deployApp() {
this.inProgress = true;
const formGroupValue = this.applicationPropertiesForm.formGroup.getRawValue();
// Verify if selected package version is compatible with current platform versions.
this.package.manifest.version = this.model.selected.version;
const verifyVersionCompatibility = await this.ecosystemService.verifyBlueprintVersionsCompatibility(this.package.manifest);
if (!verifyVersionCompatibility) {
this.cancel();
return;
}
const { contextPath, license, name, manifest } = this.package;
const type = this.pluginService.getPackageType(this.package);
const licensedApp = {
contextPath,
license: license || manifest.license,
name,
type,
version: this.model.selected.version
};
const isArchived = await this.ecosystemService.verifyArchived([licensedApp]);
if (!isArchived) {
this.cancel();
return;
}
const licensesVerifiedByUser = await this.ecosystemService.verifyLicenses([licensedApp]);
if (!licensesVerifiedByUser) {
this.cancel();
return;
}
try {
this.deployedApp = await this.ecosystemService.deployApp(this.package, formGroupValue, this.model);
const applicationCustomEventInfo = pick(this.package, [
'id',
'name',
'contextPath',
'label',
'key'
]);
this.deployedWithSuccess = true;
this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.DEPLOY_APPLICATION, {
component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.DEPLOY_APPLICATION,
action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DEPLOY_APPLICATION,
result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.DEPLOYED,
url: this.CURRENT_LOCATION,
...applicationCustomEventInfo,
package: this.deployedApp?.manifest?.package ?? null
});
}
catch (error) {
this.ecosystemService.alertError(error);
this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.DEPLOY_APPLICATION, {
component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.DEPLOY_APPLICATION,
action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DEPLOY_APPLICATION,
result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
url: this.CURRENT_LOCATION,
error
});
}
finally {
this.markAsDeployed();
}
}
cancel() {
this.wizardComponent.close();
}
onAppVersionSelect(appVersion) {
Object.assign(this.model, {
selected: appVersion
});
this.canDeploy = true;
}
open() {
this.router.navigateByUrl(ViewContext.Application.replace(':id', `${this.deployedApp.id}`));
this.cancel();
}
markAsDeployed() {
this.isDeployed = true;
this.inProgress = false;
}
getHeaderText() {
return this.translate.instant(this.descriptionTemplate, {
packageName: this.package.name
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeployApplicationComponent, deps: [{ token: i1.EcosystemService }, { token: i2.WizardComponent }, { token: i6.TranslateService }, { token: i2.PluginsService }, { token: i2.GainsightService }, { token: i1$2.Router }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DeployApplicationComponent, isStandalone: true, selector: "c8y-deploy-application", viewQueries: [{ propertyName: "applicationPropertiesForm", first: true, predicate: ApplicationPropertiesFormComponent, descendants: true }], ngImport: i0, template: "<c8y-wizard-header>\n <div class=\"modal-header dialog-header\">\n <i c8yIcon=\"output\"></i>\n <h4 id=\"modal-title\">{{ 'Deploy application' | translate }}</h4>\n </div>\n</c8y-wizard-header>\n\n<c8y-wizard-body id=\"modal-body\">\n <ng-container *ngIf=\"!isDeployed\">\n <div class=\"fadeIn animated d-flex a-i-center j-c-center d-col\" style=\"min-height: 309px\">\n <p\n class=\"bg-level-0 fit-w p-16 text-center text-medium sticky-top bg-level-0 separator-bottom\"\n *ngIf=\"!inProgress\"\n >\n {{ headerText | translate }}\n </p>\n <c8y-application-properties-form\n *ngIf=\"!inProgress\"\n [application]=\"newAppConfig\"\n class=\"d-block fit-w bg-level-1\"\n ></c8y-application-properties-form>\n\n <ng-container *ngIf=\"!inProgress\">\n <div [ngStyle]=\"{ padding: '0 16px' }\" class=\"d-block fit-w bg-gray-white\">\n <c8y-package-version-select\n [ngModel]=\"model.selected\"\n (ngModelChange)=\"onAppVersionSelect($event)\"\n [packageId]=\"package?.id\"\n [label]=\"'Use extension package version' | translate\"\n ></c8y-package-version-select>\n </div>\n </ng-container>\n\n <c8y-loading\n *ngIf=\"inProgress\"\n [message]=\"'Deploying\u2026' | translate\"\n class=\"text-center\"\n layout=\"application\"\n ></c8y-loading>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isDeployed\">\n <div\n *ngIf=\"deployedWithSuccess; else failedDeploy\"\n class=\"modal-body fadeIn animated\"\n style=\"min-height: 309px\"\n >\n <div class=\"d-flex a-i-center j-c-center d-col\">\n <c8y-operation-result\n type=\"success\"\n [size]=\"84\"\n [vertical]=\"true\"\n [text]=\"successMessageTemplate | translate: { packageName: package.name }\"\n class=\"lead d-block m-b-16\"\n ></c8y-operation-result>\n </div>\n </div>\n <ng-template #failedDeploy>\n <div class=\"modal-body fadeIn animated text-center\" style=\"min-height: 257px\">\n <c8y-operation-result\n type=\"error\"\n [size]=\"84\"\n [vertical]=\"true\"\n text=\"{{ 'Application creation failed' | translate }}\"\n class=\"lead\"\n ></c8y-operation-result>\n </div>\n </ng-template>\n </ng-container>\n</c8y-wizard-body>\n\n<c8y-wizard-footer>\n <button\n (click)=\"cancel()\"\n type=\"button\"\n class=\"btn btn-default\"\n data-cy=\"c8y-deploy-application--cancel-blueprint-button\"\n title=\"{{ (isDeployed && deployedWithSuccess ? doneLabel : cancelLabel) | translate }}\"\n >\n {{ (isDeployed && deployedWithSuccess ? doneLabel : cancelLabel) | translate }}\n </button>\n\n <button\n (click)=\"deployApp()\"\n *ngIf=\"!isDeployed\"\n [disabled]=\"inProgress || !canDeploy\"\n [ngClass]=\"{ 'btn-pending': inProgress }\"\n class=\"btn btn-primary\"\n type=\"button\"\n data-cy=\"c8y-deploy-application--deploy-blueprint-button\"\n title=\"{{ 'Deploy' | translate }}\"\n >\n {{ 'Deploy' | translate }}\n </button>\n\n <button\n (click)=\"open()\"\n type=\"button\"\n class=\"btn btn-primary\"\n *ngIf=\"isDeployed && deployedWithSuccess\"\n title=\"{{ 'Open the application details' | translate }}\"\n translate\n >\n Open\n </button>\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: ApplicationPropertiesFormComponent, selector: "c8y-application-properties-form", inputs: ["application", "disabled"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: PackageVersionSelectComponent, selector: "c8y-package-version-select", inputs: ["label", "packageContextPath", "packageId"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: OperationResultComponent, selector: "c8y-operation-result", inputs: ["text", "vertical", "size", "type"] }, { kind: "component", type: WizardFooterComponent, selector: "c8y-wizard-footer" }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DeployApplicationComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-deploy-application', imports: [
WizardHeaderComponent,
IconDirective,
WizardBodyComponent,
NgIf,
ApplicationPropertiesFormComponent,
NgStyle,
PackageVersionSelectComponent,
FormsModule,
LoadingComponent,
OperationResultComponent,
WizardFooterComponent,
NgClass,
C8yTranslateDirective,
C8yTranslatePipe
], template: "<c8y-wizard-header>\n <div class=\"modal-header dialog-header\">\n <i c8yIcon=\"output\"></i>\n <h4 id=\"modal-title\">{{ 'Deploy application' | translate }}</h4>\n </div>\n</c8y-wizard-header>\n\n<c8y-wizard-body id=\"modal-body\">\n <ng-container *ngIf=\"!isDeployed\">\n <div class=\"fadeIn animated d-flex a-i-center j-c-center d-col\" style=\"min-height: 309px\">\n <p\n class=\"bg-level-0 fit-w p-16 text-center text-medium sticky-top bg-level-0 separator-bottom\"\n *ngIf=\"!inProgress\"\n >\n {{ headerText | translate }}\n </p>\n <c8y-application-properties-form\n *ngIf=\"!inProgress\"\n [application]=\"newAppConfig\"\n class=\"d-block fit-w bg-level-1\"\n ></c8y-application-properties-form>\n\n <ng-container *ngIf=\"!inProgress\">\n <div [ngStyle]=\"{ padding: '0 16px' }\" class=\"d-block fit-w bg-gray-white\">\n <c8y-package-version-select\n [ngModel]=\"model.selected\"\n (ngModelChange)=\"onAppVersionSelect($event)\"\n [packageId]=\"package?.id\"\n [label]=\"'Use extension package version' | translate\"\n ></c8y-package-version-select>\n </div>\n </ng-container>\n\n <c8y-loading\n *ngIf=\"inProgress\"\n [message]=\"'Deploying\u2026' | translate\"\n class=\"text-center\"\n layout=\"application\"\n ></c8y-loading>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"isDeployed\">\n <div\n *ngIf=\"deployedWithSuccess; else failedDeploy\"\n class=\"modal-body fadeIn animated\"\n style=\"min-height: 309px\"\n >\n <div class=\"d-flex a-i-center j-c-center d-col\">\n <c8y-operation-result\n type=\"success\"\n [size]=\"84\"\n [vertical]=\"true\"\n [text]=\"successMessageTemplate | translate: { packageName: package.name }\"\n class=\"lead d-block m-b-16\"\n ></c8y-operation-result>\n </div>\n </div>\n <ng-template #failedDeploy>\n <div class=\"modal-body fadeIn animated text-center\" style=\"min-height: 257px\">\n <c8y-operation-result\n type=\"error\"\n [size]=\"84\"\n [vertical]=\"true\"\n text=\"{{ 'Application creation failed' | translate }}\"\n class=\"lead\"\n ></c8y-operation-result>\n </div>\n </ng-template>\n </ng-container>\n</c8y-wizard-body>\n\n<c8y-wizard-footer>\n <button\n (click)=\"cancel()\"\n type=\"button\"\n class=\"btn btn-default\"\n data-cy=\"c8y-deploy-application--cancel-blueprint-button\"\n title=\"{{ (isDeployed && deployedWithSuccess ? doneLabel : cancelLabel) | translate }}\"\n >\n {{ (isDeployed && deployedWithSuccess ? doneLabel : cancelLabel) | translate }}\n </button>\n\n <button\n (click)=\"deployApp()\"\n *ngIf=\"!isDeployed\"\n [disabled]=\"inProgress || !canDeploy\"\n [ngClass]=\"{ 'btn-pending': inProgress }\"\n class=\"btn btn-primary\"\n type=\"button\"\n data-cy=\"c8y-deploy-application--deploy-blueprint-button\"\n title=\"{{ 'Deploy' | translate }}\"\n >\n {{ 'Deploy' | translate }}\n </button>\n\n <button\n (click)=\"open()\"\n type=\"button\"\n class=\"btn btn-primary\"\n *ngIf=\"isDeployed && deployedWithSuccess\"\n title=\"{{ 'Open the application details' | translate }}\"\n translate\n >\n Open\n </button>\n</c8y-wizard-footer>\n" }]
}], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.WizardComponent }, { type: i6.TranslateService }, { type: i2.PluginsService }, { type: i2.GainsightService }, { type: i1$2.Router }], propDecorators: { applicationPropertiesForm: [{
type: ViewChild,
args: [ApplicationPropertiesFormComponent]
}] } });
class PackageDetailsComponent {
constructor(activatedRoute, wizardModalService, ecosystemService, contextRouteService, pluginsService, packageAvailabilityService, ui, gainsightService) {
this.activatedRoute = activatedRoute;
this.wizardModalService = wizardModalService;
this.ecosystemService = ecosystemService;
this.contextRouteService = contextRouteService;
this.pluginsService = pluginsService;
this.packageAvailabilityService = packageAvailabilityService;
this.ui = ui;
this.gainsightService = gainsightService;
this.package = {};
this.exportedPlugins$ = new BehaviorSubject([]);
this.isChangingAvailability = false;
this.isOwnedByCurrentTenant = false;
this.isAllowedToCreateSubtenants = false;
this.packageTypeLabels = PACKAGE_TYPE_LABELS;
this.PACKAGE_TYPE = PackageType;
this.packageProperties = packageProperties;
}
async ngOnInit() {
this.isAllowedToCreateSubtenants = !!this.ui.currentTenant.value?.allowCreateTenants;
await this.loadData();
}
deploy() {
this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_PLUGINS, {
component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_DETAILS,
action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DEPLOY_APPLICATION_INITIATED
});
const initialState = {
wizardConfig: {},
id: EcosystemWizards.BLUEPRINT_DEPLOYMENT,
package: this.package
};
const modalOptions = { initialState };
this.wizardModalService.show(modalOptions);
}
async togglePackageAvailability(pckg, newAvailability) {
this.isChangingAvailability = true;
pckg = await this.packageAvailabilityService.askIfAvailabilityShouldBeSetTo(pckg, newAvailability);
const availabilityHasChanged = pckg.availability === newAvailability;
if (availabilityHasChanged) {
await this.loadData(pckg);
this.contextRouteService.setContext(this.activatedRoute, pckg);
}
else {
this.packageAvailability = this.package.availability;
}
this.isChangingAvailability = false;
}
async showPluginOverview(plugin) {
this.selectedPlugin = plugin;
const baseUrl = `/apps/${plugin.id}/`;
this.pluginBaseUrl = baseUrl;
this.pluginMarkdown = await this.pluginsService.getReadmeFileContent(baseUrl);
}
closeOverview() {
this.selectedPlugin = null;
}
async loadData(pckg) {
this.package = pckg
? pckg
: this.contextRouteService.getContextData(this.activatedRoute)?.contextData;
this.packageAvailability = this.package.availability;
this.packageContentState = this.ecosystemService.getPackageContentState(this.package);
this.packageType = this.pluginsService.getPackageType(this.package);
this.name = this.package?.name;
this.description = this.package?.manifest?.description;
const baseUrl = `/apps/${this.package.contextPath}/`;
this.markdown = await this.pluginsService.getReadmeFileContent(baseUrl);
this.baseUrl = baseUrl;
this.appState = this.ecosystemService.getAppState(this.package);
this.isPackageBlueprint = this.ecosystemService.isPackageBlueprint(this.package);
this.isOwnedByCurrentTenant =
this.package?.owner?.tenant?.id === this.ui.currentTenant.value?.name;
this.extractPackageMFExports();
}
extractPackageMFExports() {
const exports = this.pluginsService.getMFExports(this.package);
this.exportedPlugins$.next(exports);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageDetailsComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i2.WizardModalService }, { token: i1.EcosystemService }, { token: i2.ContextRouteService }, { token: i2.PluginsService }, { token: i1.PackageAvailabilityService }, { token: i2.AppStateService }, { token: i2.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: PackageDetailsComponent, isStandalone: true, selector: "c8y-package-details", ngImport: i0, template: "<c8y-title>{{ name | 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]=\"'big-parcel'\"\n [label]=\"'Extensions' | translate\"\n [path]=\"'ecosystem/extension/extensions'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"name | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Extension package' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n placement=\"right\"\n itemClass=\"navbar-form\"\n *ngIf=\"isOwnedByCurrentTenant && isAllowedToCreateSubtenants\"\n>\n <div class=\"d-flex a-i-center\">\n <label\n class=\"m-b-0 m-r-8\"\n for=\"availability\"\n translate\n >\n Availability`of package based on app state`\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control\"\n id=\"availability\"\n [(ngModel)]=\"packageAvailability\"\n [disabled]=\"isChangingAvailability\"\n (ngModelChange)=\"togglePackageAvailability(package, $event)\"\n >\n <option\n *ngFor=\"let availability of packageAvailabilityService.availabilities\"\n [ngValue]=\"availability.value\"\n >\n {{ availability.label | translate }}\n </option>\n </select>\n </div>\n </div>\n</c8y-action-bar-item>\n\n<div\n class=\"card content-fullpage d-grid grid__row--fit-auto\"\n [ngClass]=\"{ 'grid__col--8-4-0': !selectedPlugin, 'grid__col--0-4-8': !!selectedPlugin }\"\n>\n <div class=\"bg-level-1 grid__col--fullspan separator-bottom\">\n <div class=\"card-block p-t-24 p-b-24 large-padding\">\n <button\n class=\"card__ribbon btn-clean\"\n [attr.aria-label]=\"\n (package.label || package.manifest.label | translatePackageLabel) +\n ': ' +\n (packageTypeLabels[packageType].tooltip | translate)\n \"\n tooltip=\"{{ packageTypeLabels[packageType].tooltip | translate }}\"\n placement=\"bottom\"\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 {{ package.label || package.manifest.label | translatePackageLabel }}\n </span>\n </button>\n <div class=\"content-flex-70\">\n <div class=\"text-center\">\n <i\n class=\"c8y-icon-duocolor icon-48\"\n c8yIcon=\"big-parcel\"\n ></i>\n <button\n class=\"btn-clean\"\n [attr.aria-label]=\"\n (appState?.label | translate) + ': ' + (appState?.tooltip | translate)\n \"\n [tooltip]=\"appState?.tooltip | translate\"\n placement=\"top\"\n type=\"button\"\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 | translate)\n \"\n [tooltip]=\"packageContentState?.tooltip | translate\"\n placement=\"bottom\"\n type=\"button\"\n [delay]=\"500\"\n >\n <span\n class=\"label\"\n [ngClass]=\"packageContentState?.class\"\n >\n {{ packageContentState?.label | translate }}\n </span>\n </button>\n </div>\n\n <div class=\"flex-grow col-10\">\n <div class=\"content-flex-80\">\n <div class=\"col-8\">\n <div class=\"card-title h4 m-b-8\">{{ name | humanizeAppName | async }}</div>\n <p *ngIf=\"description\">{{ description }}</p>\n <p\n class=\"text-muted\"\n *ngIf=\"!description\"\n >\n <em>{{ 'No description available.' | translate }}</em>\n </p>\n </div>\n <div\n class=\"col-3 text-right-md p-r-md-40\"\n *ngIf=\"isPackageBlueprint\"\n >\n <button\n class=\"btn btn-primary btn-sm\"\n (click)=\"deploy()\"\n data-cy=\"c8y-package-details--deploy-application-button\"\n >\n <i\n class=\"m-r-4\"\n c8yIcon=\"output\"\n ></i>\n {{ 'Deploy application' | translate }}\n </button>\n </div>\n <div class=\"flex-grow\">\n <c8y-properties-list\n [data]=\"package.manifest\"\n [properties]=\"packageProperties\"\n ></c8y-properties-list>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"card-header separator sticky-top\">\n <div class=\"card-title\">{{ 'Extension package overview' | translate }}</div>\n </div>\n <div class=\"card-block p-l-16 p-r-16\">\n <div\n class=\"alert alert-warning m-b-16\"\n style=\"margin: auto\"\n *ngIf=\"packageType === PACKAGE_TYPE.ARCHIVED\"\n translate\n >\n The package was archived by the owner marking it as out of maintenance. It is not\n recommended to install the package.\n </div>\n <c8y-ui-empty-state\n [icon]=\"'user-manual'\"\n [title]=\"'No README.md found' | translate\"\n [subtitle]=\"\n 'To view the contents of "README", add the file "README.md" to the package.'\n | translate\n \"\n *ngIf=\"!markdown\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n <div\n class=\"markdown-content\"\n [innerHTML]=\"markdown | markdownToHtml: { baseUrl } | async\"\n ></div>\n </div>\n <div class=\"separator-bottom visible-sm visible-xs\"></div>\n </div>\n\n <div\n class=\"inner-scroll d-flex d-col bg-level-1 split-view__list\"\n [ngClass]=\"{ 'border-right': !!selectedPlugin }\"\n >\n <div class=\"card-header separator sticky-top\">\n <div class=\"card-title\">{{ 'Package plugins' | translate }}</div>\n </div>\n <div class=\"border-left flex-grow\">\n <!-- empty state -->\n <div\n class=\"p-16\"\n *ngIf=\"(exportedPlugins$ | async).length === 0\"\n >\n <c8y-ui-empty-state\n [icon]=\"'plugin'\"\n [title]=\"'No plugins to display.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain plugins.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n <c8y-plugin-list\n [plugins$]=\"exportedPlugins$\"\n [selectable]=\"false\"\n [installable]=\"true\"\n [package]=\"package\"\n [selectedPlugin]=\"selectedPlugin\"\n (showOverview)=\"showPluginOverview($event)\"\n ></c8y-plugin-list>\n </div>\n </div>\n\n <div class=\"inner-scroll split-view__detail\"\n [ngClass]=\"{ 'split-view__detail--selected': selectedPlugin }\">\n <div\n class=\"card-header separator sticky-top\"\n *ngIf=\"selectedPlugin\"\n >\n <button\n class=\"btn-clean\"\n (click)=\"closeOverview()\"\n >\n <i c8yIcon=\"caret-back\"></i>\n {{ 'Back to package overview ' | translate }}\n </button>\n </div>\n <div\n class=\"card-block p-l-16 p-r-16 overflow-visible\"\n *ngIf=\"selectedPlugin\"\n >\n <div\n class=\"markdown-content\"\n *ngIf=\"pluginMarkdown\"\n [innerHTML]=\"pluginMarkdown | markdownToHtml: { baseUrl: pluginBaseUrl } | async\"\n ></div>\n <c8y-ui-empty-state\n [icon]=\"'user-manual'\"\n [title]=\"'No README.md found for plugin' | translate\"\n [subtitle]=\"\n 'To view the contents of "README", add the file "README.md" to the plugin.'\n | translate\n \"\n *ngIf=\"!pluginMarkdown\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.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: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: PropertiesListComponent, selector: "c8y-properties-list", inputs: ["properties", "title", "icon", "data", "groups", "noParse", "emptyLabel"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "component", type: PluginListComponent, selector: "c8y-plugin-list", inputs: ["plugins$", "emptyListText", "selectable", "hideSource", "installable", "package", "selectedPlugin"], outputs: ["selectedItems", "showOverview"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: HumanizeAppNamePipe, name: "humanizeAppName" }, { kind: "pipe", type: MarkdownToHtmlPipe, name: "markdownToHtml" }, { kind: "pipe", type: TranslatePackageLabelPipe, name: "translatePackageLabel" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageDetailsComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-package-details', imports: [
TitleComponent,
BreadcrumbComponent,
BreadcrumbItemComponent,
NgIf,
ActionBarItemComponent,
C8yTranslateDirective,
FormsModule,
NgFor,
NgClass,
TooltipDirective,
IconDirective,
PropertiesListComponent,
EmptyStateComponent,
PluginListComponent,
C8yTranslatePipe,
AsyncPipe,
HumanizeAppNamePipe,
MarkdownToHtmlPipe,
TranslatePackageLabelPipe
], template: "<c8y-title>{{ name | 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]=\"'big-parcel'\"\n [label]=\"'Extensions' | translate\"\n [path]=\"'ecosystem/extension/extensions'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"name | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Extension package' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n placement=\"right\"\n itemClass=\"navbar-form\"\n *ngIf=\"isOwnedByCurrentTenant && isAllowedToCreateSubtenants\"\n>\n <div class=\"d-flex a-i-center\">\n <label\n class=\"m-b-0 m-r-8\"\n for=\"availability\"\n translate\n >\n Availability`of package based on app state`\n </label>\n <div class=\"c8y-select-wrapper\">\n <select\n class=\"form-control\"\n id=\"availability\"\n [(ngModel)]=\"packageAvailability\"\n [disabled]=\"isChangingAvailability\"\n (ngModelChange)=\"togglePackageAvailability(package, $event)\"\n >\n <option\n *ngFor=\"let availability of packageAvailabilityService.availabilities\"\n [ngValue]=\"availability.value\"\n >\n {{ availability.label | translate }}\n </option>\n </select>\n </div>\n </div>\n</c8y-action-bar-item>\n\n<div\n class=\"card content-fullpage d-grid grid__row--fit-auto\"\n [ngClass]=\"{ 'grid__col--8-4-0': !selectedPlugin, 'grid__col--0-4-8': !!selectedPlugin }\"\n>\n <div class=\"bg-level-1 grid__col--fullspan separator-bottom\">\n <div class=\"card-block p-t-24 p-b-24 large-padding\">\n <button\n class=\"card__ribbon btn-clean\"\n [attr.aria-label]=\"\n (package.label || package.manifest.label | translatePackageLabel) +\n ': ' +\n (packageTypeLabels[packageType].tooltip | translate)\n \"\n tooltip=\"{{ packageTypeLabels[packageType].tooltip | translate }}\"\n placement=\"bottom\"\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 {{ package.label || package.manifest.label | translatePackageLabel }}\n </span>\n </button>\n <div class=\"content-flex-70\">\n <div class=\"text-center\">\n <i\n class=\"c8y-icon-duocolor icon-48\"\n c8yIcon=\"big-parcel\"\n ></i>\n <button\n class=\"btn-clean\"\n [attr.aria-label]=\"\n (appState?.label | translate) + ': ' + (appState?.tooltip | translate)\n \"\n [tooltip]=\"appState?.tooltip | translate\"\n placement=\"top\"\n type=\"button\"\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 | translate)\n \"\n [tooltip]=\"packageContentState?.tooltip | translate\"\n placement=\"bottom\"\n type=\"button\"\n [delay]=\"500\"\n >\n <span\n class=\"label\"\n [ngClass]=\"packageContentState?.class\"\n >\n {{ packageContentState?.label | translate }}\n </span>\n </button>\n </div>\n\n <div class=\"flex-grow col-10\">\n <div class=\"content-flex-80\">\n <div class=\"col-8\">\n <div class=\"card-title h4 m-b-8\">{{ name | humanizeAppName | async }}</div>\n <p *ngIf=\"description\">{{ description }}</p>\n <p\n class=\"text-muted\"\n *ngIf=\"!description\"\n >\n <em>{{ 'No description available.' | translate }}</em>\n </p>\n </div>\n <div\n class=\"col-3 text-right-md p-r-md-40\"\n *ngIf=\"isPackageBlueprint\"\n >\n <button\n class=\"btn btn-primary btn-sm\"\n (click)=\"deploy()\"\n data-cy=\"c8y-package-details--deploy-application-button\"\n >\n <i\n class=\"m-r-4\"\n c8yIcon=\"output\"\n ></i>\n {{ 'Deploy application' | translate }}\n </button>\n </div>\n <div class=\"flex-grow\">\n <c8y-properties-list\n [data]=\"package.manifest\"\n [properties]=\"packageProperties\"\n ></c8y-properties-list>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"inner-scroll\">\n <div class=\"card-header separator sticky-top\">\n <div class=\"card-title\">{{ 'Extension package overview' | translate }}</div>\n </div>\n <div class=\"card-block p-l-16 p-r-16\">\n <div\n class=\"alert alert-warning m-b-16\"\n style=\"margin: auto\"\n *ngIf=\"packageType === PACKAGE_TYPE.ARCHIVED\"\n translate\n >\n The package was archived by the owner marking it as out of maintenance. It is not\n recommended to install the package.\n </div>\n <c8y-ui-empty-state\n [icon]=\"'user-manual'\"\n [title]=\"'No README.md found' | translate\"\n [subtitle]=\"\n 'To view the contents of "README", add the file "README.md" to the package.'\n | translate\n \"\n *ngIf=\"!markdown\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n <div\n class=\"markdown-content\"\n [innerHTML]=\"markdown | markdownToHtml: { baseUrl } | async\"\n ></div>\n </div>\n <div class=\"separator-bottom visible-sm visible-xs\"></div>\n </div>\n\n <div\n class=\"inner-scroll d-flex d-col bg-level-1 split-view__list\"\n [ngClass]=\"{ 'border-right': !!selectedPlugin }\"\n >\n <div class=\"card-header separator sticky-top\">\n <div class=\"card-title\">{{ 'Package plugins' | translate }}</div>\n </div>\n <div class=\"border-left flex-grow\">\n <!-- empty state -->\n <div\n class=\"p-16\"\n *ngIf=\"(exportedPlugins$ | async).length === 0\"\n >\n <c8y-ui-empty-state\n [icon]=\"'plugin'\"\n [title]=\"'No plugins to display.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain plugins.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n <c8y-plugin-list\n [plugins$]=\"exportedPlugins$\"\n [selectable]=\"false\"\n [installable]=\"true\"\n [package]=\"package\"\n [selectedPlugin]=\"selectedPlugin\"\n (showOverview)=\"showPluginOverview($event)\"\n ></c8y-plugin-list>\n </div>\n </div>\n\n <div class=\"inner-scroll split-view__detail\"\n [ngClass]=\"{ 'split-view__detail--selected': selectedPlugin }\">\n <div\n class=\"card-header separator sticky-top\"\n *ngIf=\"selectedPlugin\"\n >\n <button\n class=\"btn-clean\"\n (click)=\"closeOverview()\"\n >\n <i c8yIcon=\"caret-back\"></i>\n {{ 'Back to package overview ' | translate }}\n </button>\n </div>\n <div\n class=\"card-block p-l-16 p-r-16 overflow-visible\"\n *ngIf=\"selectedPlugin\"\n >\n <div\n class=\"markdown-content\"\n *ngIf=\"pluginMarkdown\"\n [innerHTML]=\"pluginMarkdown | markdownToHtml: { baseUrl: pluginBaseUrl } | async\"\n ></div>\n <c8y-ui-empty-state\n [icon]=\"'user-manual'\"\n [title]=\"'No README.md found for plugin' | translate\"\n [subtitle]=\"\n 'To view the contents of "README", add the file "README.md" to the plugin.'\n | translate\n \"\n *ngIf=\"!pluginMarkdown\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i2.WizardModalService }, { type: i1.EcosystemService }, { type: i2.ContextRouteService }, { type: i2.PluginsService }, { type: i1.PackageAvailabilityService }, { type: i2.AppStateService }, { type: i2.GainsightService }] });
class PackagesListComponent {
constructor(ecosystemService, wizardModalService, permissions) {
this.ecosystemService = ecosystemService;
this.wizardModalService = wizardModalService;
this.permissions = permissions;
this.reloading = false;
this.reload$ = new BehaviorSubject(null);
this.hasAdminPermissions = false;
this.emptyStateSubtitle = gettext('Add your first package by clicking below.');
this.packageTypes = defaultPackageTypes;
this.packageAvailabilities = [
APP_STATE.SUBSCRIBED.label,
APP_STATE.CUSTOM.label
];
this.packageContents = defaultPackageContents;
this.destroy$ = new Subject();
this.packages$ = this.reload$.pipe(takeUntil(this.destroy$), tap(() => (this.reloading = true)), switchMap(() => this.ecosystemService.getPackageApplications()), tap(packages => {
packages.forEach(pckg => {
pckg.filterProps = this.ecosystemService.getAppFilterProps(pckg);
});
}), tap(() => (this.reloading = false)), shareReplay(1));
}
ngOnInit() {
this.hasAdminPermissions = this.permissions.hasRole(Permissions.ROLE_APPLICATION_MANAGEMENT_ADMIN);
this.loadPackages();
}
loadPackages() {
this.reload$.next();
}
addPackage() {
const initialState = {
id: EcosystemWizards.PACKAGE_UPLOAD
};
const modalOptions = { initialState };
const modalRef = this.wizardModalService.show(modalOptions);
modalRef.content.onClose.subscribe(() => {
this.loadPackages();
});
}
ngOnDestroy() {
this.destroy$.next(true);
this.destroy$.complete();
}
setFilterPipe(pipe) {
this.filteredPackages$ = this.packages$.pipe(src => pipe(src));
}
resetFilters() {
this.filtersComponent?.resetAllFilters();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackagesListComponent, deps: [{ token: i1.EcosystemService }, { token: i2.WizardModalService }, { token: i2.Permissions }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: PackagesListComponent, isStandalone: true, selector: "c8y-packages-list", viewQueries: [{ propertyName: "filtersComponent", first: true, predicate: ListFiltersComponent, descendants: true }], ngImport: i0, template: "<c8y-title>{{ 'Extensions' | translate }}</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]=\"'big-parcel'\"\n [path]=\"'ecosystem/extension/extensions'\"\n [label]=\"'Extensions' | translate\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n *ngIf=\"hasAdminPermissions\"\n>\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add extension package' | translate }}\"\n type=\"button\"\n data-cy=\"packages-list--add-extension-package\"\n (click)=\"addPackage()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add extension package' | 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=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"loadPackages()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"p-r-8 p-l-8\"\n>\n <c8y-list-filters\n *ngIf=\"packages$ | async\"\n [packageTypes]=\"packageTypes\"\n [packageAvailabilities]=\"packageAvailabilities\"\n [packageContents]=\"packageContents\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n >\n <c8y-archived-filter></c8y-archived-filter>\n </c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(packages$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<c8y-help src=\"/docs/standard-tenant/ecosystem/#extensions\"></c8y-help>\n\n<div\n class=\"card-group\"\n [ngClass]=\"listClass\"\n>\n <div\n class=\"page-sticky-header hidden-xs d-flex m-b-8\"\n *ngIf=\"(filteredPackages$ | async)?.length > 0\"\n >\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Package' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80 m-r-40\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n <div class=\"card-block card-column-20\"></div>\n </div>\n </div>\n <div\n class=\"col-xs-12 col-sm-4 col-md-3\"\n *ngFor=\"let app of filteredPackages$ | async\"\n >\n <c8y-application-card\n class=\"d-contents\"\n (onAppDeleted)=\"loadPackages()\"\n (onAppCloned)=\"loadPackages()\"\n [app]=\"app\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [title]=\"'No extensions to display.' | translate\"\n [subtitle]=\"hasAdminPermissions ? (emptyStateSubtitle | translate) : ''\"\n *ngIf=\"(packages$ | async)?.length === 0\"\n>\n <div *ngIf=\"hasAdminPermissions\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add extension package' | translate }}\"\n type=\"button\"\n (click)=\"addPackage()\"\n >\n {{ 'Add extension package' | translate }}\n </button>\n </div>\n</c8y-ui-empty-state>\n\n<c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No matching extensions.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n *ngIf=\"(packages$ | async)?.length > 0 && (filteredPackages$ | async)?.length === 0\"\n>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset filters' | translate }}\"\n type=\"button\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n", dependencies: [{ kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ListFiltersComponent, selector: "c8y-list-filters", inputs: ["packageTypes", "packageAvailabilities", "packageContents"], outputs: ["filterPipeChange"] }, { kind: "component", type: ArchivedFilterComponent, selector: "c8y-archived-filter" }, { kind: "component", type: ListDisplaySwitchComponent, selector: "c8y-list-display-switch", inputs: ["listKey", "listLength", "filterPipe"], outputs: ["onListClassChange"] }, { kind: "component", type: HelpComponent, selector: "c8y-help", inputs: ["src", "isCollapsed", "priority", "icon"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ApplicationCardComponent, selector: "c8y-application-card", inputs: ["app", "canEdit"], outputs: ["onAppDeleted", "onAppCloned"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackagesListComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-packages-list', imports: [
TitleComponent,
BreadcrumbComponent,
BreadcrumbItemComponent,
NgIf,
ActionBarItemComponent,
IconDirective,
NgClass,
ListFiltersComponent,
ArchivedFilterComponent,
ListDisplaySwitchComponent,
HelpComponent,
NgFor,
ApplicationCardComponent,
EmptyStateComponent,
C8yTranslatePipe,
AsyncPipe
], template: "<c8y-title>{{ 'Extensions' | translate }}</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]=\"'big-parcel'\"\n [path]=\"'ecosystem/extension/extensions'\"\n [label]=\"'Extensions' | translate\"\n ></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-action-bar-item\n [placement]=\"'right'\"\n *ngIf=\"hasAdminPermissions\"\n>\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Add extension package' | translate }}\"\n type=\"button\"\n data-cy=\"packages-list--add-extension-package\"\n (click)=\"addPackage()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add extension package' | 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=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"loadPackages()\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reloading }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"p-r-8 p-l-8\"\n>\n <c8y-list-filters\n *ngIf=\"packages$ | async\"\n [packageTypes]=\"packageTypes\"\n [packageAvailabilities]=\"packageAvailabilities\"\n [packageContents]=\"packageContents\"\n (filterPipeChange)=\"setFilterPipe($event)\"\n >\n <c8y-archived-filter></c8y-archived-filter>\n </c8y-list-filters>\n</c8y-action-bar-item>\n\n<c8y-action-bar-item\n [placement]=\"'left'\"\n itemClass=\"navbar-form hidden-xs\"\n>\n <c8y-list-display-switch\n (onListClassChange)=\"listClass = $event\"\n [listLength]=\"(packages$ | async)?.length\"\n ></c8y-list-display-switch>\n</c8y-action-bar-item>\n\n<c8y-help src=\"/docs/standard-tenant/ecosystem/#extensions\"></c8y-help>\n\n<div\n class=\"card-group\"\n [ngClass]=\"listClass\"\n>\n <div\n class=\"page-sticky-header hidden-xs d-flex m-b-8\"\n *ngIf=\"(filteredPackages$ | async)?.length > 0\"\n >\n <div class=\"card-block card-column-40\">\n <div class=\"card-appicon p-l-32 p-r-16 m-r-0 m-l-4\"></div>\n {{ 'Package' | translate }}\n </div>\n <div class=\"card-block p-0 card-column-80 m-r-40\">\n <div class=\"card-block card-column-80\">{{ 'Description' | translate }}</div>\n <div class=\"card-block card-column-20\">{{ 'Type' | translate }}</div>\n <div class=\"card-block card-column-20\"></div>\n </div>\n </div>\n <div\n class=\"col-xs-12 col-sm-4 col-md-3\"\n *ngFor=\"let app of filteredPackages$ | async\"\n >\n <c8y-application-card\n class=\"d-contents\"\n (onAppDeleted)=\"loadPackages()\"\n (onAppCloned)=\"loadPackages()\"\n [app]=\"app\"\n ></c8y-application-card>\n </div>\n</div>\n\n<c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [title]=\"'No extensions to display.' | translate\"\n [subtitle]=\"hasAdminPermissions ? (emptyStateSubtitle | translate) : ''\"\n *ngIf=\"(packages$ | async)?.length === 0\"\n>\n <div *ngIf=\"hasAdminPermissions\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Add extension package' | translate }}\"\n type=\"button\"\n (click)=\"addPackage()\"\n >\n {{ 'Add extension package' | translate }}\n </button>\n </div>\n</c8y-ui-empty-state>\n\n<c8y-ui-empty-state\n [icon]=\"'search'\"\n [title]=\"'No matching extensions.' | translate\"\n [subtitle]=\"'Refine your search terms and/or the filters' | translate\"\n *ngIf=\"(packages$ | async)?.length > 0 && (filteredPackages$ | async)?.length === 0\"\n>\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Reset filters' | translate }}\"\n type=\"button\"\n (click)=\"resetFilters()\"\n >\n {{ 'Reset filters' | translate }}\n </button>\n</c8y-ui-empty-state>\n" }]
}], ctorParameters: () => [{ type: i1.EcosystemService }, { type: i2.WizardModalService }, { type: i2.Permissions }], propDecorators: { filtersComponent: [{
type: ViewChild,
args: [ListFiltersComponent]
}] } });
class PackageVersionsGuard {
canActivate(route) {
const app = route.data.contextData || route.parent.data.contextData;
return !!app?.applicationVersions?.length;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageVersionsGuard, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageVersionsGuard }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageVersionsGuard, decorators: [{
type: Injectable
}] });
class PackageVersionsAppsComponent {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageVersionsAppsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: PackageVersionsAppsComponent, isStandalone: true, selector: "c8y-contents-apps", inputs: { selectedVersionManifest: "selectedVersionManifest" }, ngImport: i0, template: "<p class=\"legend form-block\">\n {{ 'Application' | translate }}\n</p>\n\n<div *ngIf=\"selectedVersionManifest?.name; else emptyApp\">\n <c8y-li>\n <c8y-li-icon icon=\"big-parcel\"></c8y-li-icon>\n <h5 class=\"text-medium text-16 p-b-8\">\n {{ selectedVersionManifest?.name | humanizeAppName | async }}\n <small class=\"m-l-8\" *ngIf=\"selectedVersionManifest?.requiredPlatformVersion\">\n <em>{{ selectedVersionManifest?.requiredPlatformVersion }}</em>\n </small>\n </h5>\n <p *ngIf=\"selectedVersionManifest?.description; else notAvailable\">\n {{ selectedVersionManifest?.description }}\n </p>\n </c8y-li>\n</div>\n\n<ng-template #notAvailable>\n <p class=\"text-muted\">\n <em>{{ 'No description available.' | translate }}</em>\n </p>\n</ng-template>\n\n<ng-template #emptyApp>\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [horizontal]=\"true\"\n [title]=\"'No application.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain an application.' | translate\"\n ></c8y-ui-empty-state>\n</ng-template>", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { 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: "19.2.14", ngImport: i0, type: PackageVersionsAppsComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-contents-apps', imports: [
NgIf,
ListItemComponent,
ListItemIconComponent,
EmptyStateComponent,
C8yTranslatePipe,
AsyncPipe,
HumanizeAppNamePipe
], template: "<p class=\"legend form-block\">\n {{ 'Application' | translate }}\n</p>\n\n<div *ngIf=\"selectedVersionManifest?.name; else emptyApp\">\n <c8y-li>\n <c8y-li-icon icon=\"big-parcel\"></c8y-li-icon>\n <h5 class=\"text-medium text-16 p-b-8\">\n {{ selectedVersionManifest?.name | humanizeAppName | async }}\n <small class=\"m-l-8\" *ngIf=\"selectedVersionManifest?.requiredPlatformVersion\">\n <em>{{ selectedVersionManifest?.requiredPlatformVersion }}</em>\n </small>\n </h5>\n <p *ngIf=\"selectedVersionManifest?.description; else notAvailable\">\n {{ selectedVersionManifest?.description }}\n </p>\n </c8y-li>\n</div>\n\n<ng-template #notAvailable>\n <p class=\"text-muted\">\n <em>{{ 'No description available.' | translate }}</em>\n </p>\n</ng-template>\n\n<ng-template #emptyApp>\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [horizontal]=\"true\"\n [title]=\"'No application.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain an application.' | translate\"\n ></c8y-ui-empty-state>\n</ng-template>" }]
}], propDecorators: { selectedVersionManifest: [{
type: Input,
args: ['selectedVersionManifest']
}] } });
class PackageVersionsPluginsComponent {
constructor(activatedRoute) {
this.activatedRoute = activatedRoute;
this.showOverview = new EventEmitter();
this.exportedPlugins$ = new BehaviorSubject([]);
this.appParentData = this.activatedRoute.parent?.snapshot.data.contextData;
}
async ngOnChanges() {
this.exportedPlugins$.next(this.getExportedPlugins());
}
showPluginOverview(plugin) {
this.showOverview.emit(plugin);
}
getExportedPlugins() {
if (!this.selectedVersionManifest?.exports) {
return [];
}
const originApp = {
label: this.appParentData?.label || this.appParentData?.manifest.label,
owner: this.appParentData?.owner
};
return this.selectedVersionManifest.exports.map(plugin => ({
...plugin,
id: PluginsService.createPluginId(this.selectedVersionManifest.contextPath, plugin, this.selectedVersionManifest.version, false),
originApp
}));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageVersionsPluginsComponent, deps: [{ token: i1$2.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: PackageVersionsPluginsComponent, isStandalone: true, selector: "c8y-contents-plugins", inputs: { selectedVersionManifest: "selectedVersionManifest", selectedPlugin: "selectedPlugin" }, outputs: { showOverview: "showOverview" }, usesOnChanges: true, ngImport: i0, template: "<p class=\"legend form-block\">\n {{ 'Plugins' | translate }}\n</p>\n<!-- empty state -->\n<c8y-ui-empty-state\n [icon]=\"'plugin'\"\n [title]=\"'No plugins to display.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain plugins.' | translate\"\n *ngIf=\"(exportedPlugins$ | async).length === 0\"\n [horizontal]=\"true\"\n></c8y-ui-empty-state>\n\n<c8y-plugin-list\n [plugins$]=\"exportedPlugins$\"\n [selectable]=\"false\"\n [selectedPlugin]=\"selectedPlugin\"\n (showOverview)=\"showPluginOverview($event)\"\n></c8y-plugin-list>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "component", type: PluginListComponent, selector: "c8y-plugin-list", inputs: ["plugins$", "emptyListText", "selectable", "hideSource", "installable", "package", "selectedPlugin"], outputs: ["selectedItems", "showOverview"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageVersionsPluginsComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-contents-plugins', imports: [NgIf, EmptyStateComponent, PluginListComponent, C8yTranslatePipe, AsyncPipe], template: "<p class=\"legend form-block\">\n {{ 'Plugins' | translate }}\n</p>\n<!-- empty state -->\n<c8y-ui-empty-state\n [icon]=\"'plugin'\"\n [title]=\"'No plugins to display.' | translate\"\n [subtitle]=\"'This package doesn\\'t contain plugins.' | translate\"\n *ngIf=\"(exportedPlugins$ | async).length === 0\"\n [horizontal]=\"true\"\n></c8y-ui-empty-state>\n\n<c8y-plugin-list\n [plugins$]=\"exportedPlugins$\"\n [selectable]=\"false\"\n [selectedPlugin]=\"selectedPlugin\"\n (showOverview)=\"showPluginOverview($event)\"\n></c8y-plugin-list>\n" }]
}], ctorParameters: () => [{ type: i1$2.ActivatedRoute }], propDecorators: { selectedVersionManifest: [{
type: Input,
args: ['selectedVersionManifest']
}], selectedPlugin: [{
type: Input
}], showOverview: [{
type: Output
}] } });
class PackageContentsComponent {
constructor(activatedRoute, applicationService, alertService, contextRouteService) {
this.activatedRoute = activatedRoute;
this.applicationService = applicationService;
this.alertService = alertService;
this.contextRouteService = contextRouteService;
this.showOverview = new EventEmitter();
this.package = {};
this.isLoading = false;
this.packageVersionProperties = packageProperties;
}
showPluginOverview(plugin) {
this.showOverview.emit(plugin);
}
async ngOnChanges(changes) {
if (changes.selectedVersion?.currentValue) {
this.loadManifest(this.selectedVersion);
this.previousVersion = this.getPreviousVersion();
}
}
async loadManifest(version) {
this.package = this.contextRouteService.getContextData(this.activatedRoute)?.contextData;
this.isLoading = true;
this.selectedVersionManifest = await this.getManifest(version);
this.isLoading = false;
}
async getManifest(version) {
try {
return await this.applicationService.getAppManifest(this.package, version);
}
catch (error) {
this.alertService.addServerFailure(error);
}
return undefined;
}
getPreviousVersion() {
if (this.package.applicationVersions.length === 1) {
return null;
}
const selectedVersionIndex = this.package.applicationVersions.findIndex(version => version.version === this.selectedVersion);
if (selectedVersionIndex === 0) {
return null;
}
return this.package.applicationVersions[selectedVersionIndex - 1].version;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageContentsComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i4.ApplicationService }, { token: i2.AlertService }, { token: i2.ContextRouteService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: PackageContentsComponent, isStandalone: true, selector: "c8y-package-contents", inputs: { selectedVersion: "selectedVersion", selectedPlugin: "selectedPlugin" }, outputs: { showOverview: "showOverview" }, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"!selectedVersionManifest && !isLoading\">\n <div class=\"p-16\">\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [title]=\"'No package selected' | translate\"\n [subtitle]=\"'Select a package from the list to display the package contents.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n</ng-container>\n\n<ng-container *ngIf=\"isLoading\">\n <c8y-loading></c8y-loading>\n</ng-container>\n\n<ng-container *ngIf=\"selectedVersionManifest && !isLoading\">\n <!-- DETAILS -->\n <div class=\"card-block\">\n <c8y-properties-list\n [data]=\"selectedVersionManifest\"\n [emptyLabel]=\"'--'\"\n [properties]=\"packageVersionProperties\"\n ></c8y-properties-list>\n\n <!-- APPS -->\n <c8y-contents-apps\n class=\"p-t-16 d-block\"\n [selectedVersionManifest]=\"selectedVersionManifest\"\n ></c8y-contents-apps>\n\n <!-- PLUGINS -->\n <c8y-contents-plugins\n class=\"p-t-16 d-block\"\n [selectedVersionManifest]=\"selectedVersionManifest\"\n [selectedPlugin]=\"selectedPlugin\"\n (showOverview)=\"showPluginOverview($event)\"\n ></c8y-contents-plugins>\n\n <!-- CHANGELOG -->\n <p class=\"legend form-block\">\n {{ 'Change log' | translate }}\n </p>\n\n <c8y-contents-changelog\n [package]=\"package\"\n [selectedVersion]=\"selectedVersion\"\n [previousVersion]=\"previousVersion\"\n ></c8y-contents-changelog>\n </div>\n</ng-container>\n", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: PropertiesListComponent, selector: "c8y-properties-list", inputs: ["properties", "title", "icon", "data", "groups", "noParse", "emptyLabel"] }, { kind: "component", type: PackageVersionsAppsComponent, selector: "c8y-contents-apps", inputs: ["selectedVersionManifest"] }, { kind: "component", type: PackageVersionsPluginsComponent, selector: "c8y-contents-plugins", inputs: ["selectedVersionManifest", "selectedPlugin"], outputs: ["showOverview"] }, { kind: "component", type: PackageChangelogComponent, selector: "c8y-contents-changelog", inputs: ["package", "selectedVersion", "previousVersion"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageContentsComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-package-contents', imports: [
NgIf,
EmptyStateComponent,
LoadingComponent,
PropertiesListComponent,
PackageVersionsAppsComponent,
PackageVersionsPluginsComponent,
PackageChangelogComponent,
C8yTranslatePipe
], template: "<ng-container *ngIf=\"!selectedVersionManifest && !isLoading\">\n <div class=\"p-16\">\n <c8y-ui-empty-state\n [icon]=\"'big-parcel'\"\n [title]=\"'No package selected' | translate\"\n [subtitle]=\"'Select a package from the list to display the package contents.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n</ng-container>\n\n<ng-container *ngIf=\"isLoading\">\n <c8y-loading></c8y-loading>\n</ng-container>\n\n<ng-container *ngIf=\"selectedVersionManifest && !isLoading\">\n <!-- DETAILS -->\n <div class=\"card-block\">\n <c8y-properties-list\n [data]=\"selectedVersionManifest\"\n [emptyLabel]=\"'--'\"\n [properties]=\"packageVersionProperties\"\n ></c8y-properties-list>\n\n <!-- APPS -->\n <c8y-contents-apps\n class=\"p-t-16 d-block\"\n [selectedVersionManifest]=\"selectedVersionManifest\"\n ></c8y-contents-apps>\n\n <!-- PLUGINS -->\n <c8y-contents-plugins\n class=\"p-t-16 d-block\"\n [selectedVersionManifest]=\"selectedVersionManifest\"\n [selectedPlugin]=\"selectedPlugin\"\n (showOverview)=\"showPluginOverview($event)\"\n ></c8y-contents-plugins>\n\n <!-- CHANGELOG -->\n <p class=\"legend form-block\">\n {{ 'Change log' | translate }}\n </p>\n\n <c8y-contents-changelog\n [package]=\"package\"\n [selectedVersion]=\"selectedVersion\"\n [previousVersion]=\"previousVersion\"\n ></c8y-contents-changelog>\n </div>\n</ng-container>\n" }]
}], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i4.ApplicationService }, { type: i2.AlertService }, { type: i2.ContextRouteService }], propDecorators: { selectedVersion: [{
type: Input
}], selectedPlugin: [{
type: Input
}], showOverview: [{
type: Output
}] } });
const DEFAULT_VERSIONS_LIMIT = 20;
class PackageVersionsListComponent {
constructor(activatedRoute, pluginsService, ecosystemService, translateService, modal, alertService, optionsService, permissions, gainsightService) {
this.activatedRoute = activatedRoute;
this.pluginsService = pluginsService;
this.ecosystemService = ecosystemService;
this.translateService = translateService;
this.modal = modal;
this.alertService = alertService;
this.optionsService = optionsService;
this.permissions = permissions;
this.gainsightService = gainsightService;
this.CURRENT_LOCATION = location.href;
this.isLoading = false;
this.hasAdminPermissions = false;
this.isPackageOwnedByCurrentTenant = false;
this.onVersionSelect = new EventEmitter();
}
async ngOnInit() {
this.isLoading = true;
this.hasAdminPermissions = this.permissions.hasRole(Permissions.ROLE_APPLICATION_MANAGEMENT_ADMIN);
this.package = this.activatedRoute?.snapshot?.parent?.data?.contextData;
this.isPackageOwnedByCurrentTenant = this.ecosystemService.isOwner(this.package);
this.versionsLimit = (await this.optionsService.getSystemOption('application', 'versions.limit', DEFAULT_VERSIONS_LIMIT));
this.sortVersions();
this.isLoading = false;
}
async downloadArchive(appVersion) {
this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DOWNLOAD,
url: this.CURRENT_LOCATION
});
const archiveMO = await this.ecosystemService.getArchiveManagedObject(appVersion.binaryId);
await this.ecosystemService.downloadArchive(this.package, {
id: appVersion.binaryId,
name: archiveMO.name
});
}
packageVersionUploaded() {
this.activatedRoute.snapshot.parent.data.contextData = this.package;
this.sortVersions();
this.setUploadedVersionAsLatest();
}
selectVersion(version) {
this.selectedVersion = version;
this.onVersionSelect.emit(version);
}
async removeVersionPackage(version) {
try {
await this.ecosystemService.deletePackageVersion(this.package, { version });
this.alertService.success(this.translateService.instant(gettext('Package version {{version}} has been removed'), {
version
}));
this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DELETE,
result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SUCCESS,
url: this.CURRENT_LOCATION
});
}
catch (e) {
this.alertService.addServerFailure(e);
this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.DELETE,
result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
url: this.CURRENT_LOCATION
});
}
if (version === this.selectedVersion) {
this.selectVersion(null);
}
await this.refreshPackage();
}
async setVersionAsLatest(appVersion) {
try {
await this.ecosystemService.setPackageVersionTag(this.package, appVersion.version, [
...appVersion.tags,
'latest'
]);
// TODO added it due to: https://cumulocity.atlassian.net/browse/MTM-48553
// Remove it when BE fixes issues with activeVersion.
await this.ecosystemService.setAppActiveVersion(this.package, appVersion.binaryId);
this.alertService.success(gettext('Tag has been set.'));
this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.SET_AS_LATEST,
result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SUCCESS,
url: this.CURRENT_LOCATION
});
}
catch (e) {
this.alertService.addServerFailure(e);
this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.SET_AS_LATEST,
result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SERVER_FAILURE,
url: this.CURRENT_LOCATION
});
return;
}
await this.refreshPackage();
}
async acknowledgeLimitReached() {
await this.modal.acknowledge(gettext('Package limit exceeded'), this.translateService.instant(gettext('You have reached the maximum number of {{ versionsLimit }} package versions. To add another version, first delete one from the list.'), { versionsLimit: this.versionsLimit }), Status.INFO, gettext('Close'));
throw undefined;
}
async refreshPackage() {
this.isLoading = true;
this.package = await this.ecosystemService.getApplication(this.package.id);
this.activatedRoute.snapshot.parent.data.contextData = this.package;
this.sortVersions();
this.isLoading = false;
}
sortVersions() {
this.sortedVersions = this.pluginsService.sortVersions({
list: this.package.applicationVersions,
path: ['version']
}, 'desc');
this.toggleUploadPossibility();
}
async setUploadedVersionAsLatest() {
const uploadedVersion = this.package.applicationVersions[this.package.applicationVersions.length - 1];
try {
this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.EVENTS.PACKAGE_VERSIONS, {
component: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.COMPONENTS.PACKAGE_VERSIONS,
action: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.ACTIONS.UPLOAD,
result: PRODUCT_EXPERIENCE_ECOSYSTEM.APPLICATIONS.RESULTS.SUCCESS,
url: this.CURRENT_LOCATION
});
await this.modal.confirm(gettext('Upload successful'), this.translateService.instant(gettext('Do you want to set version {{version}} as the latest? Deploying a new application will always use this version.'), { version: uploadedVersion.version }), Status.SUCCESS, {
ok: gettext('Set as latest`version`'),
cancel: gettext('Keep unchanged`version`')
});
}
catch (e) {
await this.refreshPackage();
return;
}
await this.setVersionAsLatest(uploadedVersion);
}
toggleUploadPossibility() {
this.preUploadCallback =
this.sortedVersions.length < this.versionsLimit
? null
: this.acknowledgeLimitReached.bind(this);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageVersionsListComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i2.PluginsService }, { token: i1.EcosystemService }, { token: i6.TranslateService }, { token: i2.ModalService }, { token: i2.AlertService }, { token: i2.OptionsService }, { token: i2.Permissions }, { token: i2.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: PackageVersionsListComponent, isStandalone: true, selector: "c8y-package-versions-list", outputs: { onVersionSelect: "onVersionSelect" }, ngImport: i0, template: "<div class=\"inner-scroll split-view__list\">\n <div class=\"card-header separator sticky-top bg-component\">\n <div class=\"card-title\" translate>Versions</div>\n </div>\n\n <div class=\"bg-level-1 flex-grow\">\n <div class=\"p-16\" *ngIf=\"isLoading\">\n <c8y-loading></c8y-loading>\n </div>\n <ul class=\"nav c8y-nav-stacked\" *ngIf=\"!isLoading\">\n <li\n class=\"c8y-stacked-item p-t-0 p-b-0 p-r-4\"\n [ngClass]=\"{ active: selectedVersion === applicationVersion.version }\"\n *ngFor=\"let applicationVersion of sortedVersions\"\n >\n <div\n class=\"flex-grow d-flex a-i-center gap-4 p-t-8 p-b-8\"\n (click)=\"selectVersion(applicationVersion.version)\"\n >\n <i c8yIcon=\"big-parcel\" class=\"icon-20\"></i>\n <span class=\"text-label-small\">\n {{ 'Version' | translate }}\n </span>\n <span class=\"text-medium\">{{ applicationVersion.version }}</span>\n <div class=\"text-truncate d-flex j-c-end flex-grow gap-4 flex-wrap m-l-auto\">\n <span *ngFor=\"let tag of applicationVersion.tags\" class=\"label label-info\">\n {{ tag }}\n </span>\n </div>\n </div>\n <div class=\"dropdown\" dropdown *ngIf=\"hasAdminPermissions && isPackageOwnedByCurrentTenant\">\n <button\n class=\"dropdown-toggle c8y-dropdown\"\n type=\"button\"\n title=\"{{ 'Settings' | translate }}\"\n dropdownToggle\n >\n <i c8yIcon=\"ellipsis-v\"></i>\n </button>\n <ul *dropdownMenu class=\"dropdown-menu dropdown-menu-right\">\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Set as latest`version`' | translate }}\"\n (click)=\"setVersionAsLatest(applicationVersion)\"\n [disabled]=\"applicationVersion.tags?.includes('latest')\"\n >\n <i c8yIcon=\"collect\" class=\"m-r-4\"></i>\n {{ 'Set as latest`version`' | translate }}\n </button>\n </li>\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Download' | translate }}\"\n (click)=\"downloadArchive(applicationVersion)\"\n >\n <i c8yIcon=\"download\" class=\"m-r-4\"></i>\n {{ 'Download' | translate }}\n </button>\n </li>\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Delete' | translate }}\"\n (click)=\"removeVersionPackage(applicationVersion.version)\"\n [disabled]=\"applicationVersion.tags?.includes('latest')\"\n >\n <i c8yIcon=\"trash\" class=\"m-r-4\"></i>\n {{ 'Delete' | translate }}\n </button>\n </li>\n </ul>\n </div>\n </li>\n </ul>\n </div>\n\n <div\n class=\"card-footer separator sticky-bottom\"\n *ngIf=\"!isLoading && isPackageOwnedByCurrentTenant\"\n >\n <div class=\"form-group m-b-0\">\n <label translate>Upload a new version</label>\n <c8y-upload-archive\n [(application)]=\"package\"\n [uploadNewVersion]=\"true\"\n (refresh)=\"packageVersionUploaded()\"\n [preUploadCallback]=\"preUploadCallback\"\n ></c8y-upload-archive>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { 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: BsDropdownToggleDirective, selector: "[bsDropdownToggle],[dropdownToggle]", exportAs: ["bs-dropdown-toggle"] }, { kind: "directive", type: BsDropdownMenuDirective, selector: "[bsDropdownMenu],[dropdownMenu]", exportAs: ["bs-dropdown-menu"] }, { kind: "component", type: UploadArchiveComponent, selector: "c8y-upload-archive", inputs: ["application", "uploadNewVersion", "preUploadCallback"], outputs: ["applicationChange", "refresh"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageVersionsListComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-package-versions-list', imports: [
C8yTranslateDirective,
NgIf,
LoadingComponent,
NgFor,
NgClass,
IconDirective,
BsDropdownDirective,
BsDropdownToggleDirective,
BsDropdownMenuDirective,
UploadArchiveComponent,
C8yTranslatePipe
], template: "<div class=\"inner-scroll split-view__list\">\n <div class=\"card-header separator sticky-top bg-component\">\n <div class=\"card-title\" translate>Versions</div>\n </div>\n\n <div class=\"bg-level-1 flex-grow\">\n <div class=\"p-16\" *ngIf=\"isLoading\">\n <c8y-loading></c8y-loading>\n </div>\n <ul class=\"nav c8y-nav-stacked\" *ngIf=\"!isLoading\">\n <li\n class=\"c8y-stacked-item p-t-0 p-b-0 p-r-4\"\n [ngClass]=\"{ active: selectedVersion === applicationVersion.version }\"\n *ngFor=\"let applicationVersion of sortedVersions\"\n >\n <div\n class=\"flex-grow d-flex a-i-center gap-4 p-t-8 p-b-8\"\n (click)=\"selectVersion(applicationVersion.version)\"\n >\n <i c8yIcon=\"big-parcel\" class=\"icon-20\"></i>\n <span class=\"text-label-small\">\n {{ 'Version' | translate }}\n </span>\n <span class=\"text-medium\">{{ applicationVersion.version }}</span>\n <div class=\"text-truncate d-flex j-c-end flex-grow gap-4 flex-wrap m-l-auto\">\n <span *ngFor=\"let tag of applicationVersion.tags\" class=\"label label-info\">\n {{ tag }}\n </span>\n </div>\n </div>\n <div class=\"dropdown\" dropdown *ngIf=\"hasAdminPermissions && isPackageOwnedByCurrentTenant\">\n <button\n class=\"dropdown-toggle c8y-dropdown\"\n type=\"button\"\n title=\"{{ 'Settings' | translate }}\"\n dropdownToggle\n >\n <i c8yIcon=\"ellipsis-v\"></i>\n </button>\n <ul *dropdownMenu class=\"dropdown-menu dropdown-menu-right\">\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Set as latest`version`' | translate }}\"\n (click)=\"setVersionAsLatest(applicationVersion)\"\n [disabled]=\"applicationVersion.tags?.includes('latest')\"\n >\n <i c8yIcon=\"collect\" class=\"m-r-4\"></i>\n {{ 'Set as latest`version`' | translate }}\n </button>\n </li>\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Download' | translate }}\"\n (click)=\"downloadArchive(applicationVersion)\"\n >\n <i c8yIcon=\"download\" class=\"m-r-4\"></i>\n {{ 'Download' | translate }}\n </button>\n </li>\n <li>\n <button\n type=\"button\"\n title=\"{{ 'Delete' | translate }}\"\n (click)=\"removeVersionPackage(applicationVersion.version)\"\n [disabled]=\"applicationVersion.tags?.includes('latest')\"\n >\n <i c8yIcon=\"trash\" class=\"m-r-4\"></i>\n {{ 'Delete' | translate }}\n </button>\n </li>\n </ul>\n </div>\n </li>\n </ul>\n </div>\n\n <div\n class=\"card-footer separator sticky-bottom\"\n *ngIf=\"!isLoading && isPackageOwnedByCurrentTenant\"\n >\n <div class=\"form-group m-b-0\">\n <label translate>Upload a new version</label>\n <c8y-upload-archive\n [(application)]=\"package\"\n [uploadNewVersion]=\"true\"\n (refresh)=\"packageVersionUploaded()\"\n [preUploadCallback]=\"preUploadCallback\"\n ></c8y-upload-archive>\n </div>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i2.PluginsService }, { type: i1.EcosystemService }, { type: i6.TranslateService }, { type: i2.ModalService }, { type: i2.AlertService }, { type: i2.OptionsService }, { type: i2.Permissions }, { type: i2.GainsightService }], propDecorators: { onVersionSelect: [{
type: Output
}] } });
class PackageVersionsComponent {
constructor(activatedRoute, contextRouteService, pluginsService) {
this.activatedRoute = activatedRoute;
this.contextRouteService = contextRouteService;
this.pluginsService = pluginsService;
this.package = {};
this.packageContentsTitle = gettext('Version {{ selectedVersion }} package contents');
}
async ngOnInit() {
this.package = this.contextRouteService.getContextData(this.activatedRoute)?.contextData;
}
async showPluginOverview(plugin) {
this.selectedPlugin = plugin;
const baseUrl = `/apps/${plugin.id}/`;
this.pluginBaseUrl = baseUrl;
this.pluginMarkdown = await this.pluginsService.getReadmeFileContent(baseUrl);
}
closeOverview() {
this.selectedPlugin = null;
}
clearSelectedVersion() {
this.selectedVersion = null;
}
selectVersion(version) {
if (this.selectedVersion !== version) {
this.selectedVersion = version;
this.closeOverview();
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageVersionsComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i2.ContextRouteService }, { token: i2.PluginsService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: PackageVersionsComponent, isStandalone: true, selector: "c8y-package-versions", ngImport: i0, template: "<c8y-title>{{ package?.name | 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]=\"'big-parcel'\"\n [label]=\"'Extensions' | translate\"\n [path]=\"'ecosystem/extension/extensions'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"package?.name | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Versions' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<div\n class=\"card content-fullpage d-grid\"\n [ngClass]=\"{ 'grid__col--6-6-0': !selectedPlugin, 'grid__col--0-6-6': !!selectedPlugin }\"\n>\n <c8y-package-versions-list\n class=\"d-contents\"\n (onVersionSelect)=\"selectVersion($event)\"\n ></c8y-package-versions-list>\n\n <!-- Package contents -->\n <div\n class=\"inner-scroll split-view__detail\"\n [ngClass]=\"{ 'split-view__detail--selected': selectedVersion }\"\n >\n <div class=\"large-padding card-header separator visible-sm visible-xs fit-w sticky-top\">\n <div class=\"d-flex a-i-center\">\n <button\n class=\"btn-clean text-primary m-r-8\"\n title=\"{{ 'Back' | translate }}\"\n (click)=\"clearSelectedVersion()\"\n >\n <i c8yIcon=\"chevron-left\"></i>\n <span translate>Back</span>\n </button>\n <div class=\"card-title\">\n {{ packageContentsTitle | translate: { selectedVersion } }}\n </div>\n </div>\n </div>\n <div class=\"card-header large-padding separator sticky-top visible-md visible-lg\">\n <div class=\"card-title\">\n <ng-container *ngIf=\"selectedVersion\">\n {{ packageContentsTitle | translate: { selectedVersion } }}\n </ng-container>\n </div>\n </div>\n <div class=\"inner-scroll split-view__list\">\n <c8y-package-contents\n [selectedVersion]=\"selectedVersion\"\n [selectedPlugin]=\"selectedPlugin\"\n (showOverview)=\"showPluginOverview($event)\"\n ></c8y-package-contents>\n </div>\n </div>\n\n <!-- Plugin readme -->\n <div\n class=\"inner-scroll split-view__detail\"\n [ngClass]=\"{ 'split-view__detail--selected': selectedPlugin }\"\n >\n <div\n class=\"card-header separator sticky-top\"\n *ngIf=\"selectedPlugin\"\n >\n <button\n class=\"btn-clean\"\n (click)=\"closeOverview()\"\n >\n <i c8yIcon=\"caret-back\"></i>\n {{ 'Back to package versions overview ' | translate }}\n </button>\n </div>\n <div\n class=\"card-block p-l-16 p-r-16 overflow-visible\"\n *ngIf=\"selectedPlugin\"\n >\n <div\n class=\"markdown-content\"\n *ngIf=\"pluginMarkdown\"\n [innerHTML]=\"pluginMarkdown | markdownToHtml: { baseUrl: pluginBaseUrl } | async\"\n ></div>\n <c8y-ui-empty-state\n [icon]=\"'user-manual'\"\n [title]=\"'No README.md found for plugin' | translate\"\n [subtitle]=\"\n 'To view the contents of "README", add the file "README.md" to the plugin.'\n | translate\n \"\n *ngIf=\"!pluginMarkdown\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "component", type: BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PackageVersionsListComponent, selector: "c8y-package-versions-list", outputs: ["onVersionSelect"] }, { kind: "directive", type: IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PackageContentsComponent, selector: "c8y-package-contents", inputs: ["selectedVersion", "selectedPlugin"], outputs: ["showOverview"] }, { kind: "component", type: EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: HumanizeAppNamePipe, name: "humanizeAppName" }, { kind: "pipe", type: MarkdownToHtmlPipe, name: "markdownToHtml" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageVersionsComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-package-versions', imports: [
TitleComponent,
BreadcrumbComponent,
BreadcrumbItemComponent,
NgClass,
PackageVersionsListComponent,
IconDirective,
C8yTranslateDirective,
NgIf,
PackageContentsComponent,
EmptyStateComponent,
C8yTranslatePipe,
AsyncPipe,
HumanizeAppNamePipe,
MarkdownToHtmlPipe
], template: "<c8y-title>{{ package?.name | 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]=\"'big-parcel'\"\n [label]=\"'Extensions' | translate\"\n [path]=\"'ecosystem/extension/extensions'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"package?.name | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Versions' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<div\n class=\"card content-fullpage d-grid\"\n [ngClass]=\"{ 'grid__col--6-6-0': !selectedPlugin, 'grid__col--0-6-6': !!selectedPlugin }\"\n>\n <c8y-package-versions-list\n class=\"d-contents\"\n (onVersionSelect)=\"selectVersion($event)\"\n ></c8y-package-versions-list>\n\n <!-- Package contents -->\n <div\n class=\"inner-scroll split-view__detail\"\n [ngClass]=\"{ 'split-view__detail--selected': selectedVersion }\"\n >\n <div class=\"large-padding card-header separator visible-sm visible-xs fit-w sticky-top\">\n <div class=\"d-flex a-i-center\">\n <button\n class=\"btn-clean text-primary m-r-8\"\n title=\"{{ 'Back' | translate }}\"\n (click)=\"clearSelectedVersion()\"\n >\n <i c8yIcon=\"chevron-left\"></i>\n <span translate>Back</span>\n </button>\n <div class=\"card-title\">\n {{ packageContentsTitle | translate: { selectedVersion } }}\n </div>\n </div>\n </div>\n <div class=\"card-header large-padding separator sticky-top visible-md visible-lg\">\n <div class=\"card-title\">\n <ng-container *ngIf=\"selectedVersion\">\n {{ packageContentsTitle | translate: { selectedVersion } }}\n </ng-container>\n </div>\n </div>\n <div class=\"inner-scroll split-view__list\">\n <c8y-package-contents\n [selectedVersion]=\"selectedVersion\"\n [selectedPlugin]=\"selectedPlugin\"\n (showOverview)=\"showPluginOverview($event)\"\n ></c8y-package-contents>\n </div>\n </div>\n\n <!-- Plugin readme -->\n <div\n class=\"inner-scroll split-view__detail\"\n [ngClass]=\"{ 'split-view__detail--selected': selectedPlugin }\"\n >\n <div\n class=\"card-header separator sticky-top\"\n *ngIf=\"selectedPlugin\"\n >\n <button\n class=\"btn-clean\"\n (click)=\"closeOverview()\"\n >\n <i c8yIcon=\"caret-back\"></i>\n {{ 'Back to package versions overview ' | translate }}\n </button>\n </div>\n <div\n class=\"card-block p-l-16 p-r-16 overflow-visible\"\n *ngIf=\"selectedPlugin\"\n >\n <div\n class=\"markdown-content\"\n *ngIf=\"pluginMarkdown\"\n [innerHTML]=\"pluginMarkdown | markdownToHtml: { baseUrl: pluginBaseUrl } | async\"\n ></div>\n <c8y-ui-empty-state\n [icon]=\"'user-manual'\"\n [title]=\"'No README.md found for plugin' | translate\"\n [subtitle]=\"\n 'To view the contents of "README", add the file "README.md" to the plugin.'\n | translate\n \"\n *ngIf=\"!pluginMarkdown\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </div>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i2.ContextRouteService }, { type: i2.PluginsService }] });
class PackageGuard {
constructor(ecosystemService) {
this.ecosystemService = ecosystemService;
}
canActivate(route) {
const app = route.data.contextData || route.parent.data.contextData;
if (!app) {
return false;
}
return this.ecosystemService.isPackage(app);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageGuard, deps: [{ token: i1.EcosystemService }], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageGuard }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageGuard, decorators: [{
type: Injectable
}], ctorParameters: () => [{ type: i1.EcosystemService }] });
class PackageChangelogTabComponent {
constructor(activatedRoute, contextRouteService) {
this.activatedRoute = activatedRoute;
this.contextRouteService = contextRouteService;
this.package = {};
}
async ngOnInit() {
this.package = this.contextRouteService.getContextData(this.activatedRoute)?.contextData;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageChangelogTabComponent, deps: [{ token: i1$2.ActivatedRoute }, { token: i2.ContextRouteService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: PackageChangelogTabComponent, isStandalone: true, selector: "c8y-package-changelog-tab", ngImport: i0, template: "<c8y-title>{{ package?.name | 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]=\"'big-parcel'\"\n [label]=\"'Extensions' | translate\"\n [path]=\"'ecosystem/extension/extensions'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"package?.name | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Change logs' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-contents-changelog [package]=\"package\"></c8y-contents-changelog>\n", dependencies: [{ kind: "component", type: PackageChangelogComponent, selector: "c8y-contents-changelog", inputs: ["package", "selectedVersion", "previousVersion"] }, { kind: "component", type: TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "pipe", type: HumanizeAppNamePipe, name: "humanizeAppName" }, { kind: "component", type: BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "pipe", type: C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageChangelogTabComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-package-changelog-tab', standalone: true, imports: [
PackageChangelogComponent,
TitleComponent,
HumanizeAppNamePipe,
BreadcrumbComponent,
BreadcrumbItemComponent,
C8yTranslatePipe,
AsyncPipe
], template: "<c8y-title>{{ package?.name | 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]=\"'big-parcel'\"\n [label]=\"'Extensions' | translate\"\n [path]=\"'ecosystem/extension/extensions'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"package?.name | humanizeAppName | async\"></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [label]=\"'Change logs' | translate\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n\n<c8y-contents-changelog [package]=\"package\"></c8y-contents-changelog>\n" }]
}], ctorParameters: () => [{ type: i1$2.ActivatedRoute }, { type: i2.ContextRouteService }] });
class PackageChangelogGuard {
constructor() {
this.pluginsService = inject(PluginsService);
this.router = inject(Router);
}
async canActivate(route) {
const app = route.data.contextData || route.parent.data.contextData;
const packageChangelogUrl = `/apps/${app.contextPath}/`;
const changelog = await this.pluginsService.getChangelogFileContent(packageChangelogUrl);
return !!changelog;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageChangelogGuard, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageChangelogGuard }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PackageChangelogGuard, decorators: [{
type: Injectable
}] });
const ecosystemMainRoutes = [
{
path: 'ecosystem/application',
redirectTo: 'ecosystem/application/applications',
pathMatch: 'full'
},
{
// keeps legacy links functional
path: 'ecosystem/applications',
redirectTo: 'ecosystem/application/applications',
pathMatch: 'full'
},
{
path: 'ecosystem/application/applications',
component: ApplicationListComponent
},
{
path: 'ecosystem/extension/extensions',
component: PackagesListComponent
},
{
path: 'ecosystem/application/features',
component: FeatureListComponent
},
{
path: 'ecosystem/microservice/microservices',
component: MicroserviceListComponent
}
];
const applicationDetailsRoutes = [
{
path: 'properties',
component: ApplicationPropertiesComponent,
icon: 'list',
label: gettext('Properties'),
context: ViewContext.Application,
priority: 5,
canActivate: [ApplicationPropertiesGuard]
},
{
path: 'application-versions',
component: PackageVersionsComponent,
icon: 'c8y-modules',
label: gettext('Versions'),
context: ViewContext.Application,
priority: 1,
canActivate: [PackageVersionsGuard]
},
{
path: 'properties',
component: ApplicationPropertiesComponent,
icon: 'list',
label: gettext('Properties'),
context: ViewContext.Feature,
priority: 5,
canActivate: [ApplicationPropertiesGuard]
},
{
path: 'package-details',
component: PackageDetailsComponent,
icon: 'big-parcel',
label: gettext('Extension package'),
context: ViewContext.Extension,
priority: 10,
canActivate: [PackageGuard]
},
{
path: 'package-versions',
component: PackageVersionsComponent,
icon: 'c8y-modules',
label: gettext('Versions'),
context: ViewContext.Extension,
priority: 5,
canActivate: [PackageGuard, PackageVersionsGuard]
},
{
path: 'package-changelog',
component: PackageChangelogTabComponent,
icon: 'list',
label: gettext('Change log'),
context: ViewContext.Extension,
priority: 1,
canActivate: [PackageGuard, PackageChangelogGuard]
},
{
path: 'properties',
component: ApplicationPropertiesComponent,
icon: 'list',
label: gettext('Properties'),
context: ViewContext.Microservice,
priority: 5,
canActivate: [ApplicationPropertiesGuard]
}
];
class EcosystemModule {
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: EcosystemModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: EcosystemModule, imports: [CoreModule,
BsDropdownModule,
TooltipModule,
FormsModule$1,
ReactiveFormsModule, i1$2.RouterModule, PopoverModule,
ApplicationPluginsModule,
SharedEcosystemModule,
LicenseConfirmModule,
IconSelectorModule,
A11yModule,
ArchivedConfirmModule,
PackageChangelogTabComponent,
ApplicationListComponent,
MicroserviceListComponent,
ApplicationPropertiesComponent,
AddMicroserviceComponent,
ActivityLogComponent,
AddWebApplicationComponent,
AddExternalApplicationComponent,
InstallFromPackageComponent,
PackagesListComponent,
PackageDetailsComponent,
DeployApplicationComponent,
AddPackageComponent,
FeatureListComponent,
PackageVersionsComponent,
PackageVersionsPluginsComponent,
PackageVersionsAppsComponent,
PackageContentsComponent,
PackageVersionsListComponent,
SubscriptionModalComponent,
UpdateApplicationModalComponent], exports: [ApplicationPropertiesComponent, UpdateApplicationModalComponent] }); }
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: EcosystemModule, providers: [
hookTab(EcosystemTabs),
hookRoute(applicationDetailsRoutes),
PackageGuard,
PackageVersionsGuard,
PackageChangelogGuard,
ApplicationPropertiesGuard,
hookWizard({
wizardId: EcosystemWizards.APPLICATION_UPLOAD,
component: AddWebApplicationComponent,
name: gettext('Upload web application'),
c8yIcon: 'upload'
}),
hookWizard({
name: undefined,
wizardId: EcosystemWizards.PACKAGE_UPLOAD,
component: AddPackageComponent
}),
hookWizard({
wizardId: EcosystemWizards.APPLICATION_UPLOAD,
component: AddExternalApplicationComponent,
name: gettext('External application'),
c8yIcon: 'cloud-link'
}),
hookWizard({
wizardId: EcosystemWizards.BLUEPRINT_DEPLOYMENT,
component: DeployApplicationComponent,
name: gettext('Deploy package'),
c8yIcon: 'big-parcel'
}),
hookWizard({
wizardId: EcosystemWizards.APPLICATION_UPLOAD,
component: InstallFromPackageComponent,
name: gettext('Install from available extension packages'),
c8yIcon: 'big-parcel'
}),
hookWizard({
name: undefined,
wizardId: EcosystemWizards.MICROSERVICE_UPLOAD,
component: AddMicroserviceComponent
})
], imports: [CoreModule,
BsDropdownModule,
TooltipModule,
FormsModule$1,
ReactiveFormsModule,
RouterModule.forChild(ecosystemMainRoutes),
PopoverModule,
ApplicationPluginsModule,
SharedEcosystemModule,
LicenseConfirmModule,
IconSelectorModule,
A11yModule,
ArchivedConfirmModule,
PackageChangelogTabComponent,
ApplicationListComponent,
MicroserviceListComponent,
ApplicationPropertiesComponent,
AddMicroserviceComponent,
ActivityLogComponent,
AddWebApplicationComponent,
AddExternalApplicationComponent,
InstallFromPackageComponent,
PackagesListComponent,
PackageDetailsComponent,
DeployApplicationComponent,
AddPackageComponent,
FeatureListComponent,
PackageVersionsComponent,
PackageVersionsPluginsComponent,
PackageVersionsAppsComponent,
PackageContentsComponent,
PackageVersionsListComponent,
SubscriptionModalComponent,
UpdateApplicationModalComponent] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: EcosystemModule, decorators: [{
type: NgModule,
args: [{
imports: [
CoreModule,
BsDropdownModule,
TooltipModule,
FormsModule$1,
ReactiveFormsModule,
RouterModule.forChild(ecosystemMainRoutes),
PopoverModule,
ApplicationPluginsModule,
SharedEcosystemModule,
LicenseConfirmModule,
IconSelectorModule,
A11yModule,
ArchivedConfirmModule,
PackageChangelogTabComponent,
ApplicationListComponent,
MicroserviceListComponent,
ApplicationPropertiesComponent,
AddMicroserviceComponent,
ActivityLogComponent,
AddWebApplicationComponent,
AddExternalApplicationComponent,
InstallFromPackageComponent,
PackagesListComponent,
PackageDetailsComponent,
DeployApplicationComponent,
AddPackageComponent,
FeatureListComponent,
PackageVersionsComponent,
PackageVersionsPluginsComponent,
PackageVersionsAppsComponent,
PackageContentsComponent,
PackageVersionsListComponent,
SubscriptionModalComponent,
UpdateApplicationModalComponent
],
exports: [ApplicationPropertiesComponent, UpdateApplicationModalComponent],
providers: [
hookTab(EcosystemTabs),
hookRoute(applicationDetailsRoutes),
PackageGuard,
PackageVersionsGuard,
PackageChangelogGuard,
ApplicationPropertiesGuard,
hookWizard({
wizardId: EcosystemWizards.APPLICATION_UPLOAD,
component: AddWebApplicationComponent,
name: gettext('Upload web application'),
c8yIcon: 'upload'
}),
hookWizard({
name: undefined,
wizardId: EcosystemWizards.PACKAGE_UPLOAD,
component: AddPackageComponent
}),
hookWizard({
wizardId: EcosystemWizards.APPLICATION_UPLOAD,
component: AddExternalApplicationComponent,
name: gettext('External application'),
c8yIcon: 'cloud-link'
}),
hookWizard({
wizardId: EcosystemWizards.BLUEPRINT_DEPLOYMENT,
component: DeployApplicationComponent,
name: gettext('Deploy package'),
c8yIcon: 'big-parcel'
}),
hookWizard({
wizardId: EcosystemWizards.APPLICATION_UPLOAD,
component: InstallFromPackageComponent,
name: gettext('Install from available extension packages'),
c8yIcon: 'big-parcel'
}),
hookWizard({
name: undefined,
wizardId: EcosystemWizards.MICROSERVICE_UPLOAD,
component: AddMicroserviceComponent
})
]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { ActivityLogComponent, AddExternalApplicationComponent, AddMicroserviceComponent, AddPackageComponent, AddWebApplicationComponent, ApplicationListComponent, ApplicationPropertiesComponent, ApplicationPropertiesGuard, DeployApplicationComponent, EcosystemModule, EcosystemTabs, FeatureListComponent, InstallFromPackageComponent, MicroserviceListComponent, PackageDetailsComponent, PackageGuard, PackageVersionsComponent, PackageVersionsPluginsComponent, PackagesListComponent, UpdateApplicationModalComponent };
//# sourceMappingURL=c8y-ngx-components-ecosystem.mjs.map