From 101e460b8109b2e9134005d101aaf03dd9986f14 Mon Sep 17 00:00:00 2001 From: tsiorifamonjena Date: Thu, 19 Dec 2024 18:41:05 +0100 Subject: [PATCH 1/3] feat(pci.load-balancer): use regionselector for loadbalancer ref: TAPC-2270 Signed-off-by: tsiorifamonjena --- .../src/api/hook/useNetwork.tsx | 1 - .../pages/create/steps/region/RegionStep.tsx | 45 ++++++++++--------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/manager/apps/pci-load-balancer/src/api/hook/useNetwork.tsx b/packages/manager/apps/pci-load-balancer/src/api/hook/useNetwork.tsx index b2d969842fc3..70956d3b0c3f 100644 --- a/packages/manager/apps/pci-load-balancer/src/api/hook/useNetwork.tsx +++ b/packages/manager/apps/pci-load-balancer/src/api/hook/useNetwork.tsx @@ -80,7 +80,6 @@ export const useGetPrivateNetworkSubnets = ( ], queryFn: () => getPrivateNetworkSubnets(projectId, region, networkId), enabled: !!projectId && !!region && !!networkId, - throwOnError: true, }); const list = useMemo(() => { diff --git a/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/RegionStep.tsx b/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/RegionStep.tsx index a5b858275145..b35d177de823 100644 --- a/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/RegionStep.tsx +++ b/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/RegionStep.tsx @@ -7,7 +7,11 @@ import { ODS_TEXT_LEVEL, ODS_TEXT_SIZE } from '@ovhcloud/ods-components'; import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; import { StepComponent } from '@ovh-ux/manager-react-components'; import { useTranslation } from 'react-i18next'; -import { ShapesInputComponent } from '@ovh-ux/manager-pci-common'; +import { + RegionSelector, + useProject, + ShapesInputComponent, +} from '@ovh-ux/manager-pci-common'; import { useEffect, useRef } from 'react'; import { TRegion } from '@/api/hook/useRegions'; import { REGION_AVAILABILITY_LINK } from '@/constants'; @@ -33,7 +37,7 @@ export const RegionStep = ({ }: Readonly): JSX.Element => { const { t: tCommon } = useTranslation('pci-common'); const { t: tCreate } = useTranslation('load-balancer/create'); - + const { data: project } = useProject(); const columnsCount = useColumnsCount(); const { trackStep } = useTracking(); @@ -77,7 +81,7 @@ export const RegionStep = ({ store.open(StepsEnum.IP); }, label: tCommon('common_stepper_next_button_label'), - isDisabled: store.region === null, + isDisabled: !store.region?.isEnabled, }} edit={{ action: () => { @@ -117,26 +121,23 @@ export const RegionStep = ({ ) : ( - - items={regions?.get(store.addon?.code) || []} - onInput={(region) => store.set.region(region)} - value={store.region} - columnsCount={columnsCount} - item={{ - LabelComponent, - getId: (item) => item.name, - isDisabled: (item) => !item.isEnabled, - }} - stack={{ - by: (item) => item?.macroName || '', - LabelComponent: StackLabelComponent, - TitleComponent: StackTitleComponent, - }} - group={{ - by: (item) => item.continent, - LabelComponent: GroupLabelComponent, + { + if (selectedRegion) { + const region = regions + ?.get(store.addon?.code) + ?.find(({ name }) => selectedRegion.name === name); + + store.set.region(region); + } }} - isMobile={isMobile} + regionFilter={(region) => + region.isMacro || + regions + ?.get(store.addon?.code) + ?.some(({ name }) => name === region.name) + } /> )} From 15eefe12065f2582c578627ad9cf9da56cc7f15a Mon Sep 17 00:00:00 2001 From: tsiorifamonjena Date: Fri, 20 Dec 2024 10:47:00 +0100 Subject: [PATCH 2/3] feat(pci.load-balancer): clean useless code ref: TAPC-2270 Signed-off-by: tsiorifamonjena --- .../src/pages/create/Create.page.tsx | 3 - .../create/steps/region/RegionStep.spec.tsx | 253 +----------------- .../pages/create/steps/region/RegionStep.tsx | 179 +++++-------- .../components/GroupLabel.component.tsx | 31 --- .../components/StackLabel.component.tsx | 22 -- .../components/StackTitle.component.tsx | 19 -- 6 files changed, 78 insertions(+), 429 deletions(-) delete mode 100644 packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/components/GroupLabel.component.tsx delete mode 100644 packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/components/StackLabel.component.tsx delete mode 100644 packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/components/StackTitle.component.tsx diff --git a/packages/manager/apps/pci-load-balancer/src/pages/create/Create.page.tsx b/packages/manager/apps/pci-load-balancer/src/pages/create/Create.page.tsx index 46eeeb150a39..5144a99d79a2 100644 --- a/packages/manager/apps/pci-load-balancer/src/pages/create/Create.page.tsx +++ b/packages/manager/apps/pci-load-balancer/src/pages/create/Create.page.tsx @@ -11,7 +11,6 @@ import { useTranslation } from 'react-i18next'; import { ODS_TEXT_LEVEL, ODS_TEXT_SIZE } from '@ovhcloud/ods-components'; import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; import { useEffect } from 'react'; -import { useMedia } from 'react-use'; import { useCreateStore } from './store'; import { useGetPrivateNetworkSubnets, @@ -32,7 +31,6 @@ import { useGetFloatingIps } from '@/api/hook/useFloatingIps'; export default function CreatePage(): JSX.Element { const { me } = useMe(); const { data: addons, isPending: isAddonsPending } = useGetAddons(); - const isMobile = useMedia(`(max-width: 768px)`); const projectHref = useProjectUrl('public-cloud'); @@ -161,7 +159,6 @@ export default function CreatePage(): JSX.Element { isLoading={isRegionsPending} regions={regions} ovhSubsidiary={me?.ovhSubsidiary} - isMobile={isMobile} /> ({ + useProject: vi.fn().mockReturnValue({ data: { project_id: 'project_id' } }), + RegionSelector: () =>
, +})); vi.mock('react-i18next', async () => { const { ...rest } = await vi.importActual('react-i18next'); @@ -68,30 +63,14 @@ vi.mock('@ovh-ux/manager-react-components', async () => { .mockImplementation(ActualStepComponent as typeof StepComponent), }; }); -vi.mock('@ovh-ux/manager-pci-common', async () => { - const { - ShapesInputComponent: ActualShapesInputComponent, - ...rest - } = await vi.importActual('@ovh-ux/manager-pci-common'); - return { - ...rest, - ShapesInputComponent: vi - .fn() - .mockImplementation( - ActualShapesInputComponent as typeof ShapesInputComponent, - ), - }; -}); const renderStep = ( { isLoading = false, - isMobile = false, regions = undefined, ovhSubsidiary = undefined, }: Partial = { isLoading: false, - isMobile: false, regions: undefined, ovhSubsidiary: undefined, }, @@ -99,7 +78,6 @@ const renderStep = ( render( , @@ -199,225 +177,6 @@ describe('RegionStep', () => { expect(getByTestId('spinner')).toBeInTheDocument(); }); - - describe('isLoading is false', () => { - beforeAll(() => { - ((ShapesInputComponent as unknown) as Mock).mockImplementationOnce( - () =>
, - ); - }); - it('should show input if regions are not pending and data is defined', () => { - const regions: TRegion[] = [ - { name: 'test', isEnabled: true, continent: 'Europe' }, - { name: 'test2', isEnabled: true, continent: 'Asia' }, - ] as Array; - - const { result } = renderStore(); - - act(() => result.current.set.addon({ code: 's' } as TAddon)); - - renderStep({ regions: new Map([['s', regions]]) }); - - const { calls } = (ShapesInputComponent as Mock).mock; - const call = calls[calls.length - 1][0] as TShapesInputProps; - - expect(call.items).toEqual(regions); - expect(call.value).toBe(null); - - expect(call.item.LabelComponent).toEqual(LabelComponent); - expect(call.item.getId({ name: 'test' } as TRegion)).toBe('test'); - expect(call.item.isDisabled({ isEnabled: true } as TRegion)).toBe( - false, - ); - - expect(call.stack.by({ macroName: 'test' } as TRegion)).toBe('test'); - expect(call.stack.by({} as TRegion)).toBe(''); - expect(call.stack.LabelComponent).toEqual(StackLabelComponent); - expect(call.stack.TitleComponent).toEqual(StackTitleComponent); - - expect(call.group.by({ continent: 'Europe' } as TRegion)).toBe( - 'Europe', - ); - expect(call.group.LabelComponent).toEqual(GroupLabelComponent); - }); - }); - }); - }); - - describe('Actions', () => { - beforeAll(() => { - (ShapesInputComponent as Mock).mockImplementationOnce(() => ( -
- )); - }); - - describe('next', () => { - describe('render', () => { - test('Next button should be disabled if region is not set', () => { - const { getByText } = renderStep(); - - const nextButton = getByText( - 'pci-common | common_stepper_next_button_label', - ); - expect( - nextButton.attributes.getNamedItem('disabled').value, - ).toBeTruthy(); - }); - - test('Next button should be enabled if region is set', () => { - (ShapesInputComponent as Mock).mockImplementationOnce(() => ( -
- )); - - const { result } = renderStore(); - act(() => result.current.set.region({} as TRegion)); - - const { getByText } = renderStep(); - const nextButton = getByText( - 'pci-common | common_stepper_next_button_label', - ); - expect( - nextButton.attributes.getNamedItem('disabled')?.value, - ).toBeFalsy(); - }); - }); - describe('click', () => { - beforeEach(() => { - const { result } = renderStore(); - act(() => { - result.current.set.region({} as TRegion); - }); - }); - it('Should track on next click', async () => { - (ShapesInputComponent as Mock).mockImplementationOnce(() => ( -
- )); - const trackStepSpy = vi.fn(); - - (useTracking as Mock).mockImplementationOnce(() => ({ - trackStep: trackStepSpy, - })); - - const { result } = renderStore(); - - act(() => { - result.current.set.region({} as TRegion); - }); - - const { getByText } = renderStep(); - - const nextButton = getByText( - 'pci-common | common_stepper_next_button_label', - ); - - act(() => nextButton.click()); - - expect(trackStepSpy).toHaveBeenCalledWith(2); - }); - - it('Should prepare next step on next click', async () => { - (ShapesInputComponent as Mock).mockImplementationOnce(() => ( -
- )); - - const { result } = renderStore(); - - act(() => { - result.current.set.region({} as TRegion); - }); - - const { getByText } = renderStep(); - - const nextButton = getByText( - 'pci-common | common_stepper_next_button_label', - ); - - const { check, lock, open } = { ...result.current }; - - result.current.check = vi.fn(); - result.current.lock = vi.fn(); - result.current.open = vi.fn(); - - act(() => nextButton.click()); - - expect(result.current.check).toHaveBeenCalledWith(StepsEnum.REGION); - expect(result.current.lock).toHaveBeenCalledWith(StepsEnum.REGION); - expect(result.current.open).toHaveBeenCalledWith(StepsEnum.IP); - - result.current.check = check; - result.current.lock = lock; - result.current.open = open; - }); - }); - }); - - describe('edit', () => { - describe('render', () => { - it('should not display if step is not checked', () => { - const { queryByText } = renderStep(); - - const editButton = queryByText( - 'pci-common | common_stepper_modify_this_step', - ); - expect(editButton).not.toBeInTheDocument(); - }); - it('should have the right label', () => { - const { result } = renderStore(); - act(() => result.current.lock(StepsEnum.REGION)); - - ((OsdsLink as unknown) as Mock).mockImplementation( - ({ href, ...props }) => ( - - ), - ); - - const { queryByText } = renderStep(); - - const editButton = queryByText( - 'pci-common | common_stepper_modify_this_step', - ); - - expect(editButton).toBeInTheDocument(); - }); - }); - - describe('click', () => { - it('should prepare steps on click', () => { - const { result } = renderStore(); - - const { unlock, uncheck, open, reset } = { ...result.current }; - - act(() => result.current.lock(StepsEnum.REGION)); - - result.current.unlock = vi.fn(); - result.current.uncheck = vi.fn(); - result.current.open = vi.fn(); - result.current.reset = vi.fn(); - - const { getByText } = renderStep(); - - const editButton = getByText( - 'pci-common | common_stepper_modify_this_step', - ); - - act(() => editButton.click()); - - expect(result.current.unlock).toHaveBeenCalledWith(StepsEnum.REGION); - expect(result.current.uncheck).toHaveBeenCalledWith(StepsEnum.REGION); - expect(result.current.open).toHaveBeenCalledWith(StepsEnum.REGION); - expect(result.current.reset).toHaveBeenCalledWith( - StepsEnum.IP, - StepsEnum.NETWORK, - StepsEnum.INSTANCE, - StepsEnum.NAME, - ); - - result.current.unlock = unlock; - result.current.uncheck = uncheck; - result.current.open = open; - result.current.reset = reset; - }); - }); }); }); }); diff --git a/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/RegionStep.tsx b/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/RegionStep.tsx index b35d177de823..51c7e861d6c7 100644 --- a/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/RegionStep.tsx +++ b/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/RegionStep.tsx @@ -7,140 +7,105 @@ import { ODS_TEXT_LEVEL, ODS_TEXT_SIZE } from '@ovhcloud/ods-components'; import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; import { StepComponent } from '@ovh-ux/manager-react-components'; import { useTranslation } from 'react-i18next'; -import { - RegionSelector, - useProject, - ShapesInputComponent, -} from '@ovh-ux/manager-pci-common'; -import { useEffect, useRef } from 'react'; +import { RegionSelector, useProject } from '@ovh-ux/manager-pci-common'; import { TRegion } from '@/api/hook/useRegions'; import { REGION_AVAILABILITY_LINK } from '@/constants'; import { StepsEnum, useCreateStore } from '@/pages/create/store'; import { useTracking } from '@/pages/create/hooks/useTracking'; -import { LabelComponent } from './components/Label.component'; -import { StackLabelComponent } from './components/StackLabel.component'; -import { GroupLabelComponent } from './components/GroupLabel.component'; -import { StackTitleComponent } from '@/pages/create/steps/region/components/StackTitle.component'; -import { useColumnsCount } from '@/pages/create/hooks/useColumnsCount'; export type TRegionStepProps = { isLoading: boolean; - isMobile: boolean; regions: Map; ovhSubsidiary: string; }; export const RegionStep = ({ isLoading, - isMobile, regions, ovhSubsidiary, }: Readonly): JSX.Element => { - const { t: tCommon } = useTranslation('pci-common'); - const { t: tCreate } = useTranslation('load-balancer/create'); + const { t } = useTranslation(['load-balancer/create', 'pci-common']); const { data: project } = useProject(); - const columnsCount = useColumnsCount(); const { trackStep } = useTracking(); const store = useCreateStore(); - // TODO: remove this once the class is added to step component directly in manager-react-components - useEffect(() => { - const refEl = document.getElementById('ref'); - if (refEl) { - const stepEl = refEl.nextSibling; - if (stepEl) { - const targetEl = stepEl.childNodes.item(1); - - if (targetEl.nodeName === 'DIV') { - const target = targetEl as HTMLDivElement; - if (!target.classList.contains('max-w-[calc(100%-76px)]')) { - target.classList.add('max-w-[calc(100%-76px)]'); - } - } - } - } - }, []); - return ( - <> -
- { - trackStep(2); + { + trackStep(2); - store.check(StepsEnum.REGION); - store.lock(StepsEnum.REGION); + store.check(StepsEnum.REGION); + store.lock(StepsEnum.REGION); - store.open(StepsEnum.IP); - }, - label: tCommon('common_stepper_next_button_label'), - isDisabled: !store.region?.isEnabled, - }} - edit={{ - action: () => { - store.unlock(StepsEnum.REGION); - store.uncheck(StepsEnum.REGION); - store.open(StepsEnum.REGION); - store.reset( - StepsEnum.IP, - StepsEnum.NETWORK, - StepsEnum.INSTANCE, - StepsEnum.NAME, - ); - }, - label: tCommon('common_stepper_modify_this_step'), - }} - > -
- { + store.unlock(StepsEnum.REGION); + store.uncheck(StepsEnum.REGION); + store.open(StepsEnum.REGION); + store.reset( + StepsEnum.IP, + StepsEnum.NETWORK, + StepsEnum.INSTANCE, + StepsEnum.NAME, + ); + }, + label: t('pci-common:common_stepper_modify_this_step'), + }} + > +
+ + {t('octavia_load_balancer_create_region_intro')} + - {tCreate('octavia_load_balancer_create_region_intro')}{' '} - - {tCreate('octavia_load_balancer_create_region_link')} - - + {t('octavia_load_balancer_create_region_link')} + + +
+ {isLoading ? ( +
+
- {isLoading ? ( -
- -
- ) : ( - { - if (selectedRegion) { - const region = regions - ?.get(store.addon?.code) - ?.find(({ name }) => selectedRegion.name === name); - - store.set.region(region); - } - }} - regionFilter={(region) => - region.isMacro || - regions + ) : ( + { + if (selectedRegion) { + const region = regions ?.get(store.addon?.code) - ?.some(({ name }) => name === region.name) + ?.find(({ name }) => selectedRegion.name === name); + + store.set.region(region); } - /> - )} - - + }} + regionFilter={(region) => + region.isMacro || + regions + ?.get(store.addon?.code) + ?.some(({ name }) => name === region.name) + } + /> + )} + ); }; diff --git a/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/components/GroupLabel.component.tsx b/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/components/GroupLabel.component.tsx deleted file mode 100644 index 4bd3a41ab907..000000000000 --- a/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/components/GroupLabel.component.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { OsdsText } from '@ovhcloud/ods-components/react'; -import { ODS_TEXT_LEVEL, ODS_TEXT_SIZE } from '@ovhcloud/ods-components'; -import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; -import { useTranslation } from 'react-i18next'; - -export const GroupLabelComponent = ({ - groupName, - isGroupSelected, - isMobile, -}: { - groupName: string; - isGroupSelected: boolean; - isMobile: boolean; -}) => { - const { t: tRegionsList } = useTranslation('regions-list'); - - const shouldBeBold = isMobile || (isGroupSelected && !isMobile); - - return ( -
- - {groupName || tRegionsList('pci_project_regions_list_continent_all')} - -
- ); -}; diff --git a/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/components/StackLabel.component.tsx b/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/components/StackLabel.component.tsx deleted file mode 100644 index ed26951a7bb5..000000000000 --- a/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/components/StackLabel.component.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { OsdsText } from '@ovhcloud/ods-components/react'; -import { ODS_TEXT_LEVEL, ODS_TEXT_SIZE } from '@ovhcloud/ods-components'; -import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; -import { TRegion } from '@/api/hook/useRegions'; - -export const StackLabelComponent = ({ - isStackSelected, - stackItems, -}: { - isStackSelected: boolean; - stackItems: TRegion[]; -}) => ( -
- - {stackItems[0].macroName} - -
-); diff --git a/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/components/StackTitle.component.tsx b/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/components/StackTitle.component.tsx deleted file mode 100644 index 0ded4a14cd97..000000000000 --- a/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/components/StackTitle.component.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { OsdsText } from '@ovhcloud/ods-components/react'; -import { ODS_TEXT_LEVEL, ODS_TEXT_SIZE } from '@ovhcloud/ods-components'; -import { ODS_THEME_COLOR_INTENT } from '@ovhcloud/ods-common-theming'; -import { useTranslation } from 'react-i18next'; - -export const StackTitleComponent = () => { - const { t: tRegionsList } = useTranslation('regions-list'); - return ( -
- - {tRegionsList('pci_project_regions_list_region')} - -
- ); -}; From b44cfeb23323433c456df0aa0ffcdbfce6daf0c4 Mon Sep 17 00:00:00 2001 From: tsiorifamonjena Date: Fri, 20 Dec 2024 14:31:06 +0100 Subject: [PATCH 3/3] feat(pci.load-balancer): fix unit test ref: TAPC-2270 Signed-off-by: tsiorifamonjena --- .../src/pages/create/steps/region/RegionStep.spec.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/RegionStep.spec.tsx b/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/RegionStep.spec.tsx index 0663aec47829..83e7559d5040 100644 --- a/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/RegionStep.spec.tsx +++ b/packages/manager/apps/pci-load-balancer/src/pages/create/steps/region/RegionStep.spec.tsx @@ -106,7 +106,7 @@ describe('RegionStep', () => { const call = calls[calls.length - 1][0] as TStepProps; expect(call.title).toBe( - 'load-balancer/create | octavia_load_balancer_create_region_title', + 'load-balancer/create,pci-common | octavia_load_balancer_create_region_title', ); expect(call.isOpen).toBe(true); @@ -118,12 +118,12 @@ describe('RegionStep', () => { expect(call.order).toBe(2); expect(call.next.label).toBe( - 'pci-common | common_stepper_next_button_label', + 'load-balancer/create,pci-common | pci-common:common_stepper_next_button_label', ); expect(call.next.isDisabled).toBe(true); expect(call.edit.label).toBe( - 'pci-common | common_stepper_modify_this_step', + 'load-balancer/create,pci-common | pci-common:common_stepper_modify_this_step', ); }); @@ -131,12 +131,12 @@ describe('RegionStep', () => { const { getByText } = renderStep(); expect( getByText( - 'load-balancer/create | octavia_load_balancer_create_region_intro', + 'load-balancer/create,pci-common | octavia_load_balancer_create_region_intro', ), ).toBeInTheDocument(); expect( getByText( - 'load-balancer/create | octavia_load_balancer_create_region_link', + 'load-balancer/create,pci-common | octavia_load_balancer_create_region_link', ), ).toBeInTheDocument(); });