Skip to content

Commit 301fb64

Browse files
Refactor Domain Page Metadata and adopt a more reusable query hook pattern (#883)
* Move domain metadata table into a dedicated component, so that DomainPageMetadata is just a loader * Add fixture for Domain Metadata * Delete useSuspenseDomainPageMetadata and move the DomainMetadata type to domain-page-metadata/ * Refactor hooks for DescribeDomain and IsExtendedMetadataEnabled, to separate the query configs for reusability across places
1 parent e781668 commit 301fb64

21 files changed

+318
-178
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { type DomainMetadata } from '../domain-page-metadata/domain-page-metadata.types';
2+
3+
import { mockDomainDescription } from './domain-description';
4+
5+
export const mockDomainMetadata = {
6+
domainDescription: mockDomainDescription,
7+
isExtendedMetadataEnabled: false,
8+
} as const satisfies DomainMetadata;

src/views/domain-page/config/domain-page-metadata-extended-table.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { createElement } from 'react';
22

3-
import { type MetadataItem } from '../domain-page-metadata/domain-page-metadata.types';
43
import DomainPageMetadataClusters from '../domain-page-metadata-clusters/domain-page-metadata-clusters';
54
import DomainPageMetadataDescription from '../domain-page-metadata-description/domain-page-metadata-description';
5+
import { type MetadataItem } from '../domain-page-metadata-table/domain-page-metadata-table.types';
66
import DomainPageMetadataViewJson from '../domain-page-metadata-view-json/domain-page-metadata-view-json';
77

88
const domainPageMetadataExtendedTableConfig = [

src/views/domain-page/domain-page-header-info-loader/domain-page-header-info-loader.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client';
22
import React from 'react';
33

4-
import useSuspenseDomainDescription from '@/views/shared/hooks/use-suspense-domain-description';
4+
import useSuspenseDomainDescription from '@/views/shared/hooks/use-domain-description/use-suspense-domain-description';
55

66
import DomainPageHeaderInfo from '../domain-page-header-info/domain-page-header-info';
77

src/views/domain-page/domain-page-header-status-tag/domain-page-header-status-tag.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import DomainStatusTag from '@/views/shared/domain-status-tag/domain-status-tag';
2-
import useSuspenseDomainDescription from '@/views/shared/hooks/use-suspense-domain-description';
2+
import useSuspenseDomainDescription from '@/views/shared/hooks/use-domain-description/use-suspense-domain-description';
33

44
import { type Props } from './domain-page-header-status-tag.types';
55

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { render, screen } from '@/test-utils/rtl';
2+
3+
import { type Props as ListTableProps } from '@/components/list-table/list-table.types';
4+
import { type Props as ListTableNestedProps } from '@/components/list-table-nested/list-table-nested.types';
5+
6+
import { mockDomainMetadata } from '../../__fixtures__/domain-metadata';
7+
import { type DomainMetadata } from '../../domain-page-metadata/domain-page-metadata.types';
8+
import { type DomainDescription } from '../../domain-page.types';
9+
import DomainPageMetadataTable from '../domain-page-metadata-table';
10+
11+
jest.mock('../../config/domain-page-metadata-table.config', () => [
12+
{
13+
key: 'id',
14+
label: 'Domain ID',
15+
renderValue: (domainDescription: DomainDescription) => domainDescription.id,
16+
},
17+
{
18+
key: 'activeClusterName',
19+
label: 'Active Cluster',
20+
renderValue: (domainDescription: DomainDescription) =>
21+
domainDescription.activeClusterName,
22+
},
23+
]);
24+
25+
jest.mock('../../config/domain-page-metadata-extended-table.config', () => [
26+
{
27+
key: 'basic',
28+
label: 'Basic Information',
29+
description: 'Basic domain information',
30+
kind: 'group',
31+
items: [
32+
{
33+
key: 'id',
34+
label: 'Domain ID',
35+
getValue: (props: DomainMetadata) => props.domainDescription.id,
36+
},
37+
{
38+
key: 'activeClusterName',
39+
label: 'Active Cluster',
40+
getValue: (props: DomainMetadata) =>
41+
props.domainDescription.activeClusterName,
42+
},
43+
],
44+
},
45+
{
46+
key: 'ownerEmail',
47+
label: 'Owner Email',
48+
description: 'Email address of the domain owner',
49+
getValue: (props: DomainMetadata) => props.domainDescription.ownerEmail,
50+
},
51+
]);
52+
53+
jest.mock('@/components/list-table/list-table', () =>
54+
jest.fn(({ data, listTableConfig }: ListTableProps<object>) => (
55+
<div>
56+
Mock ListTable
57+
{listTableConfig.map((config) => (
58+
<div key={config.key}>
59+
{config.label}: <config.renderValue {...data} />
60+
</div>
61+
))}
62+
</div>
63+
))
64+
);
65+
66+
jest.mock('@/components/list-table-nested/list-table-nested', () =>
67+
jest.fn(({ items }: ListTableNestedProps) => (
68+
<div>
69+
Mock ListTableNested
70+
{items.map((item) => (
71+
<div key={item.key}>
72+
<div>{item.label}</div>
73+
{item.description && <div>{item.description}</div>}
74+
{item.kind === 'group' ? (
75+
<div>
76+
{item.items.map((subItem) => (
77+
<div key={subItem.key}>
78+
{subItem.label}: {subItem.value}
79+
</div>
80+
))}
81+
</div>
82+
) : (
83+
<div>{item.value}</div>
84+
)}
85+
</div>
86+
))}
87+
</div>
88+
))
89+
);
90+
91+
describe(DomainPageMetadataTable.name, () => {
92+
it('renders basic metadata table when extended metadata is disabled', () => {
93+
render(<DomainPageMetadataTable {...mockDomainMetadata} />);
94+
95+
expect(screen.getByText('Mock ListTable')).toBeInTheDocument();
96+
97+
expect(
98+
screen.getByText('Domain ID: mock-domain-staging-uuid')
99+
).toBeInTheDocument();
100+
expect(screen.getByText('Active Cluster: cluster_1')).toBeInTheDocument();
101+
});
102+
103+
it('renders extended metadata table when extended metadata is enabled', () => {
104+
render(
105+
<DomainPageMetadataTable
106+
{...mockDomainMetadata}
107+
isExtendedMetadataEnabled={true}
108+
/>
109+
);
110+
111+
expect(screen.getByText('Mock ListTableNested')).toBeInTheDocument();
112+
113+
expect(screen.getByText('Basic Information')).toBeInTheDocument();
114+
expect(screen.getByText('Basic domain information')).toBeInTheDocument();
115+
expect(
116+
screen.getByText('Domain ID: mock-domain-staging-uuid')
117+
).toBeInTheDocument();
118+
expect(screen.getByText('Active Cluster: cluster_1')).toBeInTheDocument();
119+
120+
expect(screen.getByText('Owner Email')).toBeInTheDocument();
121+
expect(
122+
screen.getByText('Email address of the domain owner')
123+
).toBeInTheDocument();
124+
expect(screen.getByText('[email protected]')).toBeInTheDocument();
125+
});
126+
});
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from 'react';
2+
3+
import ListTable from '@/components/list-table/list-table';
4+
import ListTableNested from '@/components/list-table-nested/list-table-nested';
5+
6+
import domainPageMetadataExtendedTableConfig from '../config/domain-page-metadata-extended-table.config';
7+
import domainPageMetadataTableConfig from '../config/domain-page-metadata-table.config';
8+
import { type DomainMetadata } from '../domain-page-metadata/domain-page-metadata.types';
9+
10+
import { styled } from './domain-page-metadata-table.styles';
11+
import { type MetadataItem } from './domain-page-metadata-table.types';
12+
13+
export default function DomainPageMetadataTable(props: DomainMetadata) {
14+
return (
15+
<styled.MetadataContainer>
16+
{props.isExtendedMetadataEnabled ? (
17+
<ListTableNested
18+
items={domainPageMetadataExtendedTableConfig.map(
19+
(row: MetadataItem) => ({
20+
key: row.key,
21+
label: row.label,
22+
description: row.description,
23+
...(row.kind === 'group'
24+
? {
25+
kind: 'group',
26+
items: row.items.map((item) => ({
27+
key: item.key,
28+
label: item.label,
29+
value: item.getValue(props),
30+
})),
31+
}
32+
: {
33+
kind: 'simple',
34+
value: row.getValue(props),
35+
}),
36+
})
37+
)}
38+
/>
39+
) : (
40+
<ListTable
41+
data={props.domainDescription}
42+
listTableConfig={domainPageMetadataTableConfig}
43+
/>
44+
)}
45+
</styled.MetadataContainer>
46+
);
47+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import {
2+
type ListTableNestedSimpleItem,
3+
type ListTableNestedSublistItem,
4+
type ListTableNestedGroup,
5+
} from '@/components/list-table-nested/list-table-nested.types';
6+
7+
import { type DomainMetadata } from '../domain-page-metadata/domain-page-metadata.types';
8+
9+
type MetadataSimpleItem = Omit<ListTableNestedSimpleItem, 'value'> & {
10+
getValue: (metadata: DomainMetadata) => React.ReactNode;
11+
};
12+
13+
type MetadataSublistItem = Omit<ListTableNestedSublistItem, 'value'> & {
14+
getValue: (metadata: DomainMetadata) => React.ReactNode;
15+
};
16+
17+
type MetadataGroup = Omit<ListTableNestedGroup, 'items'> & {
18+
items: Array<MetadataSublistItem>;
19+
};
20+
21+
export type MetadataItem = MetadataSimpleItem | MetadataGroup;

src/views/domain-page/domain-page-metadata/__tests__/domain-page-metadata.test.tsx

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,24 @@ import { HttpResponse } from 'msw';
44

55
import { render, screen, act } from '@/test-utils/rtl';
66

7-
import { type ListTableNestedItem } from '@/components/list-table-nested/list-table-nested.types';
87
import { type GetConfigResponse } from '@/route-handlers/get-config/get-config.types';
98

109
import { mockDomainDescription } from '../../__fixtures__/domain-description';
11-
import { type DomainDescription } from '../../domain-page.types';
1210
import DomainPageMetadata from '../domain-page-metadata';
11+
import { type DomainMetadata } from '../domain-page-metadata.types';
1312

14-
jest.mock('@/components/list-table/list-table', () =>
15-
jest.fn(({ data }: { data: DomainDescription }) => (
16-
<div>
17-
Mock metadata table
18-
<div>Domain ID: {data.id}</div>
19-
<div>Active cluster: {data.activeClusterName}</div>
20-
</div>
21-
))
22-
);
23-
24-
jest.mock('@/components/list-table-nested/list-table-nested', () =>
25-
jest.fn(({ items }: { items: Array<ListTableNestedItem> }) => (
26-
<div>
27-
Mock items table
28-
{items.map((item) => (
29-
<div key={item.key}>{item.label}</div>
30-
))}
31-
</div>
32-
))
13+
jest.mock('../../domain-page-metadata-table/domain-page-metadata-table', () =>
14+
jest.fn(
15+
({ domainDescription, isExtendedMetadataEnabled }: DomainMetadata) => (
16+
<div>
17+
{isExtendedMetadataEnabled
18+
? 'Mock extended metadata table'
19+
: 'Mock metadata table'}
20+
<div>Domain ID: {domainDescription.id}</div>
21+
<div>Active cluster: {domainDescription.activeClusterName}</div>
22+
</div>
23+
)
24+
)
3325
);
3426

3527
describe(DomainPageMetadata.name, () => {
@@ -46,9 +38,13 @@ describe(DomainPageMetadata.name, () => {
4638
it('renders extended metadata without error', async () => {
4739
await setup({ enableExtendedMetadata: true });
4840

49-
expect(await screen.findByText('Mock items table')).toBeInTheDocument();
50-
expect(screen.getByText('Domain ID')).toBeInTheDocument();
51-
expect(screen.getByText('Clusters')).toBeInTheDocument();
41+
expect(
42+
await screen.findByText('Mock extended metadata table')
43+
).toBeInTheDocument();
44+
expect(
45+
screen.getByText('Domain ID: mock-domain-staging-uuid')
46+
).toBeInTheDocument();
47+
expect(screen.getByText('Active cluster: cluster_1')).toBeInTheDocument();
5248
});
5349

5450
it('does not render if the initial call fails', async () => {
Lines changed: 25 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,36 @@
11
'use client';
22
import React from 'react';
33

4-
import ListTable from '@/components/list-table/list-table';
5-
import ListTableNested from '@/components/list-table-nested/list-table-nested';
4+
import { useSuspenseQueries } from '@tanstack/react-query';
5+
6+
import getDomainDescriptionQueryOptions from '@/views/shared/hooks/use-domain-description/get-domain-description-query-options';
67

7-
import domainPageMetadataExtendedTableConfig from '../config/domain-page-metadata-extended-table.config';
8-
import domainPageMetadataTableConfig from '../config/domain-page-metadata-table.config';
98
import { type DomainPageTabContentProps } from '../domain-page-content/domain-page-content.types';
10-
import useSuspenseDomainPageMetadata from '../hooks/use-suspense-domain-page-metadata';
9+
import DomainPageMetadataTable from '../domain-page-metadata-table/domain-page-metadata-table';
10+
import getIsExtendedMetadataEnabledQueryOptions from '../hooks/use-is-extended-metadata-enabled/get-is-extended-metadata-enabled-query-options';
1111

12-
import { styled } from './domain-page-metadata.styles';
13-
import { type MetadataItem } from './domain-page-metadata.types';
12+
import { type DomainMetadata } from './domain-page-metadata.types';
1413

1514
export default function DomainPageMetadata(props: DomainPageTabContentProps) {
16-
const domainMetadata = useSuspenseDomainPageMetadata({
17-
domain: props.domain,
18-
cluster: props.cluster,
15+
const [
16+
{ data: domainDescription },
17+
{
18+
data: { metadata: isExtendedMetadataEnabled },
19+
},
20+
] = useSuspenseQueries({
21+
queries: [
22+
getDomainDescriptionQueryOptions({
23+
domain: props.domain,
24+
cluster: props.cluster,
25+
}),
26+
getIsExtendedMetadataEnabledQueryOptions(),
27+
],
1928
});
2029

21-
return (
22-
<styled.MetadataContainer>
23-
{domainMetadata.isExtendedMetadataEnabled ? (
24-
<ListTableNested
25-
items={domainPageMetadataExtendedTableConfig.map(
26-
(row: MetadataItem) => ({
27-
key: row.key,
28-
label: row.label,
29-
description: row.description,
30-
...(row.kind === 'group'
31-
? {
32-
kind: 'group',
33-
items: row.items.map((item) => ({
34-
key: item.key,
35-
label: item.label,
36-
value: item.getValue(domainMetadata),
37-
})),
38-
}
39-
: {
40-
kind: 'simple',
41-
value: row.getValue(domainMetadata),
42-
}),
43-
})
44-
)}
45-
/>
46-
) : (
47-
<ListTable
48-
data={domainMetadata.domainDescription}
49-
listTableConfig={domainPageMetadataTableConfig}
50-
/>
51-
)}
52-
</styled.MetadataContainer>
53-
);
30+
const domainMetadata: DomainMetadata = {
31+
domainDescription,
32+
isExtendedMetadataEnabled,
33+
};
34+
35+
return <DomainPageMetadataTable {...domainMetadata} />;
5436
}

0 commit comments

Comments
 (0)