hunk.code_window:       apiService = this.KubernetesDeploymentService;
       } else if (app.ApplicationType === KubernetesApplicationTypes.DaemonSet) {
         apiService = this.KubernetesDaemonSetService;
       } else if (app.ApplicationType === KubernetesApplicationTypes.StatefulSet) {
         apiService = this.KubernetesStatefulSetService;
       } else if (app.ApplicationType === KubernetesApplicationTypes.Pod) {
         apiService = this.KubernetesPodService;
       } else {
         throw new PortainerError('Unable to determine which association to use to retrieve API Service');
       }
  
hunk.labels: keep keep keep keep keep replace keep keep keep keep
hunk.after_edit:     } else if (app instanceof KubernetesPod || (app instanceof KubernetesApplication && app.ApplicationType === KubernetesApplicationTypes.Pod)) {
  
hunk.file_path: app/kubernetes/services/applicationService.js
hunk.type: replace
file: import _ from 'lodash-es';
  import angular from 'angular';
  import PortainerError from 'Portainer/error';
  
  import KubernetesApplicationHelper from 'Kubernetes/helpers/application';
  import KubernetesApplicationConverter from 'Kubernetes/converters/application';
  import { KubernetesStatefulSet } from 'Kubernetes/models/stateful-set/models';
  import KubernetesServiceHelper from 'Kubernetes/helpers/serviceHelper';
  import { KubernetesHorizontalPodAutoScalerHelper } from 'Kubernetes/horizontal-pod-auto-scaler/helper';
  import { KubernetesHorizontalPodAutoScalerConverter } from 'Kubernetes/horizontal-pod-auto-scaler/converter';
  import KubernetesPodConverter from 'Kubernetes/pod/converter';
  import { notifyError } from '@/portainer/services/notifications';
  import { KubernetesIngressConverter } from 'Kubernetes/ingress/converter';
  import { generateNewIngressesFromFormPaths } from '@/react/kubernetes/applications/CreateView/application-services/utils';
  import { KubernetesApplicationDeploymentTypes, KubernetesApplicationTypes } from 'Kubernetes/models/application/models/appConstants';
  
  class KubernetesApplicationService {
    /* #region  CONSTRUCTOR */
    /* @ngInject */
    constructor(
      $async,
      Authentication,
      KubernetesDeploymentService,
      KubernetesDaemonSetService,
      KubernetesStatefulSetService,
      KubernetesServiceService,
      KubernetesSecretService,
      KubernetesPersistentVolumeClaimService,
      KubernetesNamespaceService,
      KubernetesPodService,
      KubernetesHorizontalPodAutoScalerService,
      KubernetesIngressService
    ) {
      this.$async = $async;
      this.Authentication = Authentication;
      this.KubernetesDeploymentService = KubernetesDeploymentService;
      this.KubernetesDaemonSetService = KubernetesDaemonSetService;
      this.KubernetesStatefulSetService = KubernetesStatefulSetService;
      this.KubernetesServiceService = KubernetesServiceService;
      this.KubernetesSecretService = KubernetesSecretService;
      this.KubernetesPersistentVolumeClaimService = KubernetesPersistentVolumeClaimService;
      this.KubernetesNamespaceService = KubernetesNamespaceService;
      this.KubernetesPodService = KubernetesPodService;
      this.KubernetesHorizontalPodAutoScalerService = KubernetesHorizontalPodAutoScalerService;
      this.KubernetesIngressService = KubernetesIngressService;
  
      this.getAsync = this.getAsync.bind(this);
      this.getAllAsync = this.getAllAsync.bind(this);
      this.createAsync = this.createAsync.bind(this);
      this.patchAsync = this.patchAsync.bind(this);
      this.patchPartialAsync = this.patchPartialAsync.bind(this);
      this.deleteAsync = this.deleteAsync.bind(this);
    }
    /* #endregion */
  
    /* #region  UTILS */
    _getApplicationApiService(app) {
      let apiService;
      if (app.ApplicationType === KubernetesApplicationTypes.Deployment) {
        apiService = this.KubernetesDeploymentService;
      } else if (app.ApplicationType === KubernetesApplicationTypes.DaemonSet) {
        apiService = this.KubernetesDaemonSetService;
      } else if (app.ApplicationType === KubernetesApplicationTypes.StatefulSet) {
        apiService = this.KubernetesStatefulSetService;
      } else if (app.ApplicationType === KubernetesApplicationTypes.Pod) {
        apiService = this.KubernetesPodService;
      } else {
        throw new PortainerError('Unable to determine which association to use to retrieve API Service');
      }
      return apiService;
    }
  
    _generateIngressPatchPromises(oldIngresses, newIngresses) {
      return _.map(newIngresses, (newIng) => {
        const oldIng = _.find(oldIngresses, { Name: newIng.Name });
        return this.KubernetesIngressService.patch(oldIng, newIng);
      });
    }
    /* #endregion */
  
    /* #region  GET */
    async getAsync(namespace, name) {
      const [deployment, daemonSet, statefulSet, pod, pods, autoScalers, ingresses] = await Promise.allSettled([
        this.KubernetesDeploymentService.get(namespace, name),
        this.KubernetesDaemonSetService.get(namespace, name),
        this.KubernetesStatefulSetService.get(namespace, name),
        this.KubernetesPodService.get(namespace, name),
        this.KubernetesPodService.get(namespace),
        this.KubernetesHorizontalPodAutoScalerService.get(namespace),
        this.KubernetesIngressService.get(namespace),
      ]);
  
      let rootItem;
      let converterFunc;
      if (deployment.status === 'fulfilled') {
        rootItem = deployment;
        converterFunc = KubernetesApplicationConverter.apiDeploymentToApplication;
      } else if (daemonSet.status === 'fulfilled') {
        rootItem = daemonSet;
        converterFunc = KubernetesApplicationConverter.apiDaemonSetToApplication;
      } else if (statefulSet.status === 'fulfilled') {
        rootItem = statefulSet;
        converterFunc = KubernetesApplicationConverter.apiStatefulSetToapplication;
      } else if (pod.status === 'fulfilled') {
        rootItem = pod;
        converterFunc = KubernetesApplicationConverter.apiPodToApplication;
      } else {
        throw new PortainerError('Unable to determine which association to use to convert application');
      }
  
      const services = await this.KubernetesServiceService.get(namespace);
      const boundService = KubernetesServiceHelper.findApplicationBoundService(services, rootItem.value.Raw);
      const service = boundService ? await this.KubernetesServiceService.get(namespace, boundService.metadata.name) : {};
      const boundServices = KubernetesServiceHelper.findApplicationBoundServices(services, rootItem.value.Raw);
  
      const application = converterFunc(rootItem.value.Raw, pods.value, service.Raw, ingresses.value);
      application.Yaml = rootItem.value.Yaml;
      application.Raw = rootItem.value.Raw;
      application.Pods = _.map(application.Pods, (item) => KubernetesPodConverter.apiToModel(item));
      application.Containers = KubernetesApplicationHelper.associateContainersAndApplication(application);
      application.Services = boundServices;
  
      const boundScaler = KubernetesHorizontalPodAutoScalerHelper.findApplicationBoundScaler(autoScalers.value, application);
      const scaler = boundScaler ? await this.KubernetesHorizontalPodAutoScalerService.get(namespace, boundScaler.Name) : undefined;
      application.AutoScaler = scaler;
  
      if (service.Yaml) {
        application.Yaml += '---\n' + service.Yaml;
      }
      if (scaler && scaler.Yaml) {
        application.Yaml += '---\n' + scaler.Yaml;
      }
      // TODO: refactor @LP
      // append ingress yaml ?
      return application;
    }
  
    async getAllAsync(namespace) {
      const namespaces = namespace ? [namespace] : _.map(await this.KubernetesNamespaceService.get(), 'Name');
  
      const convertToApplication = (item, converterFunc, services, pods, ingresses) => {
        const service = KubernetesServiceHelper.findApplicationBoundService(services, item);
        const servicesFound = KubernetesServiceHelper.findApplicationBoundServices(services, item);
        const application = converterFunc(item, pods, service, ingresses);
        application.Containers = KubernetesApplicationHelper.associateContainersAndApplication(application);
        application.Services = servicesFound;
        return application;
      };
  
      const res = await Promise.all(
        _.map(namespaces, async (ns) => {
          const [deployments, daemonSets, statefulSets, services, pods, ingresses, autoScalers] = await Promise.all([
            this.KubernetesDeploymentService.get(ns),
            this.KubernetesDaemonSetService.get(ns),
            this.KubernetesStatefulSetService.get(ns),
            this.KubernetesServiceService.get(ns),
            this.KubernetesPodService.get(ns),
            this.KubernetesIngressService.get(ns),
            this.KubernetesHorizontalPodAutoScalerService.get(ns),
          ]);
  
          const deploymentApplications = _.map(deployments, (item) =>
            convertToApplication(item, KubernetesApplicationConverter.apiDeploymentToApplication, services, pods, ingresses)
          );
          const daemonSetApplications = _.map(daemonSets, (item) => convertToApplication(item, KubernetesApplicationConverter.apiDaemonSetToApplication, services, pods, ingresses));
          const statefulSetApplications = _.map(statefulSets, (item) =>
            convertToApplication(item, KubernetesApplicationConverter.apiStatefulSetToapplication, services, pods, ingresses)
          );
  
          const boundPods = _.concat(_.flatMap(deploymentApplications, 'Pods'), _.flatMap(daemonSetApplications, 'Pods'), _.flatMap(statefulSetApplications, 'Pods'));
          const unboundPods = _.without(pods, ...boundPods);
          const nakedPodsApplications = _.map(unboundPods, (item) => convertToApplication(item, KubernetesApplicationConverter.apiPodToApplication, services, pods, ingresses));
  
          const applications = _.concat(deploymentApplications, daemonSetApplications, statefulSetApplications, nakedPodsApplications);
          _.forEach(applications, (app) => {
            app.Pods = _.map(app.Pods, (item) => KubernetesPodConverter.apiToModel(item));
          });
          await Promise.all(
            _.forEach(applications, async (application) => {
              const boundScaler = KubernetesHorizontalPodAutoScalerHelper.findApplicationBoundScaler(autoScalers, application);
              const scaler = boundScaler ? await this.KubernetesHorizontalPodAutoScalerService.get(ns, boundScaler.Name) : undefined;
              application.AutoScaler = scaler;
            })
          );
          return applications;
        })
      );
      return _.flatten(res);
    }
  
    get(namespace, name) {
      if (name) {
        return this.$async(this.getAsync, namespace, name);
      }
      return this.$async(this.getAllAsync, namespace);
    }
    /* #endregion */
  
    /* #region  CREATE */
    // TODO: review
    // resource creation flow
    // should we keep formValues > Resource_1 || Resource_2
    // or should we switch to formValues > Composite > Resource_1 || Resource_2
    /**
     * NOTE: Keep this method flow in sync with `getCreatedApplicationResources` method in the `applicationService` file
     *    To synchronise with kubernetes resource creation summary output, any new resources created in this method should
     *    also be displayed in the summary output (getCreatedApplicationResources)
     */
    async createAsync(formValues, hideStacks) {
      // formValues -> Application
      let [app, headlessService, services, , claims] = KubernetesApplicationConverter.applicationFormValuesToApplication(formValues);
  
      if (hideStacks) {
        app.StackName = '';
      }
  
      if (services) {
        services.forEach(async (service) => {
          try {
            await this.KubernetesServiceService.create(service);
          } catch (error) {
            notifyError('Unable to create service', error);
          }
        });
  
        try {
          //Generate all ingresses from current form by passing services object
          const newServicePorts = formValues.Services.flatMap((service) => service.Ports);
          const newIngresses = generateNewIngressesFromFormPaths(formValues.OriginalIngresses, newServicePorts);
          if (newIngresses) {
            //Update original ingress with current ingress
            await Promise.all(this._generateIngressPatchPromises(formValues.OriginalIngresses, newIngresses));
          }
        } catch (error) {
          notifyError('Unable to update service', error);
        }
      }
  
      const apiService = this._getApplicationApiService(app);
  
      if (app instanceof KubernetesStatefulSet) {
        app.VolumeClaims = claims;
        try {
          headlessService = await this.KubernetesServiceService.create(headlessService);
        } catch (error) {
          notifyError('Unable to create service', error);
        }
        app.ServiceName = headlessService.metadata.name;
      } else {
        const claimPromises = _.map(claims, (item) => {
          if (!item.PreviousName && !item.Id) {
            return this.KubernetesPersistentVolumeClaimService.create(item);
          }
        });
        await Promise.all(_.without(claimPromises, undefined));
      }
  
      if (formValues.AutoScaler.isUsed && formValues.DeploymentType !== KubernetesApplicationDeploymentTypes.Global) {
        const kind = app.ApplicationType;
        const autoScaler = KubernetesHorizontalPodAutoScalerConverter.applicationFormValuesToModel(formValues, kind);
        await this.KubernetesHorizontalPodAutoScalerService.create(autoScaler);
      }
  
      await apiService.create(app);
    }
  
    create(formValues, _, hideStacks) {
      return this.$async(this.createAsync, formValues, hideStacks);
    }
    /* #endregion */
  
    /* #region  PATCH */
    // this function accepts KubernetesApplicationFormValues as parameters
    /**
     * NOTE: Keep this method flow in sync with `getUpdatedApplicationResources` method in the `applicationService` file
     *    To synchronise with kubernetes resource creation, update and delete summary output, any new resources created
     *    in this method should also be displayed in the summary output (getUpdatedApplicationResources)
     */
    async patchAsync(oldFormValues, newFormValues, originalServicePorts) {
      const [oldApp, oldHeadlessService, oldServices, , oldClaims] = KubernetesApplicationConverter.applicationFormValuesToApplication(oldFormValues);
      const [newApp, newHeadlessService, newServices, , newClaims] = KubernetesApplicationConverter.applicationFormValuesToApplication(newFormValues);
      const oldApiService = this._getApplicationApiService(oldApp);
      const newApiService = this._getApplicationApiService(newApp);
  
      if (oldApiService !== newApiService) {
        // delete services first
        if (oldServices) {
          await this.KubernetesServiceService.delete(oldServices);
        }
  
        // delete the app
        await this.delete(oldApp);
  
        // sleep for 5 seconds to allow the app/services to be deleted
        await new Promise((r) => setTimeout(r, 5000));
  
        // create the app
        return await this.create(newFormValues);
      }
  
      if (newApp instanceof KubernetesStatefulSet) {
        try {
          await this.KubernetesServiceService.patch(oldHeadlessService, newHeadlessService);
        } catch (error) {
          notifyError('Unable to update service', error);
        }
      } else {
        const claimPromises = _.map(newClaims, (newClaim) => {
          if (!newClaim.PreviousName && !newClaim.Id) {
            return this.KubernetesPersistentVolumeClaimService.create(newClaim);
          } else if (!newClaim.Id) {
            const oldClaim = _.find(oldClaims, { Name: newClaim.PreviousName });
            return this.KubernetesPersistentVolumeClaimService.patch(oldClaim, newClaim);
          }
        });
        await Promise.all(claimPromises);
      }
  
      await newApiService.patch(oldApp, newApp);
  
      // Create services
      if (oldServices.length === 0 && newServices.length !== 0) {
        newServices.forEach(async (service) => {
          try {
            await this.KubernetesServiceService.create(service);
          } catch (error) {
            notifyError('Unable to create service', error);
          }
        });
      }
  
      // Delete services ( only called when all services been deleted )
      if (oldServices.length !== 0 && newServices.length === 0) {
        await this.KubernetesServiceService.deleteAll(oldServices);
      }
  
      // Patch services ( Action including: Delete, Update, Create )
      if (oldServices.length !== 0 && newServices.length !== 0) {
        oldServices.forEach(async (oldService) => {
          const newServiceMatched = _.find(newServices, { Name: oldService.Name });
          if (!newServiceMatched) {
            await this.KubernetesServiceService.deleteSingle(oldService);
          }
        });
  
        newServices.forEach(async (newService) => {
          const oldServiceMatched = _.find(oldServices, { Name: newService.Name });
          if (oldServiceMatched) {
            try {
              await this.KubernetesServiceService.patch(oldServiceMatched, newService);
            } catch (error) {
              notifyError('Unable to update service', error);
            }
          } else {
            try {
              await this.KubernetesServiceService.create(newService);
            } catch (error) {
              notifyError('Unable to create service', error);
            }
          }
        });
      }
  
      // Update ingresses
      if (newServices) {
        try {
          //Generate all ingresses from current form by passing services object
          const newServicePorts = newFormValues.Services.flatMap((service) => service.Ports);
          const newIngresses = generateNewIngressesFromFormPaths(newFormValues.OriginalIngresses, newServicePorts, originalServicePorts);
          if (newIngresses) {
            //Update original ingress with current ingress
            await Promise.all(this._generateIngressPatchPromises(newFormValues.OriginalIngresses, newIngresses));
          }
        } catch (error) {
          notifyError('Unable to update service', error);
        }
      }
  
      const newKind = newApp.ApplicationType;
      const newAutoScaler = KubernetesHorizontalPodAutoScalerConverter.applicationFormValuesToModel(newFormValues, newKind);
      if (!oldFormValues.AutoScaler.isUsed) {
        if (newFormValues.AutoScaler.isUsed) {
          await this.KubernetesHorizontalPodAutoScalerService.create(newAutoScaler);
        }
      } else {
        const oldKind = oldApp.ApplicationType;
        const oldAutoScaler = KubernetesHorizontalPodAutoScalerConverter.applicationFormValuesToModel(oldFormValues, oldKind);
        if (newFormValues.AutoScaler.isUsed) {
          await this.KubernetesHorizontalPodAutoScalerService.patch(oldAutoScaler, newAutoScaler);
        } else {
          await this.KubernetesHorizontalPodAutoScalerService.delete(oldAutoScaler);
        }
      }
    }
  
    // this function accepts KubernetesApplication as parameters
    async patchPartialAsync(oldApp, newApp) {
      const oldAppPayload = {
        Name: oldApp.Name,
        Namespace: oldApp.ResourcePool,
        StackName: oldApp.StackName,
        Note: oldApp.Note,
      };
      const newAppPayload = {
        Name: newApp.Name,
        Namespace: newApp.ResourcePool,
        StackName: newApp.StackName,
        Note: newApp.Note,
      };
      const apiService = this._getApplicationApiService(oldApp);
      await apiService.patch(oldAppPayload, newAppPayload);
    }
  
    // accept either formValues or applications as parameters depending on partial value
    // true = KubernetesApplication
    // false = KubernetesApplicationFormValues
    //
    // e.g. signatures are
    //
    // patch(oldValues: KubernetesApplication, newValues: KubernetesApplication, partial: (undefined | false)): Promise<unknown>
    // patch(oldValues: KubernetesApplicationFormValues, newValues: KubernetesApplicationFormValues, partial: true): Promise<unknown>
    patch(oldValues, newValues, partial = false, originalServicePorts) {
      if (partial) {
        return this.$async(this.patchPartialAsync, oldValues, newValues);
      }
      return this.$async(this.patchAsync, oldValues, newValues, originalServicePorts);
    }
    /* #endregion */
  
    /* #region  DELETE */
    async deleteAsync(application) {
      const payload = {
        Namespace: application.ResourcePool || application.Namespace,
        Name: application.Name,
      };
      const servicePayload = angular.copy(payload);
      servicePayload.Name = application.Name;
  
      const apiService = this._getApplicationApiService(application);
      await apiService.delete(payload);
  
      if (apiService === this.KubernetesStatefulSetService) {
        const headlessServicePayload = angular.copy(payload);
        headlessServicePayload.Name = application instanceof KubernetesStatefulSet ? application.ServiceName : application.HeadlessServiceName;
      }
  
      if (application.ServiceType) {
        // delete headless service && non-headless service
        await this.KubernetesServiceService.delete(application.Services);
        const appHasIngressPath = application.PublishedPorts && application.PublishedPorts.flatMap((pp) => pp.IngressRules).length >= 1;
        if (appHasIngressPath) {
          const originalIngresses = await this.KubernetesIngressService.get(payload.Namespace);
          const formValues = {
            OriginalIngresses: originalIngresses,
            PublishedPorts: KubernetesApplicationHelper.generatePublishedPortsFormValuesFromPublishedPorts(application.ServiceType, application.PublishedPorts),
          };
          const ingresses = KubernetesIngressConverter.applicationFormValuesToDeleteIngresses(formValues, application);
  
          await Promise.all(this._generateIngressPatchPromises(formValues.OriginalIngresses, ingresses));
        }
      }
      if (!_.isEmpty(application.AutoScaler)) {
        await this.KubernetesHorizontalPodAutoScalerService.delete(application.AutoScaler);
      }
    }
  
    delete(application) {
      return this.$async(this.deleteAsync, application);
    }
    /* #endregion */
  }
  
  export default KubernetesApplicationService;
  angular.module('portainer.kubernetes').service('KubernetesApplicationService', KubernetesApplicationService);
  