From a468c55fc77d05a858ecacd8081a2910ce866a79 Mon Sep 17 00:00:00 2001 From: Thomas Heartman Date: Tue, 20 Feb 2024 18:14:44 +0800 Subject: [PATCH] feat: add environment selection to connected instances screen (#6277) This PR adds an environment selector to the connected instances table, using query parameters to store the environment selection. I'm still using the old data to populate this, so it'll show you all data when nothing is selected and only filtered data when you select an env. There is no way to unselect an env at the moment: I'm not sure that's something we'll need to do, so we'll handle that when we know. I imagine in the future, we might update the component to make separate calls per environments and a call to determine which envs are available, but for now, this will do just fine. image --- .../ConnectedInstances/ConnectedInstances.tsx | 128 +++++++++++++++--- .../getters/useApplication/useApplication.ts | 2 +- 2 files changed, 108 insertions(+), 22 deletions(-) diff --git a/frontend/src/component/application/ConnectedInstances/ConnectedInstances.tsx b/frontend/src/component/application/ConnectedInstances/ConnectedInstances.tsx index b3b05592e1..f04bfe07cb 100644 --- a/frontend/src/component/application/ConnectedInstances/ConnectedInstances.tsx +++ b/frontend/src/component/application/ConnectedInstances/ConnectedInstances.tsx @@ -4,39 +4,125 @@ import { formatDateYMDHMS } from 'utils/formatDate'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; import { useConnectedInstancesTable } from './useConnectedInstancesTable'; import { ConnectedInstancesTable } from './ConnectedInstancesTable'; +import { IApplication } from 'interfaces/application'; +import { useQueryParam } from 'use-query-params'; +import { styled } from '@mui/material'; + +const Container = styled('div')(({ theme }) => ({ + '* + *': { + marginBlockStart: theme.spacing(2), + }, +})); + +const EnvironmentSelectionContainer = styled('div')(({ theme }) => ({ + label: { + color: theme.palette.primary.main, + background: theme.palette.background, + paddingInline: theme.spacing(2), + paddingBlock: theme.spacing(1), + border: `1px solid ${theme.palette.background.alternative}`, + borderInlineStart: 'none', + fontWeight: 'bold', + }, + 'label:first-of-type': { + borderInlineStart: `1px solid ${theme.palette.background.alternative}`, + borderRadius: `${theme.shape.borderRadiusMedium}px 0 0 ${theme.shape.borderRadiusMedium}px`, + }, + 'label:last-of-type': { + borderRadius: `0 ${theme.shape.borderRadiusMedium}px ${theme.shape.borderRadiusMedium}px 0`, + }, + 'label:has(input:checked)': { + background: theme.palette.background.alternative, + color: theme.palette.primary.contrastText, + }, + 'label:focus-within': { + outline: `2px solid ${theme.palette.background.alternative}`, + outlineOffset: theme.spacing(0.5), + }, + + input: { + border: 0, + clip: 'rect(0 0 0 0)', + height: 'auto', + margin: 0, + overflow: 'hidden', + padding: 0, + position: 'absolute', + width: '1px', + whiteSpace: 'nowrap', + }, +})); export const ConnectedInstances = () => { const name = useRequiredPathParam('name'); const { application } = useApplication(name); + const [currentEnvironment, setCurrentEnvironment] = + useQueryParam('environment'); + const availableEnvironments = new Set( + application?.instances.map( + // @ts-expect-error: the type definition here is incomplete. It + // should be updated as part of this project. + (instance) => instance.environment, + ), + ); + const allEnvironmentsSorted = Array.from(availableEnvironments).sort( + (a, b) => a.localeCompare(b), + ); const tableData = useMemo(() => { - return ( - application.instances + const map = ({ + instanceId, + sdkVersion, + clientIp, + lastSeen, + }: IApplication['instances'][number]) => ({ + instanceId, + ip: clientIp, + sdkVersion, + lastSeen: formatDateYMDHMS(lastSeen), + }); + if (!currentEnvironment) { + return application.instances.map(map); + } + return application.instances + .filter( // @ts-expect-error: the type definition here is incomplete. It // should be updated as part of this project. - .filter((instance) => instance.environment === 'production') - .map(({ instanceId, sdkVersion, clientIp, lastSeen }) => { - return { - instanceId, - ip: clientIp, - sdkVersion, - lastSeen: formatDateYMDHMS(lastSeen), - }; - }) - ); - }, [application]); + (instance) => instance.environment === currentEnvironment, + ) + .map(map); + }, [application, currentEnvironment]); const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useConnectedInstancesTable(tableData); return ( - + + + {allEnvironmentsSorted.map((env) => { + return ( + + ); + })} + + + ); }; diff --git a/frontend/src/hooks/api/getters/useApplication/useApplication.ts b/frontend/src/hooks/api/getters/useApplication/useApplication.ts index b8bc0e43df..0dd933ac37 100644 --- a/frontend/src/hooks/api/getters/useApplication/useApplication.ts +++ b/frontend/src/hooks/api/getters/useApplication/useApplication.ts @@ -47,7 +47,7 @@ const useApplication = ( appName: name, color: '', createdAt: '2022-02-02T21:04:00.268Z', - descriotion: '', + description: '', instances: [], strategies: [], seenToggles: [],