Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create foundation for a controller status history view #1402

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
a60b508
Create foundation for a controller status history view
kiahna-tucker Dec 16, 2024
515ed8f
Rename Details table column to Event
kiahna-tucker Dec 16, 2024
728c9d6
Correct styling of ControllerErrors when no errors exist
kiahna-tucker Dec 16, 2024
01bfec6
Move control-plane related types into deps/control-plane
kiahna-tucker Dec 17, 2024
02ec799
Move getEntityStatus into a file within src/api
kiahna-tucker Dec 17, 2024
4fb88cd
Merge branch 'main' into kiahna-tucker/entity-status/init-controller-…
kiahna-tucker Dec 18, 2024
34a4fc1
Move controller status history table cells into entityStatus directory
kiahna-tucker Dec 19, 2024
b40b47b
Update format of /status request URL
kiahna-tucker Dec 19, 2024
eb1873c
Update /status response URL and associated types
kiahna-tucker Dec 19, 2024
fb0cff7
Create a foundation for controller status overview component
kiahna-tucker Jan 3, 2025
048f618
Create foundation for auto-discovery status overview component
kiahna-tucker Jan 4, 2025
9a96839
Merge branch 'main' into kiahna-tucker/entity-status/init-controller-…
kiahna-tucker Jan 6, 2025
3172ab0
Rename EntityStatusResponse.status to controller_status
kiahna-tucker Jan 7, 2025
f9986c9
Move component-defined colors to theme
kiahna-tucker Jan 7, 2025
d8e77c5
Hide auto-discovery overview for non-captures
kiahna-tucker Jan 7, 2025
0250ebe
Add refresh cta to status section
kiahna-tucker Jan 7, 2025
9d17a18
Toggle between dashboard and code views
kiahna-tucker Jan 7, 2025
09ec67a
Display time the endpoint was last successfully reached
kiahna-tucker Jan 7, 2025
edeec18
Remove superfluous padding on SectionUpdated
kiahna-tucker Jan 7, 2025
d1c750d
Replace response store state with computed value
kiahna-tucker Jan 7, 2025
e70c8f7
Identify loading view state using computed value
kiahna-tucker Jan 7, 2025
6fab387
Reset entity status store state when details page unmounts
kiahna-tucker Jan 8, 2025
436c508
Remove logging statements
kiahna-tucker Jan 8, 2025
d314ea7
Create production env variable for base entity status url
kiahna-tucker Jan 8, 2025
62787e2
Update status section styling
kiahna-tucker Jan 9, 2025
70ef39a
Update the overview card style
kiahna-tucker Jan 10, 2025
fb22211
Update auto discovery failure timestamp
kiahna-tucker Jan 10, 2025
33fdaa4
Distinguish between loading and hydrating states
kiahna-tucker Jan 13, 2025
78840b7
Display server error
kiahna-tucker Jan 14, 2025
f5ca921
Store entity status swr mutator
kiahna-tucker Jan 14, 2025
27f7dec
Remove loading-related store state and action
kiahna-tucker Jan 14, 2025
e942402
Display response viewer loading state when refreshing
kiahna-tucker Jan 14, 2025
973ab4c
Convert getSingleResponse to store hook
kiahna-tucker Jan 14, 2025
d787efc
Update control-plane declaration file comments
kiahna-tucker Jan 14, 2025
531b353
Address a handful of nits
kiahna-tucker Jan 14, 2025
ac3b0d9
Add log rocket events
kiahna-tucker Jan 14, 2025
b317aa6
Hide section for non-support users
kiahna-tucker Jan 14, 2025
87ed464
Merge branch 'main' into kiahna-tucker/entity-status/init-controller-…
kiahna-tucker Jan 14, 2025
648a999
Move control-plane types from deps/ to src/types/
kiahna-tucker Jan 16, 2025
b336ecc
Merge branch 'main' into kiahna-tucker/entity-status/init-controller-…
kiahna-tucker Jan 16, 2025
9f0f7d1
Replace temp number formatting util with readable
kiahna-tucker Jan 17, 2025
06af24e
Set active during hydration only when store is not hydrated
kiahna-tucker Jan 17, 2025
5c70228
Remove optional controller status history table column code
kiahna-tucker Jan 17, 2025
6dedc93
Merge branch 'main' into kiahna-tucker/entity-status/init-controller-…
travjenkins Jan 21, 2025
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: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFz
VITE_TASK_AUTHORIZATION_URL=https://agent-api-1084703453822.us-central1.run.app/authorize/user/task
VITE_COLLECTION_AUTHORIZATION_URL=https://agent-api-1084703453822.us-central1.run.app/authorize/user/collection

