fix(ingress): ingress ui feedback [EE-5852] (#9982)

Co-authored-by: testa113 <testa113>
pull/9986/head
Ali 2023-08-03 23:03:09 +12:00 committed by GitHub
parent 9845518aa9
commit acf9203580
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 157 additions and 88 deletions

View File

@ -199,7 +199,7 @@ export function IngressClassDatatable({
</p> </p>
<ul className="ml-6"> <ul className="ml-6">
{usedControllersToDisallow.map((controller) => ( {usedControllersToDisallow.map((controller) => (
<li key={controller.ClassName}>${controller.ClassName}</li> <li key={controller.ClassName}>{controller.ClassName}</li>
))} ))}
</ul> </ul>
<p> <p>

View File

@ -66,10 +66,8 @@ export function CreateIngressView() {
environmentId, environmentId,
namespaces ? Object.keys(namespaces || {}) : [] namespaces ? Object.keys(namespaces || {}) : []
); );
const ingressControllersQuery = useIngressControllers( const { data: ingressControllers, ...ingressControllersQuery } =
environmentId, useIngressControllers(environmentId, namespace);
namespace
);
const createIngressMutation = useCreateIngress(); const createIngressMutation = useCreateIngress();
const updateIngressMutation = useUpdateIngress(); const updateIngressMutation = useUpdateIngress();
@ -171,39 +169,84 @@ export function CreateIngressView() {
const existingIngressClass = useMemo( const existingIngressClass = useMemo(
() => () =>
ingressControllersQuery.data?.find( ingressControllers?.find(
(i) => (controller) =>
i.ClassName === ingressRule.IngressClassName || controller.ClassName === ingressRule.IngressClassName ||
(i.Type === 'custom' && ingressRule.IngressClassName === '') (controller.Type === 'custom' && ingressRule.IngressClassName === '')
), ),
[ingressControllersQuery.data, ingressRule.IngressClassName] [ingressControllers, ingressRule.IngressClassName]
); );
const ingressClassOptions: Option<string>[] = useMemo( const ingressClassOptions: Option<string>[] = useMemo(() => {
() => const allowedIngressClassOptions =
ingressControllersQuery.data ingressControllers
?.filter((cls) => cls.Availability) ?.filter((controller) => !!controller.Availability)
.map((cls) => ({ .map((cls) => ({
label: cls.ClassName, label: cls.ClassName,
value: cls.ClassName, value: cls.ClassName,
})) || [], })) || [];
[ingressControllersQuery.data]
// if the ingress class is not set, return only the allowed ingress classes
if (ingressRule.IngressClassName === '' || !isEdit) {
return allowedIngressClassOptions;
}
// if the ingress class is set and it exists (even if disallowed), return the allowed ingress classes + the disallowed option
const disallowedIngressClasses =
ingressControllers
?.filter(
(controller) =>
!controller.Availability &&
existingIngressClass?.ClassName === controller.ClassName
)
.map((controller) => ({
label: `${controller.ClassName} - DISALLOWED`,
value: controller.ClassName,
})) || [];
const existingIngressClassFound = ingressControllers?.find(
(controller) => existingIngressClass?.ClassName === controller.ClassName
);
if (existingIngressClassFound) {
return [...allowedIngressClassOptions, ...disallowedIngressClasses];
}
// if the ingress class is set and it doesn't exist, return the allowed ingress classes + the not found option
const notFoundIngressClassOption = {
label: `${ingressRule.IngressClassName} - NOT FOUND`,
value: ingressRule.IngressClassName || '',
};
return [...allowedIngressClassOptions, notFoundIngressClassOption];
}, [
existingIngressClass?.ClassName,
ingressControllers,
ingressRule.IngressClassName,
isEdit,
]);
const handleIngressChange = useCallback(
(key: string, val: string) => {
setIngressRule((prevRules) => {
const rule = { ...prevRules, [key]: val };
if (key === 'IngressClassName') {
rule.IngressType = ingressControllers?.find(
(c) => c.ClassName === val
)?.Type;
}
return rule;
});
},
[ingressControllers]
); );
if ( // when the ingress class options update the value to an available one
(!existingIngressClass || useEffect(() => {
(existingIngressClass && !existingIngressClass.Availability)) && const ingressClasses = ingressClassOptions.map((option) => option.value);
ingressRule.IngressClassName && if (!ingressClasses.includes(ingressRule.IngressClassName)) {
!ingressControllersQuery.isLoading // setting to the first available option (or undefined when there are no options)
) { handleIngressChange('IngressClassName', ingressClasses[0]);
const optionLabel = !ingressRule.IngressType }
? `${ingressRule.IngressClassName} - NOT FOUND` }, [handleIngressChange, ingressClassOptions, ingressRule.IngressClassName]);
: `${ingressRule.IngressClassName} - DISALLOWED`;
ingressClassOptions.push({
label: optionLabel,
value: ingressRule.IngressClassName,
});
}
const matchedConfigs = configResults?.data?.filter( const matchedConfigs = configResults?.data?.filter(
(config) => (config) =>
@ -234,7 +277,7 @@ export function CreateIngressView() {
(ing) => ing.Name === params.name && ing.Namespace === params.namespace (ing) => ing.Name === params.name && ing.Namespace === params.namespace
); );
if (ing) { if (ing) {
const type = ingressControllersQuery.data?.find( const type = ingressControllers?.find(
(c) => (c) =>
c.ClassName === ing.ClassName || c.ClassName === ing.ClassName ||
(c.Type === 'custom' && !ing.ClassName) (c.Type === 'custom' && !ing.ClassName)
@ -248,7 +291,7 @@ export function CreateIngressView() {
}, [ }, [
params.name, params.name,
ingressesResults.data, ingressesResults.data,
ingressControllersQuery.data, ingressControllers,
ingressRule.IngressName, ingressRule.IngressName,
params.namespace, params.namespace,
]); ]);
@ -559,18 +602,6 @@ export function CreateIngressView() {
} }
} }
function handleIngressChange(key: string, val: string) {
setIngressRule((prevRules) => {
const rule = { ...prevRules, [key]: val };
if (key === 'IngressClassName') {
rule.IngressType = ingressControllersQuery.data?.find(
(c) => c.ClassName === val
)?.Type;
}
return rule;
});
}
function handleTLSChange(hostIndex: number, tls: string) { function handleTLSChange(hostIndex: number, tls: string) {
setIngressRule((prevRules) => { setIngressRule((prevRules) => {
const rule = { ...prevRules }; const rule = { ...prevRules };

View File

@ -119,17 +119,6 @@ export function IngressForm({
} }
}, [namespacesOptions, namespace, handleNamespaceChange]); }, [namespacesOptions, namespace, handleNamespaceChange]);
// when the ingress class options update update the value to an available one
useEffect(() => {
const ingressClasses = ingressClassOptions.map((option) => option.value);
if (
!ingressClasses.includes(rule.IngressClassName) &&
ingressClasses.length > 0
) {
handleIngressChange('IngressClassName', ingressClasses[0]);
}
}, [ingressClassOptions, rule.IngressClassName, handleIngressChange]);
return ( return (
<Widget> <Widget>
<WidgetTitle icon={Route} title="Ingress" /> <WidgetTitle icon={Route} title="Ingress" />
@ -157,12 +146,22 @@ export function IngressForm({
) : ( ) : (
<Select <Select
name="namespaces" name="namespaces"
options={namespacesOptions || []} options={namespacesOptions}
value={{ value: namespace, label: namespace }} value={
namespace
? { value: namespace, label: namespace }
: null
}
isDisabled={isEdit} isDisabled={isEdit}
onChange={(val) => onChange={(val) =>
handleNamespaceChange(val?.value || '') handleNamespaceChange(val?.value || '')
} }
placeholder={
namespacesOptions.length
? 'Select a namespace'
: 'No namespaces available'
}
noOptionsMessage={() => 'No namespaces available'}
/> />
)} )}
</div> </div>
@ -222,18 +221,27 @@ export function IngressForm({
<> <>
<Select <Select
name="ingress_class" name="ingress_class"
placeholder="Ingress name" placeholder={
ingressClassOptions.length
? 'Select an ingress class'
: 'No ingress classes available'
}
options={ingressClassOptions} options={ingressClassOptions}
value={{ value={
label: rule.IngressClassName, rule.IngressClassName
value: rule.IngressClassName, ? {
}} label: rule.IngressClassName,
value: rule.IngressClassName,
}
: null
}
onChange={(ingressClassOption) => onChange={(ingressClassOption) =>
handleIngressChange( handleIngressChange(
'IngressClassName', 'IngressClassName',
ingressClassOption?.value || '' ingressClassOption?.value || ''
) )
} }
noOptionsMessage={() => 'No ingress classes available'}
/> />
{errors.className && ( {errors.className && (
<FormError className="error-inline mt-1"> <FormError className="error-inline mt-1">
@ -242,11 +250,6 @@ export function IngressForm({
)} )}
</> </>
)} )}
{errors.className && (
<FormError className="error-inline mt-1">
{errors.className}
</FormError>
)}
</div> </div>
</div> </div>
</div> </div>
@ -401,13 +404,23 @@ export function IngressForm({
<Select <Select
key={tlsOptions.toString() + host.Secret} key={tlsOptions.toString() + host.Secret}
name={`ingress_tls_${hostIndex}`} name={`ingress_tls_${hostIndex}`}
value={{ value={
value: rule.Hosts[hostIndex].Secret, host.Secret !== undefined
label: rule.Hosts[hostIndex].Secret || 'No TLS', ? {
}} value: host.Secret,
label: host.Secret || 'No TLS',
}
: null
}
onChange={(TLSOption) => onChange={(TLSOption) =>
handleTLSChange(hostIndex, TLSOption?.value || '') handleTLSChange(hostIndex, TLSOption?.value || '')
} }
placeholder={
tlsOptions.length
? 'Select a TLS secret'
: 'No TLS secrets available'
}
noOptionsMessage={() => 'No TLS secrets available'}
size="sm" size="sm"
/> />
{!host.NoHost && ( {!host.NoHost && (
@ -472,10 +485,14 @@ export function IngressForm({
key={serviceOptions.toString() + path.ServiceName} key={serviceOptions.toString() + path.ServiceName}
name={`ingress_service_${hostIndex}_${pathIndex}`} name={`ingress_service_${hostIndex}_${pathIndex}`}
options={serviceOptions} options={serviceOptions}
value={{ value={
value: path.ServiceName, path.ServiceName
label: path.ServiceName || 'Select a service', ? {
}} value: path.ServiceName,
label: path.ServiceName,
}
: null
}
onChange={(serviceOption) => onChange={(serviceOption) =>
handlePathChange( handlePathChange(
hostIndex, hostIndex,
@ -484,6 +501,12 @@ export function IngressForm({
serviceOption?.value || '' serviceOption?.value || ''
) )
} }
placeholder={
serviceOptions.length
? 'Select a service'
: 'No services available'
}
noOptionsMessage={() => 'No services available'}
size="sm" size="sm"
/> />
</InputGroup> </InputGroup>
@ -526,15 +549,20 @@ export function IngressForm({
option?.value || '' option?.value || ''
) )
} }
value={{ value={
label: ( path.ServicePort
path.ServicePort || 'Select a port' ? {
).toString(), label: path.ServicePort.toString(),
value: value: path.ServicePort.toString(),
rule.Hosts[hostIndex].Paths[ }
pathIndex : null
].ServicePort.toString(), }
}} placeholder={
servicePorts[path.ServiceName]?.length
? 'Select a port'
: 'No ports available'
}
noOptionsMessage={() => 'No ports available'}
size="sm" size="sm"
/> />
</InputGroup> </InputGroup>
@ -573,10 +601,20 @@ export function IngressForm({
option?.value || '' option?.value || ''
) )
} }
value={{ value={
label: path.PathType || 'Select a path type', path.PathType
value: path.PathType || '', ? {
}} label: path.PathType,
value: path.PathType,
}
: null
}
placeholder={
pathTypes?.length
? 'Select a path type'
: 'No path types available'
}
noOptionsMessage={() => 'No path types available'}
size="sm" size="sm"
/> />
</InputGroup> </InputGroup>