mirror of
https://github.com/portainer/portainer.git
synced 2025-07-20 22:09:41 +02:00
feat(app): rearrange app form services [EE-5566] (#9056)
This commit is contained in:
parent
d7fc2046d7
commit
2d69e93efa
18 changed files with 1104 additions and 739 deletions
|
@ -0,0 +1,139 @@
|
|||
import { Plus, RotateCw } 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';
|
||||
|
||||
import { Card } from '@@/Card';
|
||||
import { TextTip } from '@@/Tip/TextTip';
|
||||
import { Button } from '@@/buttons';
|
||||
import { FormError } from '@@/form-components/FormError';
|
||||
import { Link } from '@@/Link';
|
||||
|
||||
import { generateUniqueName, newPort, serviceFormDefaultValues } from './utils';
|
||||
import { ServiceFormValues, ServicePort } from './types';
|
||||
import { LoadBalancerServiceForm } from './LoadBalancerServiceForm';
|
||||
|
||||
interface Props {
|
||||
services: ServiceFormValues[];
|
||||
onChangeService: (services: ServiceFormValues[]) => void;
|
||||
errors?: FormikErrors<ServiceFormValues[]>;
|
||||
appName: string;
|
||||
selector: Record<string, string>;
|
||||
}
|
||||
|
||||
export function LoadBalancerServicesForm({
|
||||
services,
|
||||
onChangeService,
|
||||
errors,
|
||||
appName,
|
||||
selector,
|
||||
}: Props) {
|
||||
const { isAdmin } = useCurrentUser();
|
||||
const environmentId = useEnvironmentId();
|
||||
const { data: loadBalancerEnabled, ...loadBalancerEnabledQuery } =
|
||||
useEnvironment(
|
||||
environmentId,
|
||||
(environment) => environment?.Kubernetes.Configuration.UseLoadBalancer
|
||||
);
|
||||
|
||||
const loadBalancerServiceCount = services.filter(
|
||||
(service) =>
|
||||
service.Type === KubernetesApplicationPublishingTypes.LOAD_BALANCER
|
||||
).length;
|
||||
return (
|
||||
<Card className="pb-5">
|
||||
<div className="flex flex-col gap-6">
|
||||
<TextTip color="blue">
|
||||
Allow access to traffic <b>external</b> to the cluster via a{' '}
|
||||
<b>LoadBalancer service</b>. If running on a cloud platform, this auto
|
||||
provisions a cloud load balancer.
|
||||
</TextTip>
|
||||
{!loadBalancerEnabled && loadBalancerEnabledQuery.isSuccess && (
|
||||
<div className="flex flex-col">
|
||||
<FormError>
|
||||
{isAdmin ? (
|
||||
<>
|
||||
Load balancer use is not currently enabled in this cluster.
|
||||
Configure via{' '}
|
||||
<Link
|
||||
to="kubernetes.cluster.setup"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Cluster Setup
|
||||
</Link>{' '}
|
||||
and then refresh this tab
|
||||
</>
|
||||
) : (
|
||||
'Load balancer use is not currently enabled in this cluster, contact your administrator.'
|
||||
)}
|
||||
</FormError>
|
||||
<div className="flex">
|
||||
<Button
|
||||
icon={RotateCw}
|
||||
color="default"
|
||||
className="!ml-0"
|
||||
onClick={() => loadBalancerEnabledQuery.refetch()}
|
||||
>
|
||||
Refresh
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{loadBalancerServiceCount > 0 && (
|
||||
<div className="flex w-full flex-col gap-4">
|
||||
{services.map((service, index) =>
|
||||
service.Type ===
|
||||
KubernetesApplicationPublishingTypes.LOAD_BALANCER ? (
|
||||
<LoadBalancerServiceForm
|
||||
key={index}
|
||||
serviceName={service.Name}
|
||||
servicePorts={service.Ports}
|
||||
errors={errors?.[index]?.Ports}
|
||||
onChangePort={(servicePorts: ServicePort[]) => {
|
||||
const newServices = [...services];
|
||||
newServices[index].Ports = servicePorts;
|
||||
onChangeService(newServices);
|
||||
}}
|
||||
services={services}
|
||||
serviceIndex={index}
|
||||
onChangeService={onChangeService}
|
||||
/>
|
||||
) : null
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex">
|
||||
<Button
|
||||
color="secondary"
|
||||
className="!ml-0"
|
||||
icon={Plus}
|
||||
size="small"
|
||||
onClick={() => {
|
||||
// create a new service form value and add it to the list of services
|
||||
const newService = structuredClone(serviceFormDefaultValues);
|
||||
newService.Name = generateUniqueName(
|
||||
appName,
|
||||
services.length + 1,
|
||||
services
|
||||
);
|
||||
newService.Type =
|
||||
KubernetesApplicationPublishingTypes.LOAD_BALANCER;
|
||||
const newServicePort = newPort(newService.Name);
|
||||
newService.Ports = [newServicePort];
|
||||
newService.Selector = selector;
|
||||
onChangeService([...services, newService]);
|
||||
}}
|
||||
disabled={!loadBalancerEnabled}
|
||||
data-cy="k8sAppCreate-createServiceButton"
|
||||
>
|
||||
Create service
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue