From c752b98120647eacca97598884ba4d31734403b6 Mon Sep 17 00:00:00 2001 From: Ali <83188384+testA113@users.noreply.github.com> Date: Mon, 10 Jul 2023 16:20:22 +1200 Subject: [PATCH] fix(app): fix app ingress edge cases [EE-5663] (#9150) Co-authored-by: testa113 --- .../create/createApplicationController.js | 12 +++++++++- .../cluster-ip/ClusterIpServiceForm.tsx | 2 +- .../components/ContainerPortInput.tsx | 2 +- .../ingress/AppIngressPathForm.tsx | 24 +++++++++++++++---- .../ingress/AppIngressPathsForm.tsx | 10 ++++++-- .../CreateView/application-services/utils.ts | 4 +++- 6 files changed, 44 insertions(+), 10 deletions(-) diff --git a/app/kubernetes/views/applications/create/createApplicationController.js b/app/kubernetes/views/applications/create/createApplicationController.js index fcfff49ed..e03316bf9 100644 --- a/app/kubernetes/views/applications/create/createApplicationController.js +++ b/app/kubernetes/views/applications/create/createApplicationController.js @@ -512,6 +512,17 @@ class KubernetesCreateApplicationController { /* #region SERVICES UI MANAGEMENT */ onServicesChange(services) { return this.$async(async () => { + // if the ingress isn't found in the currently loaded ingresses, then refresh the ingresses + const ingressNamesUsed = services.flatMap((s) => s.Ports.flatMap((p) => (p.ingressPaths ? p.ingressPaths.flatMap((ip) => ip.IngressName || []) : []))); + if (ingressNamesUsed.length) { + const uniqueIngressNamesUsed = Array.from(new Set(ingressNamesUsed)); // get the unique ingress names used + const ingressNamesLoaded = this.ingresses.map((i) => i.Name); + const areAllIngressesLoaded = uniqueIngressNamesUsed.every((ingressNameUsed) => ingressNamesLoaded.includes(ingressNameUsed)); + if (!areAllIngressesLoaded) { + this.refreshIngresses(); + } + } + // update the services this.formValues.Services = services; }); } @@ -1127,7 +1138,6 @@ class KubernetesCreateApplicationController { this.nodesLabels, this.ingresses ); - this.originalServicePorts = structuredClone(this.formValues.Services.flatMap((service) => service.Ports)); this.originalIngressPaths = structuredClone(this.originalServicePorts.flatMap((port) => port.ingressPaths).filter((ingressPath) => ingressPath.Host)); diff --git a/app/react/kubernetes/applications/CreateView/application-services/cluster-ip/ClusterIpServiceForm.tsx b/app/react/kubernetes/applications/CreateView/application-services/cluster-ip/ClusterIpServiceForm.tsx index 56ee950c9..45f57c7e0 100644 --- a/app/react/kubernetes/applications/CreateView/application-services/cluster-ip/ClusterIpServiceForm.tsx +++ b/app/react/kubernetes/applications/CreateView/application-services/cluster-ip/ClusterIpServiceForm.tsx @@ -79,7 +79,7 @@ export function ClusterIpServiceForm({ return (
-
+
) => void; + value?: number; }; export function ContainerPortInput({ diff --git a/app/react/kubernetes/applications/CreateView/application-services/ingress/AppIngressPathForm.tsx b/app/react/kubernetes/applications/CreateView/application-services/ingress/AppIngressPathForm.tsx index c9f8498ba..0676cf1cf 100644 --- a/app/react/kubernetes/applications/CreateView/application-services/ingress/AppIngressPathForm.tsx +++ b/app/react/kubernetes/applications/CreateView/application-services/ingress/AppIngressPathForm.tsx @@ -63,13 +63,29 @@ export function AppIngressPathForm({ isEditMode, ]); - // when the hostname options change (e.g. after a namespace change), update the selected ingress to the first available one + // when the hostname options change (e.g. after a namespace change) and the host and ingress is no longer available, update the selected ingress to the first available one useEffect(() => { if (ingressHostOptionsWithCurrentValue) { + // some rerenders might not be from a namespace or hostname change so keep the current values if they're still valid + const ingressHosts = ingressHostOptionsWithCurrentValue.map( + (i) => i.value + ); + const newIngressHostValue = ingressHosts.includes(ingressPath?.Host ?? '') + ? ingressPath?.Host + : ingressHosts[0] ?? ''; + const ingressNames = ingressHostOptionsWithCurrentValue.map( + (i) => i.ingressName + ); + const newIngressNameValue = ingressNames.includes( + ingressPath?.IngressName ?? '' + ) + ? ingressPath?.IngressName ?? '' + : ingressNames[0] ?? ''; + const newIngressPath = { ...ingressPath, - Host: ingressHostOptionsWithCurrentValue[0]?.value, - IngressName: ingressHostOptionsWithCurrentValue[0]?.ingressName, + Host: newIngressHostValue, + IngressName: newIngressNameValue, }; onChangeIngressPath(newIngressPath); setSelectedIngress(ingressHostOptionsWithCurrentValue[0] ?? null); @@ -78,7 +94,7 @@ export function AppIngressPathForm({ }, [ingressHostOptionsWithCurrentValue]); return ( -
+
Hostname diff --git a/app/react/kubernetes/applications/CreateView/application-services/ingress/AppIngressPathsForm.tsx b/app/react/kubernetes/applications/CreateView/application-services/ingress/AppIngressPathsForm.tsx index db3e4b566..f97c5bb63 100644 --- a/app/react/kubernetes/applications/CreateView/application-services/ingress/AppIngressPathsForm.tsx +++ b/app/react/kubernetes/applications/CreateView/application-services/ingress/AppIngressPathsForm.tsx @@ -1,4 +1,4 @@ -import { Plus } from 'lucide-react'; +import { Loader2, Plus } from 'lucide-react'; import { FormikErrors } from 'formik'; import { useMemo } from 'react'; @@ -13,6 +13,7 @@ import { Button } from '@@/buttons'; import { SwitchField } from '@@/form-components/SwitchField'; import { TextTip } from '@@/Tip/TextTip'; import { Link } from '@@/Link'; +import { Icon } from '@@/Icon'; import { ServicePortIngressPath } from '../types'; @@ -75,7 +76,12 @@ export function AppIngressPathsForm({ } if (ingressesQuery.isLoading || ingressControllersQuery.isLoading) { - return

Loading ingresses...

; + return ( +

+ + Loading ingresses... +

+ ); } return ( diff --git a/app/react/kubernetes/applications/CreateView/application-services/utils.ts b/app/react/kubernetes/applications/CreateView/application-services/utils.ts index 5d3b4f379..7e8747088 100644 --- a/app/react/kubernetes/applications/CreateView/application-services/utils.ts +++ b/app/react/kubernetes/applications/CreateView/application-services/utils.ts @@ -154,6 +154,8 @@ export function generateNewIngressesFromFormPaths( return newIngresses; } +/** prependWithSlash puts a '/' in front of a string if there isn't one there already. If the string is empty, it stays empty */ export function prependWithSlash(path?: string) { - return path?.startsWith('/') ? path : `/${path}`; + if (!path) return ''; + return path.startsWith('/') ? path : `/${path}`; }