Skip to content

Commit f46b350

Browse files
author
Nicolas Pierre-charles
committed
feat(ips): improve move ip for vrack
ref: #MANAGER-18624 Signed-off-by: Nicolas Pierre-charles <[email protected]>
1 parent deb72b6 commit f46b350

File tree

12 files changed

+281
-88
lines changed

12 files changed

+281
-88
lines changed

packages/manager/apps/ips/mocks/vrack.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@ export const getVrackMocks = ({
3131
getVrackKo,
3232
isVrackExpired,
3333
}: GetVrackMocksParams): Handler[] => [
34+
{
35+
url: '/vrack/:serviceName/task/:taskId',
36+
response: {},
37+
api: 'v6',
38+
status: 404,
39+
},
40+
{
41+
url: '/vrack/:serviceName/task',
42+
response: [],
43+
api: 'v6',
44+
},
3445
{
3546
url: '/vrack/:serviceName/serviceInfos',
3647
response: isVrackExpired ? expiredService : availableService,

packages/manager/apps/ips/public/translations/move-ip/Messages_fr_FR.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"step1EmptyCurrentServiceValue": "Parking des IP",
55
"step1DestinationServiceLabel": "Vers",
66
"step1NextHopLabel": "Sur",
7-
"step1VrackMessage": "Veuillez d'abord détacher votre bloc IP de vRack <Link>(ici)</Link> pour pouvoir le connecter ailleurs.",
87
"step2DescriptionWithNextHop": "Voulez vous vraiment déplacer l'IP <b>{{ip}}</b> vers <b>{{destinationService}}</b> sur <b>{{nextHop}}</b> ?",
98
"step2DescriptionWithoutNextHop": "Voulez vous vraiment déplacer l'IP <b>{{ip}}</b> vers <b>{{destinationService}}</b> ?",
109
"moveIpOnGoingTaskMessage": "Cette IP est déjà en cours de déplacement.",

packages/manager/apps/ips/src/data/api/get/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ export * from './productServices';
1717
export * from './ipRipeInformation';
1818
export * from './ipTask';
1919
export * from './moveIp';
20+
export * from './vrackTask';
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { v6, ApiResponse } from '@ovh-ux/manager-core-api';
2+
import { VrackTask } from '@/types';
3+
4+
export type GetVrackTaskParams = {
5+
serviceName: string;
6+
};
7+
8+
export const getVrackTaskQueryKey = (params: GetVrackTaskParams) => [
9+
'vRackTask',
10+
params.serviceName,
11+
];
12+
13+
export const getVrackTaskList = ({
14+
serviceName,
15+
}: GetVrackTaskParams): Promise<ApiResponse<number[]>> =>
16+
v6.get(`/vrack/${serviceName}/task`);
17+
18+
export type GetVrackTaskDetailsParams = {
19+
serviceName: string;
20+
taskId: number;
21+
};
22+
23+
export const getVrackTaskDetailsQueryKey = (
24+
params: GetVrackTaskDetailsParams,
25+
) => ['vRackTaskDetails', params.serviceName, params.taskId];
26+
27+
export const getVrackTaskDetails = ({
28+
serviceName,
29+
taskId,
30+
}: GetVrackTaskDetailsParams): Promise<ApiResponse<VrackTask>> =>
31+
v6.get(`/vrack/${serviceName}/task/${taskId}`);

packages/manager/apps/ips/src/data/api/postorput/postMoveIp.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,35 @@
11
import { ApiResponse, apiClient } from '@ovh-ux/manager-core-api';
2+
import ipaddr from 'ipaddr.js';
23
import { ipParkingOptionValue, IpTask } from '@/types';
4+
import { getTypeByServiceName } from '@/utils';
5+
import { IpTypeEnum } from '@/data/constants';
36

47
export type PostMoveIpParams = {
58
ip: string;
69
to: string | typeof ipParkingOptionValue;
10+
serviceName: string;
711
nexthop?: string;
812
};
913

1014
export const postMoveIp = async ({
1115
ip,
1216
to,
1317
nexthop,
18+
serviceName,
1419
}: PostMoveIpParams): Promise<ApiResponse<IpTask>> => {
1520
const isDetachedToParking = to === ipParkingOptionValue;
21+
const isAttachedToSomeVrack =
22+
getTypeByServiceName(serviceName) === IpTypeEnum.VRACK;
23+
24+
if (isDetachedToParking && isAttachedToSomeVrack) {
25+
return apiClient.v6.delete(
26+
`/vrack/${serviceName}/${
27+
ipaddr.IPv6.isIPv6(ip) ? 'ipv6' : 'ip'
28+
}/${encodeURIComponent(ip)}`,
29+
{},
30+
);
31+
}
32+
1633
return apiClient.v6.post(
1734
`/ip/${encodeURIComponent(ip)}/${isDetachedToParking ? 'park' : 'move'}`,
1835
isDetachedToParking

packages/manager/apps/ips/src/data/hooks/ip/useMoveIpService.ts

Lines changed: 145 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,135 @@ import {
1919
getIpTaskDetailsQueryKey,
2020
getIpTaskDetails,
2121
MoveIpAvailableDestinationsResponse,
22+
getVrackTaskList,
23+
getVrackTaskQueryKey,
24+
getVrackTaskDetailsQueryKey,
25+
getVrackTaskDetails,
2226
} from '@/data/api';
23-
import { IpTaskStatus, IpTaskFunction, IpTask } from '@/types';
24-
import { INVALIDATED_REFRESH_PERIOD, TRANSLATION_NAMESPACES } from '@/utils';
27+
import {
28+
IpTaskStatus,
29+
IpTaskFunction,
30+
IpTask,
31+
VrackTask,
32+
VrackTaskStatus,
33+
VrackTaskFunction,
34+
} from '@/types';
35+
import {
36+
getTypeByServiceName,
37+
INVALIDATED_REFRESH_PERIOD,
38+
TRANSLATION_NAMESPACES,
39+
} from '@/utils';
40+
import { IpTypeEnum } from '@/data/constants';
2541

2642
const getMoveIpOngoingTasksQueryKey = (ip: string) => [
2743
'ipMoveOngoingTasks',
2844
ip.includes('/') ? ip : `${ip}/32`,
2945
];
3046

47+
export function useVrackMoveTasks({
48+
ip,
49+
serviceName,
50+
enabled = true,
51+
}: {
52+
ip: string;
53+
serviceName?: string;
54+
enabled?: boolean;
55+
}) {
56+
const queryClient = useQueryClient();
57+
const { t } = useTranslation([
58+
TRANSLATION_NAMESPACES.ips,
59+
TRANSLATION_NAMESPACES.moveIp,
60+
]);
61+
const { clearNotifications, addSuccess } = useNotifications();
62+
const { trackPage } = useOvhTracking();
63+
const { data, isLoading } = useQuery({
64+
queryKey: getVrackTaskQueryKey({ serviceName }),
65+
queryFn: () => getVrackTaskList({ serviceName }),
66+
enabled:
67+
!!serviceName &&
68+
getTypeByServiceName(serviceName) === IpTypeEnum.VRACK &&
69+
enabled,
70+
});
71+
72+
const queries = useQueries({
73+
queries: (data?.data ?? []).map((taskId) => ({
74+
queryKey: getVrackTaskDetailsQueryKey({ serviceName, taskId }),
75+
queryFn: async () => {
76+
try {
77+
return await getVrackTaskDetails({ serviceName, taskId });
78+
} catch (err) {
79+
if ((err as ApiError).status === 404) {
80+
clearNotifications();
81+
addSuccess(
82+
t('moveIpDoneMessage', {
83+
ip,
84+
ns: TRANSLATION_NAMESPACES.moveIp,
85+
}),
86+
);
87+
trackPage({
88+
pageType: PageType.bannerSuccess,
89+
pageName: 'move-ip_success',
90+
});
91+
queryClient.invalidateQueries({
92+
queryKey: getIpDetailsQueryKey({ ip }),
93+
});
94+
return {} as ApiResponse<VrackTask>;
95+
}
96+
throw err;
97+
}
98+
},
99+
refetchInterval: (query: Query<ApiResponse<VrackTask>, ApiError>) => {
100+
if (
101+
!query.state.error &&
102+
[
103+
VrackTaskFunction.addBlockToBridgeDomain,
104+
VrackTaskFunction.removeBlockFromBridgeDomain,
105+
].includes(query.state.data?.data?.function)
106+
) {
107+
if (
108+
[
109+
VrackTaskStatus.init,
110+
VrackTaskStatus.todo,
111+
VrackTaskStatus.doing,
112+
].includes(query.state.data?.data?.status)
113+
) {
114+
return INVALIDATED_REFRESH_PERIOD;
115+
}
116+
117+
if (query.state.data?.data?.status === VrackTaskStatus.done) {
118+
clearNotifications();
119+
addSuccess(
120+
t('moveIpDoneMessage', {
121+
ip,
122+
ns: TRANSLATION_NAMESPACES.moveIp,
123+
}),
124+
);
125+
trackPage({
126+
pageType: PageType.bannerSuccess,
127+
pageName: 'move-ip_success',
128+
});
129+
queryClient.invalidateQueries({
130+
queryKey: getIpDetailsQueryKey({ ip }),
131+
});
132+
}
133+
134+
return undefined;
135+
}
136+
137+
return undefined;
138+
},
139+
})),
140+
});
141+
142+
return {
143+
isVrackTasksLoading: isLoading || queries.some((q) => q.isLoading),
144+
vrackTasksError: queries.find((q) => q.error)?.error as ApiError,
145+
hasOnGoingVrackMoveTasks:
146+
queries.map((q) => q.data).filter((d): d is ApiResponse<VrackTask> => !!d)
147+
.length > 0,
148+
};
149+
}
150+
31151
export function useMoveIpTasks({
32152
ip,
33153
enabled,
@@ -140,12 +260,24 @@ export function useMoveIpTasks({
140260

141261
export function useMoveIpService({
142262
ip,
263+
serviceName,
143264
onMoveIpSuccess,
144265
}: {
145266
ip: string;
267+
serviceName?: string;
146268
onMoveIpSuccess?: () => void;
147269
}) {
148270
const queryClient = useQueryClient();
271+
const {
272+
hasOnGoingVrackMoveTasks,
273+
isVrackTasksLoading,
274+
vrackTasksError,
275+
} = useVrackMoveTasks({
276+
ip,
277+
serviceName,
278+
enabled:
279+
!!serviceName && getTypeByServiceName(serviceName) === IpTypeEnum.VRACK,
280+
});
149281
const { hasOnGoingMoveIpTask, isTasksLoading, taskError } = useMoveIpTasks({
150282
ip,
151283
});
@@ -172,7 +304,13 @@ export function useMoveIpService({
172304
};
173305
}
174306
},
175-
enabled: !isTasksLoading && !taskError && !hasOnGoingMoveIpTask,
307+
enabled:
308+
!isTasksLoading &&
309+
!taskError &&
310+
!hasOnGoingMoveIpTask &&
311+
!hasOnGoingVrackMoveTasks &&
312+
!isVrackTasksLoading &&
313+
!vrackTasksError,
176314
});
177315

178316
const isDedicatedCloudService = useCallback(
@@ -210,7 +348,10 @@ export function useMoveIpService({
210348
mutationFn: apiPostMoveIp,
211349
onSuccess: async () => {
212350
queryClient.invalidateQueries({
213-
queryKey: getMoveIpOngoingTasksQueryKey(ip),
351+
queryKey:
352+
serviceName && getTypeByServiceName(serviceName) === IpTypeEnum.VRACK
353+
? getVrackTaskQueryKey({ serviceName })
354+
: getMoveIpOngoingTasksQueryKey(ip),
214355
});
215356
onMoveIpSuccess?.();
216357
},

packages/manager/apps/ips/src/pages/actions/moveIp/__tests__/__snapshots__/moveIp.spec.tsx.snap

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,22 @@
33
exports[`Move IP modal > displays a success message if the IP migration order is successful 1`] = `"<span class="text-sm">Voulez vous vraiment déplacer l'IP <b>239.99.244.14/32</b> vers <b>1122456</b> ?</span>"`;
44

55
exports[`Move IP modal > lets you go to step 2 if you fill correctly destination service and next hop 1`] = `
6-
<ods-text
7-
class="block mb-4 text-center flex-1"
8-
preset="paragraph"
9-
>
10-
<span
11-
class="text-sm"
12-
>
13-
Voulez vous vraiment déplacer l'IP
14-
<b>
15-
239.99.244.14/32
16-
</b>
17-
vers
18-
<b>
19-
01234506
20-
</b>
21-
?
22-
</span>
23-
</ods-text>
24-
`;
25-
26-
exports[`Move IP modal > lets you go to step 2 if you fill correctly destination service and next hop 2`] = `
276
<ods-text
287
class="block mb-4 text-center flex-1 ods-text"
298
preset="paragraph"
309
>
3110
<span
3211
class="text-sm"
3312
>
34-
Voulez vous vraiment déplacer l'IP
13+
Voulez vous vraiment déplacer l'IP
3514
<b>
3615
239.99.244.14/32
3716
</b>
38-
vers
17+
vers
3918
<b>
4019
01234506
4120
</b>
42-
sur
21+
sur
4322
<b>
4423
111.22.333.444
4524
</b>

0 commit comments

Comments
 (0)