VITE_ENTITY_STATUS_BASE_URL=https://agent-api-1084703453822.us-central1.run.app/api/v1/catalog/status

VITE_MARKETPLACE_VERIFY_URL=https://gcp-marketplace-verify-mo7rswd2xq-uc.a.run.app

VITE_DEFAULT_DATA_PLANE_SUFFIX=gcp-us-central1-c1
Expand Down
2 changes: 2 additions & 0 deletions .env.development.local
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFz
VITE_TASK_AUTHORIZATION_URL=http://localhost:8675/authorize/user/task
VITE_COLLECTION_AUTHORIZATION_URL=http://localhost:8675/authorize/user/collection

VITE_ENTITY_STATUS_BASE_URL=http://localhost:8675/api/v1/catalog/status

VITE_MARKETPLACE_VERIFY_URL=http://example.com

VITE_DEFAULT_DATA_PLANE_SUFFIX=local-cluster
Expand Down
12 changes: 12 additions & 0 deletions src/api/entityStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { client } from 'services/client';
import { EntityStatusResponse } from 'types/controlPlane';
import { getEntityStatusSettings } from 'utils/env-utils';

const { entityStatusBaseEndpoint } = getEntityStatusSettings();

// Local API documentation can be found here: http://localhost:8675/api/v1/docs
export const getEntityStatus = async (
accessToken: string,
catalogName: string
): Promise<EntityStatusResponse[]> =>
client(`${entityStatusBaseEndpoint}?name=${catalogName}`, {}, accessToken);
Copy link
Member

Choose a reason for hiding this comment

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

I think probably best to do it here - but we need to make sure catalogName is safe / escaped. Normally we have used escapeReservedCharacters but that is really for PostgREST so not 100% sure what we wanna do here.

73 changes: 38 additions & 35 deletions src/components/shared/CardWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,44 +39,47 @@ function CardWrapper({ children, height, message, tooltipMessageId }: Props) {
background: semiTransparentBackground[theme.palette.mode],
boxShadow: defaultBoxShadow,
borderRadius: 3,
minWidth: 'min-content',
}}
>
<Stack
direction="row"
spacing={1}
sx={{ mb: 2, alignItems: 'center' }}
>
{message ? (
<Typography
sx={{
...cardHeaderSx,
mb: 2,
width: '100%',
}}
component="div"
>
{message}
</Typography>
) : null}

