@@ -13,6 +13,8 @@ import {
1313 CardHeader ,
1414 CardTitle ,
1515 Content ,
16+ EmptyState ,
17+ EmptyStateBody ,
1618 FormHelperText ,
1719 Gallery ,
1820 Grid ,
@@ -25,6 +27,7 @@ import {
2527 Stack ,
2628 StackItem ,
2729} from '@patternfly/react-core' ;
30+ import { CubesIcon } from '@patternfly/react-icons' ;
2831import { useQueryClient } from '@tanstack/react-query' ;
2932import { findKey } from 'es-toolkit' ;
3033import React , { useEffect , useRef , useState } from 'react' ;
@@ -321,114 +324,128 @@ function AutomlConfigure(): React.JSX.Element {
321324 < Content component = "h3" > Configure details</ Content >
322325 </ CardHeader >
323326 < CardBody >
324- < Stack hasGutter style = { { gap : 'var(--pf-t--global--spacer--xl)' } } >
325- < StackItem >
326- < ConfigureFormGroup label = "Prediction type" isRequired >
327- < Controller
328- control = { form . control }
329- name = "task_type"
330- render = { ( { field } ) => (
331- < Gallery hasGutter minWidths = { { default : '200px' } } >
332- { PREDICTION_TYPES . map ( ( type ) => (
333- < Card
334- key = { type . value }
335- isSelectable
336- isDisabled = { ! canSelectLearningType }
337- isSelected = { field . value === type . value }
338- onClick = { ( ) => field . onChange ( type . value ) }
339- data-testid = { `task-type-card-${ type . value } ` }
340- >
341- < CardHeader
342- selectableActions = { {
343- selectableActionId : `task-type-${ type . value } ` ,
344- selectableActionAriaLabelledby : `task-type-label-${ type . value } ` ,
345- name : 'task_type' ,
346- variant : 'single' ,
347- isChecked : field . value === type . value ,
348- onChange : ( ) => field . onChange ( type . value ) ,
349- isHidden : true ,
350- } }
327+ { ! selectedSecret ? (
328+ < EmptyState
329+ variant = "xs"
330+ titleText = "Select an S3 connection or upload a file to get started"
331+ headingLevel = "h4"
332+ icon = { CubesIcon }
333+ >
334+ < EmptyStateBody >
335+ In order to configure details and run an experiment, add a document or
336+ connection in the widget on the left.
337+ </ EmptyStateBody >
338+ </ EmptyState >
339+ ) : (
340+ < Stack hasGutter style = { { gap : 'var(--pf-t--global--spacer--xl)' } } >
341+ < StackItem >
342+ < ConfigureFormGroup label = "Prediction type" isRequired >
343+ < Controller
344+ control = { form . control }
345+ name = "task_type"
346+ render = { ( { field } ) => (
347+ < Gallery hasGutter minWidths = { { default : '200px' } } >
348+ { PREDICTION_TYPES . map ( ( type ) => (
349+ < Card
350+ key = { type . value }
351+ isSelectable
352+ isDisabled = { ! canSelectLearningType }
353+ isSelected = { field . value === type . value }
354+ onClick = { ( ) => field . onChange ( type . value ) }
355+ data-testid = { `task-type-card-${ type . value } ` }
351356 >
352- < CardTitle id = { `task-type-label-${ type . value } ` } >
353- { type . label }
354- </ CardTitle >
355- </ CardHeader >
356- < CardBody >
357- < Content component = "small" > { type . description } </ Content >
358- </ CardBody >
359- </ Card >
360- ) ) }
361- </ Gallery >
362- ) }
363- />
364- </ ConfigureFormGroup >
365- </ StackItem >
366-
367- { isTimeseries ? (
368- < ConfigureTimeseriesForm
369- columns = { columns }
370- isLoadingColumns = { isLoadingColumns }
371- isFetchingColumns = { isFetchingColumns }
372- columnsError = { columnsError }
373- isFileSelected = { isFileSelected }
374- formIsSubmitting = { formIsSubmitting }
375- />
376- ) : (
377- < ConfigureTabularForm
378- columns = { columns }
379- isLoadingColumns = { isLoadingColumns }
380- isFetchingColumns = { isFetchingColumns }
381- columnsError = { columnsError }
382- isFileSelected = { isFileSelected }
383- formIsSubmitting = { formIsSubmitting }
384- />
385- ) }
357+ < CardHeader
358+ selectableActions = { {
359+ selectableActionId : `task-type-${ type . value } ` ,
360+ selectableActionAriaLabelledby : `task-type-label-${ type . value } ` ,
361+ name : 'task_type' ,
362+ variant : 'single' ,
363+ isChecked : field . value === type . value ,
364+ onChange : ( ) => field . onChange ( type . value ) ,
365+ isHidden : true ,
366+ } }
367+ >
368+ < CardTitle id = { `task-type-label-${ type . value } ` } >
369+ { type . label }
370+ </ CardTitle >
371+ </ CardHeader >
372+ < CardBody >
373+ < Content component = "small" > { type . description } </ Content >
374+ </ CardBody >
375+ </ Card >
376+ ) ) }
377+ </ Gallery >
378+ ) }
379+ />
380+ </ ConfigureFormGroup >
381+ </ StackItem >
386382
387- < StackItem >
388- < ConfigureFormGroup
389- label = "Top models to consider"
390- labelHelp = { {
391- header : 'Top models to consider' ,
392- body : 'Number of top models to select and refit. The pipeline will train multiple models and select the best performing ones for final training.' ,
393- } }
394- >
395- < Controller
396- control = { form . control }
397- name = "top_n"
398- render = { ( { field, fieldState } ) => (
399- < >
400- < NumberInput
401- id = "top-n-input"
402- value = { field . value }
403- min = { MIN_TOP_N }
404- max = { MAX_TOP_N }
405- isDisabled = { formIsSubmitting }
406- validated = { fieldState . error ? 'error' : 'default' }
407- onMinus = { ( ) => field . onChange ( Number ( field . value ) - 1 ) }
408- onPlus = { ( ) => field . onChange ( Number ( field . value ) + 1 ) }
409- onChange = { ( event : React . FormEvent < HTMLInputElement > ) => {
410- const value = parseInt ( event . currentTarget . value , 10 ) ;
411- if ( ! Number . isNaN ( value ) ) {
412- field . onChange ( value ) ;
413- }
414- } }
415- data-testid = "top-n-input"
416- />
417- { fieldState . error && (
418- < FormHelperText >
419- < HelperText >
420- < HelperTextItem variant = "error" >
421- { fieldState . error . message }
422- </ HelperTextItem >
423- </ HelperText >
424- </ FormHelperText >
425- ) }
426- </ >
427- ) }
383+ { isTimeseries ? (
384+ < ConfigureTimeseriesForm
385+ columns = { columns }
386+ isLoadingColumns = { isLoadingColumns }
387+ isFetchingColumns = { isFetchingColumns }
388+ columnsError = { columnsError }
389+ isFileSelected = { isFileSelected }
390+ formIsSubmitting = { formIsSubmitting }
428391 />
429- </ ConfigureFormGroup >
430- </ StackItem >
431- </ Stack >
392+ ) : (
393+ < ConfigureTabularForm
394+ columns = { columns }
395+ isLoadingColumns = { isLoadingColumns }
396+ isFetchingColumns = { isFetchingColumns }
397+ columnsError = { columnsError }
398+ isFileSelected = { isFileSelected }
399+ formIsSubmitting = { formIsSubmitting }
400+ />
401+ ) }
402+
403+ < StackItem >
404+ < ConfigureFormGroup
405+ label = "Top models to consider"
406+ labelHelp = { {
407+ header : 'Top models to consider' ,
408+ body : 'Number of top models to select and refit. The pipeline will train multiple models and select the best performing ones for final training.' ,
409+ } }
410+ >
411+ < Controller
412+ control = { form . control }
413+ name = "top_n"
414+ render = { ( { field, fieldState } ) => (
415+ < >
416+ < NumberInput
417+ id = "top-n-input"
418+ value = { field . value }
419+ min = { MIN_TOP_N }
420+ max = { MAX_TOP_N }
421+ isDisabled = { formIsSubmitting }
422+ validated = { fieldState . error ? 'error' : 'default' }
423+ onMinus = { ( ) => field . onChange ( Number ( field . value ) - 1 ) }
424+ onPlus = { ( ) => field . onChange ( Number ( field . value ) + 1 ) }
425+ onChange = { ( event : React . FormEvent < HTMLInputElement > ) => {
426+ const value = parseInt ( event . currentTarget . value , 10 ) ;
427+ if ( ! Number . isNaN ( value ) ) {
428+ field . onChange ( value ) ;
429+ }
430+ } }
431+ data-testid = "top-n-input"
432+ />
433+ { fieldState . error && (
434+ < FormHelperText >
435+ < HelperText >
436+ < HelperTextItem variant = "error" >
437+ { fieldState . error . message }
438+ </ HelperTextItem >
439+ </ HelperText >
440+ </ FormHelperText >
441+ ) }
442+ </ >
443+ ) }
444+ />
445+ </ ConfigureFormGroup >
446+ </ StackItem >
447+ </ Stack >
448+ ) }
432449 </ CardBody >
433450 </ div >
434451 </ Card >
0 commit comments