ui(admin): start work on server startup settings
This commit is contained in:
parent
6362731d55
commit
a615b7fa70
|
@ -39,8 +39,7 @@ rules:
|
||||||
comma-dangle:
|
comma-dangle:
|
||||||
- warn
|
- warn
|
||||||
- always-multiline
|
- always-multiline
|
||||||
spaced-comment:
|
spaced-comment: 0
|
||||||
- warn
|
|
||||||
array-bracket-spacing:
|
array-bracket-spacing:
|
||||||
- warn
|
- warn
|
||||||
- always
|
- always
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
import http from '@/api/http';
|
||||||
|
import { Egg, rawDataToEgg } from '@/api/admin/eggs/getEgg';
|
||||||
|
|
||||||
|
interface Filters {
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (nestId: number, filters?: Filters): Promise<Egg[]> => {
|
||||||
|
const params = {};
|
||||||
|
if (filters !== undefined) {
|
||||||
|
Object.keys(filters).forEach(key => {
|
||||||
|
// @ts-ignore
|
||||||
|
params['filter[' + key + ']'] = filters[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
http.get(`/api/application/nests/${nestId}/eggs`, { params: { ...params } })
|
||||||
|
.then(response => resolve(
|
||||||
|
(response.data.data || []).map(rawDataToEgg)
|
||||||
|
))
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,24 @@
|
||||||
|
import http from '@/api/http';
|
||||||
|
import { Nest, rawDataToNest } from '@/api/admin/nests/getNests';
|
||||||
|
|
||||||
|
interface Filters {
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (filters?: Filters): Promise<Nest[]> => {
|
||||||
|
const params = {};
|
||||||
|
if (filters !== undefined) {
|
||||||
|
Object.keys(filters).forEach(key => {
|
||||||
|
// @ts-ignore
|
||||||
|
params['filter[' + key + ']'] = filters[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
http.get('/api/application/nests', { params: { ...params } })
|
||||||
|
.then(response => resolve(
|
||||||
|
(response.data.data || []).map(rawDataToNest)
|
||||||
|
))
|
||||||
|
.catch(reject);
|
||||||
|
});
|
||||||
|
};
|
|
@ -0,0 +1,32 @@
|
||||||
|
import Label from '@/components/elements/Label';
|
||||||
|
import Select from '@/components/elements/Select';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Egg } from '@/api/admin/eggs/getEgg';
|
||||||
|
import searchEggs from '@/api/admin/nests/searchEggs';
|
||||||
|
|
||||||
|
export default ({ nestId, eggId }: { nestId: number | null; eggId?: number }) => {
|
||||||
|
const [ eggs, setEggs ] = useState<Egg[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (nestId === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchEggs(nestId, {})
|
||||||
|
.then(eggs => setEggs(eggs))
|
||||||
|
.catch(error => console.error(error));
|
||||||
|
}, [ nestId ]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Label>Egg</Label>
|
||||||
|
<Select defaultValue={eggId || undefined} id={'eggId'} name={'eggId'}>
|
||||||
|
{eggs.map(v => (
|
||||||
|
<option key={v.id} value={v.id.toString()}>
|
||||||
|
{v.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,30 @@
|
||||||
|
import Label from '@/components/elements/Label';
|
||||||
|
import Select from '@/components/elements/Select';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Nest } from '@/api/admin/nests/getNests';
|
||||||
|
import searchNests from '@/api/admin/nests/searchNests';
|
||||||
|
|
||||||
|
export default ({ nestId, setNestId }: { nestId: number | null; setNestId: (value: number | null) => void }) => {
|
||||||
|
const [ nests, setNests ] = useState<Nest[] | null>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(nestId || undefined);
|
||||||
|
|
||||||
|
searchNests({})
|
||||||
|
.then(nests => setNests(nests))
|
||||||
|
.catch(error => console.error(error));
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Label>Nest</Label>
|
||||||
|
<Select value={nestId || undefined} onChange={e => setNestId(Number(e.currentTarget.value))}>
|
||||||
|
{nests?.map(v => (
|
||||||
|
<option key={v.id} value={v.id.toString()}>
|
||||||
|
{v.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
|
@ -135,7 +135,7 @@ export function ServerResourceContainer () {
|
||||||
<FormikSwitch
|
<FormikSwitch
|
||||||
name={'oomKiller'}
|
name={'oomKiller'}
|
||||||
label={'Out of Memory Killer'}
|
label={'Out of Memory Killer'}
|
||||||
description={'Enabling OOM killer may cause server processes to exit unexpectedly. '}
|
description={'Enabling OOM killer may cause server processes to exit unexpectedly.'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,153 +1,112 @@
|
||||||
import React from 'react';
|
import EggSelect from '@/components/admin/servers/EggSelect';
|
||||||
import Button from '@/components/elements/Button';
|
import NestSelect from '@/components/admin/servers/NestSelect';
|
||||||
import FormikSwitch from '@/components/elements/FormikSwitch';
|
import FormikSwitch from '@/components/elements/FormikSwitch';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import Button from '@/components/elements/Button';
|
||||||
import Input from '@/components/elements/Input';
|
import Input from '@/components/elements/Input';
|
||||||
import AdminBox from '@/components/admin/AdminBox';
|
import AdminBox from '@/components/admin/AdminBox';
|
||||||
import tw from 'twin.macro';
|
import tw from 'twin.macro';
|
||||||
import { object } from 'yup';
|
import { object } from 'yup';
|
||||||
import updateServer from '@/api/admin/servers/updateServer';
|
|
||||||
import Field from '@/components/elements/Field';
|
import Field from '@/components/elements/Field';
|
||||||
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
|
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
|
||||||
import { Form, Formik, FormikHelpers, useFormikContext } from 'formik';
|
import { Form, Formik, useFormikContext } from 'formik';
|
||||||
import { Context } from '@/components/admin/servers/ServerRouter';
|
import { Context } from '@/components/admin/servers/ServerRouter';
|
||||||
import { ApplicationStore } from '@/state';
|
import { ApplicationStore } from '@/state';
|
||||||
import { Actions, useStoreActions } from 'easy-peasy';
|
import { Actions, useStoreActions } from 'easy-peasy';
|
||||||
import Label from '@/components/elements/Label';
|
import Label from '@/components/elements/Label';
|
||||||
// import { ServerEggVariable } from '@/api/server/types';
|
|
||||||
|
|
||||||
/* interface Props {
|
// interface Values {
|
||||||
variable: ServerEggVariable;
|
// startupCommand: string;
|
||||||
} */
|
// image: string;
|
||||||
|
//
|
||||||
|
// eggId: number;
|
||||||
|
// skipScripts: boolean;
|
||||||
|
// }
|
||||||
|
|
||||||
interface Values {
|
function ServerStartupLineContainer () {
|
||||||
startupCommand: string;
|
|
||||||
nestId: number;
|
|
||||||
eggId: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* const VariableBox = ({ variable }: Props) => {
|
|
||||||
const { isSubmitting } = useFormikContext();
|
const { isSubmitting } = useFormikContext();
|
||||||
|
|
||||||
const server = Context.useStoreState(state => state.server);
|
|
||||||
|
|
||||||
if (server === undefined) {
|
|
||||||
return (
|
|
||||||
<></>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AdminBox title={'Service Configuration'} css={tw`relative w-full`}>
|
|
||||||
<SpinnerOverlay visible={isSubmitting}/>
|
|
||||||
|
|
||||||
<Form css={tw`mb-0`}>
|
|
||||||
<div css={tw`md:w-full md:flex md:flex-col`}>
|
|
||||||
<Field
|
|
||||||
name={variable.envVariable}
|
|
||||||
defaultValue={variable.serverValue}
|
|
||||||
placeholder={variable.defaultValue}
|
|
||||||
description={variable.description}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
</AdminBox>
|
|
||||||
);
|
|
||||||
}; */
|
|
||||||
|
|
||||||
const ServerServiceContainer = () => {
|
|
||||||
const { isSubmitting } = useFormikContext();
|
|
||||||
|
|
||||||
const server = Context.useStoreState(state => state.server);
|
|
||||||
|
|
||||||
if (server === undefined) {
|
|
||||||
return (
|
|
||||||
<></>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<AdminBox title={'Service Configuration'} css={tw`relative w-full`}>
|
|
||||||
<SpinnerOverlay visible={isSubmitting}/>
|
|
||||||
|
|
||||||
<Form css={tw`mb-0`}>
|
|
||||||
<div css={tw`md:w-full md:flex md:flex-col`}>
|
|
||||||
<div css={tw`flex-1`}>
|
|
||||||
<div css={tw`p-3 mb-6 border-l-4 border-red-500`}>
|
|
||||||
<p css={tw`text-xs text-neutral-200`}>
|
|
||||||
This is a destructive operation in many cases. This server will be stopped immediately in order for this action to proceed.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div css={tw`p-3 mb-6 border-l-4 border-red-500`}>
|
|
||||||
<p css={tw`text-xs text-neutral-200`}>
|
|
||||||
Changing any of the below values will result in the server processing a re-install command. The server will be stopped and will then proceed. If you would like the service scripts to not run, ensure the box is checked at the bottom.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div css={tw`pb-4 mb-6 md:w-full md:flex md:flex-col md:mb-0`}>
|
|
||||||
Nest/Egg Selector HERE
|
|
||||||
</div>
|
|
||||||
<div css={tw`pb-4 mb-6 md:w-full md:flex md:flex-col md:mb-0`}>
|
|
||||||
<div css={tw`mt-6 bg-neutral-800 border border-neutral-900 shadow-inner p-4 rounded`}>
|
|
||||||
<FormikSwitch
|
|
||||||
name={'skip_install_script'}
|
|
||||||
label={'Skip Egg Install Script'}
|
|
||||||
description={'If the selected Egg has an install script attached to it, the script will run during install. If you would like to skip this step, check this box.'}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
</AdminBox>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ServerStartupContainer = () => {
|
|
||||||
const { isSubmitting } = useFormikContext();
|
|
||||||
|
|
||||||
const server = Context.useStoreState(state => state.server);
|
|
||||||
|
|
||||||
if (server === undefined) {
|
|
||||||
return (
|
|
||||||
<></>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AdminBox title={'Startup Command'} css={tw`relative w-full`}>
|
<AdminBox title={'Startup Command'} css={tw`relative w-full`}>
|
||||||
<SpinnerOverlay visible={isSubmitting}/>
|
<SpinnerOverlay visible={isSubmitting}/>
|
||||||
|
|
||||||
<Form css={tw`mb-0`}>
|
<Form css={tw`mb-0`}>
|
||||||
<div css={tw`mb-6 md:w-full md:flex md:flex-col`}>
|
<div css={tw`mb-6`}>
|
||||||
<div css={tw`mb-6 md:w-full md:flex md:flex-col md:mr-4`}>
|
|
||||||
<Field
|
<Field
|
||||||
id={'startupCommand'}
|
id={'startupCommand'}
|
||||||
name={'startupCommand'}
|
name={'startupCommand'}
|
||||||
label={'Startup Command'}
|
label={'Startup Command'}
|
||||||
type={'string'}
|
type={'text'}
|
||||||
description={'Edit your server\'s startup command here. The following variables are available by default: {{SERVER_MEMORY}}, {{SERVER_IP}}, and {{SERVER_PORT}}.'}
|
description={'Edit your server\'s startup command here. The following variables are available by default: {{SERVER_MEMORY}}, {{SERVER_IP}}, and {{SERVER_PORT}}.'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div css={tw`mb-6 md:w-full md:flex md:flex-col md:mb-0`}>
|
|
||||||
<div>
|
<div>
|
||||||
<Label>Default Startup Command</Label>
|
<Label>Default Startup Command</Label>
|
||||||
<Input
|
<Input disabled/>
|
||||||
disabled
|
</div>
|
||||||
value={server.relations.egg?.configStartup || ''}
|
</Form>
|
||||||
|
</AdminBox>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ServerServiceContainer ({ nestId: nestId2, eggId }: { nestId: number | null; eggId: number | null }) {
|
||||||
|
const { isSubmitting } = useFormikContext();
|
||||||
|
|
||||||
|
const [ nestId, setNestId ] = useState<number | null>(nestId2);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AdminBox title={'Service Configuration'} css={tw`relative w-full`}>
|
||||||
|
<SpinnerOverlay visible={isSubmitting}/>
|
||||||
|
|
||||||
|
<Form css={tw`mb-0`}>
|
||||||
|
<div css={tw`mb-6`}>
|
||||||
|
<NestSelect nestId={nestId} setNestId={setNestId}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div css={tw`mb-6`}>
|
||||||
|
<EggSelect nestId={nestId} eggId={eggId || undefined}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div css={tw`bg-neutral-800 border border-neutral-900 shadow-inner p-4 rounded`}>
|
||||||
|
<FormikSwitch
|
||||||
|
name={'skipScript'}
|
||||||
|
label={'Skip Egg Install Script'}
|
||||||
|
description={'SoonTM'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</Form>
|
||||||
|
</AdminBox>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ServerImageContainer () {
|
||||||
|
const { isSubmitting } = useFormikContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AdminBox title={'Image Configuration'} css={tw`relative w-full`}>
|
||||||
|
<SpinnerOverlay visible={isSubmitting}/>
|
||||||
|
|
||||||
|
<Form css={tw`mb-0`}>
|
||||||
|
<div css={tw`md:w-full md:flex md:flex-col`}>
|
||||||
|
<div>
|
||||||
|
<Field
|
||||||
|
id={'image'}
|
||||||
|
name={'image'}
|
||||||
|
label={'Docker Image'}
|
||||||
|
type={'text'}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</AdminBox>
|
</AdminBox>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
export default () => {
|
export default function ServerStartupContainer () {
|
||||||
const { clearFlashes, clearAndAddHttpError } = useStoreActions((actions: Actions<ApplicationStore>) => actions.flashes);
|
const { clearFlashes } = useStoreActions((actions: Actions<ApplicationStore>) => actions.flashes);
|
||||||
|
|
||||||
const server = Context.useStoreState(state => state.server);
|
const server = Context.useStoreState(state => state.server);
|
||||||
const setServer = Context.useStoreActions(actions => actions.setServer);
|
|
||||||
|
|
||||||
if (server === undefined) {
|
if (server === undefined) {
|
||||||
return (
|
return (
|
||||||
|
@ -155,16 +114,8 @@ export default () => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const submit = (values: Values, { setSubmitting }: FormikHelpers<Values>) => {
|
const submit = () => {
|
||||||
clearFlashes('server');
|
clearFlashes('server');
|
||||||
|
|
||||||
// updateServer(server.id, values)
|
|
||||||
// .then(() => setServer({ ...server, ...values }))
|
|
||||||
// .catch(error => {
|
|
||||||
// console.error(error);
|
|
||||||
// clearAndAddHttpError({ key: 'server', error });
|
|
||||||
// })
|
|
||||||
// .then(() => setSubmitting(false));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -172,24 +123,47 @@ export default () => {
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
initialValues={{
|
initialValues={{
|
||||||
startupCommand: server.container.startupCommand,
|
startupCommand: server.container.startupCommand,
|
||||||
nestId: server.nestId,
|
image: server.container.image,
|
||||||
eggId: server.eggId,
|
eggId: 0,
|
||||||
|
skipScripts: false,
|
||||||
}}
|
}}
|
||||||
validationSchema={object().shape({
|
validationSchema={object().shape({})}
|
||||||
})}
|
|
||||||
>
|
>
|
||||||
{
|
{({ isSubmitting, isValid }) => (
|
||||||
({ isSubmitting, isValid }) => (
|
|
||||||
<div css={tw`flex flex-col`}>
|
<div css={tw`flex flex-col`}>
|
||||||
<div css={tw`flex flex-col w-full mb-4 mr-0 lg:mr-2`}>
|
<div css={tw`flex flex-row mb-8`}>
|
||||||
<ServerStartupContainer/>
|
<ServerStartupLineContainer/>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`flex flex-col w-1/2 mr-0 lg:mr-2`}>
|
|
||||||
<ServerServiceContainer/>
|
<div css={tw`grid grid-cols-2 gap-x-8 mb-8`}>
|
||||||
|
<div css={tw`flex`}>
|
||||||
|
<ServerServiceContainer nestId={server?.nestId || null} eggId={server?.eggId || null}/>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`flex flex-col w-1/2 mr-0 lg:mr-2`}>
|
<div css={tw`flex`}>
|
||||||
Server Startup variables go here
|
<ServerImageContainer/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/*<div css={tw`grid gap-8 md:grid-cols-2`}>*/}
|
||||||
|
{/* {variables.map((variable, i) => (*/}
|
||||||
|
{/* <TitledGreyBox*/}
|
||||||
|
{/* key={i}*/}
|
||||||
|
{/* title={<p css={tw`text-sm uppercase`}>{variable.name}</p>}*/}
|
||||||
|
{/* >*/}
|
||||||
|
{/* <InputSpinner visible={false}>*/}
|
||||||
|
{/* <Input*/}
|
||||||
|
{/* name={variable.envVariable}*/}
|
||||||
|
{/* defaultValue={variable.serverValue}*/}
|
||||||
|
{/* placeholder={variable.defaultValue}*/}
|
||||||
|
{/* />*/}
|
||||||
|
{/* </InputSpinner>*/}
|
||||||
|
{/* <p css={tw`mt-1 text-xs text-neutral-300`}>*/}
|
||||||
|
{/* {variable.description}*/}
|
||||||
|
{/* </p>*/}
|
||||||
|
{/* </TitledGreyBox>*/}
|
||||||
|
{/* ))}*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
|
||||||
<div css={tw`py-2 pr-6 mt-4 rounded shadow-md bg-neutral-700`}>
|
<div css={tw`py-2 pr-6 mt-4 rounded shadow-md bg-neutral-700`}>
|
||||||
<div css={tw`flex flex-row`}>
|
<div css={tw`flex flex-row`}>
|
||||||
<Button type="submit" size="small" css={tw`ml-auto`} disabled={isSubmitting || !isValid}>
|
<Button type="submit" size="small" css={tw`ml-auto`} disabled={isSubmitting || !isValid}>
|
||||||
|
@ -198,8 +172,7 @@ export default () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)}
|
||||||
}
|
|
||||||
</Formik>
|
</Formik>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
Loading…
Reference in New Issue