From 8d0dd4247594a26e7cead8e2b3e9862e6512da81 Mon Sep 17 00:00:00 2001 From: Matthew Penner Date: Fri, 17 Sep 2021 14:33:38 -0600 Subject: [PATCH] ui(admin): add egg install editing --- .../Api/Application/Eggs/EggController.php | 21 ---- .../Api/Application/Eggs/UpdateEggRequest.php | 21 +++- resources/scripts/api/admin/eggs/createEgg.ts | 27 +++- resources/scripts/api/admin/eggs/getEgg.ts | 10 +- resources/scripts/api/admin/eggs/updateEgg.ts | 29 +++++ .../admin/nests/NestEditContainer.tsx | 76 ++++++----- .../admin/nests/eggs/EggInstallContainer.tsx | 118 ++++++++++++------ .../components/admin/nests/eggs/EggRouter.tsx | 2 +- 8 files changed, 193 insertions(+), 111 deletions(-) create mode 100644 resources/scripts/api/admin/eggs/updateEgg.ts diff --git a/app/Http/Controllers/Api/Application/Eggs/EggController.php b/app/Http/Controllers/Api/Application/Eggs/EggController.php index 5d5c8572d..113ab26a2 100644 --- a/app/Http/Controllers/Api/Application/Eggs/EggController.php +++ b/app/Http/Controllers/Api/Application/Eggs/EggController.php @@ -7,7 +7,6 @@ use Pterodactyl\Models\Nest; use Illuminate\Http\Response; use Illuminate\Http\JsonResponse; use Spatie\QueryBuilder\QueryBuilder; -use Pterodactyl\Contracts\Repository\EggRepositoryInterface; use Pterodactyl\Transformers\Api\Application\EggTransformer; use Pterodactyl\Http\Requests\Api\Application\Eggs\GetEggRequest; use Pterodactyl\Exceptions\Http\QueryValueOutOfRangeHttpException; @@ -19,22 +18,8 @@ use Pterodactyl\Http\Controllers\Api\Application\ApplicationApiController; class EggController extends ApplicationApiController { - private EggRepositoryInterface $repository; - - /** - * EggController constructor. - */ - public function __construct(EggRepositoryInterface $repository) - { - parent::__construct(); - - $this->repository = $repository; - } - /** * Return an array of all eggs on a given nest. - * - * @throws \Illuminate\Contracts\Container\BindingResolutionException */ public function index(GetEggsRequest $request, Nest $nest): array { @@ -58,8 +43,6 @@ class EggController extends ApplicationApiController /** * Returns a single egg. - * - * @throws \Illuminate\Contracts\Container\BindingResolutionException */ public function view(GetEggRequest $request, Egg $egg): array { @@ -70,8 +53,6 @@ class EggController extends ApplicationApiController /** * Creates a new egg. - * - * @throws \Illuminate\Contracts\Container\BindingResolutionException */ public function store(StoreEggRequest $request): JsonResponse { @@ -84,8 +65,6 @@ class EggController extends ApplicationApiController /** * Updates an egg. - * - * @throws \Illuminate\Contracts\Container\BindingResolutionException */ public function update(UpdateEggRequest $request, Egg $egg): array { diff --git a/app/Http/Requests/Api/Application/Eggs/UpdateEggRequest.php b/app/Http/Requests/Api/Application/Eggs/UpdateEggRequest.php index 0ce5db572..7eb76fa24 100644 --- a/app/Http/Requests/Api/Application/Eggs/UpdateEggRequest.php +++ b/app/Http/Requests/Api/Application/Eggs/UpdateEggRequest.php @@ -2,12 +2,27 @@ namespace Pterodactyl\Http\Requests\Api\Application\Eggs; -use Pterodactyl\Models\Egg; - class UpdateEggRequest extends StoreEggRequest { public function rules(array $rules = null): array { - return $rules ?? Egg::getRulesForUpdate($this->route()->parameter('egg')->id); + return [ + 'nest_id' => 'sometimes|numeric|exists:nests,id', + 'name' => 'sometimes|string|max:191', + 'description' => 'sometimes|string|nullable', + 'features' => 'sometimes|array|nullable', + 'docker_images' => 'sometimes|required|array|min:1', + 'docker_images.*' => 'sometimes|string', + 'file_denylist' => 'sometimes|array|nullable', + 'file_denylist.*' => 'sometimes|string', + 'config_files' => 'sometimes|nullable|json', + 'config_startup' => 'sometimes|nullable|json', + 'config_stop' => 'sometimes|nullable|string|max:191', + 'config_from' => 'sometimes|nullable|numeric|exists:eggs,id', + 'startup' => 'sometimes|nullable|string', + 'script_container' => 'sometimes|string', + 'script_entry' => 'sometimes|string', + 'script_install' => 'sometimes|string', + ]; } } diff --git a/resources/scripts/api/admin/eggs/createEgg.ts b/resources/scripts/api/admin/eggs/createEgg.ts index 023183700..5a2f8c964 100644 --- a/resources/scripts/api/admin/eggs/createEgg.ts +++ b/resources/scripts/api/admin/eggs/createEgg.ts @@ -1,12 +1,29 @@ import http from '@/api/http'; import { Egg, rawDataToEgg } from '@/api/admin/eggs/getEgg'; -export default (nestId: number, name: string): Promise => { +export default (egg: Partial): Promise => { return new Promise((resolve, reject) => { - http.post('/api/application/eggs', { - nestId, name, - }) - .then(({ data }) => resolve(rawDataToEgg(data.attributes))) + http.post( + '/api/application/eggs/', + { + nest_id: egg.nestId, + name: egg.name, + description: egg.description, + features: egg.features, + docker_images: egg.dockerImages, + config_files: egg.configFiles, + config_startup: egg.configStartup, + config_stop: egg.configStop, + config_from: egg.configFrom, + startup: egg.startup, + script_container: egg.scriptContainer, + copy_script_from: egg.copyScriptFrom, + script_entry: egg.scriptEntry, + script_is_privileged: egg.scriptIsPrivileged, + script_install: egg.scriptInstall, + }, + ) + .then(({ data }) => resolve(rawDataToEgg(data))) .catch(reject); }); }; diff --git a/resources/scripts/api/admin/eggs/getEgg.ts b/resources/scripts/api/admin/eggs/getEgg.ts index 8769335fb..622317419 100644 --- a/resources/scripts/api/admin/eggs/getEgg.ts +++ b/resources/scripts/api/admin/eggs/getEgg.ts @@ -43,7 +43,6 @@ export interface Egg { dockerImages: string[]; configFiles: string | null; configStartup: string | null; - configLogs: string | null; configStop: string | null; configFrom: number | null; startup: string; @@ -71,11 +70,10 @@ export const rawDataToEgg = ({ attributes }: FractalResponseData): Egg => ({ description: attributes.description, features: attributes.features, dockerImages: attributes.docker_images, - configFiles: attributes.config_files, - configStartup: attributes.config_startup, - configLogs: attributes.config_logs, - configStop: attributes.config_stop, - configFrom: attributes.config_from, + configFiles: attributes.config?.files, + configStartup: attributes.config?.startup, + configStop: attributes.config?.stop, + configFrom: attributes.config?.extends, startup: attributes.startup, copyScriptFrom: attributes.copy_script_from, scriptContainer: attributes.script?.container, diff --git a/resources/scripts/api/admin/eggs/updateEgg.ts b/resources/scripts/api/admin/eggs/updateEgg.ts new file mode 100644 index 000000000..e921a611a --- /dev/null +++ b/resources/scripts/api/admin/eggs/updateEgg.ts @@ -0,0 +1,29 @@ +import http from '@/api/http'; +import { Egg, rawDataToEgg } from '@/api/admin/eggs/getEgg'; + +export default (id: number, egg: Partial): Promise => { + return new Promise((resolve, reject) => { + http.patch( + `/api/application/eggs/${id}`, + { + nest_id: egg.nestId, + name: egg.name, + description: egg.description, + features: egg.features, + docker_images: egg.dockerImages, + config_files: egg.configFiles, + config_startup: egg.configStartup, + config_stop: egg.configStop, + config_from: egg.configFrom, + startup: egg.startup, + script_container: egg.scriptContainer, + copy_script_from: egg.copyScriptFrom, + script_entry: egg.scriptEntry, + script_is_privileged: egg.scriptIsPrivileged, + script_install: egg.scriptInstall, + }, + ) + .then(({ data }) => resolve(rawDataToEgg(data))) + .catch(reject); + }); +}; diff --git a/resources/scripts/components/admin/nests/NestEditContainer.tsx b/resources/scripts/components/admin/nests/NestEditContainer.tsx index cad1ab46d..d9e9c42fb 100644 --- a/resources/scripts/components/admin/nests/NestEditContainer.tsx +++ b/resources/scripts/components/admin/nests/NestEditContainer.tsx @@ -99,50 +99,48 @@ const EditInformationContainer = () => { description: string().max(255, ''), })} > - { - ({ isSubmitting, isValid }) => ( - - - + {({ isSubmitting, isValid }) => ( + + + -
-
- +
+ +
+ +
+ +
+ +
+
+ history.push('/admin/nests')} />
-
- +
+
- -
-
- history.push('/admin/nests')} - /> -
- -
- -
-
- - - - ) - } +
+ + + + )} ); }; diff --git a/resources/scripts/components/admin/nests/eggs/EggInstallContainer.tsx b/resources/scripts/components/admin/nests/eggs/EggInstallContainer.tsx index c26ffdb3e..ef81c0ae7 100644 --- a/resources/scripts/components/admin/nests/eggs/EggInstallContainer.tsx +++ b/resources/scripts/components/admin/nests/eggs/EggInstallContainer.tsx @@ -1,52 +1,98 @@ +import { Egg } from '@/api/admin/eggs/getEgg'; +import updateEgg from '@/api/admin/eggs/updateEgg'; +import Field from '@/components/elements/Field'; +import useFlash from '@/plugins/useFlash'; import { shell } from '@codemirror/legacy-modes/mode/shell'; +import { faScroll } from '@fortawesome/free-solid-svg-icons'; +import { Form, Formik, FormikHelpers } from 'formik'; import React from 'react'; import tw from 'twin.macro'; import AdminBox from '@/components/admin/AdminBox'; -import { Context } from '@/components/admin/nests/eggs/EggRouter'; import Button from '@/components/elements/Button'; import Editor from '@/components/elements/Editor'; -import Input from '@/components/elements/Input'; -import Label from '@/components/elements/Label'; import SpinnerOverlay from '@/components/elements/SpinnerOverlay'; -export default () => { - const egg = Context.useStoreState(state => state.egg); +interface Values { + scriptContainer: string; + scriptEntry: string; + scriptInstall: string; +} - if (egg === undefined) { - return ( - <> - ); - } +export default function EggInstallContainer ({ egg }: { egg: Egg }) { + const { clearFlashes, clearAndAddHttpError } = useFlash(); + + let fetchFileContent: null | (() => Promise) = null; + + const submit = async (values: Values, { setSubmitting }: FormikHelpers) => { + if (fetchFileContent === null) { + return; + } + + values.scriptInstall = await fetchFileContent(); + + clearFlashes('egg'); + + updateEgg(egg.id, values) + .catch(error => { + console.error(error); + clearAndAddHttpError({ key: 'egg', error }); + }) + .then(() => setSubmitting(false)); + }; return ( - -
- + + {({ isSubmitting, isValid }) => ( + +
+ - +
+ { + fetchFileContent = value; + }} + /> -
-
-
- - -

The Docker image to use for running this installation script.

-
+
+
+ -
- - -

The command that should be used to run this script inside of the installation container.

-
+ +
+
+ +
+ +
+
-
- -
- -
-
-
+ + )} +
); -}; +} diff --git a/resources/scripts/components/admin/nests/eggs/EggRouter.tsx b/resources/scripts/components/admin/nests/eggs/EggRouter.tsx index c541b806c..3bd8f1dba 100644 --- a/resources/scripts/components/admin/nests/eggs/EggRouter.tsx +++ b/resources/scripts/components/admin/nests/eggs/EggRouter.tsx @@ -101,7 +101,7 @@ const EggRouter = () => { - +