diff --git a/routes/ai-home/components/DeveloperSettings.tsx b/routes/ai-home/components/DeveloperSettings.tsx index 582be4253..f6a2736c9 100644 --- a/routes/ai-home/components/DeveloperSettings.tsx +++ b/routes/ai-home/components/DeveloperSettings.tsx @@ -4,7 +4,13 @@ import { Button, Spinner } from '@wordpress/components'; import { DataForm } from '@wordpress/dataviews'; import type { Field, Form } from '@wordpress/dataviews'; -import { useCallback, useMemo, useRef } from '@wordpress/element'; +import { + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { Notice } from '@wordpress/ui'; @@ -46,8 +52,26 @@ export function DeveloperSettings( { const { settings, update, clear, isSaving } = useDeveloperFeatureSettings( featureId ); + const [ draftSettings, setDraftSettings ] = + useState< DeveloperSelection | null >( null ); + const [ isSavingThis, setIsSavingThis ] = useState( false ); + + useEffect( () => { + if ( ! isSaving ) { + setIsSavingThis( false ); + } + }, [ isSaving ] ); + + useEffect( () => { + setDraftSettings( null ); + }, [ settings.provider, settings.model ] ); + + const currentSettings = draftSettings ?? settings; + const getModelElements = useCallback( () => { - const provider = providers.find( ( p ) => p.id === settings.provider ); + const provider = providers.find( + ( p ) => p.id === currentSettings.provider + ); if ( ! provider ) { return Promise.resolve( [] ); } @@ -58,7 +82,7 @@ export function DeveloperSettings( { label: m.name, } ) ), ] ); - }, [ settings.provider, providers ] ); + }, [ currentSettings.provider, providers ] ); const fields = useMemo< Field< DeveloperSelection >[] >( () => [ @@ -97,18 +121,38 @@ export function DeveloperSettings( { const handleChange = useCallback( ( changes: Partial< DeveloperSelection > ) => { if ( 'provider' in changes ) { - void update( { provider: changes.provider ?? '', model: '' } ); + setDraftSettings( { + provider: changes.provider ?? '', + model: '', + } ); } else { - void update( { ...settings, ...changes } ); + setDraftSettings( { ...currentSettings, ...changes } ); } }, - [ update, settings ] + [ currentSettings ] ); - const hasSavedSelection = settings.provider !== '' || settings.model !== ''; + const handleSave = useCallback( () => { + if ( draftSettings ) { + setIsSavingThis( true ); + if ( draftSettings.provider === '' && draftSettings.model === '' ) { + void clear(); + } else { + void update( draftSettings ); + } + } + }, [ draftSettings, update, clear ] ); + + const hasSavedSelection = + currentSettings.provider !== '' || currentSettings.model !== ''; + const hasUnsavedChanges = + draftSettings !== null && + ( draftSettings.provider !== settings.provider || + draftSettings.model !== settings.model ); + const hasStaleProvider = - !! settings.provider && - ! providers.find( ( p ) => p.id === settings.provider ); + !! currentSettings.provider && + ! providers.find( ( p ) => p.id === currentSettings.provider ); if ( capability === 'none' ) { return ( @@ -153,30 +197,47 @@ export function DeveloperSettings( { ) }
- data={ settings } + data={ currentSettings } fields={ fields } form={ form } onChange={ handleChange } />
- { hasSavedSelection && ( - - ) } +
+ { ( hasUnsavedChanges || isSavingThis ) && ( + + ) } + { hasSavedSelection && ( + + ) } +
) } diff --git a/routes/ai-home/style.scss b/routes/ai-home/style.scss index 906f93b81..9a203e201 100644 --- a/routes/ai-home/style.scss +++ b/routes/ai-home/style.scss @@ -88,7 +88,11 @@ body:has(.ai-settings-page) .components-popover { margin-bottom: var(--wpds-dimension-gap-lg, 12px); } - .ai-developer-mode-fields__reset-button { - margin-top: var(--wpds-dimension-gap-lg, 12px); + .ai-developer-mode-fields__actions { + display: flex; + align-items: center; + gap: var(--wpds-dimension-gap-lg, 16px); + margin-top: var(--wpds-dimension-gap-lg, 16px); + padding-bottom: var(--wpds-dimension-gap-sm, 8px); } }