1
1
mirror of https://github.com/pterodactyl/panel.git synced 2024-11-22 17:12:30 +01:00

Update java version modal to only suggest allowed images

This commit is contained in:
DaneEveritt 2022-05-07 18:18:14 -04:00
parent c8faf64059
commit 6d5ca5a811
No known key found for this signature in database
GPG Key ID: EEA66103B3D71F53
2 changed files with 63 additions and 56 deletions

View File

@ -1,4 +1,4 @@
import useSWR from 'swr'; import useSWR, { ConfigInterface } from 'swr';
import http, { FractalResponseList } from '@/api/http'; import http, { FractalResponseList } from '@/api/http';
import { rawDataToServerEggVariable } from '@/api/transformers'; import { rawDataToServerEggVariable } from '@/api/transformers';
import { ServerEggVariable } from '@/api/server/types'; import { ServerEggVariable } from '@/api/server/types';
@ -9,7 +9,7 @@ interface Response {
dockerImages: Record<string, string>; dockerImages: Record<string, string>;
} }
export default (uuid: string, initialData?: Response) => useSWR([ uuid, '/startup' ], async (): Promise<Response> => { export default (uuid: string, initialData?: Response | null, config?: ConfigInterface<Response>) => useSWR([ uuid, '/startup' ], async (): Promise<Response> => {
const { data } = await http.get(`/api/client/servers/${uuid}/startup`); const { data } = await http.get(`/api/client/servers/${uuid}/startup`);
const variables = ((data as FractalResponseList).data || []).map(rawDataToServerEggVariable); const variables = ((data as FractalResponseList).data || []).map(rawDataToServerEggVariable);
@ -19,4 +19,4 @@ export default (uuid: string, initialData?: Response) => useSWR([ uuid, '/startu
invocation: data.meta.startup_command, invocation: data.meta.startup_command,
dockerImages: data.meta.docker_images || {}, dockerImages: data.meta.docker_images || {},
}; };
}, { initialData, errorRetryCount: 3 }); }, { initialData: initialData || undefined, errorRetryCount: 3, ...(config || {}) });

View File

