setDataProtectionDrawerOpened(false)}
- />
- )}
-
-
- {t('domain_tab_general_information_configuration')}
-
-
-
- Serveur DNS
-
-
- Enregistré
-
-
-
-
-
-
-
-
-
- setDnssecModalOpened(!dnssecModalOpened)}
- />
- handleUpdateProtectionState()}
- onClose={() => setTransferModalOpened(!transferModalOpened)}
- />
-
- setTransferAuthInfoModalOpened(!transferAuthInfoModalOpened)
- }
- open={transferAuthInfoModalOpened}
- />
- setTagModalOpened(!tagModalOpened)}
- />
- setDataProtectionDrawerOpened(false)}
- domainResource={domainResource}
- visibleContacts={visibleContacts}
- selectedContacts={selectedContacts}
- onCheckboxChange={handleCheckboxChange}
- onClick={() => {
- handleUpdateDataProtection();
- }}
- />
-
- >
+
+
+ {t('domain_tab_general_information_configuration')}
+
+
+
+
+
+
+
+ setDnssecModalOpened(!dnssecModalOpened)}
+ />
+
+
+ handleUpdateProtectionState()}
+ onClose={() => setTransferModalOpened(!transferModalOpened)}
+ />
+
+ setTransferAuthInfoModalOpened(!transferAuthInfoModalOpened)
+ }
+ open={transferAuthInfoModalOpened}
+ />
+ setTagModalOpened(!tagModalOpened)}
+ />
+ setDataProtectionDrawerOpened(false)}
+ domainResource={domainResource}
+ visibleContacts={visibleContacts}
+ selectedContacts={selectedContacts}
+ onCheckboxChange={handleCheckboxChange}
+ onClick={() => {
+ handleUpdateDataProtection();
+ }}
+ />
+
+ setAnycastTerminateModalOpen(!anycastTerminateModalOpen)
+ }
+ />
+
);
}
diff --git a/packages/manager/apps/web-domains/src/domain/components/ConfigurationCards/DataProtection.spec.tsx b/packages/manager/apps/web-domains/src/domain/components/ConfigurationCards/DataProtection.spec.tsx
index 82da0beb6336..abae9051cb3e 100644
--- a/packages/manager/apps/web-domains/src/domain/components/ConfigurationCards/DataProtection.spec.tsx
+++ b/packages/manager/apps/web-domains/src/domain/components/ConfigurationCards/DataProtection.spec.tsx
@@ -1,6 +1,6 @@
import '@/common/setupTests';
import React from 'react';
-import { render, screen, waitFor } from '@testing-library/react';
+import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { vi } from 'vitest';
import { wrapper } from '@/common/utils/test.provider';
@@ -8,7 +8,6 @@ import DataProtection from './DataProtection';
import {
TDomainResource,
DisclosureConfigurationEnum,
- DataProtectionStatus,
} from '@/domain/types/domainResource';
import { DnsConfigurationTypeEnum } from '@/domain/enum/dnsConfigurationType.enum';
import { DomainStateEnum } from '@/domain/enum/domainState.enum';
diff --git a/packages/manager/apps/web-domains/src/domain/components/ConfigurationCards/DnsState.spec.tsx b/packages/manager/apps/web-domains/src/domain/components/ConfigurationCards/DnsState.spec.tsx
new file mode 100644
index 000000000000..14d4bf8a01b8
--- /dev/null
+++ b/packages/manager/apps/web-domains/src/domain/components/ConfigurationCards/DnsState.spec.tsx
@@ -0,0 +1,184 @@
+import '@/common/setupTests';
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import { vi } from 'vitest';
+import { wrapper } from '@/common/utils/test.provider';
+import DnsState from './DnsState';
+import { OptionStateEnum } from '@/domain/enum/optionState.enum';
+import { TDomainResource } from '@/domain/types/domainResource';
+import { DnsConfigurationTypeEnum } from '@/domain/enum/dnsConfigurationType.enum';
+import { DomainStateEnum } from '@/domain/enum/domainState.enum';
+import { ProtectionStateEnum } from '@/domain/enum/protectionState.enum';
+import { SuspensionStateEnum } from '@/domain/enum/suspensionState.enum';
+import { ResourceStatusEnum } from '@/domain/enum/resourceStatus.enum';
+import { OptionEnum } from '@/common/enum/option.enum';
+
+describe('DnsState component', () => {
+ const mockDomainResource: TDomainResource = {
+ checksum: 'checksum-value',
+ currentState: {
+ additionalStates: [],
+ dnsConfiguration: {
+ configurationType: DnsConfigurationTypeEnum.HOSTING,
+ glueRecordIPv6Supported: true,
+ hostSupported: true,
+ maxDNS: 10,
+ minDNS: 2,
+ nameServers: [
+ {
+ ipv4: '192.0.2.1',
+ ipv6: '2001:db8::1',
+ nameServer: 'ns1.example.com',
+ nameServerType: DnsConfigurationTypeEnum.HOSTING,
+ },
+ {
+ ipv4: '192.0.2.2',
+ ipv6: '2001:db8::2',
+ nameServer: 'ns2.example.com',
+ nameServerType: DnsConfigurationTypeEnum.HOSTING,
+ },
+ ],
+ dnssecSupported: true,
+ },
+ hostsConfiguration: {
+ ipv4Supported: true,
+ ipv6Supported: true,
+ multipleIPsSupported: true,
+ hostSupported: true,
+ hosts: [],
+ },
+ contactsConfiguration: {
+ contactAdministrator: {
+ id: 'contact-admin-id',
+ },
+ contactBilling: {
+ id: 'contact-billing-id',
+ },
+ contactTechnical: {
+ id: 'contact-tech-id',
+ },
+ contactOwner: {
+ id: 'contact-owner-id',
+ },
+ },
+ extension: '.com',
+ mainState: DomainStateEnum.OK,
+ name: 'example.com',
+ protectionState: ProtectionStateEnum.UNPROTECTED,
+ suspensionState: SuspensionStateEnum.NOT_SUSPENDED,
+ authInfoManagedByOVHcloud: true,
+ authInfoSupported: true,
+ createdAt: '2024-01-01T00:00:00Z',
+ },
+ currentTasks: [],
+ iam: null,
+ id: 'domain-id',
+ resourceStatus: ResourceStatusEnum.READY,
+ };
+
+ const mockAnycastOption = {
+ state: OptionStateEnum.SUBSCRIBED,
+ expirationDate: new Date('2025-12-31T23:59:59Z').toString(),
+ };
+
+ it('renders DNS state label and notes', () => {
+ render(
+
,
+ { wrapper },
+ );
+
+ expect(
+ screen.getByText('domain_tab_general_information_dns_standard'),
+ ).toBeInTheDocument();
+ expect(
+ screen.getByText('domain_tab_general_information_note_anycast'),
+ ).toBeInTheDocument();
+ });
+
+ it('renders tooltip with anycast label when anycast is subscribed', () => {
+ const { container } = render(
+
,
+ { wrapper },
+ );
+
+ const button = container.querySelector(
+ 'ods-button[label*="domain_dns_tab_button_cancel_terminate_anycast"]',
+ );
+ expect(button).toBeInTheDocument();
+ });
+
+ it('renders tooltip with anycast label when anycast is released', () => {
+ const releasedAnycastOption = {
+ ...mockAnycastOption,
+ state: OptionStateEnum.RELEASED,
+ };
+
+ const { container } = render(
+
,
+ { wrapper },
+ );
+
+ const button = container.querySelector(
+ 'ods-button[label*="domain_dns_tab_button_cancel_terminate_anycast"]',
+ );
+ expect(button).toBeInTheDocument();
+ });
+
+ it('renders tooltip with anycast label when anycast is not set', () => {
+ const { container } = render(
+
,
+ { wrapper },
+ );
+
+ const button = container.querySelector(
+ 'ods-button[label="domain_tab_DNS_anycast_order"]',
+ );
+ expect(button).toBeInTheDocument();
+ });
+});
diff --git a/packages/manager/apps/web-domains/src/domain/components/ConfigurationCards/DnsState.tsx b/packages/manager/apps/web-domains/src/domain/components/ConfigurationCards/DnsState.tsx
new file mode 100644
index 000000000000..5668af6cfe00
--- /dev/null
+++ b/packages/manager/apps/web-domains/src/domain/components/ConfigurationCards/DnsState.tsx
@@ -0,0 +1,139 @@
+import React from 'react';
+import { Trans, useTranslation } from 'react-i18next';
+import { useNavigate } from 'react-router-dom';
+import {
+ ActionMenu,
+ ManagerTile,
+ useFormatDate,
+} from '@ovh-ux/manager-react-components';
+import { NAMESPACES } from '@ovh-ux/manager-common-translations';
+import { Text, TEXT_PRESET } from '@ovhcloud/ods-react';
+import { getDnsStateDetails } from '@/domain/utils/dnsUtils';
+import { OptionStateEnum } from '@/domain/enum/optionState.enum';
+import { useGenerateUrl } from '@/domain/hooks/generateUrl/useGenerateUrl';
+import { urls } from '@/domain/routes/routes.constant';
+import { TDomainOption, TDomainResource } from '@/domain/types/domainResource';
+
+interface DnsStateProps {
+ readonly serviceName: string;
+ readonly domainResource: TDomainResource;
+ readonly anycastOption: TDomainOption;
+ readonly isFetchingAnycastOption: boolean;
+ readonly anycastTerminateModalOpen: boolean;
+ readonly setAnycastTerminateModalOpen: React.Dispatch<
+ React.SetStateAction
+ >;
+ readonly restoreAnycast: boolean;
+ readonly setRestoreAnycast: React.Dispatch>;
+}
+export default function DnsState({
+ serviceName,
+ domainResource,
+ anycastOption,
+ anycastTerminateModalOpen,
+ isFetchingAnycastOption,
+ setAnycastTerminateModalOpen,
+ restoreAnycast,
+ setRestoreAnycast,
+}: DnsStateProps) {
+ const { t } = useTranslation(['domain', NAMESPACES.ACTIONS]);
+
+ const formatDate = useFormatDate();
+
+ const navigate = useNavigate();
+
+ React.useEffect(() => {
+ if (anycastOption) {
+ switch (anycastOption.state) {
+ case OptionStateEnum.RELEASED.toLowerCase(): {
+ setRestoreAnycast(true);
+ break;
+ }
+ case OptionStateEnum.SUBSCRIBED.toLowerCase(): {
+ setRestoreAnycast(false);
+ break;
+ }
+ default:
+ setRestoreAnycast(false);
+ break;
+ }
+ }
+ }, [anycastOption]);
+
+ const dnsState = getDnsStateDetails(
+ domainResource.currentState.dnsConfiguration.configurationType,
+ );
+
+ const handleAnycastLabel = () => {
+ if (!anycastOption) {
+ return t('domain_tab_DNS_anycast_order');
+ }
+
+ if (anycastOption && restoreAnycast) {
+ return t('domain_dns_tab_button_cancel_terminate_anycast', {
+ action: t(`${NAMESPACES.ACTIONS}:${'restore'}`),
+ });
+ }
+
+ return t('domain_dns_tab_button_cancel_terminate_anycast', {
+ action: t(`${NAMESPACES.ACTIONS}:${'terminate'}`),
+ });
+ };
+
+ const handleBtnClick = () => {
+ if (anycastOption) {
+ setAnycastTerminateModalOpen(!anycastTerminateModalOpen);
+ } else {
+ navigate(
+ useGenerateUrl(urls.domainTabOrderAnycast, 'path', {
+ serviceName,
+ }),
+ { replace: true },
+ );
+ }
+ };
+
+ return (
+
+
+ {t('domain_tab_general_information_dns_title')}
+
+
+
+
{t(dnsState.label)}
+ {dnsState.anycastSupported && (
+
handleBtnClick(),
+ },
+ ]}
+ />
+ )}
+
+
+ {restoreAnycast ? (
+ }}
+ />
+ ) : (
+ t(dnsState.notes)
+ )}
+
+
+
+ );
+}
diff --git a/packages/manager/apps/web-domains/src/domain/constants/configuration.card.ts b/packages/manager/apps/web-domains/src/domain/constants/configuration.card.ts
index 3e4420a59138..4dfb625dfc80 100644
--- a/packages/manager/apps/web-domains/src/domain/constants/configuration.card.ts
+++ b/packages/manager/apps/web-domains/src/domain/constants/configuration.card.ts
@@ -2,6 +2,7 @@ import { NAMESPACES } from '@ovh-ux/manager-common-translations';
import { BADGE_COLOR } from '@ovhcloud/ods-react';
import { ProtectionStateEnum } from '@/domain/enum/protectionState.enum';
import { DataProtectionStatus } from '../types/domainResource';
+import { DnsConfigurationTypeEnum } from '../enum/dnsConfigurationType.enum';
export const ConfigurationDnssecBadgeColorAndContent = {
not_supported: {
@@ -121,3 +122,52 @@ export const ConfigurationDataProtectionBadgeColorAndContent = {
i18nkeySubContent: 'domain_tab_general_information_data_protection_partial',
},
};
+export const ConfigurationDnsStateAndContent = [
+ {
+ dnsTypes: [
+ DnsConfigurationTypeEnum.HOSTING,
+ DnsConfigurationTypeEnum.HOLD,
+ DnsConfigurationTypeEnum.PARKING,
+ ],
+ result: {
+ label: 'domain_tab_general_information_dns_standard',
+ notes: 'domain_tab_general_information_note_anycast',
+ anycastSupported: true,
+ },
+ },
+ {
+ dnsTypes: [DnsConfigurationTypeEnum.ANYCAST],
+ result: {
+ label: 'domain_tab_general_information_dns_anycast',
+ notes: '',
+ anycastSupported: true,
+ },
+ },
+ {
+ dnsTypes: [
+ DnsConfigurationTypeEnum.EXTERNAL,
+ DnsConfigurationTypeEnum.MIXED,
+ ],
+ result: {
+ label: 'domain_tab_general_information_dns_personnalised',
+ notes: '',
+ anycastSupported: false,
+ },
+ },
+ {
+ dnsTypes: [DnsConfigurationTypeEnum.DEDICATED],
+ result: {
+ label: 'domain_tab_general_information_dns_dedicated',
+ notes: '',
+ anycastSupported: false,
+ },
+ },
+ {
+ dnsTypes: [DnsConfigurationTypeEnum.EMPTY],
+ result: {
+ label: 'domain_tab_general_information_dns_empty',
+ notes: '',
+ anycastSupported: false,
+ },
+ },
+];
diff --git a/packages/manager/apps/web-domains/src/domain/utils/dnsUtils.ts b/packages/manager/apps/web-domains/src/domain/utils/dnsUtils.ts
index 715c7f5cf576..093e7a26a154 100644
--- a/packages/manager/apps/web-domains/src/domain/utils/dnsUtils.ts
+++ b/packages/manager/apps/web-domains/src/domain/utils/dnsUtils.ts
@@ -12,6 +12,7 @@ import {
DnsConfigurationTypeEnum,
} from '@/domain/enum/dnsConfigurationType.enum';
import { TDomainZone } from '@/domain/types/domainZone';
+import { ConfigurationDnsStateAndContent } from '../constants/configuration.card';
const INTERNAL_DNS_PATTERN: Record = {
EU: /^d?ns(?:\d{1,3})?\.ovh\.net/i,
@@ -198,3 +199,10 @@ export function canSaveNewDnsConfig(
areArraysDifferent()
);
}
+
+export function getDnsStateDetails(dnsConfiguration: DnsConfigurationTypeEnum) {
+ const values = ConfigurationDnsStateAndContent.find((dns) => {
+ return dns.dnsTypes.includes(dnsConfiguration);
+ });
+ return values.result;
+}