Add permissions handling to the console; remove kill permission (wrapped in with stop)
This commit is contained in:
parent
79095b526c
commit
171b21e7ee
5 changed files with 42 additions and 28 deletions
|
@ -18,11 +18,10 @@ class SendPowerRequest extends ClientApiRequest
|
||||||
case 'start':
|
case 'start':
|
||||||
return Permission::ACTION_CONTROL_START;
|
return Permission::ACTION_CONTROL_START;
|
||||||
case 'stop':
|
case 'stop':
|
||||||
|
case 'kill':
|
||||||
return Permission::ACTION_CONTROL_STOP;
|
return Permission::ACTION_CONTROL_STOP;
|
||||||
case 'restart':
|
case 'restart':
|
||||||
return Permission::ACTION_CONTROL_RESTART;
|
return Permission::ACTION_CONTROL_RESTART;
|
||||||
case 'kill':
|
|
||||||
return Permission::ACTION_CONTROL_KILL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return '__invalid';
|
return '__invalid';
|
||||||
|
|
|
@ -20,7 +20,6 @@ class Permission extends Validable
|
||||||
const ACTION_CONTROL_START = 'control.start';
|
const ACTION_CONTROL_START = 'control.start';
|
||||||
const ACTION_CONTROL_STOP = 'control.stop';
|
const ACTION_CONTROL_STOP = 'control.stop';
|
||||||
const ACTION_CONTROL_RESTART = 'control.restart';
|
const ACTION_CONTROL_RESTART = 'control.restart';
|
||||||
const ACTION_CONTROL_KILL = 'control.kill';
|
|
||||||
|
|
||||||
const ACTION_DATABASE_READ = 'database.read';
|
const ACTION_DATABASE_READ = 'database.read';
|
||||||
const ACTION_DATABASE_CREATE = 'database.create';
|
const ACTION_DATABASE_CREATE = 'database.create';
|
||||||
|
@ -111,7 +110,6 @@ class Permission extends Validable
|
||||||
'start' => 'Allows a user to start the server if it is stopped.',
|
'start' => 'Allows a user to start the server if it is stopped.',
|
||||||
'stop' => 'Allows a user to stop a server if it is running.',
|
'stop' => 'Allows a user to stop a server if it is running.',
|
||||||
'restart' => 'Allows a user to perform a server restart. This allows them to start the server if it is offline, but not put the server in a completely stopped state.',
|
'restart' => 'Allows a user to perform a server restart. This allows them to start the server if it is offline, but not put the server in a completely stopped state.',
|
||||||
'kill' => 'Allows a user to terminate a server process.',
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,9 @@ import * as TerminalFit from 'xterm/lib/addons/fit/fit';
|
||||||
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
|
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
|
||||||
import { ServerContext } from '@/state/server';
|
import { ServerContext } from '@/state/server';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import Can from '@/components/elements/Can';
|
||||||
|
import { usePermissions } from '@/plugins/usePermissions';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
const theme = {
|
const theme = {
|
||||||
background: 'transparent',
|
background: 'transparent',
|
||||||
|
@ -52,6 +55,7 @@ export default () => {
|
||||||
const useRef = useCallback(node => setTerminalElement(node), []);
|
const useRef = useCallback(node => setTerminalElement(node), []);
|
||||||
const terminal = useMemo(() => new Terminal({ ...terminalProps }), []);
|
const terminal = useMemo(() => new Terminal({ ...terminalProps }), []);
|
||||||
const { connected, instance } = ServerContext.useStoreState(state => state.socket);
|
const { connected, instance } = ServerContext.useStoreState(state => state.socket);
|
||||||
|
const [ canSendCommands ] = usePermissions([ 'control.console']);
|
||||||
|
|
||||||
const handleConsoleOutput = (line: string, prelude = false) => terminal.writeln(
|
const handleConsoleOutput = (line: string, prelude = false) => terminal.writeln(
|
||||||
(prelude ? TERMINAL_PRELUDE : '') + line.replace(/(?:\r\n|\r|\n)$/im, '') + '\u001b[0m',
|
(prelude ? TERMINAL_PRELUDE : '') + line.replace(/(?:\r\n|\r|\n)$/im, '') + '\u001b[0m',
|
||||||
|
@ -121,7 +125,9 @@ export default () => {
|
||||||
<div className={'text-xs font-mono relative'}>
|
<div className={'text-xs font-mono relative'}>
|
||||||
<SpinnerOverlay visible={!connected} size={'large'}/>
|
<SpinnerOverlay visible={!connected} size={'large'}/>
|
||||||
<div
|
<div
|
||||||
className={'rounded-t p-2 bg-black w-full'}
|
className={classNames('rounded-t p-2 bg-black w-full', {
|
||||||
|
'rounded-b': !canSendCommands,
|
||||||
|
})}
|
||||||
style={{
|
style={{
|
||||||
minHeight: '16rem',
|
minHeight: '16rem',
|
||||||
maxHeight: '32rem',
|
maxHeight: '32rem',
|
||||||
|
@ -129,6 +135,7 @@ export default () => {
|
||||||
>
|
>
|
||||||
<TerminalDiv id={'terminal'} ref={useRef}/>
|
<TerminalDiv id={'terminal'} ref={useRef}/>
|
||||||
</div>
|
</div>
|
||||||
|
{canSendCommands &&
|
||||||
<div className={'rounded-b bg-neutral-900 text-neutral-100 flex'}>
|
<div className={'rounded-b bg-neutral-900 text-neutral-100 flex'}>
|
||||||
<div className={'flex-no-shrink p-2 font-bold'}>$</div>
|
<div className={'flex-no-shrink p-2 font-bold'}>$</div>
|
||||||
<div className={'w-full'}>
|
<div className={'w-full'}>
|
||||||
|
@ -140,6 +147,7 @@ export default () => {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { faMicrochip } from '@fortawesome/free-solid-svg-icons/faMicrochip';
|
||||||
import { bytesToHuman } from '@/helpers';
|
import { bytesToHuman } from '@/helpers';
|
||||||
import SuspenseSpinner from '@/components/elements/SuspenseSpinner';
|
import SuspenseSpinner from '@/components/elements/SuspenseSpinner';
|
||||||
import TitledGreyBox from '@/components/elements/TitledGreyBox';
|
import TitledGreyBox from '@/components/elements/TitledGreyBox';
|
||||||
|
import Can from '@/components/elements/Can';
|
||||||
|
|
||||||
type PowerAction = 'start' | 'stop' | 'restart' | 'kill';
|
type PowerAction = 'start' | 'stop' | 'restart' | 'kill';
|
||||||
|
|
||||||
|
@ -109,28 +110,36 @@ export default () => {
|
||||||
{cpu.toFixed(2)} %
|
{cpu.toFixed(2)} %
|
||||||
</p>
|
</p>
|
||||||
</TitledGreyBox>
|
</TitledGreyBox>
|
||||||
<div className={'grey-box justify-center'}>
|
<Can action={[ 'control.start', 'control.stop', 'control.restart' ]} matchAny={true}>
|
||||||
<button
|
<div className={'grey-box justify-center'}>
|
||||||
className={'btn btn-secondary btn-xs mr-2'}
|
<Can action={'control.start'}>
|
||||||
disabled={status !== 'offline'}
|
<button
|
||||||
onClick={e => {
|
className={'btn btn-secondary btn-xs mr-2'}
|
||||||
e.preventDefault();
|
disabled={status !== 'offline'}
|
||||||
sendPowerCommand('start');
|
onClick={e => {
|
||||||
}}
|
e.preventDefault();
|
||||||
>
|
sendPowerCommand('start');
|
||||||
Start
|
}}
|
||||||
</button>
|
>
|
||||||
<button
|
Start
|
||||||
className={'btn btn-secondary btn-xs mr-2'}
|
</button>
|
||||||
onClick={e => {
|
</Can>
|
||||||
e.preventDefault();
|
<Can action={'control.restart'}>
|
||||||
sendPowerCommand('restart');
|
<button
|
||||||
}}
|
className={'btn btn-secondary btn-xs mr-2'}
|
||||||
>
|
onClick={e => {
|
||||||
Restart
|
e.preventDefault();
|
||||||
</button>
|
sendPowerCommand('restart');
|
||||||
<StopOrKillButton onPress={action => sendPowerCommand(action)}/>
|
}}
|
||||||
</div>
|
>
|
||||||
|
Restart
|
||||||
|
</button>
|
||||||
|
</Can>
|
||||||
|
<Can action={'control.stop'}>
|
||||||
|
<StopOrKillButton onPress={action => sendPowerCommand(action)}/>
|
||||||
|
</Can>
|
||||||
|
</div>
|
||||||
|
</Can>
|
||||||
</div>
|
</div>
|
||||||
<div className={'flex-1 mx-4 mr-4'}>
|
<div className={'flex-1 mx-4 mr-4'}>
|
||||||
<SuspenseSpinner>
|
<SuspenseSpinner>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { action, Action } from 'easy-peasy';
|
||||||
|
|
||||||
export type SubuserPermission =
|
export type SubuserPermission =
|
||||||
'websocket.*' |
|
'websocket.*' |
|
||||||
'control.console' | 'control.start' | 'control.stop' | 'control.restart' | 'control.kill' |
|
'control.console' | 'control.start' | 'control.stop' | 'control.restart' |
|
||||||
'user.create' | 'user.read' | 'user.update' | 'user.delete' |
|
'user.create' | 'user.read' | 'user.update' | 'user.delete' |
|
||||||
'file.create' | 'file.read' | 'file.update' | 'file.delete' | 'file.archive' | 'file.sftp' |
|
'file.create' | 'file.read' | 'file.update' | 'file.delete' | 'file.archive' | 'file.sftp' |
|
||||||
'allocation.read' | 'allocation.update' |
|
'allocation.read' | 'allocation.update' |
|
||||||
|
|
Loading…
Reference in a new issue