Start cleaning up the mess of useServer; make startup page update in real time
This commit is contained in:
parent
179885b546
commit
c4418640eb
16 changed files with 175 additions and 61 deletions
|
@ -1,26 +1,64 @@
|
|||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import TitledGreyBox from '@/components/elements/TitledGreyBox';
|
||||
import useServer from '@/plugins/useServer';
|
||||
import tw from 'twin.macro';
|
||||
import VariableBox from '@/components/server/startup/VariableBox';
|
||||
import ServerContentBlock from '@/components/elements/ServerContentBlock';
|
||||
import getServerStartup from '@/api/swr/getServerStartup';
|
||||
import Spinner from '@/components/elements/Spinner';
|
||||
import ServerError from '@/components/screens/ServerError';
|
||||
import { httpErrorToHuman } from '@/api/http';
|
||||
import { ServerContext } from '@/state/server';
|
||||
import { useDeepCompareEffect } from '@/plugins/useDeepCompareEffect';
|
||||
|
||||
const StartupContainer = () => {
|
||||
const { invocation, variables } = useServer();
|
||||
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
|
||||
const invocation = ServerContext.useStoreState(state => state.server.data!.invocation);
|
||||
const variables = ServerContext.useStoreState(state => state.server.data!.variables);
|
||||
|
||||
const { data, error, isValidating, mutate } = getServerStartup(uuid, { invocation, variables });
|
||||
|
||||
const setServerFromState = ServerContext.useStoreActions(actions => actions.server.setServerFromState);
|
||||
|
||||
useEffect(() => {
|
||||
// Since we're passing in initial data this will not trigger on mount automatically. We
|
||||
// want to always fetch fresh information from the API however when we're loading the startup
|
||||
// information.
|
||||
mutate();
|
||||
}, []);
|
||||
|
||||
useDeepCompareEffect(() => {
|
||||
if (!data) return;
|
||||
|
||||
setServerFromState(s => ({
|
||||
...s,
|
||||
invocation: data.invocation,
|
||||
variables: data.variables,
|
||||
}));
|
||||
}, [ data ]);
|
||||
|
||||
return (
|
||||
<ServerContentBlock title={'Startup Settings'}>
|
||||
<TitledGreyBox title={'Startup Command'}>
|
||||
<div css={tw`px-1 py-2`}>
|
||||
<p css={tw`font-mono bg-neutral-900 rounded py-2 px-4`}>
|
||||
{invocation}
|
||||
</p>
|
||||
!data ?
|
||||
(!error || (error && isValidating)) ?
|
||||
<Spinner centered size={Spinner.Size.LARGE}/>
|
||||
:
|
||||
<ServerError
|
||||
title={'Oops!'}
|
||||
message={httpErrorToHuman(error)}
|
||||
onRetry={() => mutate()}
|
||||
/>
|
||||
:
|
||||
<ServerContentBlock title={'Startup Settings'}>
|
||||
<TitledGreyBox title={'Startup Command'}>
|
||||
<div css={tw`px-1 py-2`}>
|
||||
<p css={tw`font-mono bg-neutral-900 rounded py-2 px-4`}>
|
||||
{data.invocation}
|
||||
</p>
|
||||
</div>
|
||||
</TitledGreyBox>
|
||||
<div css={tw`grid gap-8 grid-cols-2 mt-10`}>
|
||||
{data.variables.map(variable => <VariableBox key={variable.envVariable} variable={variable}/>)}
|
||||
</div>
|
||||
</TitledGreyBox>
|
||||
<div css={tw`grid gap-8 grid-cols-2 mt-10`}>
|
||||
{variables.map(variable => <VariableBox key={variable.envVariable} variable={variable}/>)}
|
||||
</div>
|
||||
</ServerContentBlock>
|
||||
</ServerContentBlock>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from 'react';
|
||||
import React, { memo, useState } from 'react';
|
||||
import { ServerEggVariable } from '@/api/server/types';
|
||||
import TitledGreyBox from '@/components/elements/TitledGreyBox';
|
||||
import { usePermissions } from '@/plugins/usePermissions';
|
||||
|
@ -8,9 +8,11 @@ import tw from 'twin.macro';
|
|||
import { debounce } from 'debounce';
|
||||
import updateStartupVariable from '@/api/server/updateStartupVariable';
|
||||
import useServer from '@/plugins/useServer';
|
||||
import { ServerContext } from '@/state/server';
|
||||
import useFlash from '@/plugins/useFlash';
|
||||
import FlashMessageRender from '@/components/FlashMessageRender';
|
||||
import getServerStartup from '@/api/swr/getServerStartup';
|
||||
import isEqual from 'react-fast-compare';
|
||||
import { ServerContext } from '@/state/server';
|
||||
|
||||
interface Props {
|
||||
variable: ServerEggVariable;
|
||||
|
@ -19,22 +21,21 @@ interface Props {
|
|||
const VariableBox = ({ variable }: Props) => {
|
||||
const FLASH_KEY = `server:startup:${variable.envVariable}`;
|
||||
|
||||
const server = useServer();
|
||||
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
|
||||
const [ loading, setLoading ] = useState(false);
|
||||
const [ canEdit ] = usePermissions([ 'startup.update' ]);
|
||||
const { clearFlashes, clearAndAddHttpError } = useFlash();
|
||||
|
||||
const setServer = ServerContext.useStoreActions(actions => actions.server.setServer);
|
||||
const { mutate } = getServerStartup(uuid);
|
||||
|
||||
const setVariableValue = debounce((value: string) => {
|
||||
setLoading(true);
|
||||
clearFlashes(FLASH_KEY);
|
||||
|
||||
updateStartupVariable(server.uuid, variable.envVariable, value)
|
||||
.then(response => setServer({
|
||||
...server,
|
||||
variables: server.variables.map(v => v.envVariable === response.envVariable ? response : v),
|
||||
}))
|
||||
updateStartupVariable(uuid, variable.envVariable, value)
|
||||
.then(([ response, invocation ]) => mutate(data => ({
|
||||
invocation,
|
||||
variables: data.variables.map(v => v.envVariable === response.envVariable ? response : v),
|
||||
}), false))
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
clearAndAddHttpError({ error, key: FLASH_KEY });
|
||||
|
@ -74,4 +75,4 @@ const VariableBox = ({ variable }: Props) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default VariableBox;
|
||||
export default memo(VariableBox, isEqual);
|
||||
|
|
Reference in a new issue