+
{typeof title === 'string' ?
-
- {icon && }{title}
+
+ {icon && }{title}
:
title
}
-
diff --git a/resources/scripts/components/screens/ScreenBlock.tsx b/resources/scripts/components/screens/ScreenBlock.tsx
index f20836493..90a39e4dd 100644
--- a/resources/scripts/components/screens/ScreenBlock.tsx
+++ b/resources/scripts/components/screens/ScreenBlock.tsx
@@ -1,10 +1,9 @@
import React from 'react';
import PageContentBlock from '@/components/elements/PageContentBlock';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faArrowLeft } from '@fortawesome/free-solid-svg-icons/faArrowLeft';
-import { faSyncAlt } from '@fortawesome/free-solid-svg-icons/faSyncAlt';
+import { faArrowLeft, faSyncAlt } from '@fortawesome/free-solid-svg-icons';
import classNames from 'classnames';
-import styled from 'styled-components/macro';
+import styled, { keyframes } from 'styled-components/macro';
import tw from 'twin.macro';
interface BaseProps {
@@ -27,17 +26,15 @@ interface PropsWithBack extends BaseProps {
type Props = PropsWithBack | PropsWithRetry;
+const spin = keyframes`
+ to { transform: rotate(360deg) }
+`;
+
const ActionButton = styled.button`
${tw`rounded-full w-8 h-8 flex items-center justify-center`};
&.hover\\:spin:hover {
- animation: spin 2s linear infinite;
- }
-
- @keyframes spin {
- to {
- transform: rotate(360deg);
- }
+ animation: ${spin} 2s linear infinite;
}
`;
diff --git a/resources/scripts/components/server/Console.tsx b/resources/scripts/components/server/Console.tsx
index 5deb90a6d..4ab66f960 100644
--- a/resources/scripts/components/server/Console.tsx
+++ b/resources/scripts/components/server/Console.tsx
@@ -4,9 +4,7 @@ import * as TerminalFit from 'xterm/lib/addons/fit/fit';
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
import { ServerContext } from '@/state/server';
import styled from 'styled-components/macro';
-import Can from '@/components/elements/Can';
import { usePermissions } from '@/plugins/usePermissions';
-import classNames from 'classnames';
import tw from 'twin.macro';
const theme = {
@@ -56,7 +54,7 @@ export default () => {
const useRef = useCallback(node => setTerminalElement(node), []);
const terminal = useMemo(() => new Terminal({ ...terminalProps }), []);
const { connected, instance } = ServerContext.useStoreState(state => state.socket);
- const [ canSendCommands ] = usePermissions([ 'control.console']);
+ const [ canSendCommands ] = usePermissions([ 'control.console' ]);
const handleConsoleOutput = (line: string, prelude = false) => terminal.writeln(
(prelude ? TERMINAL_PRELUDE : '') + line.replace(/(?:\r\n|\r|\n)$/im, '') + '\u001b[0m',
@@ -123,12 +121,13 @@ export default () => {
}, [ connected, instance ]);
return (
-
+
{
{canSendCommands &&
-
-
$
-
+
+
$
+
handleCommandKeydown(e)}
/>
diff --git a/resources/scripts/components/server/ServerConsole.tsx b/resources/scripts/components/server/ServerConsole.tsx
index 16675b35e..d2f7d5f95 100644
--- a/resources/scripts/components/server/ServerConsole.tsx
+++ b/resources/scripts/components/server/ServerConsole.tsx
@@ -13,35 +13,15 @@ import TitledGreyBox from '@/components/elements/TitledGreyBox';
import Can from '@/components/elements/Can';
import PageContentBlock from '@/components/elements/PageContentBlock';
import ContentContainer from '@/components/elements/ContentContainer';
+import tw from 'twin.macro';
+import Button from '@/components/elements/Button';
+import StopOrKillButton from '@/components/server/StopOrKillButton';
-type PowerAction = 'start' | 'stop' | 'restart' | 'kill';
+export type PowerAction = 'start' | 'stop' | 'restart' | 'kill';
const ChunkedConsole = lazy(() => import(/* webpackChunkName: "console" */'@/components/server/Console'));
const ChunkedStatGraphs = lazy(() => import(/* webpackChunkName: "graphs" */'@/components/server/StatGraphs'));
-const StopOrKillButton = ({ onPress }: { onPress: (action: PowerAction) => void }) => {
- const [ clicked, setClicked ] = useState(false);
- const status = ServerContext.useStoreState(state => state.status.value);
-
- useEffect(() => {
- setClicked(state => [ 'stopping' ].indexOf(status) < 0 ? false : state);
- }, [ status ]);
-
- return (
-
- );
-};
-
export default () => {
const [ memory, setMemory ] = useState(0);
const [ cpu, setCpu ] = useState(0);
@@ -81,17 +61,17 @@ export default () => {
};
}, [ instance, connected ]);
- const disklimit = server.limits.disk != 0 ? bytesToHuman(server.limits.disk * 1000 * 1000) : "Unlimited";
- const memorylimit = server.limits.memory != 0 ? bytesToHuman(server.limits.memory * 1000 * 1000) : "Unlimited";
+ const disklimit = server.limits.disk ? bytesToHuman(server.limits.disk * 1000 * 1000) : 'Unlimited';
+ const memorylimit = server.limits.memory ? bytesToHuman(server.limits.memory * 1000 * 1000) : 'Unlimited';
return (
-
-
+
+
-
+
{
/>
{status}
-
-
- {cpu.toFixed(2)} %
+
+ {cpu.toFixed(2)}%
-
-
- {bytesToHuman(memory)}
- / {memorylimit}
-
-
-
- {bytesToHuman(disk)}
- / {disklimit}
+
+ {bytesToHuman(memory)}
+ / {memorylimit}
+
+
+ {bytesToHuman(disk)}
+ / {disklimit}
{!server.isInstalling ?
-
-
+
+
-
+
-
+
sendPowerCommand(action)}/>
@@ -159,9 +129,9 @@ export default () => {
:
-
+
-
+
This server is currently running its installation process and most actions are
unavailable.
@@ -169,7 +139,7 @@ export default () => {
}
-
+
diff --git a/resources/scripts/components/server/StatGraphs.tsx b/resources/scripts/components/server/StatGraphs.tsx
index a7595b947..e404a8475 100644
--- a/resources/scripts/components/server/StatGraphs.tsx
+++ b/resources/scripts/components/server/StatGraphs.tsx
@@ -6,6 +6,7 @@ import merge from 'lodash-es/merge';
import TitledGreyBox from '@/components/elements/TitledGreyBox';
import { faMemory } from '@fortawesome/free-solid-svg-icons/faMemory';
import { faMicrochip } from '@fortawesome/free-solid-svg-icons/faMicrochip';
+import tw from 'twin.macro';
const chartDefaults: ChartConfiguration = {
type: 'line',
@@ -157,21 +158,21 @@ export default () => {
}, [ instance, connected, memory, cpu ]);
return (
-
-
+
+
{status !== 'offline' ?
-
+
{status !== 'offline' ?
diff --git a/resources/scripts/routers/DashboardRouter.tsx b/resources/scripts/routers/DashboardRouter.tsx
index c3abf3176..79ebbe4a1 100644
--- a/resources/scripts/routers/DashboardRouter.tsx
+++ b/resources/scripts/routers/DashboardRouter.tsx
@@ -5,35 +5,8 @@ import NavigationBar from '@/components/NavigationBar';
import DashboardContainer from '@/components/dashboard/DashboardContainer';
import AccountApiContainer from '@/components/dashboard/AccountApiContainer';
import NotFound from '@/components/screens/NotFound';
-import styled from 'styled-components/macro';
-import tw from 'twin.macro';
-import config from '@/../../tailwind.config.js';
import TransitionRouter from '@/TransitionRouter';
-
-const SubNavigation = styled.div`
- ${tw`w-full bg-neutral-700 shadow`};
-
- & > div {
- ${tw`flex items-center text-sm mx-auto px-2`};
- max-width: 1200px;
-
- & > a, & > div {
- ${tw`inline-block py-3 px-4 text-neutral-300 no-underline transition-all duration-150`};
-
- &:not(:first-of-type) {
- ${tw`ml-2`};
- }
-
- &:active, &:hover {
- ${tw`text-neutral-100`};
- }
-
- &:active, &:hover, &.active {
- box-shadow: inset 0 -2px ${config.theme.colors.cyan['500']};
- }
- }
- }
-`;
+import SubNavigation from '@/components/elements/SubNavigation';
export default ({ location }: RouteComponentProps) => (
<>
diff --git a/resources/scripts/routers/ServerRouter.tsx b/resources/scripts/routers/ServerRouter.tsx
index 82f6d0c77..a053262d6 100644
--- a/resources/scripts/routers/ServerRouter.tsx
+++ b/resources/scripts/routers/ServerRouter.tsx
@@ -23,6 +23,7 @@ import NotFound from '@/components/screens/NotFound';
import { useStoreState } from 'easy-peasy';
import useServer from '@/plugins/useServer';
import ScreenBlock from '@/components/screens/ScreenBlock';
+import SubNavigation from '@/components/elements/SubNavigation';
const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>) => {
const { rootAdmin } = useStoreState(state => state.user.data!);
@@ -71,8 +72,8 @@ const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>)
:
<>
-
-
+
+
Console
File Manager
@@ -93,7 +94,7 @@ const ServerRouter = ({ match, location }: RouteComponentProps<{ id: string }>)
Settings
-
+
{(installing && (!rootAdmin || (rootAdmin && !location.pathname.endsWith(`/server/${server.id}`)))) ?