@ -8,47 +8,46 @@ import FlashMessageRender from '@/components/FlashMessageRender';
import useFlash from '@/plugins/useFlash'; import useFlash from '@/plugins/useFlash';
import { SocketEvent, SocketRequest } from '@/components/server/events'; import { SocketEvent, SocketRequest } from '@/components/server/events';
import Select from '@/components/elements/Select'; import Select from '@/components/elements/Select';
import useWebsocketEvent from '@/plugins/useWebsocketEvent';
import Can from '@/components/elements/Can';
import getServerStartup from '@/api/swr/getServerStartup';
import InputSpinner from '@/components/elements/InputSpinner';
const dockerImageList = [ const MATCH_ERRORS = [
{ name: 'Java 17', image: 'ghcr.io/pterodactyl/yolks:java_17' },
{ name: 'Java 16', image: 'ghcr.io/pterodactyl/yolks:java_16' },
{ name: 'Java 11', image: 'ghcr.io/pterodactyl/yolks:java_11' },
{ name: 'Java 8', image: 'ghcr.io/pterodactyl/yolks:java_8' },
];
const JavaVersionModalFeature = () => {
const [ visible, setVisible ] = useState(false);
const [ loading, setLoading ] = useState(false);
const [ selectedVersion, setSelectedVersion ] = useState('ghcr.io/pterodactyl/yolks:java_17');
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
const status = ServerContext.useStoreState(state => state.status.value);
const { clearFlashes, clearAndAddHttpError } = useFlash();
const { connected, instance } = ServerContext.useStoreState(state => state.socket);
useEffect(() => {
if (!connected || !instance || status === 'running') return;
const errors = [
'minecraft 1.17 requires running the server with java 16 or above', 'minecraft 1.17 requires running the server with java 16 or above',
'minecraft 1.18 requires running the server with java 17 or above', 'minecraft 1.18 requires running the server with java 17 or above',
'java.lang.unsupportedclassversionerror', 'java.lang.unsupportedclassversionerror',
'unsupported major.minor version', 'unsupported major.minor version',
'has been compiled by a more recent version of the java runtime', 'has been compiled by a more recent version of the java runtime',
]; ];
const listener = (line: string) => { const JavaVersionModalFeature = () => {
if (errors.some(p => line.toLowerCase().includes(p))) { const [ visible, setVisible ] = useState(false);
const [ loading, setLoading ] = useState(false);
const [ selectedVersion, setSelectedVersion ] = useState('');
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
const status = ServerContext.useStoreState(state => state.status.value);
const { clearFlashes, clearAndAddHttpError } = useFlash();
const { instance } = ServerContext.useStoreState(state => state.socket);
const { data, isValidating, mutate } = getServerStartup(uuid, null, { revalidateOnMount: false });
useEffect(() => {
if (!visible) return;
mutate().then((value) => {
setSelectedVersion(Object.keys(value?.dockerImages || [])[0] || '');
});
}, [ visible ]);
useWebsocketEvent(SocketEvent.CONSOLE_OUTPUT, (data) => {
if (status === 'running') return;
if (MATCH_ERRORS.some(p => data.toLowerCase().includes(p.toLowerCase()))) {
setVisible(true); setVisible(true);
} }
}; });
instance.addListener(SocketEvent.CONSOLE_OUTPUT, listener);
return () => {
instance.removeListener(SocketEvent.CONSOLE_OUTPUT, listener);
};
}, [ connected, instance, status ]);
const updateJava = () => { const updateJava = () => {
setLoading(true); setLoading(true);
@ -59,14 +58,9 @@ const JavaVersionModalFeature = () => {
if (status === 'offline' && instance) { if (status === 'offline' && instance) {
instance.send(SocketRequest.SET_STATE, 'restart'); instance.send(SocketRequest.SET_STATE, 'restart');
} }
setLoading(false);
setVisible(false); setVisible(false);
}) })
.catch(error => { .catch(error => clearAndAddHttpError({ key: 'feature:javaVersion', error }))
console.error(error);
clearAndAddHttpError({ key: 'feature:javaVersion', error });
})
.then(() => setLoading(false)); .then(() => setLoading(false));
}; };
@ -75,30 +69,43 @@ const JavaVersionModalFeature = () => {
}, []); }, []);
return ( return (
<Modal visible={visible} onDismissed={() => setVisible(false)} closeOnBackground={false} showSpinnerOverlay={loading}> <Modal
<FlashMessageRender key={'feature:javaVersion'} css={tw`mb-4`}/> visible={visible}
<h2 css={tw`text-2xl mb-4 text-neutral-100`}>Invalid Java version, update Docker image?</h2> onDismissed={() => setVisible(false)}
<p css={tw`mt-4`}>This server is unable to start due to the required Java version not being met.</p> closeOnBackground={false}
<p css={tw`mt-4`}>By pressing {'"Update Docker Image"'} below you are acknowledging that the Docker image this server uses will be changed to an image below that has the Java version you are requesting.</p> showSpinnerOverlay={loading}
<div css={tw`sm:flex items-center mt-4`}>
<p>Please select a Java version from the list below.</p>
<Select
onChange={e => setSelectedVersion(e.target.value)}
> >
{dockerImageList.map((key, index) => { <FlashMessageRender key={'feature:javaVersion'} css={tw`mb-4`}/>
return ( <h2 css={tw`text-2xl mb-4 text-neutral-100`}>Unsupported Java Version</h2>
<option key={index} value={key.image}>{key.name}</option> <p css={tw`mt-4`}>
); This server is currently running an unsupported version of Java and cannot be started.
})} <Can action={'startup.docker-image'}>
&nbsp;Please select a supported version from the list below to continue starting the server.
</Can>
</p>
<Can action={'startup.docker-image'}>
<div css={tw`mt-4`}>
<InputSpinner visible={!data || isValidating}>
<Select disabled={!data} onChange={e => setSelectedVersion(e.target.value)}>
{!data
? <option disabled/>
: Object.keys((data.dockerImages)).map((key) => (
<option key={key} value={data.dockerImages[key]}>{key}</option>
))
}
</Select> </Select>
</InputSpinner>
</div> </div>
<div css={tw`mt-8 sm:flex items-center justify-end`}> </Can>
<Button isSecondary onClick={() => setVisible(false)} css={tw`w-full sm:w-auto border-transparent`}> <div css={tw`mt-8 flex flex-col sm:flex-row justify-end sm:space-x-4 space-y-4 sm:space-y-0`}>
<Button isSecondary onClick={() => setVisible(false)} css={tw`w-full sm:w-auto`}>
Cancel Cancel
</Button> </Button>
<Button onClick={updateJava} css={tw`mt-4 sm:mt-0 sm:ml-4 w-full sm:w-auto`}> <Can action={'startup.docker-image'}>
<Button onClick={updateJava} css={tw`w-full sm:w-auto`}>
Update Docker Image Update Docker Image
</Button> </Button>
</Can>
</div> </div>
</Modal> </Modal>
); );