{tooltipMessageId ? (
<Tooltip
placement={belowLg ? 'bottom' : 'right'}
title={intl.formatMessage({
id: 'admin.billing.graph.dataByTask.tooltip',
})}
>
<HelpCircle
style={{
marginBottom: 16,
fontSize: 12,
strokeWidth: 1,
color: theme.palette.text.primary,
{Boolean(message || tooltipMessageId) ? (
<Stack
direction="row"
spacing={1}
sx={{ mb: 2, alignItems: 'center' }}
>
{message ? (
<Typography
sx={{
...cardHeaderSx,
mb: 2,
width: '100%',
}}
/>
</Tooltip>
) : null}
</Stack>
component="div"
>
{message}
</Typography>
) : null}

{tooltipMessageId ? (
<Tooltip
placement={belowLg ? 'bottom' : 'right'}
title={intl.formatMessage({
id: 'admin.billing.graph.dataByTask.tooltip',
})}
>
<HelpCircle
style={{
marginBottom: 16,
fontSize: 12,
strokeWidth: 1,
color: theme.palette.text.primary,
}}
/>
</Tooltip>
) : null}
</Stack>
) : null}

{children}
</Box>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Skeleton, Typography } from '@mui/material';
import useGlobalSearchParams, {
GlobalSearchParams,
} from 'hooks/searchParams/useGlobalSearchParams';
import { useIntl } from 'react-intl';
import {
useEntityStatusStore_lastActivated,
useEntityStatusStore_singleResponse,
} from 'stores/EntityStatus/hooks';
import { useEntityStatusStore } from 'stores/EntityStatus/Store';
import { getDataPlaneActivationStatus } from 'utils/entityStatus-utils';
import DetailWrapper from './DetailWrapper';
import { BaseDetailProps } from './types';

export default function ActivationDetail({ headerMessageId }: BaseDetailProps) {
const catalogName = useGlobalSearchParams(GlobalSearchParams.CATALOG_NAME);

const intl = useIntl();

const hydrating = useEntityStatusStore((state) => !state.hydrated);
const lastActivated = useEntityStatusStore_lastActivated(catalogName);
const lastBuildId =
useEntityStatusStore_singleResponse(catalogName)?.last_build_id;

const contentMessageId = getDataPlaneActivationStatus(
lastActivated,
lastBuildId
);

return (
<DetailWrapper
headerMessageId={headerMessageId}
Hydrating={
hydrating ? <Skeleton height={21} width={75} /> : undefined
}
>
<Typography>
{intl.formatMessage({ id: contentMessageId })}
</Typography>
</DetailWrapper>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Divider, Stack } from '@mui/material';
import NumberDetail from './NumberDetail';
import { AutoDiscoverChangesProps } from './types';

export default function AutoDiscoverChanges({
added,
modified,
removed,
}: AutoDiscoverChangesProps) {
return (
<Stack direction="row" spacing={1}>
<NumberDetail
headerMessageId="details.ops.status.overview.autoDiscovery.subheaderAdded"
value={added?.length ?? 0}
/>

<Divider flexItem orientation="vertical" />

<NumberDetail
headerMessageId="details.ops.status.overview.autoDiscovery.subheaderModified"
value={modified?.length ?? 0}
/>

<Divider flexItem orientation="vertical" />

<NumberDetail
headerMessageId="details.ops.status.overview.autoDiscovery.subheaderRemoved"
value={removed?.length ?? 0}
/>
</Stack>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import useGlobalSearchParams, {
GlobalSearchParams,
} from 'hooks/searchParams/useGlobalSearchParams';
import {
useEntityStatusStore_autoDiscoverFailure,
useEntityStatusStore_autoDiscoverLastSuccess,
} from 'stores/EntityStatus/hooks';
import AutoDiscoverChanges from './AutoDiscoverChanges';
import TimestampDetail from './TimestampDetail';

export default function AutoDiscoverOutcome() {
const catalogName = useGlobalSearchParams(GlobalSearchParams.CATALOG_NAME);

const failure = useEntityStatusStore_autoDiscoverFailure(catalogName);
const lastSuccess =
useEntityStatusStore_autoDiscoverLastSuccess(catalogName);

if (failure) {
return (
<>
<AutoDiscoverChanges
added={failure.last_outcome.added}
modified={failure.last_outcome.modified}
removed={failure.last_outcome.removed}
/>

<TimestampDetail
headerMessageId="details.ops.status.overview.autoDiscovery.subheaderLastFailure"
time={failure.last_outcome.ts}
/>
</>
);
}

return (
<>
<AutoDiscoverChanges
added={lastSuccess?.added}
modified={lastSuccess?.modified}
removed={lastSuccess?.removed}
/>

<TimestampDetail
headerMessageId="details.ops.status.overview.autoDiscovery.subheaderLastSuccess"
time={lastSuccess?.ts}
/>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Grid, Stack, Typography } from '@mui/material';
import CardWrapper from 'components/shared/CardWrapper';
import { cardHeaderSx } from 'context/Theme';
import { useIntl } from 'react-intl';
import AutoDiscoverOutcome from './AutoDiscoverOutcome';
import AutoDiscoveryStatus from './AutoDiscoveryStatus';

export default function AutoDiscoveryOverview() {
const intl = useIntl();

return (
<Grid item xs={12} md={6} lg={3}>
<CardWrapper>
<Stack
direction="row"
style={{ marginBottom: 16, marginLeft: -4 }}
>
<AutoDiscoveryStatus />

<Typography component="div" sx={{ ...cardHeaderSx, mr: 3 }}>
{intl.formatMessage({
id: 'details.ops.status.overview.autoDiscovery.header',
})}
</Typography>
</Stack>

<Stack spacing={2} style={{ marginLeft: 14 }}>
<AutoDiscoverOutcome />
</Stack>
</CardWrapper>
</Grid>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useTheme } from '@mui/material';
import useGlobalSearchParams, {
GlobalSearchParams,
} from 'hooks/searchParams/useGlobalSearchParams';
import { useEntityStatusStore_autoDiscoverFailure } from 'stores/EntityStatus/hooks';
import { getAutoDiscoveryIndicatorState } from 'utils/entityStatus-utils';
import StatusIndicator from './StatusIndicator';

export default function AutoDiscoveryStatus() {
const catalogName = useGlobalSearchParams(GlobalSearchParams.CATALOG_NAME);

const theme = useTheme();

const autoDiscoveryFailure =
useEntityStatusStore_autoDiscoverFailure(catalogName);

const status = getAutoDiscoveryIndicatorState(
theme.palette.mode,
autoDiscoveryFailure
);
kiahna-tucker marked this conversation as resolved.
Show resolved Hide resolved

return <StatusIndicator status={status} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Grid, Stack, Typography } from '@mui/material';
import CardWrapper from 'components/shared/CardWrapper';
import { cardHeaderSx } from 'context/Theme';
import { useIntl } from 'react-intl';
import ActivationDetail from './ActivationDetail';
import ControllerStatus from './ControllerStatus';
import ControllerUpdatedDetail from './ControllerUpdatedDetail';

export default function ControllerOverview() {
const intl = useIntl();

return (
<Grid item xs={12} md={6} lg={3}>
<CardWrapper>
<Stack
direction="row"
style={{ marginBottom: 16, marginLeft: -4 }}
>
<ControllerStatus />

<Typography component="div" sx={{ ...cardHeaderSx, mr: 3 }}>
{intl.formatMessage({
id: 'details.ops.status.overview.controller.header',
})}
</Typography>
</Stack>

<Stack spacing={2} style={{ marginLeft: 14 }}>
<ActivationDetail headerMessageId="details.ops.status.overview.controller.subheaderActivation" />

<ControllerUpdatedDetail headerMessageId="details.ops.status.overview.controller.subheaderLastUpdated" />
</Stack>
</CardWrapper>
</Grid>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useTheme } from '@mui/material';
import useGlobalSearchParams, {
GlobalSearchParams,
} from 'hooks/searchParams/useGlobalSearchParams';
import { useEntityStatusStore_singleResponse } from 'stores/EntityStatus/hooks';
import { getControllerStatusIndicatorState } from 'utils/entityStatus-utils';
import StatusIndicator from './StatusIndicator';

export default function ControllerStatus() {
const catalogName = useGlobalSearchParams(GlobalSearchParams.CATALOG_NAME);

const theme = useTheme();

const controllerError =
useEntityStatusStore_singleResponse(catalogName)?.controller_error;

const controllerNextRun =
useEntityStatusStore_singleResponse(catalogName)?.controller_next_run;

const status = getControllerStatusIndicatorState(
theme.palette.mode,
controllerError,
controllerNextRun
);

return <StatusIndicator status={status} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import useGlobalSearchParams, {
GlobalSearchParams,
} from 'hooks/searchParams/useGlobalSearchParams';
import { useEntityStatusStore_singleResponse } from 'stores/EntityStatus/hooks';
import TimestampDetail from './TimestampDetail';
import { BaseDetailProps } from './types';

export default function ControllerUpdatedDetail({
headerMessageId,
}: BaseDetailProps) {
const catalogName = useGlobalSearchParams(GlobalSearchParams.CATALOG_NAME);

const lastUpdated =
useEntityStatusStore_singleResponse(catalogName)?.controller_updated_at;

return (
<TimestampDetail headerMessageId={headerMessageId} time={lastUpdated} />
);
}
Loading
Loading