Skip to content

Commit

Permalink
feat(pci-load-balancer): add create member modal
Browse files Browse the repository at this point in the history
ref: DTCORE-2660
Signed-off-by: Yoann Fievez <[email protected]>
  • Loading branch information
kqesar committed Oct 16, 2024
1 parent 2ccce0f commit 70331b5
Show file tree
Hide file tree
Showing 13 changed files with 328 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
@@ -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"
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useMutation, useQuery } from '@tanstack/react-query';
import { useMemo } from 'react';
import {
TPoolMember,
createPoolMembers,
deletePoolMember,
getPoolMember,
getPoolMembers,
Expand Down Expand Up @@ -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,
};
};
4 changes: 4 additions & 0 deletions packages/manager/apps/pci-load-balancer/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]?)$/,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
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<TPoolMember>({
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(
<Translation ns="octavia-load-balancer">
{(_t) =>
_t('octavia_load_balancer_global_error', {
message: error?.response?.data?.message || error?.message || null,
requestId: error?.config?.headers['X-OVH-MANAGER-REQUEST-ID'],
})
}
</Translation>,
true,
);
onClose();
},
onSuccess() {
addSuccess(
<Translation ns="pools/members">
{(_t) =>
_t('octavia_load_balancer_pools_detail_members_create_success')
}
</Translation>,
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 (
<PciModal
onConfirm={onConfirm}
onCancel={onCancel}
onClose={onClose}
isPending={isPendingCreate}
cancelText={tCreate(
'octavia_load_balancer_pools_detail_members_create_cancel',
)}
submitText={tCreate(
'octavia_load_balancer_pools_detail_members_create_confirm',
)}
title={tCreate('octavia_load_balancer_pools_detail_members_create_title')}
>
<OsdsFormField className="mt-8">
<LabelComponent
text={tCreate(
'octavia_load_balancer_pools_detail_members_create_name_label',
)}
slot="label"
/>
<OsdsInput
value={poolMember.name}
type={ODS_INPUT_TYPE.text}
onOdsValueChange={(event) => {
setPoolMember((state) => ({
...state,
name: event.detail.value.trim(),
}));
}}
/>
</OsdsFormField>
<OsdsFormField className="mt-8" error={errorMessageAddress}>
<LabelComponent
text={tCreate(
'octavia_load_balancer_pools_detail_members_create_address_ip_label',
)}
slot="label"
hasError={!!errorMessageAddress}
/>
<OsdsInput
value={poolMember.address}
type={ODS_INPUT_TYPE.text}
className={
errorMessageAddress
? 'bg-red-100 border-red-500 text-red-500 focus:text-red-500'
: 'border-color-[var(--ods-color-default-200)] bg-white'
}
onOdsValueChange={(event) => {
setPoolMember((state) => ({
...state,
address: event.detail.value.trim(),
}));
}}
onOdsInputBlur={() => {
setIsTouched((state) => ({
...state,
address: true,
}));
}}
/>
</OsdsFormField>
<OsdsFormField className="mt-8" error={errorMessageProtocolPort}>
<LabelComponent
text={tCreate(
'octavia_load_balancer_pools_detail_members_create_port_label',
)}
slot="label"
hasError={!!errorMessageProtocolPort}
/>
<OsdsInput
value={poolMember?.protocolPort}
min={1}
max={65535}
className={
errorMessageProtocolPort
? 'bg-red-100 border-red-500 text-red-500 focus:text-red-500'
: 'border-color-[var(--ods-color-default-200)] bg-white'
}
onOdsValueChange={(event) => {
setPoolMember((state) => ({
...state,
protocolPort: event.detail.value
? parseInt(event.detail.value, 10)
: 0,
}));
}}
onOdsInputBlur={() => {
setIsTouched((state) => ({
...state,
protocolPort: true,
}));
}}
/>
</OsdsFormField>
</PciModal>
);
}
8 changes: 8 additions & 0 deletions packages/manager/apps/pci-load-balancer/src/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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'),
);
Expand Down Expand Up @@ -190,6 +194,10 @@ const Routes = (
path={ROUTE_PATHS.POOL_MEMBERS_EDIT}
Component={PoolsMembersEditPage}
/>
<Route
path={ROUTE_PATHS.POOL_MEMBERS_CREATE}
Component={PoolsMembersCreatePage}
/>
</Route>
</Route>
<Route
Expand Down

0 comments on commit 70331b5

Please sign in to comment.