parent
9d52213ef9
commit
e038b809d9
4 changed files with 289 additions and 44 deletions
@ -1,39 +1,199 @@ |
||||
import { Grid } from '@mui/material'; |
||||
import { FC } from 'react'; |
||||
import ContainedButton, { ContainedButtonProps } from '../ContainedButton'; |
||||
import { Panel, PanelHeader } from '../Panels'; |
||||
import { HeaderText } from '../Text'; |
||||
import { Grid, Switch } from '@mui/material'; |
||||
import { FC, useMemo, useState } from 'react'; |
||||
|
||||
type SimpleOperationsPanelProps = { |
||||
strikerHostName: string; |
||||
}; |
||||
import api from '../../lib/api'; |
||||
import ContainedButton from '../ContainedButton'; |
||||
import FlexBox from '../FlexBox'; |
||||
import handleAPIError from '../../lib/handleAPIError'; |
||||
import MessageBox, { Message } from '../MessageBox'; |
||||
import { Panel, PanelHeader } from '../Panels'; |
||||
import Spinner from '../Spinner'; |
||||
import { BodyText, HeaderText } from '../Text'; |
||||
|
||||
const StretchedButton: FC<ContainedButtonProps> = (props) => ( |
||||
<ContainedButton {...props} sx={{ width: '100%' }} /> |
||||
); |
||||
|
||||
const SimpleOperationsPanel: FC<SimpleOperationsPanelProps> = ({ |
||||
strikerHostName, |
||||
}) => ( |
||||
<Panel> |
||||
<PanelHeader> |
||||
<HeaderText text={strikerHostName} /> |
||||
</PanelHeader> |
||||
<Grid columns={{ xs: 1, sm: 2 }} container spacing="1em"> |
||||
<Grid item sm={2} xs={1}> |
||||
<StretchedButton>Update system</StretchedButton> |
||||
</Grid> |
||||
<Grid item sm={2} xs={1}> |
||||
<StretchedButton>Enable "Install target"</StretchedButton> |
||||
</Grid> |
||||
<Grid item xs={1}> |
||||
<StretchedButton>Reboot</StretchedButton> |
||||
</Grid> |
||||
<Grid item xs={1}> |
||||
<StretchedButton>Shutdown</StretchedButton> |
||||
installTarget = 'disabled', |
||||
onSubmit, |
||||
title, |
||||
}) => { |
||||
const [message, setMessage] = useState<Message | undefined>(); |
||||
|
||||
const headerElement = useMemo( |
||||
() => |
||||
title ? ( |
||||
<HeaderText sx={{ textAlign: 'center' }}>{title}</HeaderText> |
||||
) : ( |
||||
<Spinner sx={{ marginTop: 0 }} /> |
||||
), |
||||
[title], |
||||
); |
||||
|
||||
return ( |
||||
<Panel> |
||||
<PanelHeader>{headerElement}</PanelHeader> |
||||
<Grid columns={{ xs: 1, sm: 2 }} container spacing="1em"> |
||||
<Grid item sm={2} xs={1}> |
||||
<FlexBox row> |
||||
<BodyText sx={{ flexGrow: 1 }}>Install target</BodyText> |
||||
<Switch |
||||
checked={installTarget === 'enabled'} |
||||
edge="end" |
||||
onChange={(event, isChecked) => { |
||||
let actionText = 'disable'; |
||||
let actionTextCap = 'Disable'; |
||||
|
||||
if (isChecked) { |
||||
actionText = 'enable'; |
||||
actionTextCap = 'Enable'; |
||||
} |
||||
|
||||
onSubmit?.call(null, { |
||||
actionProceedText: actionTextCap, |
||||
content: ( |
||||
<BodyText> |
||||
Would you like to {actionText} "Install target" |
||||
on this striker? It'll take a few moments to |
||||
complete. |
||||
</BodyText> |
||||
), |
||||
onProceedAppend: () => { |
||||
api |
||||
.put( |
||||
'/host/local', |
||||
{ isEnableInstallTarget: isChecked }, |
||||
{ params: { handler: 'install-target' } }, |
||||
) |
||||
.catch((error) => { |
||||
const emsg = handleAPIError(error); |
||||
|
||||
emsg.children = ( |
||||
<> |
||||
Failed to {actionText} "Install |
||||
target"; CAUSE: |
||||
{emsg.children} |
||||
</> |
||||
); |
||||
|
||||
setMessage(emsg); |
||||
}); |
||||
}, |
||||
titleText: `${actionTextCap} "Install target" on ${title}?`, |
||||
}); |
||||
}} |
||||
/> |
||||
</FlexBox> |
||||
</Grid> |
||||
<Grid item sm={2} xs={1}> |
||||
<StretchedButton |
||||
onClick={() => { |
||||
onSubmit?.call(null, { |
||||
actionProceedText: 'Update', |
||||
content: ( |
||||
<BodyText> |
||||
Would you like to update the operating system on this |
||||
striker? It'll be placed into maintenance mode until |
||||
the update completes. |
||||
</BodyText> |
||||
), |
||||
onProceedAppend: () => { |
||||
api.put('/command/update-system').catch((error) => { |
||||
const emsg = handleAPIError(error); |
||||
|
||||
emsg.children = ( |
||||
<> |
||||
Failed to initiate system update; CAUSE: |
||||
{emsg.children} |
||||
</> |
||||
); |
||||
|
||||
setMessage(emsg); |
||||
}); |
||||
}, |
||||
titleText: `Update operating system on ${title}?`, |
||||
}); |
||||
}} |
||||
> |
||||
Update system |
||||
</StretchedButton> |
||||
</Grid> |
||||
|
||||
<Grid item sm={2} xs={1}> |
||||
<StretchedButton>Reconfigure striker</StretchedButton> |
||||
</Grid> |
||||
<Grid item xs={1}> |
||||
<StretchedButton |
||||
onClick={() => { |
||||
onSubmit?.call(null, { |
||||
actionProceedText: 'Reboot', |
||||
content: ( |
||||
<BodyText>Would you like to reboot this striker?</BodyText> |
||||
), |
||||
onProceedAppend: () => { |
||||
api.put('/command/reboot-host').catch((error) => { |
||||
const emsg = handleAPIError(error); |
||||
|
||||
emsg.children = ( |
||||
<> |
||||
Failed to initiate system reboot; CAUSE: |
||||
{emsg.children} |
||||
</> |
||||
); |
||||
|
||||
setMessage(emsg); |
||||
}); |
||||
}, |
||||
titleText: `Reboot ${title}?`, |
||||
}); |
||||
}} |
||||
> |
||||
Reboot |
||||
</StretchedButton> |
||||
</Grid> |
||||
<Grid item xs={1}> |
||||
<StretchedButton |
||||
onClick={() => { |
||||
onSubmit?.call(null, { |
||||
actionProceedText: 'Shutdown', |
||||
content: ( |
||||
<BodyText>Would you like to shutdown this striker?</BodyText> |
||||
), |
||||
onProceedAppend: () => { |
||||
api.put('/command/poweroff-host').catch((error) => { |
||||
const emsg = handleAPIError(error); |
||||
|
||||
emsg.children = ( |
||||
<> |
||||
Failed to initiate system shutdown; CAUSE: |
||||
{emsg.children} |
||||
</> |
||||
); |
||||
|
||||
setMessage(emsg); |
||||
}); |
||||
}, |
||||
titleText: `Shutdown ${title}?`, |
||||
}); |
||||
}} |
||||
> |
||||
Shutdown |
||||
</StretchedButton> |
||||
</Grid> |
||||
<Grid item sm={2} xs={1}> |
||||
{message && ( |
||||
<MessageBox |
||||
{...message} |
||||
onClose={() => { |
||||
setMessage(undefined); |
||||
}} |
||||
/> |
||||
)} |
||||
</Grid> |
||||
</Grid> |
||||
</Grid> |
||||
</Panel> |
||||
); |
||||
</Panel> |
||||
); |
||||
}; |
||||
|
||||
export default SimpleOperationsPanel; |
||||
|
@ -1,25 +1,88 @@ |
||||
import { Box, Grid } from '@mui/material'; |
||||
import { FC } from 'react'; |
||||
import { FC, useEffect, useState } from 'react'; |
||||
|
||||
import ConfirmDialog from '../../components/ConfirmDialog'; |
||||
import Header from '../../components/Header'; |
||||
|
||||
import { |
||||
ComplexOperationsPanel, |
||||
SimpleOperationsPanel, |
||||
} from '../../components/StrikerConfig'; |
||||
import useProtect from '../../hooks/useProtect'; |
||||
import useProtectedState from '../../hooks/useProtectedState'; |
||||
import api from '../../lib/api'; |
||||
|
||||
const Config: FC = () => { |
||||
const { protect } = useProtect(); |
||||
|
||||
const [isOpenConfirmDialog, setIsOpenConfirmDialog] = |
||||
useState<boolean>(false); |
||||
const [confirmDialogProps, setConfirmDialogProps] = |
||||
useState<ConfirmDialogProps>({ |
||||
actionProceedText: '', |
||||
content: '', |
||||
dialogProps: { open: isOpenConfirmDialog }, |
||||
onCancelAppend: () => { |
||||
setIsOpenConfirmDialog(false); |
||||
}, |
||||
onProceedAppend: () => { |
||||
setIsOpenConfirmDialog(false); |
||||
}, |
||||
titleText: '', |
||||
}); |
||||
const [simpleOpsPanelHeader, setSimpleOpsPanelHeader] = |
||||
useProtectedState<string>('', protect); |
||||
const [simpleOpsInstallTarget, setSimpleOpsInstallTarget] = useState< |
||||
APIHostInstallTarget | undefined |
||||
>(); |
||||
|
||||
useEffect(() => { |
||||
if (!simpleOpsPanelHeader) { |
||||
api |
||||
.get<APIHostDetail>('/host/local') |
||||
.then(({ data: { installTarget, shortHostName } }) => { |
||||
setSimpleOpsInstallTarget(installTarget); |
||||
setSimpleOpsPanelHeader(shortHostName); |
||||
}) |
||||
.catch(() => { |
||||
setSimpleOpsPanelHeader('Unknown'); |
||||
}); |
||||
} |
||||
}, [simpleOpsPanelHeader, setSimpleOpsPanelHeader]); |
||||
|
||||
return ( |
||||
<> |
||||
<Box sx={{ display: 'flex', flexDirection: 'column' }}> |
||||
<Header /> |
||||
<Grid container columns={{ xs: 1, md: 3, lg: 4 }}> |
||||
<Grid item xs={1}> |
||||
<SimpleOperationsPanel |
||||
installTarget={simpleOpsInstallTarget} |
||||
onSubmit={({ onProceedAppend, ...restConfirmDialogProps }) => { |
||||
setConfirmDialogProps((previous) => ({ |
||||
...previous, |
||||
...restConfirmDialogProps, |
||||
onProceedAppend: (...args) => { |
||||
onProceedAppend?.call(null, ...args); |
||||
setIsOpenConfirmDialog(false); |
||||
}, |
||||
})); |
||||
|
||||
const Config: FC = () => ( |
||||
<Box sx={{ display: 'flex', flexDirection: 'column' }}> |
||||
<Header /> |
||||
<Grid container columns={{ xs: 1, md: 3, lg: 4 }}> |
||||
<Grid item xs={1}> |
||||
<SimpleOperationsPanel strikerHostName="STRIKER NAME" /> |
||||
</Grid> |
||||
<Grid item md={2} xs={1}> |
||||
<ComplexOperationsPanel /> |
||||
</Grid> |
||||
</Grid> |
||||
</Box> |
||||
); |
||||
setIsOpenConfirmDialog(true); |
||||
}} |
||||
title={simpleOpsPanelHeader} |
||||
/> |
||||
</Grid> |
||||
<Grid item md={2} xs={1}> |
||||
<ComplexOperationsPanel /> |
||||
</Grid> |
||||
</Grid> |
||||
</Box> |
||||
<ConfirmDialog |
||||
{...confirmDialogProps} |
||||
dialogProps={{ open: isOpenConfirmDialog }} |
||||
/> |
||||
</> |
||||
); |
||||
}; |
||||
|
||||
export default Config; |
||||
|
@ -0,0 +1,13 @@ |
||||
type SimpleOperationsPanelOptionalProps = { |
||||
onSubmit?: ( |
||||
props: Pick< |
||||
ConfirmDialogProps, |
||||
'actionProceedText' | 'content' | 'onProceedAppend' | 'titleText' |
||||
>, |
||||
) => void; |
||||
installTarget?: APIHostInstallTarget; |
||||
}; |
||||
|
||||
type SimpleOperationsPanelProps = SimpleOperationsPanelOptionalProps & { |
||||
title: string; |
||||
}; |
Loading…
Reference in new issue