Merge remote-tracking branch 'origin/fix/startup-and-server-switch' into pr-319

This commit is contained in:
James Pine
2026-03-21 10:18:45 -07:00
4 changed files with 98 additions and 11 deletions
+19
View File
@@ -4,6 +4,7 @@ import voiceboxLogo from '@/assets/voicebox-logo.png';
import ShinyText from '@/components/ShinyText';
import { TitleBarDragRegion } from '@/components/TitleBarDragRegion';
import { useAutoUpdater } from '@/hooks/useAutoUpdater';
import { apiClient } from '@/lib/api/client';
import { TOP_SAFE_AREA_PADDING } from '@/lib/constants/ui';
import { cn } from '@/lib/utils/cn';
import { usePlatform } from '@/platform/PlatformContext';
@@ -122,6 +123,24 @@ function App() {
serverStartingRef.current = false;
// @ts-expect-error - adding property to window
window.__voiceboxServerStartedByApp = false;
// Fall back to polling: the server may already be running externally
// (e.g. started via python/uvicorn/Docker). Poll the health endpoint
// until it responds, then transition to the main UI.
console.log('Falling back to health-check polling...');
const pollInterval = setInterval(async () => {
try {
await apiClient.getHealth();
console.log('External server detected via health check');
clearInterval(pollInterval);
setServerReady(true);
} catch {
// Server not ready yet, keep polling
}
}, 2000);
// Stop polling after 2 minutes to avoid polling forever
setTimeout(() => clearInterval(pollInterval), 120_000);
});
// Cleanup: stop server on actual unmount (not StrictMode remount)
+1 -1
View File
@@ -5,7 +5,7 @@ import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
const queryClient = new QueryClient({
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5 minutes
+20 -2
View File
@@ -30,11 +30,29 @@ interface ServerStore {
setCustomModelsDir: (dir: string | null) => void;
}
/**
* Invalidate all React Query caches and reset UI selection state.
* Called when the server URL changes so stale data from the previous
* server is not shown.
*/
function invalidateAllServerData() {
// Lazy import to avoid circular dependency (main.tsx -> serverStore -> main.tsx)
import('@/main').then(({ queryClient }) => {
queryClient.invalidateQueries();
});
}
export const useServerStore = create<ServerStore>()(
persist(
(set) => ({
(set, get) => ({
serverUrl: 'http://127.0.0.1:17493',
setServerUrl: (url) => set({ serverUrl: url }),
setServerUrl: (url) => {
const prev = get().serverUrl;
set({ serverUrl: url });
if (url !== prev) {
invalidateAllServerData();
}
},
isConnected: false,
setIsConnected: (connected) => set({ isConnected: connected }),