Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "cadence-web",
"private": true,
"config": {
"cadence_idl_version": "0e56e57909d9fa738eaa8d7a9561ea16acdf51e4"
"cadence_idl_version": "792058c9dbad5787cf8444c5d4bef0763a311b0c"
},
"scripts": {
"dev": "next dev -p ${CADENCE_WEB_PORT:-8088} -H ${CADENCE_WEB_HOSTNAME:-0.0.0.0} | pino-pretty --messageKey message",
Expand Down
10 changes: 10 additions & 0 deletions src/utils/data-formatters/schema/history-event-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,20 @@ const cronOverlapPolicySchema = z.enum([
CronOverlapPolicy.CRON_OVERLAP_POLICY_BUFFER_ONE,
]);

const clusterAttributeSchema = z.object({
scope: z.string(),
name: z.string(),
});

// TODO @adhitya.mamallan - this needs to be removed as part of active-active's redesign
const activeClusterSelectionStrategySchema = z.enum([
ActiveClusterSelectionStrategy.ACTIVE_CLUSTER_SELECTION_STRATEGY_INVALID,
ActiveClusterSelectionStrategy.ACTIVE_CLUSTER_SELECTION_STRATEGY_REGION_STICKY,
ActiveClusterSelectionStrategy.ACTIVE_CLUSTER_SELECTION_STRATEGY_EXTERNAL_ENTITY,
]);

// TODO @adhitya.mamallan - this needs to be modified as part of active-active's redesign,
// so that we only check for clusterAttributes
const activeClusterSelectionPolicySchema = z.discriminatedUnion(
'strategyConfig',
[
Expand All @@ -157,6 +165,7 @@ const activeClusterSelectionPolicySchema = z.discriminatedUnion(
stickyRegion: z.string(),
}),
activeClusterExternalEntityConfig: z.nullable(z.undefined()),
clusterAttribute: clusterAttributeSchema.nullable(),
}),
z.object({
strategy: activeClusterSelectionStrategySchema,
Expand All @@ -166,6 +175,7 @@ const activeClusterSelectionPolicySchema = z.discriminatedUnion(
externalEntityType: z.string(),
externalEntityKey: z.string(),
}),
clusterAttribute: clusterAttributeSchema.nullable(),
}),
]
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React from 'react';

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

import { mockActiveActiveDomain } from '@/views/shared/active-active/__fixtures__/active-active-domain';

import {
mockDomainDescription,
mockDomainDescriptionSingleCluster,
Expand All @@ -27,6 +29,8 @@ jest.mock('next/navigation', () => ({
}),
}));

jest.mock('../../helpers/get-cluster-replication-status-label');

