diff --git a/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_de_DE.json b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_de_DE.json new file mode 100644 index 000000000000..d58221cfbdfb --- /dev/null +++ b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_de_DE.json @@ -0,0 +1,9 @@ +{ + "octavia_load_balancer_pools_detail_members_create_title": "Manuell hinzufügen", + "octavia_load_balancer_pools_detail_members_create_description": "Fügen Sie ein Mitglied manuell hinzu, wenn es nicht in der Tabelle der verfügbaren Instanzen aufgeführt ist.", + "octavia_load_balancer_pools_detail_members_create_cancel": "Abbrechen", + "octavia_load_balancer_pools_detail_members_create_confirm": "Hinzufügen", + "octavia_load_balancer_pools_detail_members_create_name_label": "Name (optional)", + "octavia_load_balancer_pools_detail_members_create_address_ip_label": "IP-Adresse", + "octavia_load_balancer_pools_detail_members_create_port_label": "Port" +} diff --git a/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_en_GB.json b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_en_GB.json new file mode 100644 index 000000000000..1707a0443ec4 --- /dev/null +++ b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_en_GB.json @@ -0,0 +1,9 @@ +{ + "octavia_load_balancer_pools_detail_members_create_title": "Add Manually", + "octavia_load_balancer_pools_detail_members_create_description": "Manually add a member if it is not found in the available instances table.", + "octavia_load_balancer_pools_detail_members_create_cancel": "Cancel", + "octavia_load_balancer_pools_detail_members_create_confirm": "Add", + "octavia_load_balancer_pools_detail_members_create_name_label": "Surname (optional)", + "octavia_load_balancer_pools_detail_members_create_address_ip_label": "IP address", + "octavia_load_balancer_pools_detail_members_create_port_label": "Port" +} diff --git a/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_es_ES.json b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_es_ES.json new file mode 100644 index 000000000000..3668337a0ba2 --- /dev/null +++ b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_es_ES.json @@ -0,0 +1,9 @@ +{ + "octavia_load_balancer_pools_detail_members_create_title": "Añadir manualmente", + "octavia_load_balancer_pools_detail_members_create_description": "Añadir un miembro manualmente si no aparece en la tabla de instancias disponibles.", + "octavia_load_balancer_pools_detail_members_create_cancel": "Cancelar", + "octavia_load_balancer_pools_detail_members_create_confirm": "Añadir", + "octavia_load_balancer_pools_detail_members_create_name_label": "Nombre (opcional)", + "octavia_load_balancer_pools_detail_members_create_address_ip_label": "Dirección IP", + "octavia_load_balancer_pools_detail_members_create_port_label": "Puerto" +} diff --git a/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_fr_CA.json b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_fr_CA.json new file mode 100644 index 000000000000..a4f5d86a7342 --- /dev/null +++ b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_fr_CA.json @@ -0,0 +1,9 @@ +{ + "octavia_load_balancer_pools_detail_members_create_title": "Ajouter Manuellement", + "octavia_load_balancer_pools_detail_members_create_description": "Ajouter un membre manuellement s'il est introuvable dans le tableau des instances disponibles.", + "octavia_load_balancer_pools_detail_members_create_cancel": "Annuler", + "octavia_load_balancer_pools_detail_members_create_confirm": "Ajouter", + "octavia_load_balancer_pools_detail_members_create_name_label": "Nom (optionnel)", + "octavia_load_balancer_pools_detail_members_create_address_ip_label": "Adresse IP", + "octavia_load_balancer_pools_detail_members_create_port_label": "Port" +} diff --git a/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_fr_FR.json b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_fr_FR.json new file mode 100644 index 000000000000..a4f5d86a7342 --- /dev/null +++ b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_fr_FR.json @@ -0,0 +1,9 @@ +{ + "octavia_load_balancer_pools_detail_members_create_title": "Ajouter Manuellement", + "octavia_load_balancer_pools_detail_members_create_description": "Ajouter un membre manuellement s'il est introuvable dans le tableau des instances disponibles.", + "octavia_load_balancer_pools_detail_members_create_cancel": "Annuler", + "octavia_load_balancer_pools_detail_members_create_confirm": "Ajouter", + "octavia_load_balancer_pools_detail_members_create_name_label": "Nom (optionnel)", + "octavia_load_balancer_pools_detail_members_create_address_ip_label": "Adresse IP", + "octavia_load_balancer_pools_detail_members_create_port_label": "Port" +} diff --git a/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_it_IT.json b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_it_IT.json new file mode 100644 index 000000000000..a90396c235cd --- /dev/null +++ b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_it_IT.json @@ -0,0 +1,9 @@ +{ + "octavia_load_balancer_pools_detail_members_create_title": "Aggiungi manualmente", + "octavia_load_balancer_pools_detail_members_create_description": "Aggiungi un membro manualmente se non riesci a trovarlo nella tabella delle istanze disponibili.", + "octavia_load_balancer_pools_detail_members_create_cancel": "Annullare", + "octavia_load_balancer_pools_detail_members_create_confirm": "Aggiungi", + "octavia_load_balancer_pools_detail_members_create_name_label": "Nome (facoltativo)", + "octavia_load_balancer_pools_detail_members_create_address_ip_label": "Indirizzo IP", + "octavia_load_balancer_pools_detail_members_create_port_label": "Porta" +} diff --git a/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_pl_PL.json b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_pl_PL.json new file mode 100644 index 000000000000..babb2a71ba34 --- /dev/null +++ b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_pl_PL.json @@ -0,0 +1,9 @@ +{ + "octavia_load_balancer_pools_detail_members_create_title": "Dodaj ręcznie", + "octavia_load_balancer_pools_detail_members_create_description": "Jeśli użytkownika nie ma w tabeli dostępnych instancji, dodaj go ręcznie.", + "octavia_load_balancer_pools_detail_members_create_cancel": "Anuluj", + "octavia_load_balancer_pools_detail_members_create_confirm": "Dodaj", + "octavia_load_balancer_pools_detail_members_create_name_label": "Nazwa (opcjonalnie)", + "octavia_load_balancer_pools_detail_members_create_address_ip_label": "Adres IP", + "octavia_load_balancer_pools_detail_members_create_port_label": "Port" +} diff --git a/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_pt_PT.json b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_pt_PT.json new file mode 100644 index 000000000000..d2a78affcf67 --- /dev/null +++ b/packages/manager/apps/pci-load-balancer/public/translations/pools/members/create/Messages_pt_PT.json @@ -0,0 +1,9 @@ +{ + "octavia_load_balancer_pools_detail_members_create_title": "Adicionar Manualmente", + "octavia_load_balancer_pools_detail_members_create_description": "Adicionar um membro manualmente, se não for possível encontrá-lo na tabela das instâncias disponíveis.", + "octavia_load_balancer_pools_detail_members_create_cancel": "Anular", + "octavia_load_balancer_pools_detail_members_create_confirm": "Adicionar", + "octavia_load_balancer_pools_detail_members_create_name_label": "Sobrenome (facultativo)", + "octavia_load_balancer_pools_detail_members_create_address_ip_label": "Endereço IP", + "octavia_load_balancer_pools_detail_members_create_port_label": "Porta" +} diff --git a/packages/manager/apps/pci-load-balancer/src/api/data/pool-member.ts b/packages/manager/apps/pci-load-balancer/src/api/data/pool-member.ts index c4fc975e6b36..27f171b48c22 100644 --- a/packages/manager/apps/pci-load-balancer/src/api/data/pool-member.ts +++ b/packages/manager/apps/pci-load-balancer/src/api/data/pool-member.ts @@ -65,3 +65,18 @@ export const updatePoolMemberName = async ( ); return data; }; + +export const createPoolMembers = async ( + projectId: string, + region: string, + poolId: string, + members: TPoolMember[], +) => { + const { data } = await v6.post( + `/cloud/project/${projectId}/region/${region}/loadbalancing/pool/${poolId}/member`, + { + members, + }, + ); + return data; +}; diff --git a/packages/manager/apps/pci-load-balancer/src/api/hook/usePoolMember.tsx b/packages/manager/apps/pci-load-balancer/src/api/hook/usePoolMember.tsx index d0694732eeb1..0bdc09c7a1d8 100644 --- a/packages/manager/apps/pci-load-balancer/src/api/hook/usePoolMember.tsx +++ b/packages/manager/apps/pci-load-balancer/src/api/hook/usePoolMember.tsx @@ -4,6 +4,7 @@ import { useMutation, useQuery } from '@tanstack/react-query'; import { useMemo } from 'react'; import { TPoolMember, + createPoolMembers, deletePoolMember, getPoolMember, getPoolMembers, @@ -139,3 +140,37 @@ export const useUpdatePoolMember = ({ ...mutation, }; }; + +type CreatePoolMembersProps = { + projectId: string; + poolId: string; + region: string; + members: TPoolMember[]; + onError: (cause: Error) => void; + onSuccess: () => void; +}; + +export const useCreatePoolMembers = ({ + projectId, + poolId, + region, + members, + onError, + onSuccess, +}: CreatePoolMembersProps) => { + const mutation = useMutation({ + mutationFn: async () => + createPoolMembers(projectId, region, poolId, members), + onError, + onSuccess: async () => { + await queryClient.invalidateQueries({ + queryKey: ['poolMembers', projectId], + }); + onSuccess(); + }, + }); + return { + createPoolMembers: () => mutation.mutate(), + ...mutation, + }; +}; diff --git a/packages/manager/apps/pci-load-balancer/src/constants.ts b/packages/manager/apps/pci-load-balancer/src/constants.ts index 2c19b867eba1..4d5f0fd1833d 100644 --- a/packages/manager/apps/pci-load-balancer/src/constants.ts +++ b/packages/manager/apps/pci-load-balancer/src/constants.ts @@ -251,3 +251,7 @@ export const VALUE_REGEX_BY_TYPE = { }; export const KEY_REGEX = "^[a-zA-Z0-9!#$%&'*+-.^_`|~]+$"; + +export const REGEX = { + ip: /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/, +}; diff --git a/packages/manager/apps/pci-load-balancer/src/pages/detail/pools/detail/members/create/Create.page.tsx b/packages/manager/apps/pci-load-balancer/src/pages/detail/pools/detail/members/create/Create.page.tsx new file mode 100644 index 000000000000..3b9ea810c03e --- /dev/null +++ b/packages/manager/apps/pci-load-balancer/src/pages/detail/pools/detail/members/create/Create.page.tsx @@ -0,0 +1,195 @@ +import { useNotifications } from '@ovh-ux/manager-react-components'; +import { useMemo, useState } from 'react'; +import { Translation, useTranslation } from 'react-i18next'; +import { useNavigate, useParams } from 'react-router-dom'; +import { ApiError } from '@ovh-ux/manager-core-api'; +import { PciModal } from '@ovh-ux/manager-pci-common'; +import { OsdsFormField, OsdsInput } from '@ovhcloud/ods-components/react'; +import { ODS_INPUT_TYPE } from '@ovhcloud/ods-components'; +import { useCreatePoolMembers } from '@/api/hook/usePoolMember'; +import { TPoolMember } from '@/api/data/pool-member'; +import LabelComponent from '@/components/form/Label.component'; +import { REGEX } from '@/constants'; + +export default function CreatePage() { + const { addSuccess, addError } = useNotifications(); + const { projectId, region, poolId } = useParams(); + const { t: tCreate } = useTranslation('pools/members/create'); + const { t: tPciCommon } = useTranslation('pci-common'); + const navigate = useNavigate(); + const onClose = () => { + navigate('..'); + }; + + const [poolMember, setPoolMember] = useState({ + name: '', + address: '', + protocolPort: 9000, + } as TPoolMember); + const [isTouched, setIsTouched] = useState({ + address: false, + protocolPort: false, + }); + const { + createPoolMembers, + isPending: isPendingCreate, + } = useCreatePoolMembers({ + projectId, + region, + poolId, + members: [poolMember], + onError(error: ApiError) { + addError( + + {(_t) => + _t('octavia_load_balancer_global_error', { + message: error?.response?.data?.message || error?.message || null, + requestId: error?.config?.headers['X-OVH-MANAGER-REQUEST-ID'], + }) + } + , + true, + ); + onClose(); + }, + onSuccess() { + addSuccess( + + {(_t) => + _t('octavia_load_balancer_pools_detail_members_create_success') + } + , + true, + ); + navigate('..'); + }, + }); + const onConfirm = () => { + createPoolMembers(); + }; + + const onCancel = () => { + navigate('..'); + }; + const errorMessageAddress = useMemo(() => { + if (isTouched.address) { + if (!poolMember.address.trim()) { + return tPciCommon('common_field_error_required'); + } + if (!RegExp(REGEX.ip).test(poolMember.address)) { + return tPciCommon('common_field_error_pattern'); + } + } + return ''; + }, [poolMember.address, isTouched.address]); + + const errorMessageProtocolPort = useMemo(() => { + if (isTouched.protocolPort) { + if (!poolMember.protocolPort) { + return tPciCommon('common_field_error_required'); + } + if (!(poolMember.protocolPort >= 1 && poolMember.protocolPort <= 65535)) { + return tPciCommon('common_field_error_max', { max: 65535 }); + } + } + return ''; + }, [poolMember.protocolPort, isTouched.protocolPort]); + return ( + + + + { + setPoolMember((state) => ({ + ...state, + name: event.detail.value.trim(), + })); + }} + /> + + + + { + setPoolMember((state) => ({ + ...state, + address: event.detail.value.trim(), + })); + }} + onOdsInputBlur={() => { + setIsTouched((state) => ({ + ...state, + address: true, + })); + }} + /> + + + + { + setPoolMember((state) => ({ + ...state, + protocolPort: event.detail.value + ? parseInt(event.detail.value, 10) + : 0, + })); + }} + onOdsInputBlur={() => { + setIsTouched((state) => ({ + ...state, + protocolPort: true, + })); + }} + /> + + + ); +} diff --git a/packages/manager/apps/pci-load-balancer/src/routes.tsx b/packages/manager/apps/pci-load-balancer/src/routes.tsx index d1779c283da8..babc9f2cf281 100644 --- a/packages/manager/apps/pci-load-balancer/src/routes.tsx +++ b/packages/manager/apps/pci-load-balancer/src/routes.tsx @@ -31,6 +31,7 @@ export const ROUTE_PATHS = { POOL_DETAIL: ':region/:loadBalancerId/pools/:poolId', POOL_MEMBERS: 'members', POOL_MEMBERS_LIST: 'list', + POOL_MEMBERS_CREATE: 'create', POOL_MEMBERS_DELETE: ':memberId/delete', POOL_MEMBERS_EDIT: ':memberId/edit', STATISTICS: 'statistics', @@ -100,6 +101,9 @@ const PoolsMembersDeletePage = lazy(() => const PoolsMembersEditPage = lazy(() => import('@/pages/detail/pools/detail/members/edit/Edit.page'), ); +const PoolsMembersCreatePage = lazy(() => + import('@/pages/detail/pools/detail/members/create/Create.page'), +); const PoolsMembersPage = lazy(() => import('@/pages/detail/pools/detail/members/Member.page'), ); @@ -190,6 +194,10 @@ const Routes = ( path={ROUTE_PATHS.POOL_MEMBERS_EDIT} Component={PoolsMembersEditPage} /> +