Merge pull request #550 from ylei-tsubame/issues/471-force-off-server

Web UI: patch 454, and 471
main
Digimer 1 year ago committed by GitHub
commit 971ef9560c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      striker-ui-api/out/index.js
  2. 11
      striker-ui-api/src/lib/request_handlers/command/buildPowerHandler.ts
  3. 1
      striker-ui-api/src/types/BuildPowerHandlerFunction.d.ts
  4. 103
      striker-ui/components/ButtonWithMenu.tsx
  5. 66
      striker-ui/components/ConfirmDialog.tsx
  6. 2
      striker-ui/components/ContainedButton.tsx
  7. 61
      striker-ui/components/Dialog/DialogActionGroup.tsx
  8. 15
      striker-ui/components/Display/FullSize.tsx
  9. 11
      striker-ui/components/Display/Preview.tsx
  10. 1
      striker-ui/components/Hosts/AnvilHost.tsx
  11. 43
      striker-ui/components/Menu.tsx
  12. 4
      striker-ui/components/Panels/InnerPanelHeader.tsx
  13. 145
      striker-ui/components/ServerMenu.tsx
  14. 73
      striker-ui/hooks/useConfirmDialog.tsx
  15. 1
      striker-ui/out/_next/static/BhFewlGkfrUA_bCvxhgLY/_buildManifest.js
  16. 1
      striker-ui/out/_next/static/L_YVfOsZ3q029Wna3HXeD/_buildManifest.js
  17. 0
      striker-ui/out/_next/static/L_YVfOsZ3q029Wna3HXeD/_middlewareManifest.js
  18. 0
      striker-ui/out/_next/static/L_YVfOsZ3q029Wna3HXeD/_ssgManifest.js
  19. 1
      striker-ui/out/_next/static/chunks/157-0528651bf3cd10a7.js
  20. 1
      striker-ui/out/_next/static/chunks/157-d1418743accab385.js
  21. 1
      striker-ui/out/_next/static/chunks/170-357f4683929223df.js
  22. 1
      striker-ui/out/_next/static/chunks/182-08683bbe95fbb010.js
  23. 2
      striker-ui/out/_next/static/chunks/195-d5fd184cc249f755.js
  24. 1
      striker-ui/out/_next/static/chunks/195-fa06e61dd4339031.js
  25. 1
      striker-ui/out/_next/static/chunks/213-a0488f84cc98f172.js
  26. 1
      striker-ui/out/_next/static/chunks/284-03dc30df5d459e72.js
  27. 1
      striker-ui/out/_next/static/chunks/438-0147a63d98e89439.js
  28. 12
      striker-ui/out/_next/static/chunks/498-e1933a5461cd8607.js
  29. 1
      striker-ui/out/_next/static/chunks/528-72edc50189f30fa9.js
  30. 1
      striker-ui/out/_next/static/chunks/570-6bad4610969fc14b.js
  31. 1
      striker-ui/out/_next/static/chunks/62-09a1812bcc63d819.js
  32. 1
      striker-ui/out/_next/static/chunks/668-b264bf73f0c1b5eb.js
  33. 2
      striker-ui/out/_next/static/chunks/707-ee38ab2abcd0aa3f.js
  34. 1
      striker-ui/out/_next/static/chunks/82-b2661d1af04f38ff.js
  35. 1
      striker-ui/out/_next/static/chunks/839-dabd319a60c8df83.js
  36. 2
      striker-ui/out/_next/static/chunks/86-af7e2d6c5444a983.js
  37. 1
      striker-ui/out/_next/static/chunks/910-2a0e86a170f6eb77.js
  38. 1
      striker-ui/out/_next/static/chunks/936-f64829e0e2013921.js
  39. 1
      striker-ui/out/_next/static/chunks/94-f83c1e7821f76736.js
  40. 1
      striker-ui/out/_next/static/chunks/pages/anvil-3bce568d47e8eaba.js
  41. 1
      striker-ui/out/_next/static/chunks/pages/anvil-7fb5cba6fcb66e8c.js
  42. 2
      striker-ui/out/_next/static/chunks/pages/config-e3aa9a84a8baacc1.js
  43. 2
      striker-ui/out/_next/static/chunks/pages/file-manager-ef725a93a3e227aa.js
  44. 2
      striker-ui/out/_next/static/chunks/pages/index-8766524a2b0384fc.js
  45. 2
      striker-ui/out/_next/static/chunks/pages/init-b774a276c8a4ad79.js
  46. 2
      striker-ui/out/_next/static/chunks/pages/login-270fe7adf9f44c67.js
  47. 2
      striker-ui/out/_next/static/chunks/pages/manage-element-e577aadd99900dcb.js
  48. 2
      striker-ui/out/_next/static/chunks/pages/server-97d4cafd19cb2e9d.js
  49. 2
      striker-ui/out/anvil.html
  50. 2
      striker-ui/out/config.html
  51. 2
      striker-ui/out/file-manager.html
  52. 2
      striker-ui/out/index.html
  53. 2
      striker-ui/out/init.html
  54. 2
      striker-ui/out/login.html
  55. 2
      striker-ui/out/manage-element.html
  56. 2
      striker-ui/out/server.html
  57. 8
      striker-ui/types/ButtonWithMenu.d.ts
  58. 2
      striker-ui/types/ConfirmDialog.d.ts
  59. 1
      striker-ui/types/Dialog.d.ts
  60. 15
      striker-ui/types/Menu.d.ts
  61. 6
      striker-ui/types/MenuItem.d.ts
  62. 14
      striker-ui/types/ServerMenu.d.ts

