Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Add more changes
Signed-off-by: Adhitya Mamallan <adhitya.mamallan@uber.com>
  • Loading branch information
adhityamamallan committed Nov 14, 2025
commit 18f01b38ea09d104c78a2c9e56cc10baddc8daea
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { createElement } from 'react';

import { type FailoverEvent } from '@/route-handlers/list-failover-history/list-failover-history.types';

import DomainPageFailoverActiveActive from '../domain-page-failover-active-active/domain-page-failover-active-active';

import domainPageFailoversTableConfig from './domain-page-failovers-table.config';

const domainPageFailoversTableActiveActiveConfig = [
...domainPageFailoversTableConfig.slice(0, 3),
{
name: 'Failover Information AA',
id: 'failoverInfo',
width: '40%',
...domainPageFailoversTableConfig[3],
renderCell: (event: FailoverEvent) =>
JSON.stringify(event.clusterFailovers),
createElement(DomainPageFailoverActiveActive, { failoverEvent: event }),
},
];

Expand Down
15 changes: 11 additions & 4 deletions src/views/domain-page/config/domain-page-failovers-table.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ import { type TableConfig } from '@/components/table/table.types';
import { type FailoverEvent } from '@/route-handlers/list-failover-history/list-failover-history.types';
import parseGrpcTimestamp from '@/utils/datetime/parse-grpc-timestamp';

import DomainPageFailoverSingleCluster from '../domain-page-failover-single-cluster/domain-page-failover-single-cluster';
import { FAILOVER_TYPE_LABEL_MAP } from '../domain-page-failovers/domain-page-failovers.constants';

