| 1 |
import React, { useEffect, useMemo } from 'react'; |
| 2 |
import ReactSelect from 'react-select'; |
| 3 |
import { useBuilderContext, withLabel } from 'quickbuilder'; |
| 4 |
|
| 5 |
/** |
| 6 |
* Model dropdown whose options follow the selected AI platform. |
| 7 |
* |
| 8 |
* Reads the live `ai_platform` value from the builder context and renders the |
| 9 |
* curated model list for that platform (passed from PHP via the field's |
| 10 |
* `catalogue` / `defaults` props — see ModelRegistry). When the platform |
| 11 |
* changes, or the stored model is not valid for the new platform, it resets the |
| 12 |
* value to that platform's default so the saved `ai_model` is always coherent. |
| 13 |
* |
| 14 |
* Bound to the single global `ai_model` setting; no live API calls. |
| 15 |
*/ |
| 16 |
const toOptions = ( map ) => |
| 17 |
Object.keys( map || {} ).map( ( value ) => ( { value, label: map[ value ] } ) ); |
| 18 |
|
| 19 |
const PlatformModelSelect = ( props ) => { |
| 20 |
const builderContext = useBuilderContext(); |
| 21 |
const { name, onChange, placeholder, search = true } = props; |
| 22 |
|
| 23 |
const platform = builderContext.values?.ai_platform || 'openai'; |
| 24 |
const catalogue = props.catalogue || {}; |
| 25 |
const defaults = props.defaults || {}; |
| 26 |
|
| 27 |
const options = useMemo( () => toOptions( catalogue[ platform ] ), [ platform ] ); |
| 28 |
const currentValue = builderContext.values?.[ name ]; |
| 29 |
|
| 30 |
// Keep the stored model valid for the active platform. |
| 31 |
useEffect( () => { |
| 32 |
const isValid = options.some( ( option ) => option.value === currentValue ); |
| 33 |
if ( ! isValid ) { |
| 34 |
const fallback = |
| 35 |
defaults[ platform ] || ( options[ 0 ] && options[ 0 ].value ) || ''; |
| 36 |
if ( fallback !== currentValue ) { |
| 37 |
onChange( { |
| 38 |
target: { type: 'select', name, value: fallback, options, multiple: false }, |
| 39 |
} ); |
| 40 |
} |
| 41 |
} |
| 42 |
}, [ platform ] ); |
| 43 |
|
| 44 |
const selectedOption = |
| 45 |
options.find( ( option ) => option.value === currentValue ) || null; |
| 46 |
|
| 47 |
return ( |
| 48 |
<div className="wprf-select-wrapper"> |
| 49 |
<ReactSelect |
| 50 |
className="wprf-select" |
| 51 |
classNamePrefix="wprf-select" |
| 52 |
isSearchable={ search } |
| 53 |
name={ name } |
| 54 |
isMulti={ false } |
| 55 |
placeholder={ placeholder } |
| 56 |
options={ options } |
| 57 |
value={ selectedOption } |
| 58 |
onChange={ ( option ) => |
| 59 |
onChange( { |
| 60 |
target: { |
| 61 |
type: 'select', |
| 62 |
name, |
| 63 |
value: option?.value, |
| 64 |
options, |
| 65 |
multiple: false, |
| 66 |
}, |
| 67 |
} ) |
| 68 |
} |
| 69 |
/> |
| 70 |
</div> |
| 71 |
); |
| 72 |
}; |
| 73 |
|
| 74 |
export default withLabel( PlatformModelSelect ); |
| 75 |
|