import angular from 'angular'; import _ from 'lodash-es'; import KubernetesStackHelper from 'Kubernetes/helpers/stackHelper'; import KubernetesApplicationHelper from 'Kubernetes/helpers/application'; import KubernetesConfigurationHelper from 'Kubernetes/helpers/configurationHelper'; import { KubernetesApplicationTypes } from 'Kubernetes/models/application/models'; import { KubernetesPortainerApplicationStackNameLabel } from 'Kubernetes/models/application/models'; import { confirmDelete } from '@@/modals/confirm'; class KubernetesApplicationsController { /* @ngInject */ constructor( $async, $state, $scope, Notifications, KubernetesApplicationService, HelmService, KubernetesConfigurationService, Authentication, LocalStorage, StackService, KubernetesNamespaceService ) { this.$async = $async; this.$state = $state; this.$scope = $scope; this.Notifications = Notifications; this.KubernetesApplicationService = KubernetesApplicationService; this.HelmService = HelmService; this.KubernetesConfigurationService = KubernetesConfigurationService; this.Authentication = Authentication; this.LocalStorage = LocalStorage; this.StackService = StackService; this.KubernetesNamespaceService = KubernetesNamespaceService; this.onInit = this.onInit.bind(this); this.getApplications = this.getApplications.bind(this); this.getApplicationsAsync = this.getApplicationsAsync.bind(this); this.removeAction = this.removeAction.bind(this); this.removeActionAsync = this.removeActionAsync.bind(this); this.removeStacksAction = this.removeStacksAction.bind(this); this.removeStacksActionAsync = this.removeStacksActionAsync.bind(this); this.onPublishingModeClick = this.onPublishingModeClick.bind(this); this.onChangeNamespaceDropdown = this.onChangeNamespaceDropdown.bind(this); this.setSystemResources = this.setSystemResources.bind(this); } selectTab(index) { this.LocalStorage.storeActiveTab('applications', index); } async removeStacksActionAsync(selectedItems) { let actionCount = selectedItems.length; for (const stack of selectedItems) { try { const isAppFormCreated = stack.Applications.some((x) => !x.ApplicationKind); if (isAppFormCreated) { const promises = _.map(stack.Applications, (app) => this.KubernetesApplicationService.delete(app)); await Promise.all(promises); } else { const application = stack.Applications.find((x) => x.StackId !== null); if (application && application.StackId) { await this.StackService.remove({ Id: application.StackId }, false, this.endpoint.Id); } } this.Notifications.success('Stack successfully removed', stack.Name); _.remove(this.state.stacks, { Name: stack.Name }); } catch (err) { this.Notifications.error('Failure', err, 'Unable to remove stack'); } finally { --actionCount; if (actionCount === 0) { this.$state.reload(this.$state.current); } } } } removeStacksAction(selectedItems) { confirmDelete('Are you sure that you want to remove the selected stack(s) ? This will remove all the applications associated to the stack(s).').then((confirmed) => { if (confirmed) { return this.$async(this.removeStacksActionAsync, selectedItems); } }); } async removeActionAsync(selectedItems) { let actionCount = selectedItems.length; for (const application of selectedItems) { try { if (application.ApplicationType === KubernetesApplicationTypes.HELM) { await this.HelmService.uninstall(this.endpoint.Id, application); } else { await this.KubernetesApplicationService.delete(application); if (application.Metadata.labels[KubernetesPortainerApplicationStackNameLabel]) { // Update applications in stack const stack = this.state.stacks.find((x) => x.Name === application.StackName); const index = stack.Applications.indexOf(application); stack.Applications.splice(index, 1); // remove stack if no app left in the stack if (stack.Applications.length === 0 && application.StackId) { await this.StackService.remove({ Id: application.StackId }, false, this.endpoint.Id); } } } this.Notifications.success('Application successfully removed', application.Name); const index = this.state.applications.indexOf(application); this.state.applications.splice(index, 1); } catch (err) { this.Notifications.error('Failure', err, 'Unable to remove application'); } finally { --actionCount; if (actionCount === 0) { this.$state.reload(this.$state.current); } } } } removeAction(selectedItems) { confirmDelete('Do you want to remove the selected application(s)?').then((confirmed) => { if (confirmed) { return this.$async(this.removeActionAsync, selectedItems); } }); } onPublishingModeClick(application) { this.state.activeTab = 1; _.forEach(this.state.ports, (item) => { item.Expanded = false; item.Highlighted = false; if (item.Name === application.Name && item.Ports.length > 1) { item.Expanded = true; item.Highlighted = true; } }); } onChangeNamespaceDropdown(namespace) { this.state.namespace = namespace; this.getApplicationsAsync(); } async getApplicationsAsync() { try { const [applications, configurations] = await Promise.all([ this.KubernetesApplicationService.get(this.state.namespace), this.KubernetesConfigurationService.get(this.state.namespace), ]); const configuredApplications = KubernetesConfigurationHelper.getApplicationConfigurations(applications, configurations); const { helmApplications, nonHelmApplications } = KubernetesApplicationHelper.getNestedApplications(configuredApplications); this.state.applications = [...helmApplications, ...nonHelmApplications]; this.state.stacks = KubernetesStackHelper.stacksFromApplications(applications); this.state.ports = KubernetesApplicationHelper.portMappingsFromApplications(applications); this.$scope.$apply(); } catch (err) { this.Notifications.error('Failure', err, 'Unable to retrieve applications'); } } setSystemResources(flag) { this.state.isSystemResources = flag; } getApplications() { return this.$async(this.getApplicationsAsync); } async onInit() { this.state = { activeTab: this.LocalStorage.getActiveTab('applications'), currentName: this.$state.$current.name, isAdmin: this.Authentication.isAdmin(), viewReady: false, applications: [], stacks: [], ports: [], namespaces: [], namespace: '', isSystemResources: undefined, }; this.state.namespaces = await this.KubernetesNamespaceService.get(); this.state.namespaces = this.state.namespaces.filter((n) => n.Status === 'Active'); this.state.namespaces = _.sortBy(this.state.namespaces, 'Name'); this.state.namespace = this.state.namespaces.length ? (this.state.namespaces.find((n) => n.Name === 'default') ? 'default' : this.state.namespaces[0].Name) : ''; await this.getApplications(); this.state.viewReady = true; } $onInit() { return this.$async(this.onInit); } $onDestroy() { if (this.state.currentName !== this.$state.$current.name) { this.LocalStorage.storeActiveTab('applications', 0); } } } export default KubernetesApplicationsController; angular.module('portainer.kubernetes').controller('KubernetesApplicationsController', KubernetesApplicationsController);