describe(DomainPageClusterSelector.name, () => {
afterEach(() => {
jest.clearAllMocks();
Expand All @@ -35,7 +39,7 @@ describe(DomainPageClusterSelector.name, () => {
it('Should render current cluster correctly', () => {
setup({ domainDescription: mockDomainDescription });

expect(screen.getByText('cluster_1')).toBeInTheDocument();
expect(screen.getByText('cluster_1 (active)')).toBeInTheDocument();
expect(screen.getByRole('combobox')).toBeInTheDocument();
});

Expand All @@ -49,15 +53,17 @@ describe(DomainPageClusterSelector.name, () => {
it('Should show available clusters and redirect when one is selected', () => {
setup({ domainDescription: mockDomainDescription });

expect(screen.getByText('cluster_1')).toBeInTheDocument();
expect(screen.getByText('cluster_1 (active)')).toBeInTheDocument();
const clusterSelect = screen.getByRole('combobox');

act(() => {
fireEvent.click(clusterSelect);
});

const clustersMenu = screen.getByRole('listbox');
const cluster2option = within(clustersMenu).getByText('cluster_2');
const cluster2option = within(clustersMenu).getByText(
'cluster_2 (passive)'
);

act(() => {
fireEvent.click(cluster2option);
Expand All @@ -67,16 +73,54 @@ describe(DomainPageClusterSelector.name, () => {
'/domains/mock-domain/cluster_2/workflows'
);
});

it('Should show active/passive labels for active-passive domains', () => {
setup({ domainDescription: mockDomainDescription });

const clusterSelect = screen.getByRole('combobox');

act(() => {
fireEvent.click(clusterSelect);
});

const clustersMenu = screen.getByRole('listbox');

expect(
within(clustersMenu).getByText('cluster_1 (active)')
).toBeInTheDocument();
expect(
within(clustersMenu).getByText('cluster_2 (passive)')
).toBeInTheDocument();
});

it('Should show primary label only for active cluster in active-active domains', () => {
setup({ domainDescription: mockActiveActiveDomain, cluster: 'cluster0' });

const clusterSelect = screen.getByRole('combobox');

act(() => {
fireEvent.click(clusterSelect);
});

const clustersMenu = screen.getByRole('listbox');

expect(
within(clustersMenu).getByText('cluster0 (primary)')
).toBeInTheDocument();
expect(within(clustersMenu).getByText('cluster1')).toBeInTheDocument();
});
});

function setup({
domainDescription,
cluster = 'cluster_1',
}: {
domainDescription: DomainDescription;
cluster?: string;
}) {
render(
<DomainPageClusterSelector
cluster="cluster_1"
cluster={cluster}
domainDescription={domainDescription}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { type Route } from 'next';
import { useRouter, useParams } from 'next/navigation';

import { type DomainHeaderInfoItemContentProps } from '../domain-page-header-info/domain-page-header-info.types';
import getClusterReplicationStatusLabel from '../helpers/get-cluster-replication-status-label';

import { overrides, styled } from './domain-page-cluster-selector.styles';

Expand All @@ -19,15 +20,28 @@ export default function DomainPageClusterSelector(
return <styled.ItemLabel>{props.cluster}</styled.ItemLabel>;
}

const clusterSelectorOptions = props.domainDescription.clusters.map(
(cluster) => {
const replicationStatusLabel = getClusterReplicationStatusLabel(
props.domainDescription,
cluster.clusterName
);

return {
id: cluster.clusterName,
label: replicationStatusLabel
? `${cluster.clusterName} (${replicationStatusLabel})`
: cluster.clusterName,
};
}
);

return (
<Select
overrides={overrides.select}
options={props.domainDescription.clusters.map((cluster) => ({
id: cluster.clusterName,
label: cluster.clusterName,
}))}
options={clusterSelectorOptions}
value={[
{
clusterSelectorOptions.find(({ id }) => id === props.cluster) ?? {
id: props.cluster,
label: props.cluster,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
import { render, screen } from '@/test-utils/rtl';

import { mockActiveActiveDomain } from '@/views/shared/active-active/__fixtures__/active-active-domain';

import {
mockDomainDescription,
mockDomainDescriptionSingleCluster,
} from '../../__fixtures__/domain-description';
import * as isActiveClusterModule from '../../helpers/is-active-cluster';
import DomainPageMetadataClusters from '../domain-page-metadata-clusters';

jest.mock('../../helpers/is-active-cluster', () => ({
__esModule: true,
default: jest.fn().mockReturnValue(false),
}));
jest.mock('../../helpers/get-cluster-replication-status-label');

describe(DomainPageMetadataClusters.name, () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('renders plain text for single cluster', async () => {
render(
<DomainPageMetadataClusters {...mockDomainDescriptionSingleCluster} />
Expand All @@ -26,12 +20,7 @@ describe(DomainPageMetadataClusters.name, () => {
expect(screen.queryAllByRole('link')).toHaveLength(0);
});

it('renders active/passive labels and links for multiple clusters', () => {
jest
.spyOn(isActiveClusterModule, 'default')
.mockReturnValueOnce(true) // cluster_1 is active
.mockReturnValueOnce(false); // cluster_2 is passive

it('renders active/passive labels and links for active-passive domains', () => {
const { container } = render(
<DomainPageMetadataClusters {...mockDomainDescription} />
);
Expand All @@ -53,4 +42,25 @@ describe(DomainPageMetadataClusters.name, () => {
);
});
});

it('renders primary label only for active cluster in active-active domains', () => {
const { container } = render(
<DomainPageMetadataClusters {...mockActiveActiveDomain} />
);

expect(container).toHaveTextContent('cluster0 (primary), cluster1');

const links = screen.queryAllByRole('link');
expect(links).toHaveLength(2);

links.forEach((link, i) => {
expect(link.innerHTML).toBe(
mockActiveActiveDomain.clusters[i].clusterName
);
expect(link).toHaveAttribute(
'href',
`/domains/${mockActiveActiveDomain.name}/${mockActiveActiveDomain.clusters[i].clusterName}`
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React from 'react';
import Link from '@/components/link/link';

import { type DomainDescription } from '../domain-page.types';
import isActiveCluster from '../helpers/is-active-cluster';
import getClusterReplicationStatusLabel from '../helpers/get-cluster-replication-status-label';

import { styled } from './domain-page-metadata-clusters.styles';

Expand All @@ -18,12 +18,10 @@ export default function DomainPageMetadataClusters(
return (
<styled.ClusterTextContainer>
{domainDescription.clusters.map((cluster, index) => {
const replicationStatusLabel = isActiveCluster(
const replicationStatusLabel = getClusterReplicationStatusLabel(
domainDescription,
cluster.clusterName
)
? 'active'
: 'passive';
);

return (
<React.Fragment key={cluster.clusterName}>
Expand All @@ -33,7 +31,7 @@ export default function DomainPageMetadataClusters(
>
{cluster.clusterName}
</Link>
{` (${replicationStatusLabel})`}
{replicationStatusLabel ? ` (${replicationStatusLabel})` : null}
{index < numClusters - 1 ? ', ' : ''}
</React.Fragment>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import { render, screen } from '@/test-utils/rtl';

import { type Props as SublistTableProps } from '@/components/list-table-nested/sublist-table/sublist-table.types';
import { mockActiveActiveDomain } from '@/views/shared/active-active/__fixtures__/active-active-domain';

import { mockDomainDescription } from '../../__fixtures__/domain-description';
import DomainPageMetadataFailoverVersion from '../domain-page-metadata-failover-version';

jest.mock('@/components/list-table-nested/sublist-table/sublist-table', () =>
jest.fn(({ items }: SublistTableProps) => (
<div data-testid="mock-sublist-table">{JSON.stringify(items)}</div>
))
);

jest.mock('@/views/shared/active-active/helpers/is-active-active-domain');

describe(DomainPageMetadataFailoverVersion.name, () => {
Expand All @@ -23,19 +16,12 @@ describe(DomainPageMetadataFailoverVersion.name, () => {
render(<DomainPageMetadataFailoverVersion {...mockDomainDescription} />);

expect(screen.getByText('123456')).toBeInTheDocument();
expect(screen.queryByTestId('mock-sublist-table')).not.toBeInTheDocument();
});

it('renders SublistTable for active-active domains', () => {
// TODO @adhitya.mamallan: add special rendering for failover versions for different cluster attributes
it('temp: renders failover version as text for active-active domains', () => {
render(<DomainPageMetadataFailoverVersion {...mockActiveActiveDomain} />);

const sublistTable = screen.getByTestId('mock-sublist-table');
expect(sublistTable).toBeInTheDocument();
expect(sublistTable).toHaveTextContent(
/{"key":"cluster0","label":"cluster0","value":"0"}/
);
expect(sublistTable).toHaveTextContent(
/{"key":"cluster1","label":"cluster1","value":"2"}/
);
expect(screen.getByText('2')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import SublistTable from '@/components/list-table-nested/sublist-table/sublist-table';
import isActiveActiveDomain from '@/views/shared/active-active/helpers/is-active-active-domain';

import { type DomainDescription } from '../domain-page.types';
Expand All @@ -7,22 +6,8 @@ export default function DomainPageMetadataFailoverVersion(
domainDescription: DomainDescription
) {
if (isActiveActiveDomain(domainDescription)) {
return (
<SublistTable
items={Object.values(domainDescription.activeClusters.regionToCluster)
.sort(
(
{ activeClusterName: clusterA },
{ activeClusterName: clusterB }
) => (clusterA > clusterB ? 1 : -1)
)
.map(({ activeClusterName, failoverVersion }) => ({
key: activeClusterName,
label: activeClusterName,
value: failoverVersion,
}))}
/>
);
// TODO @adhitya.mamallan: add special rendering for failover versions for different cluster attributes
return domainDescription.failoverVersion;
}

return domainDescription.failoverVersion;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import isActiveActiveDomain from '@/views/shared/active-active/helpers/is-active-active-domain';

import { type DomainDescription } from '../../domain-page.types';

// Manual mock for getClusterReplicationStatusLabel
export default function getClusterReplicationStatusLabel(
domain: DomainDescription,
cluster: string
): string | undefined {
if (isActiveActiveDomain(domain)) {
return cluster === domain.activeClusterName ? 'primary' : undefined;
}

return cluster === domain.activeClusterName ? 'active' : 'passive';
}
Loading