diff --git a/app/Http/Controllers/Api/Application/Servers/ServerController.php b/app/Http/Controllers/Api/Application/Servers/ServerController.php index 40436fb7e..b426e1fd8 100644 --- a/app/Http/Controllers/Api/Application/Servers/ServerController.php +++ b/app/Http/Controllers/Api/Application/Servers/ServerController.php @@ -79,7 +79,7 @@ class ServerController extends ApplicationApiController */ public function store(StoreServerRequest $request): JsonResponse { - $server = $this->creationService->handle($request->validated(), $request->getDeploymentObject()); + $server = $this->creationService->handle($request->validated()); return $this->fractal->item($server) ->transformWith(ServerTransformer::class) diff --git a/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php b/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php index 52d798a34..063785a44 100644 --- a/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php +++ b/app/Http/Requests/Api/Application/Servers/StoreServerRequest.php @@ -74,7 +74,7 @@ class StoreServerRequest extends ApplicationApiRequest 'startup' => array_get($data, 'startup'), 'environment' => array_get($data, 'environment'), - 'egg_id' => array_get($data, 'egg'), + 'egg_id' => array_get($data, 'egg_id'), 'image' => array_get($data, 'image'), 'skip_scripts' => array_get($data, 'skip_scripts'), 'start_on_completion' => array_get($data, 'start_on_completion', false), diff --git a/resources/scripts/api/admin/node.ts b/resources/scripts/api/admin/node.ts index e92a31cb8..cac2e96b2 100644 --- a/resources/scripts/api/admin/node.ts +++ b/resources/scripts/api/admin/node.ts @@ -74,3 +74,11 @@ export const searchNodes = async (params: QueryBuilderParams<'name'>): Promise): Promise => { + const { data } = await http.get(`/api/application/nodes/${id}/allocations`, { + params: withQueryBuilderParams(params), + }); + + return data.data.map(AdminTransformers.toAllocation); +}; diff --git a/resources/scripts/api/admin/servers/createServer.ts b/resources/scripts/api/admin/servers/createServer.ts index 5ff75bc7e..3fd94ca62 100644 --- a/resources/scripts/api/admin/servers/createServer.ts +++ b/resources/scripts/api/admin/servers/createServer.ts @@ -53,9 +53,10 @@ export default (r: CreateServerRequest, include: string[] = []): Promise memory: r.limits.memory, swap: r.limits.swap, threads: r.limits.threads, + oom_killer: r.limits.oomDisabled, }, - featureLimits: { + feature_limits: { allocations: r.featureLimits.allocations, backups: r.featureLimits.backups, databases: r.featureLimits.databases, diff --git a/resources/scripts/components/admin/servers/NestSelector.tsx b/resources/scripts/components/admin/servers/NestSelector.tsx index 5b56802c0..86adf4d5b 100644 --- a/resources/scripts/components/admin/servers/NestSelector.tsx +++ b/resources/scripts/components/admin/servers/NestSelector.tsx @@ -13,7 +13,12 @@ export default ({ selectedNestId, onNestSelect }: Props) => { useEffect(() => { searchNests({}) - .then(setNests) + .then(nests => { + setNests(nests); + if (selectedNestId === 0 && nests.length > 0) { + onNestSelect(nests[0].id); + } + }) .catch(error => console.error(error)); }, []); diff --git a/resources/scripts/components/admin/servers/NewServerContainer.tsx b/resources/scripts/components/admin/servers/NewServerContainer.tsx index f17af9f5e..bdc13728e 100644 --- a/resources/scripts/components/admin/servers/NewServerContainer.tsx +++ b/resources/scripts/components/admin/servers/NewServerContainer.tsx @@ -12,25 +12,50 @@ import Label from '@/components/elements/Label'; import Select from '@/components/elements/Select'; import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; import FlashMessageRender from '@/components/FlashMessageRender'; +import useFlash from '@/plugins/useFlash'; import { faNetworkWired } from '@fortawesome/free-solid-svg-icons'; import { Form, Formik, FormikHelpers, useFormikContext } from 'formik'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; +import { useHistory } from 'react-router-dom'; import tw from 'twin.macro'; import AdminContentBlock from '@/components/admin/AdminContentBlock'; import { object } from 'yup'; -import { CreateServerRequest } from '@/api/admin/servers/createServer'; +import createServer, { CreateServerRequest } from '@/api/admin/servers/createServer'; +import { Allocation, Node, getAllocations } from '@/api/admin/node'; function InternalForm () { - const { isSubmitting, isValid, values: { environment } } = useFormikContext(); + const { isSubmitting, isValid, setFieldValue, values: { environment } } = useFormikContext(); const [ egg, setEgg ] = useState(null); + const [ node, setNode ] = useState(null); + const [ allocations, setAllocations ] = useState(null); + + useEffect(() => { + if (egg === null) { + return; + } + + setFieldValue('eggId', egg.id); + setFieldValue('startup', egg.startup); + setFieldValue('image', egg.dockerImages.length > 0 ? egg.dockerImages[0] : ''); + }, [ egg ]); + + useEffect(() => { + if (node === null) { + return; + } + + // server_id: 0 filters out assigned allocations + getAllocations(node.id, { filters: { server_id: '0' } }) + .then(setAllocations); + }, [ node ]); return (
- +
- - -
-
- - setFieldValue('allocation.default', Number(e.currentTarget.value))} + > + {node === null ? : } + {allocations?.map(a => )}
+ {/*
*/} + {/* /!* TODO: Multi-select *!/*/} + {/* */} + {/* */} + {/*
*/}
@@ -109,9 +141,18 @@ function InternalForm () { } export default () => { + const history = useHistory(); + + const { clearFlashes, clearAndAddHttpError } = useFlash(); + const submit = (r: CreateServerRequest, { setSubmitting }: FormikHelpers) => { console.log(r); - setSubmitting(false); + clearFlashes('server:create'); + + createServer(r) + .then(s => history.push(`/admin/servers/${s.id}`)) + .catch(error => clearAndAddHttpError({ key: 'server:create', error })) + .then(() => setSubmitting(false)); }; return ( diff --git a/resources/scripts/components/admin/servers/NodeSelect.tsx b/resources/scripts/components/admin/servers/NodeSelect.tsx index 63508be66..3188eb921 100644 --- a/resources/scripts/components/admin/servers/NodeSelect.tsx +++ b/resources/scripts/components/admin/servers/NodeSelect.tsx @@ -3,21 +3,18 @@ import { useFormikContext } from 'formik'; import SearchableSelect, { Option } from '@/components/elements/SearchableSelect'; import { Node, searchNodes } from '@/api/admin/node'; -export default ({ selected }: { selected?: Node }) => { - const context = useFormikContext(); +export default ({ node, setNode }: { node: Node | null, setNode: (_: Node | null) => void }) => { + const { setFieldValue } = useFormikContext(); - const [ node, setNode ] = useState(selected || null); const [ nodes, setNodes ] = useState(null); const onSearch = async (query: string) => { - setNodes( - await searchNodes({ filters: { name: query } }), - ); + setNodes(await searchNodes({ filters: { name: query } })); }; const onSelect = (node: Node | null) => { setNode(node); - context.setFieldValue('ownerId', node?.id || null); + setFieldValue('nodeId', node?.id || null); }; const getSelectedText = (node: Node | null): string => node?.name || ''; diff --git a/resources/scripts/components/admin/servers/OwnerSelect.tsx b/resources/scripts/components/admin/servers/OwnerSelect.tsx index 75c3b73df..e97f3b0b2 100644 --- a/resources/scripts/components/admin/servers/OwnerSelect.tsx +++ b/resources/scripts/components/admin/servers/OwnerSelect.tsx @@ -4,7 +4,7 @@ import SearchableSelect, { Option } from '@/components/elements/SearchableSelect import { User, searchUserAccounts } from '@/api/admin/user'; export default ({ selected }: { selected?: User }) => { - const context = useFormikContext(); + const { setFieldValue } = useFormikContext(); const [ user, setUser ] = useState(selected || null); const [ users, setUsers ] = useState(null); @@ -17,7 +17,7 @@ export default ({ selected }: { selected?: User }) => { const onSelect = (user: User | null) => { setUser(user); - context.setFieldValue('ownerId', user?.id || null); + setFieldValue('ownerId', user?.id || null); }; const getSelectedText = (user: User | null): string => user?.email || '';