diff --git a/src/vs/platform/void/common/refreshModelService.ts b/src/vs/platform/void/common/refreshModelService.ts index 09c1dd7f..9f4df4f8 100644 --- a/src/vs/platform/void/common/refreshModelService.ts +++ b/src/vs/platform/void/common/refreshModelService.ts @@ -36,7 +36,7 @@ function eq(a: T[], b: T[]): boolean { export interface IRefreshModelService { readonly _serviceBrand: undefined; refreshModels: (providerName: RefreshableProviderName) => Promise; - onDidChangeState: Event; + onDidChangeState: Event; state: RefreshModelStateOfProvider; } @@ -46,8 +46,8 @@ export class RefreshModelService extends Disposable implements IRefreshModelServ readonly _serviceBrand: undefined; - private readonly _onDidChangeState = new Emitter(); - readonly onDidChangeState: Event = this._onDidChangeState.event; // this is primarily for use in react, so react can listen + update on state changes + private readonly _onDidChangeState = new Emitter(); + readonly onDidChangeState: Event = this._onDidChangeState.event; // this is primarily for use in react, so react can listen + update on state changes constructor( @IVoidSettingsService private readonly voidSettingsService: IVoidSettingsService, @@ -67,7 +67,7 @@ export class RefreshModelService extends Disposable implements IRefreshModelServ // every time providerName.enabled changes, refresh models too, like useEffect let relevantVals = () => refreshables[providerName].map(settingName => this.voidSettingsService.state.settingsOfProvider[providerName][settingName]) - let prevVals = relevantVals() + let prevVals = relevantVals() // each iteration of a for loop has its own context and vars, so this is ok this._register( this.voidSettingsService.onDidChangeState(() => { // we might want to debounce this const newVals = relevantVals() @@ -79,9 +79,6 @@ export class RefreshModelService extends Disposable implements IRefreshModelServ ) } - - - } state: RefreshModelStateOfProvider = { @@ -133,7 +130,7 @@ export class RefreshModelService extends Disposable implements IRefreshModelServ private _setIsRefreshing(providerName: RefreshableProviderName, state: ModelRefreshState) { this.state[providerName].state = state - this._onDidChangeState.fire() + this._onDidChangeState.fire(providerName) } } diff --git a/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx b/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx index 5d85c492..234f8cd3 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx @@ -11,7 +11,7 @@ import { ReactServicesType } from '../../../helpers/reactServicesHelper.js' import { VoidSidebarState } from '../../../sidebarStateService.js' import { VoidSettingsState } from '../../../../../../../platform/void/common/voidSettingsService.js' import { ColorScheme } from '../../../../../../../platform/theme/common/theme.js' -import { RefreshModelStateOfProvider } from '../../../../../../../platform/void/common/refreshModelService.js' +import { RefreshableProviderName, RefreshModelStateOfProvider } from '../../../../../../../platform/void/common/refreshModelService.js' // normally to do this you'd use a useEffect that calls .onDidChangeState(), but useEffect mounts too late and misses initial state changes @@ -31,6 +31,7 @@ const settingsStateListeners: Set<(s: VoidSettingsState) => void> = new Set() let refreshModelState: RefreshModelStateOfProvider const refreshModelStateListeners: Set<(s: RefreshModelStateOfProvider) => void> = new Set() +const refreshModelProviderListeners: Set<(p: RefreshableProviderName, s: RefreshModelStateOfProvider) => void> = new Set() let colorThemeState: ColorScheme const colorThemeStateListeners: Set<(s: ColorScheme) => void> = new Set() @@ -78,9 +79,10 @@ export const _registerServices = (services_: ReactServicesType) => { refreshModelState = refreshModelService.state disposables.push( - refreshModelService.onDidChangeState(() => { + refreshModelService.onDidChangeState((providerName) => { refreshModelState = refreshModelService.state refreshModelStateListeners.forEach(l => l(refreshModelState)) + refreshModelProviderListeners.forEach(l => l(providerName, refreshModelState)) }) ) @@ -148,7 +150,12 @@ export const useRefreshModelState = () => { } - +export const useRefreshModelListener = (listener: (providerName: RefreshableProviderName, s: RefreshModelStateOfProvider) => void) => { + useEffect(() => { + refreshModelProviderListeners.add(listener) + return () => { refreshModelProviderListeners.delete(listener) } + }, [listener]) +} export const useIsDark = () => { diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx index 7479f76d..6e21e8c5 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx @@ -3,7 +3,7 @@ import { InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox import { ProviderName, SettingName, displayInfoOfSettingName, titleOfProviderName, providerNames, ModelInfo } from '../../../../../../../platform/void/common/voidSettingsTypes.js' import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js' import { VoidInputBox, VoidSelectBox } from '../util/inputs.js' -import { useIsDark, useRefreshModelState, useService, useSettingsState } from '../util/services.js' +import { useIsDark, useRefreshModelListener, useRefreshModelState, useService, useSettingsState } from '../util/services.js' import { X, RefreshCw, Loader2, Check } from 'lucide-react' import { RefreshableProviderName, refreshableProviderNames } from '../../../../../../../platform/void/common/refreshModelService.js' @@ -14,17 +14,21 @@ const RefreshModelButton = ({ providerName }: { providerName: RefreshableProvide const refreshModelState = useRefreshModelState() const refreshModelService = useService('refreshModelService') + const [justFinished, setJustSucceeded] = useState(false) + + useRefreshModelListener( + useCallback((providerName2, refreshModelState) => { + if (providerName2 !== providerName) return + const { state } = refreshModelState[providerName] + if (state !== 'success') return + // now we know we just entered 'success' state for this providerName + setJustSucceeded(true) + const tid = setTimeout(() => { setJustSucceeded(false) }, 2000) + return () => clearTimeout(tid) + }, [providerName]) + ) - const [justFinished, setJustFinished] = useState(false) const { state } = refreshModelState[providerName] - useEffect(() => { - if (state !== 'success') return - // if no longer refreshing - setJustFinished(true) - const tid = setTimeout(() => { setJustFinished(false) }, 2000) - return () => clearTimeout(tid) - }, [state]) - const isRefreshing = state === 'refreshing' const providerTitle = titleOfProviderName(providerName) @@ -283,9 +287,11 @@ export const Settings = () => {

Providers

- - - +
+ + + +