forked from Alex/Pterodactyl-Panel
ui(admin): add startup and file configuration editing for eggs
This commit is contained in:
parent
7d1cb2971f
commit
b125830859
@ -40,6 +40,8 @@
|
||||
"@codemirror/theme-one-dark": "^0.19.0",
|
||||
"@codemirror/view": "^0.19.4",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
||||
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
||||
"@fortawesome/free-regular-svg-icons": "^5.15.4",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
||||
"@fortawesome/react-fontawesome": "^0.1.15",
|
||||
"@hot-loader/react-dom": "^16.14.0",
|
||||
|
@ -1,7 +1,9 @@
|
||||
import http from '@/api/http';
|
||||
import { Egg, rawDataToEgg } from '@/api/admin/eggs/getEgg';
|
||||
|
||||
export default (id: number, egg: Partial<Egg>): Promise<Egg> => {
|
||||
type Egg2 = Omit<Omit<Partial<Egg>, 'configFiles'>, 'configStartup'> & { configFiles?: string, configStartup?: string };
|
||||
|
||||
export default (id: number, egg: Partial<Egg2>): Promise<Egg> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
http.patch(
|
||||
`/api/application/eggs/${id}`,
|
||||
|
@ -18,7 +18,7 @@ export default ({ className }: { className?: string }) => {
|
||||
const match = useRouteMatch<{ nestId: string }>();
|
||||
const { mutate } = getEggs(Number(match.params.nestId));
|
||||
|
||||
let fetchFileContent: null | (() => Promise<string>) = null;
|
||||
let fetchFileContent: (() => Promise<string>) | null = null;
|
||||
|
||||
const submit = async () => {
|
||||
clearFlashes('egg:import');
|
||||
|
@ -21,7 +21,7 @@ interface Values {
|
||||
export default function EggInstallContainer ({ egg }: { egg: Egg }) {
|
||||
const { clearFlashes, clearAndAddHttpError } = useFlash();
|
||||
|
||||
let fetchFileContent: null | (() => Promise<string>) = null;
|
||||
let fetchFileContent: (() => Promise<string>) | null = null;
|
||||
|
||||
const submit = async (values: Values, { setSubmitting }: FormikHelpers<Values>) => {
|
||||
if (fetchFileContent === null) {
|
||||
|
@ -8,8 +8,9 @@ import Label from '@/components/elements/Label';
|
||||
import SpinnerOverlay from '@/components/elements/SpinnerOverlay';
|
||||
import useFlash from '@/plugins/useFlash';
|
||||
import { jsonLanguage } from '@codemirror/lang-json';
|
||||
import { faEgg, faTerminal } from '@fortawesome/free-solid-svg-icons';
|
||||
import React from 'react';
|
||||
import { faDocker } from '@fortawesome/free-brands-svg-icons';
|
||||
import { faEgg, faFireAlt, faMicrochip, faTerminal } from '@fortawesome/free-solid-svg-icons';
|
||||
import React, { forwardRef, useImperativeHandle, useRef } from 'react';
|
||||
import AdminBox from '@/components/admin/AdminBox';
|
||||
import { Egg } from '@/api/admin/eggs/getEgg';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
@ -93,7 +94,7 @@ function EggImageContainer () {
|
||||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
return (
|
||||
<AdminBox icon={undefined} title={'Image'} css={tw`relative`}>
|
||||
<AdminBox icon={faDocker} title={'Docker'} css={tw`relative`}>
|
||||
<SpinnerOverlay visible={isSubmitting}/>
|
||||
|
||||
<TextareaField
|
||||
@ -106,11 +107,11 @@ function EggImageContainer () {
|
||||
);
|
||||
}
|
||||
|
||||
function EggStopContainer () {
|
||||
function EggLifecycleContainer () {
|
||||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
return (
|
||||
<AdminBox icon={undefined} title={'Stop'} css={tw`relative`}>
|
||||
<AdminBox icon={faFireAlt} title={'Lifecycle'} css={tw`relative`}>
|
||||
<SpinnerOverlay visible={isSubmitting}/>
|
||||
|
||||
<Field
|
||||
@ -124,40 +125,79 @@ function EggStopContainer () {
|
||||
);
|
||||
}
|
||||
|
||||
function EggProcessContainer ({ className, egg }: { className?: string, egg: Egg }) {
|
||||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
return (
|
||||
<AdminBox title={'Process Configuration'} css={tw`relative`} className={className}>
|
||||
<SpinnerOverlay visible={isSubmitting}/>
|
||||
|
||||
<div css={tw`mb-6`}>
|
||||
<Label>Startup Configuration</Label>
|
||||
<Editor
|
||||
mode={jsonLanguage}
|
||||
initialContent={JSON.stringify(egg.configStartup, null, '\t') || ''}
|
||||
overrides={tw`h-32 rounded`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div css={tw`mb-1`}>
|
||||
<Label>Configuration Files</Label>
|
||||
<Editor
|
||||
mode={jsonLanguage}
|
||||
initialContent={JSON.stringify(egg.configFiles, null, '\t') || ''}
|
||||
overrides={tw`h-48 rounded`}
|
||||
/>
|
||||
</div>
|
||||
</AdminBox>
|
||||
);
|
||||
interface EggProcessContainerProps {
|
||||
className?: string;
|
||||
egg: Egg;
|
||||
}
|
||||
|
||||
interface EggProcessContainerRef {
|
||||
getStartupConfiguration: () => Promise<string | null>;
|
||||
getFilesConfiguration: () => Promise<string | null>;
|
||||
}
|
||||
|
||||
const EggProcessContainer = forwardRef<any, EggProcessContainerProps>(
|
||||
function EggProcessContainer ({ className, egg }, ref) {
|
||||
const { isSubmitting } = useFormikContext();
|
||||
|
||||
let fetchStartupConfiguration: (() => Promise<string>) | null = null;
|
||||
let fetchFilesConfiguration: (() => Promise<string>) | null = null;
|
||||
|
||||
useImperativeHandle<EggProcessContainerRef, EggProcessContainerRef>(ref, () => ({
|
||||
getStartupConfiguration: async () => {
|
||||
if (fetchStartupConfiguration === null) {
|
||||
return new Promise<null>(resolve => resolve(null));
|
||||
}
|
||||
return await fetchStartupConfiguration();
|
||||
},
|
||||
|
||||
getFilesConfiguration: async () => {
|
||||
if (fetchFilesConfiguration === null) {
|
||||
return new Promise<null>(resolve => resolve(null));
|
||||
}
|
||||
return await fetchFilesConfiguration();
|
||||
},
|
||||
}));
|
||||
|
||||
return (
|
||||
<AdminBox icon={faMicrochip} title={'Process Configuration'} css={tw`relative`} className={className}>
|
||||
<SpinnerOverlay visible={isSubmitting}/>
|
||||
|
||||
<div css={tw`mb-6`}>
|
||||
<Label>Startup Configuration</Label>
|
||||
<Editor
|
||||
mode={jsonLanguage}
|
||||
initialContent={JSON.stringify(egg.configStartup, null, '\t') || ''}
|
||||
overrides={tw`h-32 rounded`}
|
||||
fetchContent={value => {
|
||||
fetchStartupConfiguration = value;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div css={tw`mb-1`}>
|
||||
<Label>Configuration Files</Label>
|
||||
<Editor
|
||||
mode={jsonLanguage}
|
||||
initialContent={JSON.stringify(egg.configFiles, null, '\t') || ''}
|
||||
overrides={tw`h-48 rounded`}
|
||||
fetchContent={value => {
|
||||
fetchFilesConfiguration = value;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</AdminBox>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
interface Values {
|
||||
name: string;
|
||||
description: string;
|
||||
startup: string;
|
||||
dockerImages: string;
|
||||
stopCommand: string;
|
||||
configStartup: string;
|
||||
configFiles: string;
|
||||
}
|
||||
|
||||
export default function EggSettingsContainer ({ egg }: { egg: Egg }) {
|
||||
@ -165,10 +205,13 @@ export default function EggSettingsContainer ({ egg }: { egg: Egg }) {
|
||||
|
||||
const { clearFlashes, clearAndAddHttpError } = useFlash();
|
||||
|
||||
const submit = (values: Values, { setSubmitting }: FormikHelpers<Values>) => {
|
||||
const ref = useRef<EggProcessContainerRef>();
|
||||
|
||||
const submit = async (values: Values, { setSubmitting }: FormikHelpers<Values>) => {
|
||||
clearFlashes('egg');
|
||||
|
||||
// TODO: Send data from code blocks.
|
||||
values.configStartup = await ref.current?.getStartupConfiguration() || '';
|
||||
values.configFiles = await ref.current?.getFilesConfiguration() || '';
|
||||
|
||||
updateEgg(egg.id, { ...values, dockerImages: values.dockerImages.split('\n') })
|
||||
.catch(error => {
|
||||
@ -187,6 +230,8 @@ export default function EggSettingsContainer ({ egg }: { egg: Egg }) {
|
||||
startup: egg.startup,
|
||||
dockerImages: egg.dockerImages.join('\n'),
|
||||
stopCommand: egg.configStop || '',
|
||||
configStartup: '',
|
||||
configFiles: '',
|
||||
}}
|
||||
validationSchema={object().shape({
|
||||
})}
|
||||
@ -202,10 +247,14 @@ export default function EggSettingsContainer ({ egg }: { egg: Egg }) {
|
||||
|
||||
<div css={tw`grid grid-cols-1 md:grid-cols-2 gap-x-8 gap-y-6 mb-6`}>
|
||||
<EggImageContainer/>
|
||||
<EggStopContainer/>
|
||||
<EggLifecycleContainer/>
|
||||
</div>
|
||||
|
||||
<EggProcessContainer egg={egg} css={tw`mb-6`}/>
|
||||
<EggProcessContainer
|
||||
ref={ref}
|
||||
egg={egg}
|
||||
css={tw`mb-6`}
|
||||
/>
|
||||
|
||||
<div css={tw`bg-neutral-700 rounded shadow-md py-2 px-6 mb-16`}>
|
||||
<div css={tw`flex flex-row`}>
|
||||
|
@ -36,8 +36,7 @@ export default () => {
|
||||
const setDirectory = ServerContext.useStoreActions(actions => actions.files.setDirectory);
|
||||
const { addError, clearFlashes } = useFlash();
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
let fetchFileContent: null | (() => Promise<string>) = null;
|
||||
let fetchFileContent: (() => Promise<string>) | null = null;
|
||||
|
||||
useEffect(() => {
|
||||
if (action === 'new') return;
|
||||
|
20
yarn.lock
20
yarn.lock
@ -2178,6 +2178,24 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@fortawesome/free-brands-svg-icons@npm:^5.15.4":
|
||||
version: 5.15.4
|
||||
resolution: "@fortawesome/free-brands-svg-icons@npm:5.15.4"
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types": ^0.2.36
|
||||
checksum: 06e38132fbdf04d8677cf6e47e73cd566f68256f542d68d354e26f5ca7536c714b56f5f3dc6c670065b888ee08bc913bb4f213ab08225faf955d893a6a86ed02
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@fortawesome/free-regular-svg-icons@npm:^5.15.4":
|
||||
version: 5.15.4
|
||||
resolution: "@fortawesome/free-regular-svg-icons@npm:5.15.4"
|
||||
dependencies:
|
||||
"@fortawesome/fontawesome-common-types": ^0.2.36
|
||||
checksum: 2e6039e3bb2125940ed2cb5738b6562b082755c1e45b73571ee92d976773ab81118c9efb9a7b57453b664a025613e81e1dafd2235aafeaadd8f0d75f8e1fe25e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@fortawesome/free-solid-svg-icons@npm:^5.15.4":
|
||||
version: 5.15.4
|
||||
resolution: "@fortawesome/free-solid-svg-icons@npm:5.15.4"
|
||||
@ -9923,6 +9941,8 @@ fsevents@^1.2.7:
|
||||
"@codemirror/theme-one-dark": ^0.19.0
|
||||
"@codemirror/view": ^0.19.4
|
||||
"@fortawesome/fontawesome-svg-core": ^1.2.36
|
||||
"@fortawesome/free-brands-svg-icons": ^5.15.4
|
||||
"@fortawesome/free-regular-svg-icons": ^5.15.4
|
||||
"@fortawesome/free-solid-svg-icons": ^5.15.4
|
||||
"@fortawesome/react-fontawesome": ^0.1.15
|
||||
"@hot-loader/react-dom": ^16.14.0
|
||||
|
Loading…
Reference in New Issue
Block a user