Start cleaning up the mess of useServer; make startup page update in real time

This commit is contained in:
Dane Everitt 2020-08-25 21:25:31 -07:00
parent 179885b546
commit c4418640eb
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
16 changed files with 175 additions and 61 deletions

View file

@ -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>
);
};

View file

@ -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);