ui(admin): server editing improvements
This commit is contained in:
parent
23a160b9e1
commit
6df2368264
9 changed files with 153 additions and 90 deletions
|
@ -1,4 +1,36 @@
|
|||
import http, { FractalResponseData } from '@/api/http';
|
||||
import { Nest } from '@/api/admin/nests/getNests';
|
||||
import { rawDataToServer, Server } from '@/api/admin/servers/getServers';
|
||||
import http, { FractalResponseData, FractalResponseList } from '@/api/http';
|
||||
|
||||
export interface EggVariable {
|
||||
id: number;
|
||||
eggId: number;
|
||||
name: string;
|
||||
description: string;
|
||||
envVariable: string;
|
||||
defaultValue: string;
|
||||
userViewable: boolean;
|
||||
userEditable: boolean;
|
||||
rules: string;
|
||||
required: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
const rawDataToEggVariable = ({ attributes }: FractalResponseData): EggVariable => ({
|
||||
id: attributes.id,
|
||||
eggId: attributes.egg_id,
|
||||
name: attributes.name,
|
||||
description: attributes.description,
|
||||
envVariable: attributes.env_variable,
|
||||
defaultValue: attributes.default_value,
|
||||
userViewable: attributes.user_viewable,
|
||||
userEditable: attributes.user_editable,
|
||||
rules: attributes.rules,
|
||||
required: attributes.required,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
});
|
||||
|
||||
export interface Egg {
|
||||
id: number;
|
||||
|
@ -22,6 +54,12 @@ export interface Egg {
|
|||
scriptInstall: string | null;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
relations: {
|
||||
nest?: Nest;
|
||||
servers?: Server[];
|
||||
variables?: EggVariable[];
|
||||
};
|
||||
}
|
||||
|
||||
export const rawDataToEgg = ({ attributes }: FractalResponseData): Egg => ({
|
||||
|
@ -46,11 +84,17 @@ export const rawDataToEgg = ({ attributes }: FractalResponseData): Egg => ({
|
|||
scriptInstall: attributes.script?.install,
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
|
||||
relations: {
|
||||
nest: undefined,
|
||||
servers: ((attributes.relationships?.servers as FractalResponseList | undefined)?.data || []).map(rawDataToServer),
|
||||
variables: ((attributes.relationships?.variables as FractalResponseList | undefined)?.data || []).map(rawDataToEggVariable),
|
||||
},
|
||||
});
|
||||
|
||||
export default (id: number): Promise<Egg> => {
|
||||
export default (id: number, include: string[] = []): Promise<Egg> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.get(`/api/application/eggs/${id}`)
|
||||
http.get(`/api/application/eggs/${id}`, { params: { include: include.join(',') } })
|
||||
.then(({ data }) => resolve(rawDataToEgg(data)))
|
||||
.catch(reject);
|
||||
});
|
||||
|
|
|
@ -22,6 +22,7 @@ export interface Server {
|
|||
io: number;
|
||||
cpu: number;
|
||||
threads: string | null;
|
||||
oomDisabled: boolean;
|
||||
}
|
||||
|
||||
featureLimits: {
|
||||
|
@ -43,8 +44,6 @@ export interface Server {
|
|||
environment: Map<string, string>;
|
||||
}
|
||||
|
||||
oomKiller: boolean;
|
||||
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
|
||||
|
@ -71,6 +70,7 @@ export const rawDataToServer = ({ attributes }: FractalResponseData): Server =>
|
|||
io: attributes.limits.io,
|
||||
cpu: attributes.limits.cpu,
|
||||
threads: attributes.limits.threads,
|
||||
oomDisabled: attributes.limits.oom_disabled,
|
||||
},
|
||||
|
||||
featureLimits: {
|
||||
|
@ -92,8 +92,6 @@ export const rawDataToServer = ({ attributes }: FractalResponseData): Server =>
|
|||
environment: attributes.container.environment,
|
||||
},
|
||||
|
||||
oomKiller: attributes.oom_killer,
|
||||
|
||||
createdAt: new Date(attributes.created_at),
|
||||
updatedAt: new Date(attributes.updated_at),
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ export interface Values {
|
|||
externalId: string;
|
||||
name: string;
|
||||
ownerId: number;
|
||||
oomKiller: boolean;
|
||||
|
||||
memory: number;
|
||||
swap: number;
|
||||
|
@ -13,6 +12,7 @@ export interface Values {
|
|||
io: number;
|
||||
cpu: number;
|
||||
threads: string;
|
||||
oomDisabled: boolean;
|
||||
|
||||
databases: number;
|
||||
allocations: number;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Server } from '@/api/admin/servers/getServers';
|
||||
import ServerDeleteButton from '@/components/admin/servers/ServerDeleteButton';
|
||||
import { faBalanceScale, faCogs, faConciergeBell, faNetworkWired } from '@fortawesome/free-solid-svg-icons';
|
||||
import React from 'react';
|
||||
import AdminBox from '@/components/admin/AdminBox';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
@ -20,7 +21,7 @@ export function ServerFeatureContainer () {
|
|||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
return (
|
||||
<AdminBox title={'Feature Limits'} css={tw`relative w-full`}>
|
||||
<AdminBox icon={faConciergeBell} title={'Feature Limits'} css={tw`relative w-full`}>
|
||||
<SpinnerOverlay visible={isSubmitting}/>
|
||||
|
||||
<div css={tw`mb-6 md:w-full md:flex md:flex-row`}>
|
||||
|
@ -62,7 +63,7 @@ export function ServerResourceContainer () {
|
|||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
return (
|
||||
<AdminBox title={'Resource Management'} css={tw`relative w-full`}>
|
||||
<AdminBox icon={faBalanceScale} title={'Resource Management'} css={tw`relative w-full`}>
|
||||
<SpinnerOverlay visible={isSubmitting}/>
|
||||
|
||||
<div css={tw`mb-6 md:w-full md:flex md:flex-row`}>
|
||||
|
@ -147,7 +148,7 @@ export function ServerSettingsContainer ({ server }: { server?: Server }) {
|
|||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
return (
|
||||
<AdminBox title={'Settings'} css={tw`relative w-full`}>
|
||||
<AdminBox icon={faCogs} title={'Settings'} css={tw`relative w-full`}>
|
||||
<SpinnerOverlay visible={isSubmitting}/>
|
||||
|
||||
<div css={tw`mb-6 md:w-full md:flex md:flex-row`}>
|
||||
|
@ -179,6 +180,18 @@ export function ServerSettingsContainer ({ server }: { server?: Server }) {
|
|||
);
|
||||
}
|
||||
|
||||
export function ServerAllocationsContainer () {
|
||||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
return (
|
||||
<AdminBox icon={faNetworkWired} title={'Allocations'} css={tw`relative w-full`}>
|
||||
<SpinnerOverlay visible={isSubmitting}/>
|
||||
</AdminBox>
|
||||
);
|
||||
}
|
||||
|
||||
type Values2 = Omit<Values, 'oomDisabled'> & { oomKiller: boolean };
|
||||
|
||||
export default function ServerSettingsContainer2 () {
|
||||
const history = useHistory();
|
||||
|
||||
|
@ -193,11 +206,10 @@ export default function ServerSettingsContainer2 () {
|
|||
);
|
||||
}
|
||||
|
||||
const submit = (values: Values, { setSubmitting }: FormikHelpers<Values>) => {
|
||||
const submit = (values: Values2, { setSubmitting }: FormikHelpers<Values2>) => {
|
||||
clearFlashes('server');
|
||||
console.log(values);
|
||||
|
||||
updateServer(server.id, values)
|
||||
updateServer(server.id, { ...values, oomDisabled: !values.oomKiller })
|
||||
.then(() => setServer({ ...server, ...values }))
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
|
@ -213,7 +225,6 @@ export default function ServerSettingsContainer2 () {
|
|||
externalId: server.externalId || '',
|
||||
name: server.name,
|
||||
ownerId: server.ownerId,
|
||||
oomKiller: server.oomKiller,
|
||||
|
||||
memory: server.limits.memory,
|
||||
swap: server.limits.swap,
|
||||
|
@ -221,6 +232,9 @@ export default function ServerSettingsContainer2 () {
|
|||
io: server.limits.io,
|
||||
cpu: server.limits.cpu,
|
||||
threads: server.limits.threads || '',
|
||||
// Yes, this is named differently on purpose. Naming it like this makes the toggle switch
|
||||
// be in an ON state when the oom killer is enabled, instead of when its disabled.
|
||||
oomKiller: !server.limits.oomDisabled,
|
||||
|
||||
databases: server.featureLimits.databases,
|
||||
allocations: server.featureLimits.allocations,
|
||||
|
@ -229,38 +243,43 @@ export default function ServerSettingsContainer2 () {
|
|||
validationSchema={object().shape({
|
||||
})}
|
||||
>
|
||||
{
|
||||
({ isSubmitting, isValid }) => (
|
||||
<Form>
|
||||
<div css={tw`flex flex-col lg:flex-row`}>
|
||||
<div css={tw`flex flex-col w-full mt-4 ml-0 lg:w-1/2 lg:ml-2 lg:mt-0`}>
|
||||
<div css={tw`flex flex-col w-full mr-0 lg:mr-2`}>
|
||||
<ServerSettingsContainer server={server}/>
|
||||
</div>
|
||||
<div css={tw`flex flex-col w-full mt-4 mr-0 lg:mr-2`}>
|
||||
<ServerFeatureContainer/>
|
||||
</div>
|
||||
{({ isSubmitting, isValid }) => (
|
||||
<Form>
|
||||
<div css={tw`grid grid-cols-2 gap-x-8`}>
|
||||
<div css={tw`flex flex-col`}>
|
||||
<div css={tw`flex mb-6`}>
|
||||
<ServerSettingsContainer server={server}/>
|
||||
</div>
|
||||
<div css={tw`flex flex-col w-full mt-4 ml-0 lg:w-1/2 lg:ml-2 lg:mt-0`}>
|
||||
<div css={tw`flex flex-col w-full mr-0 lg:mr-2`}>
|
||||
<ServerResourceContainer/>
|
||||
</div>
|
||||
<div css={tw`rounded shadow-md bg-neutral-700 mt-4 py-2 px-6`}>
|
||||
<div css={tw`flex flex-row`}>
|
||||
<ServerDeleteButton
|
||||
serverId={server?.id}
|
||||
onDeleted={() => history.push('/admin/servers')}
|
||||
/>
|
||||
<Button type="submit" size="small" css={tw`ml-auto`} disabled={isSubmitting || !isValid}>
|
||||
Save Changes
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div css={tw`flex mb-6`}>
|
||||
<ServerFeatureContainer/>
|
||||
</div>
|
||||
|
||||
<div css={tw`flex mb-6`}>
|
||||
<ServerAllocationsContainer/>
|
||||
</div>
|
||||
|
||||
<div css={tw`bg-neutral-700 rounded shadow-md py-2 px-6`}>
|
||||
<div css={tw`flex flex-row`}>
|
||||
<ServerDeleteButton
|
||||
serverId={server?.id}
|
||||
onDeleted={() => history.push('/admin/servers')}
|
||||
/>
|
||||
<Button type="submit" size="small" css={tw`ml-auto`} disabled={isSubmitting || !isValid}>
|
||||
Save Changes
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
<div css={tw`flex flex-col`}>
|
||||
<div css={tw`flex mb-8`}>
|
||||
<ServerResourceContainer/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { Egg } from '@/api/admin/eggs/getEgg';
|
||||
import EggSelect from '@/components/admin/servers/EggSelect';
|
||||
import NestSelect from '@/components/admin/servers/NestSelect';
|
||||
import FormikSwitch from '@/components/elements/FormikSwitch';
|
||||
|
@ -106,18 +107,20 @@ function ServerImageContainer () {
|
|||
export default function ServerStartupContainer () {
|
||||
const { clearFlashes } = useStoreActions((actions: Actions<ApplicationStore>) => actions.flashes);
|
||||
|
||||
const [ egg, setEgg ] = useState<Egg | null>(null);
|
||||
|
||||
const server = Context.useStoreState(state => state.server);
|
||||
|
||||
const submit = () => {
|
||||
clearFlashes('server');
|
||||
};
|
||||
|
||||
if (server === undefined) {
|
||||
return (
|
||||
<></>
|
||||
);
|
||||
}
|
||||
|
||||
const submit = () => {
|
||||
clearFlashes('server');
|
||||
};
|
||||
|
||||
return (
|
||||
<Formik
|
||||
onSubmit={submit}
|
||||
|
|
|
@ -39,7 +39,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|||
import tw, { styled, TwStyle } from 'twin.macro';
|
||||
import { ayuMirage } from '@/components/elements/EditorTheme';
|
||||
|
||||
type EditorMode = LanguageSupport | LRLanguage | StreamParser<any>;
|
||||
type EditorMode = LanguageSupport | LRLanguage | StreamParser<unknown>;
|
||||
|
||||
export interface Mode {
|
||||
name: string,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue