Skip to content

Commit d06e8da

Browse files
Add connector status overview to entity details page (#1535)
* Placeholder: create connector status overview card * Create connector status overview card * Hide entity status section for non-support users * Consolidate last updated status overview subheading ids * Add comment contextualizing the connector status indicator state * Fix linting issues after merging with main * Hide connector status overview card for collections
1 parent aad289b commit d06e8da

File tree

9 files changed

+163
-2
lines changed

9 files changed

+163
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { Grid, Stack, Typography } from '@mui/material';
2+
3+
import { useIntl } from 'react-intl';
4+
5+
import CardWrapper from 'src/components/shared/CardWrapper';
6+
import ConnectorStatus from 'src/components/shared/Entity/Details/Logs/Status/Overview/ConnectorStatus';
7+
import ConnectorStatusDetail from 'src/components/shared/Entity/Details/Logs/Status/Overview/ConnectorStatusDetail';
8+
import ConnectorUpdatedDetail from 'src/components/shared/Entity/Details/Logs/Status/Overview/ConnectorUpdatedDetail';
9+
import { cardHeaderSx } from 'src/context/Theme';
10+
11+
export default function ConnectorOverview() {
12+
const intl = useIntl();
13+
14+
return (
15+
<Grid item xs={12} md={6} lg={3}>
16+
<CardWrapper>
17+
<Stack
18+
direction="row"
19+
style={{ marginBottom: 16, marginLeft: -4 }}
20+
>
21+
<ConnectorStatus />
22+
23+
<Typography component="div" sx={{ ...cardHeaderSx, mr: 3 }}>
24+
{intl.formatMessage({
25+
id: 'details.ops.status.overview.connector.header',
26+
})}
27+
</Typography>
28+
</Stack>
29+
30+
<Stack spacing={2} style={{ marginLeft: 14 }}>
31+
<ConnectorStatusDetail headerMessageId="details.ops.status.overview.connector.subheaderLastStatus" />
32+
33+
<ConnectorUpdatedDetail headerMessageId="details.ops.status.overview.generic.subheaderLastUpdated" />
34+
</Stack>
35+
</CardWrapper>
36+
</Grid>
37+
);
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useTheme } from '@mui/material';
2+
3+
import StatusIndicator from 'src/components/shared/Entity/Details/Logs/Status/Overview/StatusIndicator';
4+
import useGlobalSearchParams, {
5+
GlobalSearchParams,
6+
} from 'src/hooks/searchParams/useGlobalSearchParams';
7+
import { useEntityStatusStore_singleResponse } from 'src/stores/EntityStatus/hooks';
8+
import { getConnectorStatusIndicatorState } from 'src/utils/entityStatus-utils';
9+
10+
export default function ConnectorStatus() {
11+
const catalogName = useGlobalSearchParams(GlobalSearchParams.CATALOG_NAME);
12+
13+
const theme = useTheme();
14+
15+
const connectorStatus =
16+
useEntityStatusStore_singleResponse(catalogName)?.connector_status;
17+
18+
const status = getConnectorStatusIndicatorState(
19+
theme.palette.mode,
20+
connectorStatus
21+
);
22+
23+
return <StatusIndicator status={status} />;
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import type { BaseDetailProps } from 'src/components/shared/Entity/Details/Logs/Status/Overview/types';
2+
3+
import { Skeleton, Typography } from '@mui/material';
4+
5+
import DetailWrapper from 'src/components/shared/Entity/Details/Logs/Status/Overview/DetailWrapper';
6+
import useGlobalSearchParams, {
7+
GlobalSearchParams,
8+
} from 'src/hooks/searchParams/useGlobalSearchParams';
9+
import { useEntityStatusStore_singleResponse } from 'src/stores/EntityStatus/hooks';
10+
import { useEntityStatusStore } from 'src/stores/EntityStatus/Store';
11+
12+
export default function ConnectorStatusDetail({
13+
headerMessageId,
14+
}: BaseDetailProps) {
15+
const catalogName = useGlobalSearchParams(GlobalSearchParams.CATALOG_NAME);
16+
17+
const hydrating = useEntityStatusStore((state) => !state.hydrated);
18+
19+
const lastStatus =
20+
useEntityStatusStore_singleResponse(catalogName)?.connector_status
21+
?.message;
22+
23+
return (
24+
<DetailWrapper
25+
headerMessageId={headerMessageId}
26+
Hydrating={
27+
hydrating ? <Skeleton height={21} width={75} /> : undefined
28+
}
29+
>
30+
<Typography> {lastStatus ?? '--'} </Typography>
31+
</DetailWrapper>
32+
);
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import type { BaseDetailProps } from 'src/components/shared/Entity/Details/Logs/Status/Overview/types';
2+
3+
import TimestampDetail from 'src/components/shared/Entity/Details/Logs/Status/Overview/TimestampDetail';
4+
import useGlobalSearchParams, {
5+
GlobalSearchParams,
6+
} from 'src/hooks/searchParams/useGlobalSearchParams';
7+
import { useEntityStatusStore_singleResponse } from 'src/stores/EntityStatus/hooks';
8+
9+
export default function ConnectorUpdatedDetail({
10+
headerMessageId,
11+
}: BaseDetailProps) {
12+
const catalogName = useGlobalSearchParams(GlobalSearchParams.CATALOG_NAME);
13+
14+
const lastUpdated =
15+
useEntityStatusStore_singleResponse(catalogName)?.connector_status?.ts;
16+
17+
return (
18+
<TimestampDetail headerMessageId={headerMessageId} time={lastUpdated} />
19+
);
20+
}

Diff for: src/components/shared/Entity/Details/Logs/Status/Overview/ControllerOverview.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default function ControllerOverview() {
3030
<Stack spacing={2} style={{ marginLeft: 14 }}>
3131
<ActivationDetail headerMessageId="details.ops.status.overview.controller.subheaderActivation" />
3232

33-
<ControllerUpdatedDetail headerMessageId="details.ops.status.overview.controller.subheaderLastUpdated" />
33+
<ControllerUpdatedDetail headerMessageId="details.ops.status.overview.generic.subheaderLastUpdated" />
3434
</Stack>
3535
</CardWrapper>
3636
</Grid>

Diff for: src/components/shared/Entity/Details/Logs/Status/Overview/index.tsx

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Grid, useMediaQuery, useTheme } from '@mui/material';
22

3+
import ConnectorOverview from 'src/components/shared/Entity/Details/Logs/Status/Overview//ConnectorOverview';
34
import AutoDiscoveryOverview from 'src/components/shared/Entity/Details/Logs/Status/Overview/AutoDiscoveryOverview';
45
import ControllerOverview from 'src/components/shared/Entity/Details/Logs/Status/Overview/ControllerOverview';
56
import { useEntityType } from 'src/context/EntityContext';
@@ -26,6 +27,8 @@ export default function Overview() {
2627
},
2728
}}
2829
>
30+
{entityType === 'collection' ? null : <ConnectorOverview />}
31+
2932
<ControllerOverview />
3033

3134
{entityType === 'capture' ? <AutoDiscoveryOverview /> : null}

Diff for: src/lang/en-US/Details.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@ export const Details: Record<string, string> = {
2121
'details.ops.status.overview.autoDiscovery.subheaderAdded': `Added`,
2222
'details.ops.status.overview.autoDiscovery.subheaderModified': `Modified`,
2323
'details.ops.status.overview.autoDiscovery.subheaderRemoved': `Removed`,
24+
'details.ops.status.overview.connector.header': `Connector`,
25+
'details.ops.status.overview.connector.subheaderLastStatus': `Status`,
2426
'details.ops.status.overview.controller.header': `Controller`,
2527
'details.ops.status.overview.controller.subheaderActivation': `Data Plane Activation`,
26-
'details.ops.status.overview.controller.subheaderLastUpdated': `Last Updated`,
28+
'details.ops.status.overview.generic.subheaderLastUpdated': `Last Updated`,
2729
'details.ops.status.overview.menuLabel.details': `View details`,
2830
'details.ops.status.overview.menuLabel.troubleshoot': `Contact support`,
2931
'details.ops.status.table.label': `Controller Status History Table`,

Diff for: src/types/controlPlane.ts

+15
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ export interface CollectionControllerStatus extends EntityControllerStatus {
4747
inferred_schema?: InferredSchemaStatus | null;
4848
}
4949

50+
interface ConnectorStatus {
51+
message: string;
52+
shard: ShardRef;
53+
ts: string;
54+
fields?: object;
55+
}
56+
5057
interface DiscoverChange {
5158
disable: boolean;
5259
resource_path: string[];
@@ -61,6 +68,7 @@ export interface EntityControllerStatus extends PublicationControllerStatus {
6168

6269
export interface EntityStatusResponse {
6370
catalog_name: string;
71+
connector_status: ConnectorStatus | null;
6472
controller_failures: number;
6573
controller_next_run: string | null;
6674
controller_updated_at: string;
@@ -122,6 +130,13 @@ interface PublicationStatus {
122130
max_observed_pub_id?: string;
123131
}
124132

133+
interface ShardRef {
134+
build: string;
135+
keyBegin: string;
136+
name: string;
137+
rClockBegin: string;
138+
}
139+
125140
interface SourceCaptureStatus {
126141
add_bindings?: string[];
127142
up_to_date?: boolean;

Diff for: src/utils/entityStatus-utils.ts

+26
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,32 @@ export const getAutoDiscoveryIndicatorState = (
136136
};
137137
};
138138

139+
// This logic is bound to change and, more or less, functions as a placeholder. According to Phil,
140+
// a null connector_status could be indicative of one of three things:
141+
// * A connector status has not come through yet.
142+
// * The task is not working.
143+
// * The ops catalog is not working.
144+
145+
export const getConnectorStatusIndicatorState = (
146+
_colorMode: PaletteMode,
147+
connectorStatus: EntityStatusResponse['connector_status'] | undefined
148+
): StatusIndicatorState => {
149+
if (!connectorStatus) {
150+
return {
151+
color: { hex: warningMain, id: 'warning' },
152+
messageId: 'status.error.medium',
153+
};
154+
}
155+
156+
return {
157+
color: {
158+
hex: successMain,
159+
id: 'success',
160+
},
161+
messageId: 'status.error.low',
162+
};
163+
};
164+
139165
export const isEntityControllerStatus = (
140166
value: ControllerStatus
141167
): value is EntityControllerStatus =>

0 commit comments

Comments
 (0)