1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

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.

<img width="848" alt="image"
src="https://github.com/Unleash/unleash/assets/17786332/ef7562d5-c0ab-48c6-ba43-7c0007719ab4">
This commit is contained in:
Thomas Heartman 2024-02-20 18:14:44 +08:00 committed by GitHub
parent a9cd81a61c
commit a468c55fc7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 108 additions and 22 deletions

View File

@ -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 (
<ConnectedInstancesTable
loading={false}
headerGroups={headerGroups}
prepareRow={prepareRow}
getTableBodyProps={getTableBodyProps}
getTableProps={getTableProps}
rows={rows}
/>
<Container>
<EnvironmentSelectionContainer>
{allEnvironmentsSorted.map((env) => {
return (
<label key={env}>
{env}
<input
defaultChecked={currentEnvironment === env}
type='radio'
name='active-environment'
onClick={() => {
setCurrentEnvironment(env);
}}
/>
</label>
);
})}
</EnvironmentSelectionContainer>
<ConnectedInstancesTable
loading={false}
headerGroups={headerGroups}
prepareRow={prepareRow}
getTableBodyProps={getTableBodyProps}
getTableProps={getTableProps}
rows={rows}
/>
</Container>
);
};

View File

@ -47,7 +47,7 @@ const useApplication = (
appName: name,
color: '',
createdAt: '2022-02-02T21:04:00.268Z',
descriotion: '',
description: '',
instances: [],
strategies: [],
seenToggles: [],