File diff suppressed because one or more lines are too long

@ -49,8 +49,10 @@ const MAP_TO_POWER_JOB_PARAMS_BUILDER: Record<
job_name: 'set_power::off', job_name: 'set_power::off',
job_title: 'job_0332', job_title: 'job_0332',
}), }),
stopserver: ({ uuid } = {}) => ({ stopserver: ({ force, uuid } = {}) => ({
job_command: `${SERVER_PATHS.usr.sbin['anvil-shutdown-server'].self} --server-uuid '${uuid}'`, job_command: `${
SERVER_PATHS.usr.sbin['anvil-shutdown-server'].self
} --server-uuid '${uuid}'${force ? ' --immediate' : ''}`,
job_description: 'job_0343', job_description: 'job_0343',
job_name: 'set_power::server::off', job_name: 'set_power::server::off',
job_title: 'job_0342', job_title: 'job_0342',
@ -76,8 +78,11 @@ export const buildPowerHandler: (
(task) => async (request, response) => { (task) => async (request, response) => {
const { const {
params: { uuid }, params: { uuid },
query: { force: rForce },
} = request; } = request;
const force = sanitize(rForce, 'boolean');
try { try {
if (uuid) { if (uuid) {
assert( assert(
@ -92,7 +97,7 @@ export const buildPowerHandler: (
} }
try { try {
await queuePowerJob(task, { uuid }); await queuePowerJob(task, { force, uuid });
} catch (error) { } catch (error) {
stderr(`Failed to ${task} ${uuid ?? LOCAL}; CAUSE: ${error}`); stderr(`Failed to ${task} ${uuid ?? LOCAL}; CAUSE: ${error}`);

@ -9,6 +9,7 @@ type PowerTask =
type PowerJobParams = Omit<JobParams, 'file' | 'line'>; type PowerJobParams = Omit<JobParams, 'file' | 'line'>;
type BuildPowerJobParamsOptions = { type BuildPowerJobParamsOptions = {
force?: boolean;
isStopServers?: boolean; isStopServers?: boolean;
uuid?: string; uuid?: string;
}; };

@ -0,0 +1,103 @@
import { MoreVert as MoreVertIcon } from '@mui/icons-material';
import { Box } from '@mui/material';
import { FC, MouseEventHandler, useCallback, useMemo, useState } from 'react';
import ContainedButton from './ContainedButton';
import IconButton from './IconButton/IconButton';
import Menu from './Menu';
const ButtonWithMenu: FC<ButtonWithMenuProps> = (props) => {
const {
children,
containedButtonProps,
iconButtonProps,
muiMenuProps,
onButtonClick,
onItemClick,
variant = 'icon',
...menuProps
} = props;
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
const open = useMemo(() => Boolean(anchorEl), [anchorEl]);
const buttonContent = useMemo(() => {
if (children) {
return children;
}
if (variant === 'icon') {
return <MoreVertIcon fontSize={iconButtonProps?.size} />;
}
return 'Options';
}, [children, iconButtonProps?.size, variant]);
const buttonClickHandler = useCallback<MouseEventHandler<HTMLButtonElement>>(
(...args) => {
const {
0: { currentTarget },
} = args;
setAnchorEl(currentTarget);
return onButtonClick?.call(null, ...args);
},
[onButtonClick],
);
const buttonElement = useMemo(() => {
if (variant === 'contained') {
return (
<ContainedButton onClick={buttonClickHandler} {...containedButtonProps}>
{buttonContent}
</ContainedButton>
);
}
return (
<IconButton onClick={buttonClickHandler} {...iconButtonProps}>
{buttonContent}
</IconButton>
);
}, [
buttonClickHandler,
buttonContent,
containedButtonProps,
iconButtonProps,
variant,
]);
const itemClickHandler = useCallback<
Exclude<MenuProps['onItemClick'], undefined>
>(
(key, value, ...rest) => {
setAnchorEl(null);
return onItemClick?.call(null, key, value, ...rest);
},
[onItemClick],
);
return (
<Box>
{buttonElement}
<Menu
muiMenuProps={{
anchorEl,
keepMounted: true,
onClose: () => setAnchorEl(null),
...muiMenuProps,
}}
onItemClick={itemClickHandler}
open={open}
{...menuProps}
/>
</Box>
);
};
export default ButtonWithMenu as <T>(
...args: Parameters<FC<ButtonWithMenuProps<T>>>
) => ReturnType<FC<ButtonWithMenuProps<T>>>;

@ -39,6 +39,8 @@ const ConfirmDialog: ForwardRefExoticComponent<
proceedColour = 'blue', proceedColour = 'blue',
scrollContent = false, scrollContent = false,
scrollBoxProps, scrollBoxProps,
showActionArea = true,
showCancel,
showClose, showClose,
titleText, titleText,
wide, wide,
@ -64,27 +66,9 @@ const ConfirmDialog: ForwardRefExoticComponent<
[contentElement, scrollBoxProps, scrollContent], [contentElement, scrollBoxProps, scrollContent],
); );
useImperativeHandle( const actionArea = useMemo(
ref, () =>
() => ({ showActionArea && (
setOpen: (open) => dialogRef.current?.setOpen(open),
}),
[],
);
return (
<DialogWithHeader
dialogProps={dialogProps}
header={titleText}
loading={loading}
openInitially={openInitially}
ref={dialogRef}
showClose={showClose}
wide={wide}
>
<FlexBox {...contentContainerProps}>
{bodyElement}
{preActionArea}
<DialogActionArea <DialogActionArea
cancelProps={{ cancelProps={{
children: actionCancelText, children: actionCancelText,
@ -105,7 +89,47 @@ const ConfirmDialog: ForwardRefExoticComponent<
}, },
...proceedButtonProps, ...proceedButtonProps,
}} }}
showCancel={showCancel}
/> />
),
[
actionCancelText,
actionProceedText,
closeOnProceed,
disableProceed,
loadingAction,
onActionAppend,
onCancelAppend,
onProceedAppend,
proceedButtonProps,
proceedColour,
showActionArea,
showCancel,
],
);
useImperativeHandle(
ref,
() => ({
setOpen: (open) => dialogRef.current?.setOpen(open),
}),
[],
);
return (
<DialogWithHeader
dialogProps={dialogProps}
header={titleText}
loading={loading}
openInitially={openInitially}
ref={dialogRef}
showClose={showClose}
wide={wide}
>
<FlexBox {...contentContainerProps}>
{bodyElement}
{preActionArea}
{actionArea}
</FlexBox> </FlexBox>
</DialogWithHeader> </DialogWithHeader>
); );

@ -59,4 +59,6 @@ const ContainedButton = styled(Base)((props) => {
}; };
}); });
export { MAP_TO_COLOUR };
export default ContainedButton; export default ContainedButton;

@ -20,6 +20,7 @@ const DialogActionGroup: FC<DialogActionGroupProps> = (props) => {
onProceed = handleAction, onProceed = handleAction,
proceedColour, proceedColour,
proceedProps, proceedProps,
showCancel = true,
// Dependents // Dependents
cancelChildren = cancelProps?.children, cancelChildren = cancelProps?.children,
proceedChildren = proceedProps?.children, proceedChildren = proceedProps?.children,
@ -61,36 +62,36 @@ const DialogActionGroup: FC<DialogActionGroupProps> = (props) => {
[closeOnProceed, dialogContext, onProceed, proceedProps?.onClick], [closeOnProceed, dialogContext, onProceed, proceedProps?.onClick],
); );
const actions = useMemo( const actions = useMemo(() => {
() => ( const acts: ContainedButtonProps[] = [
<ActionGroup {
actions={[ background: proceedColour,
{ ...proceedProps,
...cancelProps, children: proceedChildren,
children: cancelChildren, onClick: proceedHandler,
onClick: cancelHandler, },
}, ];
{
background: proceedColour, if (showCancel) {
...proceedProps, acts.unshift({
children: proceedChildren, ...cancelProps,
onClick: proceedHandler, children: cancelChildren,
}, onClick: cancelHandler,
]} });
loading={loading} }
/>
), return <ActionGroup actions={acts} loading={loading} />;
[ }, [
cancelChildren, cancelChildren,
cancelHandler, cancelHandler,
cancelProps, cancelProps,
loading, loading,
proceedChildren, proceedChildren,
proceedColour, proceedColour,
proceedHandler, proceedHandler,
proceedProps, proceedProps,
], showCancel,
); ]);
return actions; return actions;
}; };

@ -12,6 +12,7 @@ import IconButton from '../IconButton';
import keyCombinations from './keyCombinations'; import keyCombinations from './keyCombinations';
import MenuItem from '../MenuItem'; import MenuItem from '../MenuItem';
import { Panel, PanelHeader } from '../Panels'; import { Panel, PanelHeader } from '../Panels';
import ServerMenu from '../ServerMenu';
import Spinner from '../Spinner'; import Spinner from '../Spinner';
import { HeaderText } from '../Text'; import { HeaderText } from '../Text';
import useIsFirstRender from '../../hooks/useIsFirstRender'; import useIsFirstRender from '../../hooks/useIsFirstRender';
@ -215,11 +216,23 @@ const FullSize: FC<FullSizeProps> = ({
showScreen && ( showScreen && (
<> <>
{keyboardMenuElement} {keyboardMenuElement}
<ServerMenu
serverName={serverName}
serverState="running"
serverUuid={serverUUID}
/>
{returnHomeElement} {returnHomeElement}
{vncDisconnectElement} {vncDisconnectElement}
</> </>
), ),
[keyboardMenuElement, returnHomeElement, showScreen, vncDisconnectElement], [
keyboardMenuElement,
returnHomeElement,
serverName,
serverUUID,
showScreen,
vncDisconnectElement,
],
); );
useEffect(() => { useEffect(() => {

@ -19,6 +19,7 @@ import api from '../../lib/api';
import FlexBox from '../FlexBox'; import FlexBox from '../FlexBox';
import IconButton, { IconButtonProps } from '../IconButton'; import IconButton, { IconButtonProps } from '../IconButton';
import { InnerPanel, InnerPanelHeader, Panel, PanelHeader } from '../Panels'; import { InnerPanel, InnerPanelHeader, Panel, PanelHeader } from '../Panels';
import ServerMenu from '../ServerMenu';
import Spinner from '../Spinner'; import Spinner from '../Spinner';
import { BodyText, HeaderText } from '../Text'; import { BodyText, HeaderText } from '../Text';
import { elapsed, last, now } from '../../lib/time'; import { elapsed, last, now } from '../../lib/time';
@ -105,7 +106,7 @@ const Preview: FC<PreviewProps> = ({
isShowControls = PREVIEW_DEFAULT_PROPS.isShowControls, isShowControls = PREVIEW_DEFAULT_PROPS.isShowControls,
isUseInnerPanel = PREVIEW_DEFAULT_PROPS.isUseInnerPanel, isUseInnerPanel = PREVIEW_DEFAULT_PROPS.isUseInnerPanel,
onClickPreview: previewClickHandler, onClickPreview: previewClickHandler,
serverName, serverName = PREVIEW_DEFAULT_PROPS.serverName,
serverState = PREVIEW_DEFAULT_PROPS.serverState, serverState = PREVIEW_DEFAULT_PROPS.serverState,
serverUUID, serverUUID,
onClickConnectButton: connectButtonClickHandle = previewClickHandler, onClickConnectButton: connectButtonClickHandle = previewClickHandler,
@ -239,12 +240,18 @@ const Preview: FC<PreviewProps> = ({
<PreviewPanel isUseInnerPanel={isUseInnerPanel}> <PreviewPanel isUseInnerPanel={isUseInnerPanel}>
<PreviewPanelHeader isUseInnerPanel={isUseInnerPanel} text={serverName}> <PreviewPanelHeader isUseInnerPanel={isUseInnerPanel} text={serverName}>
{headerEndAdornment} {headerEndAdornment}
<ServerMenu
iconButtonProps={{ size: isUseInnerPanel ? 'small' : undefined }}
serverName={serverName}
serverState={serverState}
serverUuid={serverUUID}
/>
</PreviewPanelHeader> </PreviewPanelHeader>
<FlexBox row sx={{ '& > :first-child': { flexGrow: 1 } }}> <FlexBox row sx={{ '& > :first-child': { flexGrow: 1 } }}>
{/* Box wrapper below is required to keep external preview size sane. */} {/* Box wrapper below is required to keep external preview size sane. */}
<Box textAlign="center">{iconButton}</Box> <Box textAlign="center">{iconButton}</Box>
{isShowControls && preview && ( {isShowControls && preview && (
<FlexBox> <FlexBox spacing=".3em">
<IconButton onClick={connectButtonClickHandle}> <IconButton onClick={connectButtonClickHandle}>
<DesktopWindowsIcon /> <DesktopWindowsIcon />
</IconButton> </IconButton>

@ -45,7 +45,6 @@ const StyledBox = styled(Box)(({ theme }) => ({
[`& .${classes.decoratorBox}`]: { [`& .${classes.decoratorBox}`]: {
alignSelf: 'stretch', alignSelf: 'stretch',
paddingRight: '.3em',
}, },
})); }));

@ -0,0 +1,43 @@
import { Menu as MuiMenu } from '@mui/material';
import { FC, useMemo } from 'react';
import MenuItem from './MenuItem';
const Menu: FC<MenuProps> = (props) => {
const {
getItemDisabled,
items = {},
muiMenuProps: menuProps,
onItemClick,
open,
renderItem,
} = props;
const pairs = useMemo(() => Object.entries(items), [items]);
const itemElements = useMemo(
() =>
pairs.map(([key, value]) => (
<MenuItem
disabled={getItemDisabled?.call(null, key, value)}
onClick={(...parent) =>
onItemClick?.call(null, key, value, ...parent)
}
// The key is only relevant within the same branch; i.e., instance of
// the same key under a different parent is OK.
key={key}
>
{renderItem?.call(null, key, value)}
</MenuItem>
)),
[getItemDisabled, onItemClick, pairs, renderItem],
);
return (
<MuiMenu open={open} {...menuProps}>
{itemElements}
</MuiMenu>
);
};
export default Menu as <T>(props: MenuProps<T>) => ReturnType<FC<MenuProps<T>>>;

@ -26,6 +26,10 @@ const InnerPanelHeader: FC = ({ children }) => (
'& > :first-child': { '& > :first-child': {
flexGrow: 1, flexGrow: 1,
}, },
'& > :not(:first-child, :last-child)': {
marginRight: '.3em',
},
}} }}
> >
{children} {children}

@ -0,0 +1,145 @@
import { PowerSettingsNew as PowerSettingsNewIcon } from '@mui/icons-material';
import { Box } from '@mui/material';
import { FC, useMemo } from 'react';
import api from '../lib/api';
import ButtonWithMenu from './ButtonWithMenu';
import { MAP_TO_COLOUR } from './ContainedButton';
import handleAPIError from '../lib/handleAPIError';
import { BodyText } from './Text';
import useConfirmDialog from '../hooks/useConfirmDialog';
const ServerMenu: FC<ServerMenuProps> = (props) => {
const {
// Props to ignore, for now:
getItemDisabled,
items,
onItemClick,
renderItem,
// ----------
serverName,
serverState,
serverUuid,
...buttonWithMenuProps
} = props;
const {
confirmDialog,
setConfirmDialogOpen,
setConfirmDialogProps,
finishConfirm,
} = useConfirmDialog();
const powerOptions = useMemo<MapToServerPowerOption>(
() => ({
'force-off': {
colour: 'red',
description: (
<>
This is equal to pulling the power cord, which may cause data loss
or system corruption.
</>
),
label: 'Force off',
path: `/command/stop-server/${serverUuid}?force=1`,
},
'power-off': {
description: (
<>
This is equal to pushing the power button. If the server
doesn&apos;t respond to the corresponding signals, you may have to
manually shut it down.
</>
),
label: 'Power off',
path: `/command/stop-server/${serverUuid}`,
},
'power-on': {
description: <>This is equal to pushing the power button.</>,
label: 'Power on',
path: `/command/start-server/${serverUuid}`,
},
}),
[serverUuid],
);
return (
<Box>
<ButtonWithMenu
getItemDisabled={(key) => {
const optionOn = key.includes('on');
const serverRunning = serverState === 'running';
return serverRunning === optionOn;
}}
items={powerOptions}
onItemClick={(key, value) => {
const { colour, description, label, path } = value;
const op = label.toLocaleLowerCase();
setConfirmDialogProps({
actionProceedText: label,
content: <BodyText>{description}</BodyText>,
onProceedAppend: () => {
setConfirmDialogProps((previous) => ({
...previous,
loading: true,
}));
api
.put(path)
.then(() => {
finishConfirm('Success', {
children: (
<>
Successfully registered {op} job on {serverName}.
</>
),
});
})
.catch((error) => {
const emsg = handleAPIError(error);
emsg.children = (
<>
Failed to register {op} job on {serverName}; CAUSE:{' '}
{emsg.children}.
</>
);
finishConfirm('Error', emsg);
});
},
proceedColour: colour,
titleText: `${label} server ${serverName}?`,
});
setConfirmDialogOpen(true);
}}
renderItem={(key, value) => {
const { colour, label } = value;
let ccode: string | undefined;
if (colour) {
ccode = MAP_TO_COLOUR[colour];
}
return (
<BodyText inheritColour color={ccode}>
{label}
</BodyText>
);
}}
{...buttonWithMenuProps}
>
<PowerSettingsNewIcon
fontSize={buttonWithMenuProps?.iconButtonProps?.size}
/>
</ButtonWithMenu>
{confirmDialog}
</Box>
);
};
export default ServerMenu;

@ -0,0 +1,73 @@
import {
Dispatch,
MutableRefObject,
ReactElement,
ReactNode,
SetStateAction,
useCallback,
useMemo,
useRef,
useState,
} from 'react';
import ConfirmDialog from '../components/ConfirmDialog';
import MessageBox from '../components/MessageBox';
const useConfirmDialog = (
args: {
initial?: Partial<ConfirmDialogProps>;
} = {},
): {
confirmDialog: ReactElement;
confirmDialogRef: MutableRefObject<ConfirmDialogForwardedRefContent | null>;
setConfirmDialogOpen: (value: boolean) => void;
setConfirmDialogProps: Dispatch<SetStateAction<ConfirmDialogProps>>;
finishConfirm: (title: ReactNode, message: Message) => void;
} => {
const {
initial: { actionProceedText = '', content = '', titleText = '' } = {},
} = args;
const confirmDialogRef = useRef<ConfirmDialogForwardedRefContent | null>(
null,
);
const [confirmDialogProps, setConfirmDialogProps] =
useState<ConfirmDialogProps>({
actionProceedText,
content,
titleText,
});
const setConfirmDialogOpen = useCallback(
(value: boolean) => confirmDialogRef?.current?.setOpen?.call(null, value),
[],
);
const finishConfirm = useCallback(
(title: ReactNode, message: Message) =>
setConfirmDialogProps({
actionProceedText: '',
content: <MessageBox {...message} />,
showActionArea: false,
showClose: true,
titleText: title,
}),
[],
);
const confirmDialog = useMemo<ReactElement>(
() => <ConfirmDialog {...confirmDialogProps} ref={confirmDialogRef} />,
[confirmDialogProps],
);
return {
confirmDialog,
confirmDialogRef,
setConfirmDialogOpen,
setConfirmDialogProps,
finishConfirm,
};
};
export default useConfirmDialog;

@ -1 +0,0 @@
self.__BUILD_MANIFEST=function(s,c,a,e,t,n,i,f,d,b,u,k,h,j,r,g,l){return{__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":[s,a,e,f,d,"static/chunks/82-b2661d1af04f38ff.js",c,t,n,i,h,j,"static/chunks/pages/index-0bfb652a4f03dc4d.js"],"/_error":["static/chunks/pages/_error-2280fa386d040b66.js"],"/anvil":[s,a,e,f,d,"static/chunks/638-13a283c3a7da370b.js",c,t,n,i,h,"static/chunks/pages/anvil-3bce568d47e8eaba.js"],"/config":[s,a,e,u,"static/chunks/519-4b7761e884c88eb9.js",c,t,n,i,b,k,r,"static/chunks/pages/config-511a465cb55668af.js"],"/file-manager":["static/chunks/29107295-fbcfe2172188e46f.js",s,a,e,f,"static/chunks/176-7308c25ba374961e.js",c,t,i,b,"static/chunks/pages/file-manager-a085c3bead0f489f.js"],"/init":[s,a,f,d,u,g,c,t,n,i,l,"static/chunks/pages/init-59fe9f29b6489800.js"],"/login":[s,a,e,c,t,n,b,k,"static/chunks/pages/login-183a6e481fd67cca.js"],"/manage-element":[s,a,e,f,d,u,g,"static/chunks/111-2605129c170ed35d.js",c,t,n,i,b,k,l,r,"static/chunks/pages/manage-element-d8b8ab9027cbbb98.js"],"/server":[s,e,"static/chunks/528-72edc50189f30fa9.js",c,j,"static/chunks/pages/server-8faafa80170f67f2.js"],sortedPages:["/","/_app","/_error","/anvil","/config","/file-manager","/init","/login","/manage-element","/server"]}}("static/chunks/412-d77d0985f9905450.js","static/chunks/62-09a1812bcc63d819.js","static/chunks/438-0147a63d98e89439.js","static/chunks/894-e57948de523bcf96.js","static/chunks/195-fa06e61dd4339031.js","static/chunks/27-7790e406eb2ea28d.js","static/chunks/157-d1418743accab385.js","static/chunks/182-08683bbe95fbb010.js","static/chunks/209-4e2794319babfeec.js","static/chunks/48-d4400834d0a31c6e.js","static/chunks/644-4eec2b397fdacb0c.js","static/chunks/336-33ece0c8120f3bd4.js","static/chunks/707-705fb5e735d81042.js","static/chunks/94-f83c1e7821f76736.js","static/chunks/560-a9c9ecda0eca25a9.js","static/chunks/404-b8e9ff2043a0d30c.js","static/chunks/86-d7025c9609028f44.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

@ -0,0 +1 @@
self.__BUILD_MANIFEST=function(s,c,e,a,t,n,i,f,u,k,h,j,b,d,r,g,l,_,o){return{__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":[s,e,a,i,u,k,d,"static/chunks/936-f64829e0e2013921.js",c,t,n,f,r,g,"static/chunks/pages/index-8766524a2b0384fc.js"],"/_error":["static/chunks/pages/_error-2280fa386d040b66.js"],"/anvil":[s,e,a,i,u,k,"static/chunks/638-13a283c3a7da370b.js",c,t,n,f,r,"static/chunks/pages/anvil-7fb5cba6fcb66e8c.js"],"/config":[s,e,a,j,"static/chunks/519-4b7761e884c88eb9.js",c,t,n,f,h,b,l,"static/chunks/pages/config-e3aa9a84a8baacc1.js"],"/file-manager":["static/chunks/29107295-fbcfe2172188e46f.js",s,e,a,i,u,"static/chunks/176-7308c25ba374961e.js",c,t,n,h,"static/chunks/pages/file-manager-ef725a93a3e227aa.js"],"/init":[s,e,i,u,k,j,_,c,t,n,f,o,"static/chunks/pages/init-b774a276c8a4ad79.js"],"/login":[s,e,a,c,t,f,h,b,"static/chunks/pages/login-270fe7adf9f44c67.js"],"/manage-element":[s,e,a,i,u,k,j,_,"static/chunks/195-d5fd184cc249f755.js",c,t,n,f,h,b,o,l,"static/chunks/pages/manage-element-e577aadd99900dcb.js"],"/server":[s,a,i,d,c,n,g,"static/chunks/pages/server-97d4cafd19cb2e9d.js"],sortedPages:["/","/_app","/_error","/anvil","/config","/file-manager","/init","/login","/manage-element","/server"]}}("static/chunks/498-e1933a5461cd8607.js","static/chunks/668-b264bf73f0c1b5eb.js","static/chunks/910-2a0e86a170f6eb77.js","static/chunks/894-e57948de523bcf96.js","static/chunks/284-03dc30df5d459e72.js","static/chunks/157-0528651bf3cd10a7.js","static/chunks/839-dabd319a60c8df83.js","static/chunks/27-7790e406eb2ea28d.js","static/chunks/213-a0488f84cc98f172.js","static/chunks/209-4e2794319babfeec.js","static/chunks/48-d4400834d0a31c6e.js","static/chunks/644-4eec2b397fdacb0c.js","static/chunks/336-33ece0c8120f3bd4.js","static/chunks/570-6bad4610969fc14b.js","static/chunks/707-ee38ab2abcd0aa3f.js","static/chunks/170-357f4683929223df.js","static/chunks/560-a9c9ecda0eca25a9.js","static/chunks/404-b8e9ff2043a0d30c.js","static/chunks/86-af7e2d6c5444a983.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,8 @@
type ButtonWithMenuOptionalProps<T = unknown> = Omit<MenuProps<T>, 'open'> & {
containedButtonProps?: Partial<ContainedButtonProps>;
iconButtonProps?: Partial<import('../components/IconButton').IconButtonProps>;
onButtonClick?: import('react').MouseEventHandler<HTMLButtonElement>;
variant?: 'contained' | 'icon';
};
type ButtonWithMenuProps<T = unknown> = ButtonWithMenuOptionalProps<T>;

@ -17,9 +17,11 @@ type ConfirmDialogOptionalProps = {
proceedColour?: 'blue' | 'red'; proceedColour?: 'blue' | 'red';
scrollContent?: boolean; scrollContent?: boolean;
scrollBoxProps?: import('@mui/material').BoxProps; scrollBoxProps?: import('@mui/material').BoxProps;
showActionArea?: boolean;
}; };
type ConfirmDialogProps = Omit<DialogWithHeaderProps, 'header'> & type ConfirmDialogProps = Omit<DialogWithHeaderProps, 'header'> &
Pick<DialogActionGroupProps, 'showCancel'> &
ConfirmDialogOptionalProps & { ConfirmDialogOptionalProps & {
actionProceedText: string; actionProceedText: string;
titleText: import('react').ReactNode; titleText: import('react').ReactNode;

@ -31,6 +31,7 @@ type DialogActionGroupOptionalProps = {
proceedChildren?: ContainedButtonProps['children']; proceedChildren?: ContainedButtonProps['children'];
proceedColour?: ContainedButtonProps['background']; proceedColour?: ContainedButtonProps['background'];
proceedProps?: Partial<ContainedButtonProps>; proceedProps?: Partial<ContainedButtonProps>;
showCancel?: boolean;
}; };
type DialogActionGroupProps = DialogActionGroupOptionalProps; type DialogActionGroupProps = DialogActionGroupOptionalProps;

@ -0,0 +1,15 @@
type MuiMenuProps = import('@mui/material').MenuProps;
type MenuOptionalProps<T = unknown> = Pick<MuiMenuProps, 'open'> & {
getItemDisabled?: (key: string, value: T) => boolean;
items?: Record<string, T>;
muiMenuProps?: Partial<MuiMenuProps>;
onItemClick?: (
key: string,
value: T,
...parent: Parameters<MuiMenuItemClickEventHandler>
) => ReturnType<MuiMenuItemClickEventHandler>;
renderItem?: (key: string, value: T) => import('react').ReactNode;
};
type MenuProps<T = unknown> = MenuOptionalProps<T>;

@ -0,0 +1,6 @@
type MuiMenuItemProps = import('@mui/material').MenuItemProps;
type MuiMenuItemClickEventHandler = Exclude<
MuiMenuItemProps['onClick'],
undefined
>;

@ -0,0 +1,14 @@
type ServerPowerOption = {
description: import('react').ReactNode;
label: string;
path: string;
colour?: Exclude<ContainedButtonBackground, 'normal'>;
};
type MapToServerPowerOption = Record<string, ServerPowerOption>;
type ServerMenuProps = ButtonWithMenuProps & {
serverName: string;
serverState: string;
serverUuid: string;
};
Loading…
Cancel
Save