Skip to content

Commit 148ba1c

Browse files
authored
Merge pull request #20603 from ovh/feat/DCE-34
feat(web-domains): init order webhosting from module federation
2 parents 85588cb + aee9031 commit 148ba1c

File tree

11 files changed

+256
-2
lines changed

11 files changed

+256
-2
lines changed

packages/manager/apps/web-domains/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"test": "manager-test run"
2222
},
2323
"dependencies": {
24+
"@module-federation/runtime": "^0.21.2",
2425
"@ovh-ux/manager-common-translations": "^0.23.1",
2526
"@ovh-ux/manager-config": "^8.7.1",
2627
"@ovh-ux/manager-core-api": "^0.16.0",

packages/manager/apps/web-domains/src/domain/components/AssociatedServicesCards/Hosting.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import {
1717

1818
import FreeHostingDrawer from './FreeHostingDrawer';
1919
import { FREE_HOSTING_PLAN_CODE } from '@/domain/constants/order';
20+
import { useNavigate } from 'react-router-dom';
21+
import { useGenerateUrl } from '@/common/hooks/generateUrl/useGenerateUrl';
22+
import { urls } from '@/domain/routes/routes.constant';
2023

2124
interface HostingProps {
2225
readonly serviceName: string;
@@ -50,6 +53,7 @@ export default function Hosting({ serviceName }: HostingProps) {
5053
dnsMx: false,
5154
consent: false,
5255
});
56+
const navigate = useNavigate();
5357

5458
const { data: associatedHosting } = useGetAssociatedHosting(serviceName);
5559
const {
@@ -103,6 +107,14 @@ export default function Hosting({ serviceName }: HostingProps) {
103107
label: t(
104108
'domain_tab_general_information_associated_services_hosting_action_order',
105109
),
110+
onClick: () => {
111+
navigate(
112+
useGenerateUrl(urls.domainTabWebHostingOrder, 'path', {
113+
serviceName,
114+
}),
115+
{ replace: true },
116+
);
117+
},
106118
},
107119
];
108120

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Suspense, useContext } from 'react';
2+
import { WebHostingComponent } from './webHostingOrderModule';
3+
import { ShellContext } from '@ovh-ux/manager-react-shell-client';
4+
import { getLanguageKey } from '@/domain/utils/utils';
5+
import { useTranslation } from 'react-i18next';
6+
import Loading from '../Loading/Loading';
7+
8+
export default function WebHostingOrderComponent() {
9+
const { i18n } = useTranslation();
10+
const {
11+
environment: { user },
12+
} = useContext(ShellContext);
13+
const langCode = getLanguageKey(i18n.language);
14+
15+
return (
16+
<div className="suspend-module">
17+
<Suspense fallback={<Loading />}>
18+
<WebHostingComponent
19+
subsidiary={user.ovhSubsidiary}
20+
language={langCode}
21+
hostAppName="manager"
22+
/>
23+
</Suspense>
24+
</div>
25+
);
26+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import React, { lazy, useEffect, useRef } from 'react';
2+
import { loadRemote } from '@module-federation/runtime';
3+
import { Subsidiary } from '@ovh-ux/manager-config';
4+
import { LangCode } from '@/domain/constants/guideLinks';
5+
export interface WebHostingOptions {
6+
subsidiary: Subsidiary;
7+
language?: LangCode;
8+
hostAppName?: string;
9+
}
10+
11+
export interface ConfigoModuleFederationConfiguration {
12+
options: WebHostingOptions;
13+
}
14+
15+
type WebHostingModuleFederationFactory = (
16+
slot: HTMLElement,
17+
moduleConfiguration: ConfigoModuleFederationConfiguration,
18+
) => () => void;
19+
20+
export const WebHostingComponent = lazy(() =>
21+
loadRemote<{ default: WebHostingModuleFederationFactory }>(
22+
'react-order/webhosting',
23+
).then((module) => {
24+
if (!module) {
25+
throw new Error('Failed to load WebHosting module from react-order');
26+
}
27+
let factoryFunction = module.default || module;
28+
if (typeof factoryFunction === 'object' && factoryFunction.default) {
29+
factoryFunction = factoryFunction.default;
30+
}
31+
32+
return {
33+
default: ({ subsidiary, language, hostAppName }: WebHostingOptions) => {
34+
const containerRef = useRef<HTMLDivElement>(null);
35+
useEffect(() => {
36+
const container = containerRef.current;
37+
if (!container || !subsidiary) {
38+
return undefined;
39+
}
40+
41+
const configuration: ConfigoModuleFederationConfiguration = {
42+
options: {
43+
subsidiary,
44+
language,
45+
hostAppName,
46+
},
47+
};
48+
49+
const cleanup = (factoryFunction as WebHostingModuleFederationFactory)(
50+
container,
51+
configuration,
52+
);
53+
54+
return () => {
55+
if (cleanup && typeof cleanup === 'function') {
56+
cleanup();
57+
}
58+
if (container) {
59+
container.innerHTML = '';
60+
}
61+
};
62+
}, [subsidiary, language]);
63+
64+
return <div ref={containerRef} className="max-w-7xl" />;
65+
},
66+
};
67+
}),
68+
);
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import {
2+
Breadcrumb,
3+
BreadcrumbItem,
4+
BreadcrumbLink,
5+
} from '@ovhcloud/ods-react';
6+
import React from 'react';
7+
import { useTranslation } from 'react-i18next';
8+
import config from '@/web-domains.config';
9+
import { urls } from '@/domain/routes/routes.constant';
10+
import { useNavigationGetUrl } from '@ovh-ux/manager-react-shell-client';
11+
12+
interface BreadcrumbAnyCastProps {
13+
readonly serviceName: string;
14+
}
15+
16+
export const BreadcrumbWebHostingOrder: React.FC<BreadcrumbAnyCastProps> = ({
17+
serviceName,
18+
}: BreadcrumbAnyCastProps) => {
19+
const { t } = useTranslation(['domain']);
20+
const detailsUrl = `${urls.domainDetail.replace(
21+
':serviceName',
22+
serviceName,
23+
)}/information`;
24+
const { data: url } = useNavigationGetUrl([config.rootLabel, detailsUrl, {}]);
25+
const { data: parentUrl } = useNavigationGetUrl([
26+
config.rootLabel,
27+
urls.domainRoot,
28+
{},
29+
]);
30+
return (
31+
<Breadcrumb>
32+
<BreadcrumbItem>
33+
<BreadcrumbLink href={parentUrl}>Domain</BreadcrumbLink>
34+
</BreadcrumbItem>
35+
<BreadcrumbItem>
36+
<BreadcrumbLink href={url}>{serviceName}</BreadcrumbLink>
37+
</BreadcrumbItem>
38+
<BreadcrumbItem>
39+
<BreadcrumbLink>
40+
{t(
41+
'domain_tab_general_information_associated_services_hosting_action_order',
42+
)}
43+
</BreadcrumbLink>
44+
</BreadcrumbItem>
45+
</Breadcrumb>
46+
);
47+
};
48+
49+
export default BreadcrumbWebHostingOrder;

packages/manager/apps/web-domains/src/domain/pages/domainTabs/generalInformations/generalInformations.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import React from 'react';
1+
import React, { Suspense } from 'react';
22
import { useParams } from 'react-router-dom';
33
import { ManagerTile } from '@ovh-ux/manager-react-components';
44
import BannerStatus from '@/domain/components/BannerStatus/BannerStatus';
55
import GeneralInformationsCards from '@/domain/components/InformationsCards/GeneralInformations';
66
import SubscriptionCards from '@/domain/components/SubscriptionCards/SubscriptionCards';
77
import AssociatedServicesCards from '@/domain/components/AssociatedServicesCards/AssociatedServicesCards';
8+
import WebHostingOrderComponent from '@/domain/components/WebHostingOrder/webHostingOrderComponent';
89

910
export default function GeneralInformations() {
1011
const { serviceName } = useParams<{ serviceName: string }>();
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { GUIDES_LIST } from '@/domain/constants/guideLinks';
2+
import { changelogLinks } from '@/domain/constants/serviceDetail';
3+
import { getLanguageKey } from '@/domain/utils/utils';
4+
import {
5+
BaseLayout,
6+
ChangelogButton,
7+
GuideButton,
8+
GuideItem,
9+
HeadersProps,
10+
} from '@ovh-ux/manager-react-components';
11+
import { useTranslation } from 'react-i18next';
12+
import { Outlet, useHref, useParams } from 'react-router-dom';
13+
import config from '@/web-domains.config';
14+
import { urls } from '@/domain/routes/routes.constant';
15+
import WebHostingOrderComponent from '@/domain/components/WebHostingOrder/webHostingOrderComponent';
16+
import BreadcrumbWebHostingOrder from './breadcrumb';
17+
18+
export default function WebHostingOrderPage() {
19+
const { t, i18n } = useTranslation(['domain', 'web-domains/error']);
20+
21+
const { serviceName } = useParams<{ serviceName: string }>();
22+
const langCode = getLanguageKey(i18n.language);
23+
24+
const guideItems: GuideItem[] = [
25+
{
26+
id: 1,
27+
href: GUIDES_LIST.domains.url[langCode],
28+
target: '_blank',
29+
label: t('domain_guide_button_label'),
30+
},
31+
];
32+
const hrefPrevious = useHref(
33+
`/${config.rootLabel}${urls.domainDetail.replace(
34+
':serviceName',
35+
serviceName,
36+
)}`,
37+
);
38+
39+
const header: HeadersProps = {
40+
title: serviceName,
41+
changelogButton: <ChangelogButton links={changelogLinks} />,
42+
headerButton: <GuideButton items={guideItems} />,
43+
};
44+
return (
45+
<BaseLayout
46+
breadcrumb={<BreadcrumbWebHostingOrder serviceName={serviceName} />}
47+
header={header}
48+
hrefPrevious={`/${hrefPrevious}`}
49+
backLinkLabel={t('domain_back_to_service_details')}
50+
>
51+
<section data-testid="order-component">
52+
<WebHostingOrderComponent />
53+
</section>
54+
<Outlet />
55+
</BaseLayout>
56+
);
57+
}

packages/manager/apps/web-domains/src/domain/routes/routes.constant.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const urls = {
66
domainTabZone: '/domain/:serviceName/zone',
77
domainTabDns: '/domain/:serviceName/dns',
88
domainTabOrderAnycast: '/domain/:serviceName/anycast/order',
9+
domainTabWebHostingOrder: '/domain/:serviceName/webhosting/order',
910
domainTabDnsModify: '/domain/:serviceName/dns-modify',
1011
domainTabRedirection: '/domain/:serviceName/redirection',
1112
domainTabDynHost: '/domain/:serviceName/dynhost',

packages/manager/apps/web-domains/src/domain/routes/routes.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Navigate, Outlet, Route, useParams } from 'react-router-dom';
33
import { PageType } from '@ovh-ux/manager-react-shell-client';
44
import { ErrorBoundary } from '@ovh-ux/manager-react-components';
55
import { urls } from '@/domain/routes/routes.constant';
6+
import WebHostingOrderPage from '../pages/domainTabs/generalInformations/webhostingOrder';
67

78
const LayoutPage = React.lazy(() => import('@/domain/pages/layout'));
89
const DomainListingPage = React.lazy(() =>
@@ -102,6 +103,10 @@ export default (
102103
/>
103104
</Route>
104105
<Route path={urls.domainTabOrderAnycast} Component={AnycastOrderPage} />
106+
<Route
107+
path={urls.domainTabWebHostingOrder}
108+
Component={WebHostingOrderPage}
109+
/>
105110
<Route path={urls.domainTabDnsModify} Component={DnsModifyPage} />
106111
<Route
107112
path={urls.domainOnboarding}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { init } from '@module-federation/runtime';
2+
3+
const isStagingEnvironment = /\.dtci\./.test(window.location.hostname);
4+
const isLocal = /localhost|127\.0\.0\.1/.test(window.location.hostname);
5+
6+
const getWillOrderUrl = () => {
7+
if (isStagingEnvironment) {
8+
return 'https://ovhcloudcomdev.static.ovh.net/order/builder/assets/remoteEntry.js';
9+
}
10+
// Run module federation in local mode `yarn dev:mf`
11+
if (isLocal) {
12+
return 'http://localhost:5001/assets/remoteEntry.js';
13+
}
14+
return '/order/builder/assets/remoteEntry.js';
15+
};
16+
17+
/**
18+
* Initialize Module Federation runtime
19+
* Called once at application startup (see index.tsx)
20+
*/
21+
export const initModuleFederation = (): void => {
22+
init({
23+
name: 'webhosting',
24+
remotes: [
25+
{
26+
name: 'react-order',
27+
entry: getWillOrderUrl(),
28+
type: 'module',
29+
},
30+
],
31+
});
32+
};

0 commit comments

Comments
 (0)