mirror of
https://github.com/portainer/portainer.git
synced 2025-07-24 15:59:41 +02:00
refactor(app): migrate app summary section [EE-6239] (#10910)
Some checks are pending
ci / build_images (map[arch:amd64 platform:linux]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
Some checks are pending
ci / build_images (map[arch:amd64 platform:linux]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run
This commit is contained in:
parent
7a4314032a
commit
abf517de28
61 changed files with 1461 additions and 661 deletions
|
@ -1,7 +1,6 @@
|
|||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { FormikErrors } from 'formik';
|
||||
|
||||
import { KubernetesApplicationPublishingTypes } from '@/kubernetes/models/application/models';
|
||||
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
|
||||
import {
|
||||
useIngressControllers,
|
||||
|
@ -10,12 +9,7 @@ import {
|
|||
|
||||
import { FormSection } from '@@/form-components/FormSection';
|
||||
|
||||
import {
|
||||
ServiceFormValues,
|
||||
ServiceTypeAngularEnum,
|
||||
ServiceTypeOption,
|
||||
ServiceTypeValue,
|
||||
} from './types';
|
||||
import { ServiceFormValues, ServiceTypeOption, ServiceType } from './types';
|
||||
import { generateUniqueName } from './utils';
|
||||
import { ClusterIpServicesForm } from './cluster-ip/ClusterIpServicesForm';
|
||||
import { ServiceTabs } from './components/ServiceTabs';
|
||||
|
@ -24,15 +18,6 @@ import { LoadBalancerServicesForm } from './load-balancer/LoadBalancerServicesFo
|
|||
import { ServiceTabLabel } from './components/ServiceTabLabel';
|
||||
import { PublishingExplaination } from './PublishingExplaination';
|
||||
|
||||
const serviceTypeEnumsToValues: Record<
|
||||
ServiceTypeAngularEnum,
|
||||
ServiceTypeValue
|
||||
> = {
|
||||
[KubernetesApplicationPublishingTypes.CLUSTER_IP]: 'ClusterIP',
|
||||
[KubernetesApplicationPublishingTypes.NODE_PORT]: 'NodePort',
|
||||
[KubernetesApplicationPublishingTypes.LOAD_BALANCER]: 'LoadBalancer',
|
||||
};
|
||||
|
||||
interface Props {
|
||||
values: ServiceFormValues[];
|
||||
onChange: (services: ServiceFormValues[]) => void;
|
||||
|
@ -53,7 +38,7 @@ export function KubeServicesForm({
|
|||
namespace,
|
||||
}: Props) {
|
||||
const [selectedServiceType, setSelectedServiceType] =
|
||||
useState<ServiceTypeValue>('ClusterIP');
|
||||
useState<ServiceType>('ClusterIP');
|
||||
|
||||
// start loading ingresses and controllers early to reduce perceived loading time
|
||||
const environmentId = useEnvironmentId();
|
||||
|
@ -195,17 +180,17 @@ function getUniqNames(appName: string, services: ServiceFormValues[]) {
|
|||
*/
|
||||
function getServiceTypeCounts(
|
||||
services: ServiceFormValues[]
|
||||
): Record<ServiceTypeValue, number> {
|
||||
): Record<ServiceType, number> {
|
||||
return services.reduce(
|
||||
(acc, service) => {
|
||||
const type = serviceTypeEnumsToValues[service.Type];
|
||||
const type = service.Type;
|
||||
const count = acc[type];
|
||||
return {
|
||||
...acc,
|
||||
[type]: count ? count + 1 : 1,
|
||||
};
|
||||
},
|
||||
{} as Record<ServiceTypeValue, number>
|
||||
{} as Record<ServiceType, number>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -215,10 +200,10 @@ function getServiceTypeCounts(
|
|||
function getServiceTypeHasErrors(
|
||||
services: ServiceFormValues[],
|
||||
errors: FormikErrors<ServiceFormValues[] | undefined>
|
||||
): Record<ServiceTypeValue, boolean> {
|
||||
): Record<ServiceType, boolean> {
|
||||
return services.reduce(
|
||||
(acc, service, index) => {
|
||||
const type = serviceTypeEnumsToValues[service.Type];
|
||||
const type = service.Type;
|
||||
const serviceHasErrors = !!errors?.[index];
|
||||
// if the service type already has an error, don't overwrite it
|
||||
if (acc[type] === true) return acc;
|
||||
|
@ -228,6 +213,6 @@ function getServiceTypeHasErrors(
|
|||
[type]: serviceHasErrors,
|
||||
};
|
||||
},
|
||||
{} as Record<ServiceTypeValue, boolean>
|
||||
{} as Record<ServiceType, boolean>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -88,10 +88,7 @@ export function ClusterIpServiceForm({
|
|||
value={servicePort.targetPort}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||
const newServicePorts = [...servicePorts];
|
||||
const newValue =
|
||||
e.target.value === ''
|
||||
? undefined
|
||||
: Number(e.target.value);
|
||||
const newValue = e.target.valueAsNumber;
|
||||
newServicePorts[portIndex] = {
|
||||
...newServicePorts[portIndex],
|
||||
targetPort: newValue,
|
||||
|
@ -113,10 +110,7 @@ export function ClusterIpServiceForm({
|
|||
const newServicePorts = [...servicePorts];
|
||||
newServicePorts[portIndex] = {
|
||||
...newServicePorts[portIndex],
|
||||
port:
|
||||
e.target.value === ''
|
||||
? undefined
|
||||
: Number(e.target.value),
|
||||
port: e.target.valueAsNumber,
|
||||
};
|
||||
onChangePort(newServicePorts);
|
||||
}}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import { Plus } from 'lucide-react';
|
||||
import { FormikErrors } from 'formik';
|
||||
|
||||
import { KubernetesApplicationPublishingTypes } from '@/kubernetes/models/application/models';
|
||||
|
||||
import { Card } from '@@/Card';
|
||||
import { TextTip } from '@@/Tip/TextTip';
|
||||
import { Button } from '@@/buttons';
|
||||
|
@ -36,8 +34,7 @@ export function ClusterIpServicesForm({
|
|||
isEditMode,
|
||||
}: Props) {
|
||||
const clusterIPServiceCount = services.filter(
|
||||
(service) =>
|
||||
service.Type === KubernetesApplicationPublishingTypes.CLUSTER_IP
|
||||
(service) => service.Type === 'ClusterIP'
|
||||
).length;
|
||||
return (
|
||||
<Card className="pb-5">
|
||||
|
@ -50,8 +47,7 @@ export function ClusterIpServicesForm({
|
|||
{clusterIPServiceCount > 0 && (
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
{services.map((service, index) =>
|
||||
service.Type ===
|
||||
KubernetesApplicationPublishingTypes.CLUSTER_IP ? (
|
||||
service.Type === 'ClusterIP' ? (
|
||||
<ClusterIpServiceForm
|
||||
key={index}
|
||||
serviceName={service.Name}
|
||||
|
@ -86,7 +82,7 @@ export function ClusterIpServicesForm({
|
|||
services.length + 1,
|
||||
services
|
||||
);
|
||||
newService.Type = KubernetesApplicationPublishingTypes.CLUSTER_IP;
|
||||
newService.Type = 'ClusterIP';
|
||||
const newServicePort = newPort(newService.Name);
|
||||
newService.Ports = [newServicePort];
|
||||
newService.Selector = selector;
|
||||
|
|
|
@ -22,7 +22,7 @@ export function ContainerPortInput({
|
|||
type="number"
|
||||
className="form-control min-w-max"
|
||||
name={`container_port_${portIndex}`}
|
||||
placeholder="80"
|
||||
placeholder="e.g. 80"
|
||||
min="1"
|
||||
max="65535"
|
||||
value={value ?? ''}
|
||||
|
|
|
@ -22,7 +22,7 @@ export function ServicePortInput({
|
|||
type="number"
|
||||
className="form-control min-w-max"
|
||||
name={`service_port_${portIndex}`}
|
||||
placeholder="80"
|
||||
placeholder="e.g. 80"
|
||||
min="1"
|
||||
max="65535"
|
||||
value={value ?? ''}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import clsx from 'clsx';
|
||||
|
||||
import { ServiceTypeOption, ServiceTypeValue } from '../types';
|
||||
import { ServiceTypeOption, ServiceType } from '../types';
|
||||
|
||||
type Props = {
|
||||
serviceTypeOptions: ServiceTypeOption[];
|
||||
selectedServiceType: ServiceTypeValue;
|
||||
setSelectedServiceType: (serviceTypeValue: ServiceTypeValue) => void;
|
||||
selectedServiceType: ServiceType;
|
||||
setSelectedServiceType: (serviceTypeValue: ServiceType) => void;
|
||||
};
|
||||
|
||||
export function ServiceTabs({
|
||||
|
@ -32,7 +32,7 @@ export function ServiceTabs({
|
|||
value={serviceTypeOptions[index].value}
|
||||
checked={selectedServiceType === serviceTypeOptions[index].value}
|
||||
onChange={(e) =>
|
||||
setSelectedServiceType(e.target.value as ServiceTypeValue)
|
||||
setSelectedServiceType(e.target.value as ServiceType)
|
||||
}
|
||||
/>
|
||||
{label}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import { SchemaOf, array, object, boolean, string, mixed, number } from 'yup';
|
||||
|
||||
import { KubernetesApplicationPublishingTypes } from '@/kubernetes/models/application/models';
|
||||
|
||||
import { ServiceFormValues, ServicePort } from './types';
|
||||
import { prependWithSlash } from './utils';
|
||||
|
||||
|
@ -46,11 +44,7 @@ export function kubeServicesValidation(
|
|||
Namespace: string(),
|
||||
Name: string(),
|
||||
StackName: string(),
|
||||
Type: mixed().oneOf([
|
||||
KubernetesApplicationPublishingTypes.CLUSTER_IP,
|
||||
KubernetesApplicationPublishingTypes.NODE_PORT,
|
||||
KubernetesApplicationPublishingTypes.LOAD_BALANCER,
|
||||
]),
|
||||
Type: mixed().oneOf(['ClusterIP', 'NodePort', 'LoadBalancer']),
|
||||
ClusterIP: string(),
|
||||
ApplicationName: string(),
|
||||
ApplicationOwner: string(),
|
||||
|
@ -61,6 +55,7 @@ export function kubeServicesValidation(
|
|||
object({
|
||||
port: number()
|
||||
.required('Service port number is required.')
|
||||
.typeError('Service port number is required.')
|
||||
.min(1, 'Service port number must be inside the range 1-65535.')
|
||||
.max(65535, 'Service port number must be inside the range 1-65535.')
|
||||
.test(
|
||||
|
@ -93,6 +88,7 @@ export function kubeServicesValidation(
|
|||
),
|
||||
targetPort: number()
|
||||
.required('Container port number is required.')
|
||||
.typeError('Container port number is required.')
|
||||
.min(1, 'Container port number must be inside the range 1-65535.')
|
||||
.max(
|
||||
65535,
|
||||
|
@ -116,8 +112,7 @@ export function kubeServicesValidation(
|
|||
);
|
||||
if (
|
||||
matchingService === undefined ||
|
||||
matchingService.Type !==
|
||||
KubernetesApplicationPublishingTypes.NODE_PORT // ignore validation unless the service is of type nodeport
|
||||
matchingService.Type !== 'NodePort'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
@ -143,8 +138,7 @@ export function kubeServicesValidation(
|
|||
|
||||
if (
|
||||
matchingService === undefined ||
|
||||
matchingService.Type !==
|
||||
KubernetesApplicationPublishingTypes.NODE_PORT // ignore validation unless the service is of type nodeport
|
||||
matchingService.Type !== 'NodePort'
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
@ -163,8 +157,7 @@ export function kubeServicesValidation(
|
|||
const formNodePortsWithoutCurrentService = formServices
|
||||
.filter(
|
||||
(formService) =>
|
||||
formService.Type ===
|
||||
KubernetesApplicationPublishingTypes.NODE_PORT &&
|
||||
formService.Type === 'NodePort' &&
|
||||
formService.Name !== matchingService.Name
|
||||
)
|
||||
.flatMap((formService) => formService.Ports)
|
||||
|
@ -187,11 +180,7 @@ export function kubeServicesValidation(
|
|||
context.parent as ServicePort,
|
||||
formServices
|
||||
);
|
||||
if (
|
||||
!matchingService ||
|
||||
matchingService.Type !==
|
||||
KubernetesApplicationPublishingTypes.NODE_PORT
|
||||
) {
|
||||
if (!matchingService || matchingService.Type !== 'NodePort') {
|
||||
return true;
|
||||
}
|
||||
return nodePort >= 30000;
|
||||
|
@ -209,11 +198,7 @@ export function kubeServicesValidation(
|
|||
context.parent as ServicePort,
|
||||
formServices
|
||||
);
|
||||
if (
|
||||
!matchingService ||
|
||||
matchingService.Type !==
|
||||
KubernetesApplicationPublishingTypes.NODE_PORT
|
||||
) {
|
||||
if (!matchingService || matchingService.Type !== 'NodePort') {
|
||||
return true;
|
||||
}
|
||||
return nodePort <= 32767;
|
||||
|
|
|
@ -93,10 +93,7 @@ export function LoadBalancerServiceForm({
|
|||
value={servicePort.targetPort}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||
const newServicePorts = [...servicePorts];
|
||||
const newValue =
|
||||
e.target.value === ''
|
||||
? undefined
|
||||
: Number(e.target.value);
|
||||
const newValue = e.target.valueAsNumber;
|
||||
newServicePorts[portIndex] = {
|
||||
...newServicePorts[portIndex],
|
||||
targetPort: newValue,
|
||||
|
@ -119,10 +116,7 @@ export function LoadBalancerServiceForm({
|
|||
const newServicePorts = [...servicePorts];
|
||||
newServicePorts[portIndex] = {
|
||||
...newServicePorts[portIndex],
|
||||
port:
|
||||
e.target.value === ''
|
||||
? undefined
|
||||
: Number(e.target.value),
|
||||
port: e.target.valueAsNumber,
|
||||
};
|
||||
onChangePort(newServicePorts);
|
||||
}}
|
||||
|
@ -140,7 +134,7 @@ export function LoadBalancerServiceForm({
|
|||
type="number"
|
||||
className="form-control min-w-max"
|
||||
name={`loadbalancer_port_${portIndex}`}
|
||||
placeholder="80"
|
||||
placeholder="e.g. 80"
|
||||
min="1"
|
||||
max="65535"
|
||||
value={servicePort.port || ''}
|
||||
|
@ -148,10 +142,7 @@ export function LoadBalancerServiceForm({
|
|||
const newServicePorts = [...servicePorts];
|
||||
newServicePorts[portIndex] = {
|
||||
...newServicePorts[portIndex],
|
||||
port:
|
||||
e.target.value === ''
|
||||
? undefined
|
||||
: Number(e.target.value),
|
||||
port: e.target.valueAsNumber,
|
||||
};
|
||||
onChangePort(newServicePorts);
|
||||
}}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { Plus, RefreshCw } from 'lucide-react';
|
||||
import { FormikErrors } from 'formik';
|
||||
|
||||
import { KubernetesApplicationPublishingTypes } from '@/kubernetes/models/application/models';
|
||||
import { useCurrentUser } from '@/react/hooks/useUser';
|
||||
import { useEnvironment } from '@/react/portainer/environments/queries';
|
||||
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
|
||||
|
@ -49,8 +48,7 @@ export function LoadBalancerServicesForm({
|
|||
);
|
||||
|
||||
const loadBalancerServiceCount = services.filter(
|
||||
(service) =>
|
||||
service.Type === KubernetesApplicationPublishingTypes.LOAD_BALANCER
|
||||
(service) => service.Type === 'LoadBalancer'
|
||||
).length;
|
||||
return (
|
||||
<Card className="pb-5">
|
||||
|
@ -95,8 +93,7 @@ export function LoadBalancerServicesForm({
|
|||
{loadBalancerServiceCount > 0 && (
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
{services.map((service, index) =>
|
||||
service.Type ===
|
||||
KubernetesApplicationPublishingTypes.LOAD_BALANCER ? (
|
||||
service.Type === 'LoadBalancer' ? (
|
||||
<LoadBalancerServiceForm
|
||||
key={index}
|
||||
serviceName={service.Name}
|
||||
|
@ -131,8 +128,7 @@ export function LoadBalancerServicesForm({
|
|||
services.length + 1,
|
||||
services
|
||||
);
|
||||
newService.Type =
|
||||
KubernetesApplicationPublishingTypes.LOAD_BALANCER;
|
||||
newService.Type = 'LoadBalancer';
|
||||
const newServicePort = newPort(newService.Name);
|
||||
newService.Ports = [newServicePort];
|
||||
newService.Selector = selector;
|
||||
|
|
|
@ -94,10 +94,7 @@ export function NodePortServiceForm({
|
|||
value={servicePort.targetPort}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||
const newServicePorts = [...servicePorts];
|
||||
const newValue =
|
||||
e.target.value === ''
|
||||
? undefined
|
||||
: Number(e.target.value);
|
||||
const newValue = e.target.valueAsNumber;
|
||||
newServicePorts[portIndex] = {
|
||||
...newServicePorts[portIndex],
|
||||
targetPort: newValue,
|
||||
|
@ -120,10 +117,7 @@ export function NodePortServiceForm({
|
|||
const newServicePorts = [...servicePorts];
|
||||
newServicePorts[portIndex] = {
|
||||
...newServicePorts[portIndex],
|
||||
port:
|
||||
e.target.value === ''
|
||||
? undefined
|
||||
: Number(e.target.value),
|
||||
port: e.target.valueAsNumber,
|
||||
};
|
||||
onChangePort(newServicePorts);
|
||||
}}
|
||||
|
@ -139,7 +133,7 @@ export function NodePortServiceForm({
|
|||
type="number"
|
||||
className="form-control min-w-max"
|
||||
name={`node_port_${portIndex}`}
|
||||
placeholder="30080"
|
||||
placeholder="e.g. 30080"
|
||||
min="30000"
|
||||
max="32767"
|
||||
value={servicePort.nodePort ?? ''}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import { FormikErrors } from 'formik';
|
||||
import { Plus } from 'lucide-react';
|
||||
|
||||
import { KubernetesApplicationPublishingTypes } from '@/kubernetes/models/application/models';
|
||||
|
||||
import { Card } from '@@/Card';
|
||||
import { TextTip } from '@@/Tip/TextTip';
|
||||
import { Button } from '@@/buttons';
|
||||
|
@ -36,7 +34,7 @@ export function NodePortServicesForm({
|
|||
isEditMode,
|
||||
}: Props) {
|
||||
const nodePortServiceCount = services.filter(
|
||||
(service) => service.Type === KubernetesApplicationPublishingTypes.NODE_PORT
|
||||
(service) => service.Type === 'NodePort'
|
||||
).length;
|
||||
return (
|
||||
<Card className="pb-5">
|
||||
|
@ -48,8 +46,7 @@ export function NodePortServicesForm({
|
|||
{nodePortServiceCount > 0 && (
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
{services.map((service, index) =>
|
||||
service.Type ===
|
||||
KubernetesApplicationPublishingTypes.NODE_PORT ? (
|
||||
service.Type === 'NodePort' ? (
|
||||
<NodePortServiceForm
|
||||
key={index}
|
||||
serviceName={service.Name}
|
||||
|
@ -84,7 +81,7 @@ export function NodePortServicesForm({
|
|||
services.length + 1,
|
||||
services
|
||||
);
|
||||
newService.Type = KubernetesApplicationPublishingTypes.NODE_PORT;
|
||||
newService.Type = 'NodePort';
|
||||
const newServicePort = newPort(newService.Name);
|
||||
newService.Ports = [newServicePort];
|
||||
newService.Selector = selector;
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import { ReactNode } from 'react';
|
||||
|
||||
import { KubernetesApplicationPublishingTypes } from '@/kubernetes/models/application/models';
|
||||
|
||||
export interface ServicePort {
|
||||
port?: number;
|
||||
port: number;
|
||||
targetPort?: number;
|
||||
nodePort?: number;
|
||||
serviceName?: string;
|
||||
|
@ -12,9 +10,6 @@ export interface ServicePort {
|
|||
ingressPaths?: ServicePortIngressPath[];
|
||||
}
|
||||
|
||||
export type ServiceTypeAngularEnum =
|
||||
(typeof KubernetesApplicationPublishingTypes)[keyof typeof KubernetesApplicationPublishingTypes];
|
||||
|
||||
export type ServicePortIngressPath = {
|
||||
IngressName?: string;
|
||||
Host?: string;
|
||||
|
@ -24,7 +19,7 @@ export type ServicePortIngressPath = {
|
|||
export type ServiceFormValues = {
|
||||
Headless: boolean;
|
||||
Ports: ServicePort[];
|
||||
Type: ServiceTypeAngularEnum;
|
||||
Type: ServiceType;
|
||||
Ingress: boolean;
|
||||
ClusterIP?: string;
|
||||
ApplicationName?: string;
|
||||
|
@ -36,9 +31,9 @@ export type ServiceFormValues = {
|
|||
Namespace?: string;
|
||||
};
|
||||
|
||||
export type ServiceTypeValue = 'ClusterIP' | 'NodePort' | 'LoadBalancer';
|
||||
export type ServiceType = 'ClusterIP' | 'NodePort' | 'LoadBalancer';
|
||||
export type ServiceTypeOption = {
|
||||
value: ServiceTypeValue;
|
||||
value: ServiceType;
|
||||
label: ReactNode;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,10 +1,21 @@
|
|||
import { Ingress } from '@/react/kubernetes/ingresses/types';
|
||||
import { compare } from 'fast-json-patch';
|
||||
import { Service, ServiceSpec } from 'kubernetes-types/core/v1';
|
||||
import { ObjectMeta } from 'kubernetes-types/meta/v1';
|
||||
import angular from 'angular';
|
||||
|
||||
import { Ingress as IngressFormValues } from '@/react/kubernetes/ingresses/types';
|
||||
|
||||
import {
|
||||
appNameLabel,
|
||||
appOwnerLabel,
|
||||
appStackNameLabel,
|
||||
} from '../../constants';
|
||||
|
||||
import { ServiceFormValues, ServicePort } from './types';
|
||||
|
||||
export function newPort(serviceName?: string) {
|
||||
export function newPort(serviceName?: string): ServicePort {
|
||||
return {
|
||||
port: undefined,
|
||||
port: 80,
|
||||
targetPort: undefined,
|
||||
name: '',
|
||||
protocol: 'TCP',
|
||||
|
@ -43,7 +54,7 @@ export const serviceFormDefaultValues: ServiceFormValues = {
|
|||
Name: '',
|
||||
StackName: '',
|
||||
Ports: [],
|
||||
Type: 1, // clusterip type as default
|
||||
Type: 'ClusterIP',
|
||||
ClusterIP: '',
|
||||
ApplicationName: '',
|
||||
ApplicationOwner: '',
|
||||
|
@ -54,16 +65,16 @@ export const serviceFormDefaultValues: ServiceFormValues = {
|
|||
|
||||
/**
|
||||
* Generates new Ingress objects from form path data
|
||||
* @param {Ingress[]} oldIngresses - The old Ingress objects
|
||||
* @param {IngressFormValues[]} oldIngresses - The old Ingress objects
|
||||
* @param {ServicePort[]} newServicesPorts - The new ServicePort objects from the form
|
||||
* @param {ServicePort[]} oldServicesPorts - The old ServicePort objects
|
||||
* @returns {Ingress[]} The new Ingress objects
|
||||
* @returns {IngressFormValues[]} The new Ingress objects
|
||||
*/
|
||||
export function generateNewIngressesFromFormPaths(
|
||||
oldIngresses?: Ingress[],
|
||||
oldIngresses?: IngressFormValues[],
|
||||
newServicesPorts?: ServicePort[],
|
||||
oldServicesPorts?: ServicePort[]
|
||||
): Ingress[] {
|
||||
): IngressFormValues[] {
|
||||
// filter the ports to only the ones that have an ingress
|
||||
const oldIngressPaths = oldServicesPorts
|
||||
?.flatMap((port) => port.ingressPaths)
|
||||
|
@ -77,7 +88,7 @@ export function generateNewIngressesFromFormPaths(
|
|||
}
|
||||
|
||||
// remove the old paths from the newIngresses copy
|
||||
const newIngresses = structuredClone(oldIngresses) ?? [];
|
||||
const newIngresses: IngressFormValues[] = angular.copy(oldIngresses) ?? []; // the current jest version doesn't support structured cloning, so we need to use angular.copy
|
||||
oldIngressPaths?.forEach((oldIngressPath) => {
|
||||
if (!oldIngressPath?.Path) return;
|
||||
const newMatchingIng = newIngresses?.find(
|
||||
|
@ -151,3 +162,57 @@ export function prependWithSlash(path?: string) {
|
|||
if (!path) return '';
|
||||
return path.startsWith('/') ? path : `/${path}`;
|
||||
}
|
||||
|
||||
export function getServicePatchPayload(
|
||||
oldService: ServiceFormValues,
|
||||
newService: ServiceFormValues
|
||||
) {
|
||||
const oldPayload = getServicePayload(oldService);
|
||||
const newPayload = getServicePayload(newService);
|
||||
|
||||
const payload = compare(oldPayload, newPayload);
|
||||
return payload;
|
||||
}
|
||||
|
||||
function getServicePayload(service: ServiceFormValues): Service {
|
||||
if (!service.Name || !service.Namespace) {
|
||||
throw new Error('Service name and namespace are required');
|
||||
}
|
||||
|
||||
// metadata
|
||||
const labels: Record<string, string> = {};
|
||||
if (service.ApplicationName) {
|
||||
labels[appNameLabel] = service.ApplicationName;
|
||||
}
|
||||
if (service.ApplicationOwner) {
|
||||
labels[appOwnerLabel] = service.ApplicationOwner;
|
||||
}
|
||||
if (service.StackName) {
|
||||
labels[appStackNameLabel] = service.StackName;
|
||||
}
|
||||
const metadata: ObjectMeta = {
|
||||
name: service.Name,
|
||||
namespace: service.Namespace,
|
||||
labels,
|
||||
};
|
||||
|
||||
// spec
|
||||
const ports = service.Headless ? [] : service.Ports;
|
||||
const selector = service.Selector;
|
||||
const clusterIP = service.Headless ? 'None' : service.ClusterIP;
|
||||
const type = service.Headless ? 'ClusterIP' : service.Type;
|
||||
const spec: ServiceSpec = {
|
||||
ports,
|
||||
selector,
|
||||
clusterIP,
|
||||
type,
|
||||
};
|
||||
|
||||
const servicePayload: Service = {
|
||||
apiVersion: 'v1',
|
||||
kind: 'Service',
|
||||
metadata,
|
||||
spec,
|
||||
};
|
||||
return servicePayload;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue