99 Radio ,
1010 RadioGroup ,
1111 Stack ,
12+ TextField ,
1213 Typography ,
1314} from '@mui/material' ;
1415import { AppProfileProps , AppQueryUpdateProps } from '@src/types/api' ;
@@ -61,6 +62,9 @@ export const ServerTypes = (): React.ReactElement => {
6162 const [ selectedServerType , setSelectedServerType ] = React . useState < string > (
6263 currentFormInput ?. profile || '' ,
6364 ) ;
65+ const [ profileImages , setProfileImages ] = React . useState <
66+ Record < string , string >
67+ > ( { } ) ;
6468 const [ isHeadless ] = useRecoilState < boolean > ( defaultIsHeadless ) ;
6569 const id = searchParams . get ( 'id' ) ;
6670
@@ -89,6 +93,20 @@ export const ServerTypes = (): React.ReactElement => {
8993 setCurrentFormInput ( {
9094 ...currentFormInput ,
9195 profile : slug ,
96+ profile_image : profileImages [ slug ] || '' ,
97+ } ) ;
98+ }
99+ } ;
100+
101+ const handleImageChange = ( slug : string , image : string ) => {
102+ setProfileImages ( {
103+ ...profileImages ,
104+ [ slug ] : image ,
105+ } ) ;
106+ if ( selectedServerType === slug && currentFormInput ) {
107+ setCurrentFormInput ( {
108+ ...currentFormInput ,
109+ profile_image : image ,
92110 } ) ;
93111 }
94112 } ;
@@ -108,6 +126,7 @@ export const ServerTypes = (): React.ReactElement => {
108126 env : getFriendlyEnvironmentVariables ( currentFormInput ?. env ) ,
109127 custom_command : currentFormInput ?. custom_command || '' ,
110128 profile : currentFormInput ?. profile || '' ,
129+ profile_image : currentFormInput ?. profile_image || '' ,
111130 public : currentFormInput ?. is_public || false ,
112131 share_with : {
113132 users : currentFormInput ?. share_with ?. users || [ ] ,
@@ -213,6 +232,70 @@ export const ServerTypes = (): React.ReactElement => {
213232 }
214233 } , [ error , setCurrentNotification ] ) ;
215234
235+ // Effect 1: Initialize profile images from serverTypes with default images
236+ useEffect ( ( ) => {
237+ if ( ! serverTypes || serverTypes . length === 0 ) {
238+ return ;
239+ }
240+
241+ const images : Record < string , string > = { } ;
242+ let defaultProfileSlug = '' ;
243+
244+ serverTypes . forEach ( ( type , index ) => {
245+ const defaultImage = type . kubespawner_override ?. image || '' ;
246+ images [ type . slug ] = defaultImage ;
247+
248+ // Find the default profile or use the first one
249+ if ( type . default || ( ! defaultProfileSlug && index === 0 ) ) {
250+ defaultProfileSlug = type . slug ;
251+ }
252+ } ) ;
253+
254+ setProfileImages ( images ) ;
255+
256+ // Auto-select default profile if no profile is currently selected
257+ if ( ! currentFormInput ?. profile && defaultProfileSlug && currentFormInput ) {
258+ setSelectedServerType ( defaultProfileSlug ) ;
259+ setCurrentFormInput ( {
260+ ...currentFormInput ,
261+ profile : defaultProfileSlug ,
262+ profile_image : images [ defaultProfileSlug ] || '' ,
263+ } ) ;
264+ }
265+ } , [ serverTypes ] ) ;
266+
267+ // Effect 2: Populate custom profile image when coming from edit mode
268+ // This runs when the profile changes (e.g., when navigating to this page with edit data)
269+ useEffect ( ( ) => {
270+ if (
271+ ! serverTypes ||
272+ serverTypes . length === 0 ||
273+ ! currentFormInput ?. profile
274+ ) {
275+ return ;
276+ }
277+
278+ const profileImage = currentFormInput . profile_image ;
279+ if ( ! profileImage ) {
280+ return ;
281+ }
282+
283+ // Find the matching server type to get its default image
284+ const matchingType = serverTypes . find (
285+ ( type ) => type . slug === currentFormInput . profile ,
286+ ) ;
287+ const defaultImage = matchingType ?. kubespawner_override ?. image || '' ;
288+
289+ // Only update if the profile_image is different from the default
290+ // (meaning the user had customized it previously)
291+ if ( profileImage !== defaultImage && currentFormInput . profile ) {
292+ setProfileImages ( ( prev ) => ( {
293+ ...prev ,
294+ [ currentFormInput . profile as string ] : profileImage ,
295+ } ) ) ;
296+ }
297+ } , [ serverTypes , currentFormInput ?. profile ] ) ;
298+
216299 return (
217300 < Box className = "container" >
218301 < Stack >
@@ -281,6 +364,24 @@ export const ServerTypes = (): React.ReactElement => {
281364 label = { type . display_name }
282365 />
283366 < p > { type . description } </ p >
367+ { type . kubespawner_override ?. image && (
368+ < Box
369+ sx = { { mt : 2 } }
370+ onClick = { ( e ) => e . stopPropagation ( ) }
371+ >
372+ < TextField
373+ fullWidth
374+ size = "small"
375+ label = "Image"
376+ value = { profileImages [ type . slug ] || '' }
377+ onChange = { ( e ) =>
378+ handleImageChange ( type . slug , e . target . value )
379+ }
380+ variant = "outlined"
381+ placeholder = { type . kubespawner_override . image }
382+ />
383+ </ Box >
384+ ) }
284385 </ CardContent >
285386 </ Card >
286387 ) ) }
0 commit comments