fix(striker-ui): enable drag to add NICs to networks

main
Tsu-ba-me 2 years ago
parent 7457649986
commit 8e522246a8
  1. 200
      striker-ui/pages/init/index.tsx

@ -1,10 +1,13 @@
import { FC, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import { import {
Box as MUIBox, Box as MUIBox,
BoxProps as MUIBoxProps, BoxProps as MUIBoxProps,
iconButtonClasses as muiIconButtonClasses, iconButtonClasses as muiIconButtonClasses,
} from '@mui/material'; } from '@mui/material';
import { DragHandle as MUIDragHandleIcon } from '@mui/icons-material'; import {
Check as MUICheckIcon,
DragHandle as MUIDragHandleIcon,
} from '@mui/icons-material';
import { import {
DataGrid as MUIDataGrid, DataGrid as MUIDataGrid,
DataGridProps as MUIDataGridProps, DataGridProps as MUIDataGridProps,
@ -12,14 +15,34 @@ import {
} from '@mui/x-data-grid'; } from '@mui/x-data-grid';
import API_BASE_URL from '../../lib/consts/API_BASE_URL'; import API_BASE_URL from '../../lib/consts/API_BASE_URL';
import { GREY, TEXT } from '../../lib/consts/DEFAULT_THEME'; import { BLUE, GREY, TEXT } from '../../lib/consts/DEFAULT_THEME';
import Decorator from '../../components/Decorator'; import Decorator from '../../components/Decorator';
import { Panel, PanelHeader } from '../../components/Panels'; import {
InnerPanel,
InnerPanelHeader,
Panel,
PanelHeader,
} from '../../components/Panels';
import periodicFetch from '../../lib/fetchers/periodicFetch'; import periodicFetch from '../../lib/fetchers/periodicFetch';
import Spinner from '../../components/Spinner'; import Spinner from '../../components/Spinner';
import sumstring from '../../lib/sumstring'; import sumstring from '../../lib/sumstring';
import { BodyText, BodyTextProps, HeaderText } from '../../components/Text'; import { BodyText, BodyTextProps, HeaderText } from '../../components/Text';
import OutlinedInputWithLabel from '../../components/OutlinedInputWithLabel';
type NetworkInput = {
interfaces: NetworkInterfaceOverviewMetadata[];
ipAddress: string;
name: string;
subnetMask: string;
};
type NetworkInterfaceInputMap = Record<
string,
{
isApplied?: boolean;
}
>;
const MOCK_NICS: NetworkInterfaceOverviewMetadata[] = [ const MOCK_NICS: NetworkInterfaceOverviewMetadata[] = [
{ {
@ -67,31 +90,68 @@ const DataGridCellText: FC<BodyTextProps> = ({
/> />
); );
const BriefNetworkInterface: FC<{
networkInterface: NetworkInterfaceOverviewMetadata;
}> = ({
networkInterface: { networkInterfaceName, networkInterfaceState },
}) => (
<MUIBox
sx={{
display: 'flex',
flexDirection: 'row',
'& > :not(:first-child)': { marginLeft: '.5em' },
}}
>
<Decorator
colour={networkInterfaceState === 'up' ? 'ok' : 'off'}
sx={{ height: 'auto' }}
/>
<BodyText text={networkInterfaceName} />
</MUIBox>
);
const createNetworkInterfaceTableColumns = ( const createNetworkInterfaceTableColumns = (
onMouseDownDragHandle: ( onMouseDownDragHandler: (
row: NetworkInterfaceOverviewMetadata, row: NetworkInterfaceOverviewMetadata,
...eventArgs: Parameters<Exclude<MUIBoxProps['onMouseDown'], undefined>> ...eventArgs: Parameters<Exclude<MUIBoxProps['onMouseDown'], undefined>>
) => void, ) => void,
networkInterfaceInputMap: NetworkInterfaceInputMap,
): MUIDataGridProps['columns'] => [ ): MUIDataGridProps['columns'] => [
{ {
align: 'center', align: 'center',
field: '', field: '',
renderCell: ({ row }) => ( renderCell: ({ row }) => {
const { isApplied } =
networkInterfaceInputMap[row.networkInterfaceUUID] || false;
let cursor = 'grab';
let handleOnMouseDown: MUIBoxProps['onMouseDown'] = (...eventArgs) => {
onMouseDownDragHandler(row, ...eventArgs);
};
let icon = <MUIDragHandleIcon />;
if (isApplied) {
cursor = 'auto';
handleOnMouseDown = undefined;
icon = <MUICheckIcon sx={{ color: BLUE }} />;
}
return (
<MUIBox <MUIBox
onMouseDown={(...eventArgs) => { onMouseDown={handleOnMouseDown}
onMouseDownDragHandle(row, ...eventArgs);
}}
sx={{ sx={{
alignItems: 'center', alignItems: 'center',
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
'&:hover': { cursor: 'grab' }, '&:hover': { cursor },
}} }}
> >
<MUIDragHandleIcon /> {icon}
</MUIBox> </MUIBox>
), );
},
sortable: false, sortable: false,
width: 1, width: 1,
}, },
@ -108,7 +168,7 @@ const createNetworkInterfaceTableColumns = (
}} }}
> >
<Decorator <Decorator
colour={networkInterfaceState === 'up' ? 'ok' : 'warning'} colour={networkInterfaceState === 'up' ? 'ok' : 'off'}
sx={{ height: 'auto' }} sx={{ height: 'auto' }}
/> />
<DataGridCellText text={value} /> <DataGridCellText text={value} />
@ -151,6 +211,22 @@ const createNetworkInterfaceTableColumns = (
]; ];
const NetworkInterfaceList: FC = () => { const NetworkInterfaceList: FC = () => {
const [networkInterfaceInputMap, setNetworkInterfaceInputMap] =
useState<NetworkInterfaceInputMap>({});
const [networkInputs] = useState<NetworkInput[]>([
{
ipAddress: '10.200.1.1',
name: 'Back-Channel Network 1',
interfaces: [],
subnetMask: '255.255.0.0',
},
{
ipAddress: '10.201.1.1',
name: 'Internet-Facing Network 1',
interfaces: [],
subnetMask: '255.255.0.0',
},
]);
const [networkInterfaceHeld, setNetworkInterfaceHeld] = useState< const [networkInterfaceHeld, setNetworkInterfaceHeld] = useState<
NetworkInterfaceOverviewMetadata | undefined NetworkInterfaceOverviewMetadata | undefined
>(); >();
@ -159,8 +235,41 @@ const NetworkInterfaceList: FC = () => {
NetworkInterfaceOverviewMetadata[] NetworkInterfaceOverviewMetadata[]
>(`${API_BASE_URL}/network-interface`, { >(`${API_BASE_URL}/network-interface`, {
refreshInterval: 2000, refreshInterval: 2000,
onSuccess: (data) => {
if (data instanceof Array) {
const map = data.reduce<NetworkInterfaceInputMap>(
(reduceContainer, { networkInterfaceUUID }) => {
reduceContainer[networkInterfaceUUID] =
networkInterfaceInputMap[networkInterfaceUUID] || {};
return reduceContainer;
},
{},
);
setNetworkInterfaceInputMap(map);
}
},
}); });
useEffect(() => {
const map = networkInterfaces.reduce<NetworkInterfaceInputMap>(
(reduceContainer, { networkInterfaceUUID }) => {
reduceContainer[networkInterfaceUUID] =
networkInterfaceInputMap[networkInterfaceUUID] || {};
return reduceContainer;
},
{},
);
setNetworkInterfaceInputMap(map);
// This block inits the input map for the MOCK_NICS.
// TODO: remove after testing.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return ( return (
<Panel> <Panel>
<PanelHeader> <PanelHeader>
@ -183,7 +292,7 @@ const NetworkInterfaceList: FC = () => {
autoHeight autoHeight
columns={createNetworkInterfaceTableColumns((row) => { columns={createNetworkInterfaceTableColumns((row) => {
setNetworkInterfaceHeld(row); setNetworkInterfaceHeld(row);
})} }, networkInterfaceInputMap)}
disableColumnMenu disableColumnMenu
disableSelectionOnClick disableSelectionOnClick
getRowId={({ networkInterfaceUUID }) => networkInterfaceUUID} getRowId={({ networkInterfaceUUID }) => networkInterfaceUUID}
@ -206,19 +315,78 @@ const NetworkInterfaceList: FC = () => {
networkInterfaceHeld?.networkInterfaceName || 'none' networkInterfaceHeld?.networkInterfaceName || 'none'
}`} }`}
/> />
{networkInputs.map(({ interfaces, ipAddress, name, subnetMask }) => (
<InnerPanel key={`network-input-${name.toLowerCase()}`}>
<InnerPanelHeader>
<BodyText text={name} />
</InnerPanelHeader>
<MUIBox
sx={{
display: 'flex',
flexDirection: { xs: 'column', md: 'row' },
margin: '.6em',
'& > *': {
flexBasis: '50%',
},
}}
>
<MUIBox <MUIBox
onMouseUp={() => { onMouseUp={() => {
if (networkInterfaceHeld) {
interfaces.push(networkInterfaceHeld);
networkInterfaceInputMap[
networkInterfaceHeld.networkInterfaceUUID
].isApplied = true;
}
setNetworkInterfaceHeld(undefined); setNetworkInterfaceHeld(undefined);
}} }}
sx={{ sx={{
borderColor: TEXT, borderColor: TEXT,
borderStyle: 'dashed', borderStyle: 'dashed',
borderWidth: '4px', borderWidth: '4px',
height: '100px', display: 'flex',
width: '100px', flexDirection: 'column',
padding: '.6em',
'& > :not(:first-child)': {
marginTop: '.3em',
},
}}
>
{interfaces.length > 0 ? (
interfaces.map((networkInterface) => (
<BriefNetworkInterface
key={`brief-network-interface-${networkInterface.networkInterfaceUUID}`}
networkInterface={networkInterface}
/>
))
) : (
<BodyText text="Drag interfaces here to add." />
)}
</MUIBox>
<MUIBox
sx={{
display: 'flex',
flexDirection: 'column',
}} }}
>
<OutlinedInputWithLabel
label="IP address"
value={ipAddress}
/>
<OutlinedInputWithLabel
label="Subnet mask"
value={subnetMask}
/> />
</MUIBox> </MUIBox>
</MUIBox>
</InnerPanel>
))}
</MUIBox>
)} )}
</Panel> </Panel>
); );

Loading…
Cancel
Save