const domainPageFailoversTableConfig = [
{
name: 'Failover ID',
id: 'failoverId',
width: '25%',
width: '35%',
renderCell: (event: FailoverEvent) => event.id,
},
{
Expand All @@ -27,14 +30,18 @@ const domainPageFailoversTableConfig = [
name: 'Type',
id: 'type',
width: '10%',
renderCell: (event: FailoverEvent) => event.failoverType,
renderCell: (event: FailoverEvent) =>
FAILOVER_TYPE_LABEL_MAP[event.failoverType],
},
{
name: 'Failover Information',
id: 'failoverInfo',
width: '50%',
width: '40%',
renderCell: (event: FailoverEvent) =>
JSON.stringify(event.clusterFailovers),
createElement(DomainPageFailoverSingleCluster, {
fromCluster: event.clusterFailovers[0].fromCluster?.activeClusterName,
toCluster: event.clusterFailovers[0].toCluster?.activeClusterName,
}),
},
] as const satisfies TableConfig<FailoverEvent>;

Expand Down
11 changes: 11 additions & 0 deletions src/views/domain-page/config/domain-page-query-params.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ const domainPageQueryParamsConfig: [
PageQueryParam<'sortColumnArchival', string>,
PageQueryParam<'sortOrderArchival', SortOrder>,
PageQueryParam<'queryArchival', string>,
// Failovers Tab query params
PageQueryParam<'clusterAttributeScope', string | undefined>,
PageQueryParam<'clusterAttributeValue', string | undefined>,
] = [
{
key: 'inputType',
Expand Down Expand Up @@ -163,6 +166,14 @@ const domainPageQueryParamsConfig: [
queryParamKey: 'aquery',
defaultValue: '',
},
{
key: 'clusterAttributeScope',
queryParamKey: 'cs',
},
{
key: 'clusterAttributeValue',
queryParamKey: 'cv',
},
] as const;

export default domainPageQueryParamsConfig;
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { styled as createStyled, type Theme } from 'baseui';

export const styled = {
FailoverContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({
display: 'flex',
gap: $theme.sizing.scale600,
alignItems: 'baseline',
})),
ClusterFailoverContainer: createStyled(
'div',
({ $theme }: { $theme: Theme }) => ({
display: 'flex',
alignItems: 'baseline',
gap: $theme.sizing.scale300,
})
),
ClusterAttributeLabel: createStyled(
'div',
({ $theme }: { $theme: Theme }) => ({
...$theme.typography.LabelSmall,
})
),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { useMemo } from 'react';

import { Button } from 'baseui/button';
import { MdVisibility } from 'react-icons/md';

import usePageQueryParams from '@/hooks/use-page-query-params/use-page-query-params';

import domainPageQueryParamsConfig from '../config/domain-page-query-params.config';
import DomainPageFailoverSingleCluster from '../domain-page-failover-single-cluster/domain-page-failover-single-cluster';
import { PRIMARY_CLUSTER_SCOPE } from '../domain-page-failovers/domain-page-failovers.constants';
import clusterFailoverMatchesAttribute from '../helpers/cluster-failover-matches-attribute';

import { styled } from './domain-page-failover-active-active.styles';
import { type Props } from './domain-page-failover-active-active.types';

export default function DomainPageFailoverActiveActive({
failoverEvent,
}: Props) {
const [{ clusterAttributeScope, clusterAttributeValue }] = usePageQueryParams(
domainPageQueryParamsConfig
);

const clusterFailoverForMaybeSelectedAttribute = useMemo(
() =>
failoverEvent.clusterFailovers.find((clusterFailover) =>
clusterFailoverMatchesAttribute(
clusterFailover,
clusterAttributeScope,
clusterAttributeValue
)
),
[
clusterAttributeScope,
clusterAttributeValue,
failoverEvent.clusterFailovers,
]
);

return (
<styled.FailoverContainer>
{clusterFailoverForMaybeSelectedAttribute && (
<styled.ClusterFailoverContainer>
<styled.ClusterAttributeLabel>
{clusterAttributeScope === PRIMARY_CLUSTER_SCOPE
? 'Primary:'
: `${clusterAttributeScope} (${clusterAttributeValue}):`}
</styled.ClusterAttributeLabel>
<DomainPageFailoverSingleCluster
fromCluster={
clusterFailoverForMaybeSelectedAttribute.fromCluster
?.activeClusterName
}
toCluster={
clusterFailoverForMaybeSelectedAttribute.toCluster
?.activeClusterName
}
/>
</styled.ClusterFailoverContainer>
)}
<Button
size="mini"
kind="secondary"
shape="pill"
endEnhancer={<MdVisibility />}
// TODO: open the failover modal here on click
>
See more
</Button>
</styled.FailoverContainer>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { type FailoverEvent } from '@/route-handlers/list-failover-history/list-failover-history.types';

export type Props = {
failoverEvent: FailoverEvent;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { type Theme } from 'baseui';

import type {
StyletronCSSObject,
StyletronCSSObjectOf,
} from '@/hooks/use-styletron-classes';

const cssStylesObj = {
failoverContainer: (theme: Theme) => ({
display: 'flex',
gap: theme.sizing.scale400,
alignItems: 'center',
}),
} satisfies StyletronCSSObject;

export const cssStyles: StyletronCSSObjectOf<typeof cssStylesObj> =
cssStylesObj;
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { MdArrowForward } from 'react-icons/md';

import useStyletronClasses from '@/hooks/use-styletron-classes';

import { cssStyles } from './domain-page-failover-single-cluster.styles';
import { type Props } from './domain-page-failover-single-cluster.types';

export default function DomainPageFailoverSingleCluster({
fromCluster,
toCluster,
}: Props) {
const { cls, theme } = useStyletronClasses(cssStyles);

if (!fromCluster || !toCluster) return null;

return (
<div className={cls.failoverContainer}>
{fromCluster}
<MdArrowForward color={theme.colors.contentSecondary} />
{toCluster}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type Props = {
fromCluster?: string;
toCluster?: string;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { styled as createStyled, type Theme } from 'baseui';

export const styled = {
FailoversContainer: createStyled('div', ({ $theme }: { $theme: Theme }) => ({
paddingTop: $theme.sizing.scale950,
})),
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@
import React from 'react';

import Table from '@/components/table/table';
import usePageQueryParams from '@/hooks/use-page-query-params/use-page-query-params';
import isActiveActiveDomain from '@/views/shared/active-active/helpers/is-active-active-domain';
import useSuspenseDomainDescription from '@/views/shared/hooks/use-domain-description/use-suspense-domain-description';

import domainPageFailoversTableActiveActiveConfig from '../config/domain-page-failovers-table-active-active.config';
import domainPageFailoversTableConfig from '../config/domain-page-failovers-table.config';
import domainPageQueryParamsConfig from '../config/domain-page-query-params.config';
import { type DomainPageTabContentProps } from '../domain-page-content/domain-page-content.types';
import useDomainFailoverHistory from '../hooks/use-domain-failover-history/use-domain-failover-history';

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

export default function DomainPageFailovers({
domain,
cluster,
Expand All @@ -19,6 +23,12 @@ export default function DomainPageFailovers({
cluster,
});

const isActiveActive = isActiveActiveDomain(domainDescription);

const [{ clusterAttributeScope, clusterAttributeValue }] = usePageQueryParams(
domainPageQueryParamsConfig
);

const {
filteredFailoverEvents,
allFailoverEvents,
Expand All @@ -31,26 +41,33 @@ export default function DomainPageFailovers({
domainName: domain,
domainId: domainDescription.id,
cluster,
// TODO: set and pass filters here, but only for AA domains
...(isActiveActive
? {
clusterAttributeScope,
clusterAttributeValue,
}
: {}),
});

return (
<Table
data={filteredFailoverEvents}
shouldShowResults={!isLoading && filteredFailoverEvents.length > 0}
endMessageProps={{
kind: 'infinite-scroll',
hasData: allFailoverEvents.length > 0,
error,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
}}
columns={
isActiveActiveDomain(domainDescription)
? domainPageFailoversTableActiveActiveConfig
: domainPageFailoversTableConfig
}
/>
<styled.FailoversContainer>
<Table
data={filteredFailoverEvents}
shouldShowResults={!isLoading && filteredFailoverEvents.length > 0}
endMessageProps={{
kind: 'infinite-scroll',
hasData: allFailoverEvents.length > 0,
error,
fetchNextPage,
hasNextPage,
isFetchingNextPage,
}}
columns={
isActiveActive
? domainPageFailoversTableActiveActiveConfig
: domainPageFailoversTableConfig
}
/>
</styled.FailoversContainer>
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few callouts.

  • The screenshots in the PR summary are helpful. Even better if we had ubook / storybook so that visual snapshots become part of the source code and CI.
  • For example, there's some guesswork for me regarding the two columns variants.
  • And I trust that shouldShowResults behaves correctly because Table is battle-tested. With uBook, it'd be great to see the full lifecycle of this component. I can share Flipr examples if that'd help.

}