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:
parent
a9cd81a61c
commit
a468c55fc7
@ -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>
|
||||
);
|
||||
};
|
||||
|
@ -47,7 +47,7 @@ const useApplication = (
|
||||
appName: name,
|
||||
color: '',
|
||||
createdAt: '2022-02-02T21:04:00.268Z',
|
||||
descriotion: '',
|
||||
description: '',
|
||||
instances: [],
|
||||
strategies: [],
|
||||
seenToggles: [],
|
||||
|
Loading…
Reference in New Issue
Block a user