import React, { useCallback, useEffect, useState } from 'react'; import TitledGreyBox from '@/components/elements/TitledGreyBox'; import tw from 'twin.macro'; import VariableBox from '@/components/server/startup/VariableBox'; import ServerContentBlock from '@/components/elements/ServerContentBlock'; import getServerStartup from '@/api/swr/getServerStartup'; import Spinner from '@/components/elements/Spinner'; import { ServerError } from '@/components/elements/ScreenBlock'; import { httpErrorToHuman } from '@/api/http'; import { ServerContext } from '@/state/server'; import { useDeepCompareEffect } from '@/plugins/useDeepCompareEffect'; import Select from '@/components/elements/Select'; import isEqual from 'react-fast-compare'; import Input from '@/components/elements/Input'; import setSelectedDockerImage from '@/api/server/setSelectedDockerImage'; import InputSpinner from '@/components/elements/InputSpinner'; import useFlash from '@/plugins/useFlash'; import BeforeContent from '@/blueprint/components/Server/Startup/BeforeContent'; import AfterContent from '@/blueprint/components/Server/Startup/AfterContent'; const StartupContainer = () => { const [loading, setLoading] = useState(false); const { clearFlashes, clearAndAddHttpError } = useFlash(); const uuid = ServerContext.useStoreState((state) => state.server.data!.uuid); const variables = ServerContext.useStoreState( ({ server }) => ({ variables: server.data!.variables, invocation: server.data!.invocation, dockerImage: server.data!.dockerImage, }), isEqual ); const { data, error, isValidating, mutate } = getServerStartup(uuid, { ...variables, dockerImages: { [variables.dockerImage]: variables.dockerImage }, }); const setServerFromState = ServerContext.useStoreActions((actions) => actions.server.setServerFromState); const isCustomImage = data && !Object.values(data.dockerImages) .map((v) => v.toLowerCase()) .includes(variables.dockerImage.toLowerCase()); useEffect(() => { // Since we're passing in initial data this will not trigger on mount automatically. We // want to always fetch fresh information from the API however when we're loading the startup // information. mutate(); }, []); useDeepCompareEffect(() => { if (!data) return; setServerFromState((s) => ({ ...s, invocation: data.invocation, variables: data.variables, })); }, [data]); const updateSelectedDockerImage = useCallback( (v: React.ChangeEvent) => { setLoading(true); clearFlashes('startup:image'); const image = v.currentTarget.value; setSelectedDockerImage(uuid, image) .then(() => setServerFromState((s) => ({ ...s, dockerImage: image }))) .catch((error) => { console.error(error); clearAndAddHttpError({ key: 'startup:image', error }); }) .then(() => setLoading(false)); }, [uuid] ); return !data ? ( !error || (error && isValidating) ? ( ) : ( mutate()} /> ) ) : (

{data.invocation}

{Object.keys(data.dockerImages).length > 1 && !isCustomImage ? ( <>

This is an advanced feature allowing you to select a Docker image to use when running this server instance.

) : ( <> {isCustomImage && (

This {"server's"} Docker image has been manually set by an administrator and cannot be changed through this UI.

)} )}

Variables

{data.variables.map((variable) => ( ))}
); }; export default StartupContainer;