1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-05 13:55:21 +02:00

fix(ingress): allow none controller type EE-4420 (#7883)

Co-authored-by: testA113 <alex.harris@portainer.io>
This commit is contained in:
Dakota Walsh 2022-10-25 09:41:30 +13:00 committed by GitHub
parent e48ceb15e9
commit 55211ef00e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 243 additions and 76 deletions

View file

@ -1,5 +1,7 @@
import { PropsWithChildren, useState } from 'react';
import { Icon } from '@@/Icon';
import { FormSectionTitle } from '../FormSectionTitle';
interface Props {
@ -22,11 +24,12 @@ export function FormSection({
id={`foldingButton${title}`}
type="button"
onClick={() => setIsExpanded(!isExpanded)}
className="border-0 mx-2 bg-transparent inline-flex justify-center items-center w-2"
className="border-0 mx-2 !ml-0 bg-transparent inline-flex justify-center items-center w-2"
>
<i
className={`fa fa-caret-${isExpanded ? 'down' : 'right'}`}
aria-hidden="true"
<Icon
icon={isExpanded ? 'chevron-down' : 'chevron-right'}
className="shrink-0"
feather
/>
</button>
)}

View file

@ -12,7 +12,7 @@ export function FormSectionTitle({
return (
<label
htmlFor={htmlFor}
className="col-sm-12 form-section-title cursor-pointer"
className="col-sm-12 form-section-title cursor-pointer flex items-center"
>
{children}
</label>

View file

@ -1,4 +1,4 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { confirmWarn } from '@/portainer/services/modal.service/confirm';
@ -14,29 +14,64 @@ import { createStore } from './datatable-store';
const useStore = createStore('ingressClasses');
interface Props {
onChangeAvailability: (
onChangeControllers: (
controllerClassMap: IngressControllerClassMap[]
) => void; // angular function to save the ingress class list
description: string;
ingressControllers: IngressControllerClassMap[] | undefined;
allowNoneIngressClass: boolean;
isLoading: boolean;
noIngressControllerLabel: string;
view: string;
}
export function IngressClassDatatable({
onChangeAvailability,
onChangeControllers,
description,
ingressControllers,
allowNoneIngressClass,
isLoading,
noIngressControllerLabel,
view,
}: Props) {
const [ingControllerFormValues, setIngControllerFormValues] =
useState(ingressControllers);
const [ingControllerFormValues, setIngControllerFormValues] = useState(
ingressControllers || []
);
const settings = useStore();
const columns = useColumns();
useEffect(() => {
if (allowNoneIngressClass === undefined) {
return;
}
let newIngFormValues: IngressControllerClassMap[];
const isCustomTypeExist = ingControllerFormValues.some(
(ic) => ic.Type === 'custom'
);
if (allowNoneIngressClass) {
newIngFormValues = [...ingControllerFormValues];
// add the ingress controller type 'custom' with a 'none' ingress class name
if (!isCustomTypeExist) {
newIngFormValues.push({
Name: 'none',
ClassName: 'none',
Type: 'custom',
Availability: true,
New: false,
Used: false,
});
}
} else {
newIngFormValues = ingControllerFormValues.filter(
(ingController) => ingController.ClassName !== 'none'
);
}
setIngControllerFormValues(newIngFormValues);
onChangeControllers(newIngFormValues);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [allowNoneIngressClass, onChangeControllers]);
return (
<div className="-mx-[15px]">
<Datatable
@ -134,7 +169,7 @@ export function IngressClassDatatable({
);
if (view === 'namespace') {
setIngControllerFormValues(updatedIngressControllers);
onChangeAvailability(updatedIngressControllers);
onChangeControllers(updatedIngressControllers);
return;
}
@ -180,14 +215,14 @@ export function IngressClassDatatable({
callback: (confirmed) => {
if (confirmed) {
setIngControllerFormValues(updatedIngressControllers);
onChangeAvailability(updatedIngressControllers);
onChangeControllers(updatedIngressControllers);
}
},
});
return;
}
setIngControllerFormValues(updatedIngressControllers);
onChangeAvailability(updatedIngressControllers);
onChangeControllers(updatedIngressControllers);
}
}
}
@ -196,10 +231,13 @@ function isUnsavedChanges(
oldIngressControllers: IngressControllerClassMap[],
newIngressControllers: IngressControllerClassMap[]
) {
for (let i = 0; i < oldIngressControllers.length; i += 1) {
if (oldIngressControllers.length !== newIngressControllers.length) {
return true;
}
for (let i = 0; i < newIngressControllers.length; i += 1) {
if (
oldIngressControllers[i].Availability !==
newIngressControllers[i].Availability
oldIngressControllers[i]?.Availability !==
newIngressControllers[i]?.Availability
) {
return true;
}

View file

@ -1,9 +1,13 @@
type SupportedIngControllerNames = 'nginx' | 'traefik' | 'unknown';
export type SupportedIngControllerTypes =
| 'nginx'
| 'traefik'
| 'other'
| 'custom';
export interface IngressControllerClassMap extends Record<string, unknown> {
Name: string;
ClassName: string;
Type: SupportedIngControllerNames;
Type: SupportedIngControllerTypes;
Availability: boolean;
New: boolean;
Used: boolean; // if the controller is used by any ingress in the cluster

View file

@ -70,6 +70,7 @@ export interface KubernetesConfiguration {
RestrictDefaultNamespace?: boolean;
IngressClasses: IngressClass[];
IngressAvailabilityPerNamespace: boolean;
AllowNoneIngressClass: boolean;
}
export interface KubernetesSettings {