From 34bc77027a1585e5b3978c15fb1c724e653bea6c Mon Sep 17 00:00:00 2001 From: Lily Delalande <119957291+lily-de@users.noreply.github.com> Date: Tue, 18 Mar 2025 18:53:59 -0700 Subject: [PATCH] ui: new configure provider flow (#1736) --- ui/desktop/src/App.tsx | 205 ++++++++++++++++++++++++----------------- 1 file changed, 119 insertions(+), 86 deletions(-) diff --git a/ui/desktop/src/App.tsx b/ui/desktop/src/App.tsx index c87aa5a1..1f63e9b2 100644 --- a/ui/desktop/src/App.tsx +++ b/ui/desktop/src/App.tsx @@ -62,9 +62,17 @@ export default function App() { view: 'welcome', viewOptions: {}, }); - const { getExtensions, addExtension } = useConfig(); + const { getExtensions, addExtension, read } = useConfig(); const initAttemptedRef = useRef(false); + // Utility function to extract the command from the link + function extractCommand(link: string): string { + const url = new URL(link); + const cmd = url.searchParams.get('cmd') || 'Unknown Command'; + const args = url.searchParams.getAll('arg').map(decodeURIComponent); + return `${cmd} ${args.join(' ')}`.trim(); + } + useEffect(() => { // Skip if feature flag is not enabled if (!process.env.ALPHA) { @@ -94,28 +102,82 @@ export default function App() { } }; - setupExtensions(); + const initializeApp = async () => { + try { + // Check if we have the required configuration + const provider = (await read('GOOSE_PROVIDER', false)) as string; + const model = (await read('GOOSE_MODEL', false)) as string; + + if (provider && model) { + // We have all needed configuration, initialize the system + console.log('Initializing system with stored GOOSE_MODEL and GOOSE_PROVIDER'); + await initializeSystem(provider, model); + setView('chat'); + } else { + // Missing configuration, show onboarding + console.log('Missing configuration, showing onboarding'); + setView('welcome'); + } + } catch (error) { + console.error('Error initializing app:', error); + setView('welcome'); + } + }; + + initializeApp().then(); + setupExtensions().then(); }, []); // Empty dependency array since we're using initAttemptedRef - const [isGoosehintsModalOpen, setIsGoosehintsModalOpen] = useState(false); - const [isLoadingSession, setIsLoadingSession] = useState(false); - - const { switchModel } = useModel(); - const { addRecentModel } = useRecentModels(); const setView = (view: View, viewOptions: Record = {}) => { setInternalView({ view, viewOptions }); }; - // Utility function to extract the command from the link - function extractCommand(link: string): string { - const url = new URL(link); - const cmd = url.searchParams.get('cmd') || 'Unknown Command'; - const args = url.searchParams.getAll('arg').map(decodeURIComponent); - return `${cmd} ${args.join(' ')}`.trim(); - } + const [isGoosehintsModalOpen, setIsGoosehintsModalOpen] = useState(false); + const [isLoadingSession, setIsLoadingSession] = useState(false); + const { chat, setChat } = useChat({ setView, setIsLoadingSession }); useEffect(() => window.electron.reactReady(), []); + // Keyboard shortcut handler + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if ((event.metaKey || event.ctrlKey) && event.key === 'n') { + event.preventDefault(); + window.electron.createChatWindow(undefined, window.appConfig.get('GOOSE_WORKING_DIR')); + } + }; + + window.addEventListener('keydown', handleKeyDown); + return () => { + window.removeEventListener('keydown', handleKeyDown); + }; + }, []); + + useEffect(() => { + const handleFatalError = (_: any, errorMessage: string) => { + setFatalError(errorMessage); + }; + + window.electron.on('fatal-error', handleFatalError); + return () => { + window.electron.off('fatal-error', handleFatalError); + }; + }, []); + + useEffect(() => { + const handleSetView = (_, view) => setView(view); + window.electron.on('set-view', handleSetView); + return () => window.electron.off('set-view', handleSetView); + }, []); + + // Add cleanup for session states when view changes + useEffect(() => { + if (view !== 'chat') { + setIsLoadingSession(false); + } + }, [view]); + + // TODO: modify useEffect(() => { const handleAddExtension = (_: any, link: string) => { const command = extractCommand(link); @@ -134,34 +196,51 @@ export default function App() { }; }, []); - // Keyboard shortcut handler + // TODO: modify + const handleConfirm = async () => { + if (pendingLink && !isInstalling) { + setIsInstalling(true); + try { + await addExtensionFromDeepLink(pendingLink, setView); + } catch (error) { + console.error('Failed to add extension:', error); + } finally { + setModalVisible(false); + setPendingLink(null); + setIsInstalling(false); + } + } + }; + + // TODO: modify + const handleCancel = () => { + console.log('Cancelled extension installation.'); + setModalVisible(false); + setPendingLink(null); + }; + + const { switchModel } = useModel(); // TODO: remove + const { addRecentModel } = useRecentModels(); // TODO: remove + useEffect(() => { - const handleKeyDown = (event: KeyboardEvent) => { - if ((event.metaKey || event.ctrlKey) && event.key === 'n') { - event.preventDefault(); - window.electron.createChatWindow(undefined, window.appConfig.get('GOOSE_WORKING_DIR')); + if (process.env.ALPHA) { + return; + } + + // TODO: remove + // Attempt to detect config for a stored provider + const detectStoredProvider = () => { + const config = window.electron.getConfig(); + const storedProvider = getStoredProvider(config); + if (storedProvider) { + setView('chat'); + } else { + setView('welcome'); } }; - window.addEventListener('keydown', handleKeyDown); - return () => { - window.removeEventListener('keydown', handleKeyDown); - }; - }, []); - - // Attempt to detect config for a stored provider - useEffect(() => { - const config = window.electron.getConfig(); - const storedProvider = getStoredProvider(config); - if (storedProvider) { - setView('chat'); - } else { - setView('welcome'); - } - }, []); - - // Initialize system if we have a stored provider - useEffect(() => { + // TODO: remove + // Initialize system if we have a stored provider const setupStoredProvider = async () => { const config = window.electron.getConfig(); @@ -190,57 +269,11 @@ export default function App() { } } }; - + detectStoredProvider(); setupStoredProvider(); }, []); - const { chat, setChat } = useChat({ setView, setIsLoadingSession }); - - useEffect(() => { - const handleFatalError = (_: any, errorMessage: string) => { - setFatalError(errorMessage); - }; - - window.electron.on('fatal-error', handleFatalError); - return () => { - window.electron.off('fatal-error', handleFatalError); - }; - }, []); - - useEffect(() => { - const handleSetView = (_, view) => setView(view); - window.electron.on('set-view', handleSetView); - return () => window.electron.off('set-view', handleSetView); - }, []); - - // Add cleanup for session states when view changes - useEffect(() => { - if (view !== 'chat') { - setIsLoadingSession(false); - } - }, [view]); - - const handleConfirm = async () => { - if (pendingLink && !isInstalling) { - setIsInstalling(true); - try { - await addExtensionFromDeepLink(pendingLink, setView); - } catch (error) { - console.error('Failed to add extension:', error); - } finally { - setModalVisible(false); - setPendingLink(null); - setIsInstalling(false); - } - } - }; - - const handleCancel = () => { - console.log('Cancelled extension installation.'); - setModalVisible(false); - setPendingLink(null); - }; - + // keep if (fatalError) { return window.electron.reloadApp()} />; }