mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-04-28 01:46:23 +02:00
auto-update oauth connect state in ui
This commit is contained in:
parent
24837f867b
commit
bdaca80d59
5 changed files with 86 additions and 20 deletions
|
|
@ -210,6 +210,15 @@ function emitRunEvent(event: z.infer<typeof RunEvent>): void {
|
|||
}
|
||||
}
|
||||
|
||||
export function emitOAuthEvent(event: { provider: string; success: boolean; error?: string }): void {
|
||||
const windows = BrowserWindow.getAllWindows();
|
||||
for (const win of windows) {
|
||||
if (!win.isDestroyed() && win.webContents) {
|
||||
win.webContents.send('oauth:didConnect', event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let runsWatcher: (() => void) | null = null;
|
||||
export async function startRunsWatcher(): Promise<void> {
|
||||
if (runsWatcher) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { IClientRegistrationRepo } from '@x/core/dist/auth/client-repo.js';
|
|||
import { triggerSync as triggerGmailSync } from '@x/core/dist/knowledge/sync_gmail.js';
|
||||
import { triggerSync as triggerCalendarSync } from '@x/core/dist/knowledge/sync_calendar.js';
|
||||
import { triggerSync as triggerFirefliesSync } from '@x/core/dist/knowledge/sync_fireflies.js';
|
||||
import { emitOAuthEvent } from './ipc.js';
|
||||
|
||||
const REDIRECT_URI = 'http://localhost:8080/oauth/callback';
|
||||
|
||||
|
|
@ -160,8 +161,13 @@ export async function connectProvider(provider: string): Promise<{ success: bool
|
|||
} else if (provider === 'fireflies-ai') {
|
||||
triggerFirefliesSync();
|
||||
}
|
||||
|
||||
// Emit success event to renderer
|
||||
emitOAuthEvent({ provider, success: true });
|
||||
} catch (error) {
|
||||
console.error('OAuth token exchange failed:', error);
|
||||
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
||||
emitOAuthEvent({ provider, success: false, error: errorMessage });
|
||||
throw error;
|
||||
} finally {
|
||||
// Clean up
|
||||
|
|
@ -178,6 +184,7 @@ export async function connectProvider(provider: string): Promise<{ success: bool
|
|||
console.log(`[OAuth] Cleaning up abandoned OAuth flow for ${provider} (timeout)`);
|
||||
activeFlows.delete(state);
|
||||
server.close();
|
||||
emitOAuthEvent({ provider, success: false, error: 'OAuth flow timed out' });
|
||||
}
|
||||
}, 5 * 60 * 1000); // 5 minutes
|
||||
|
||||
|
|
|
|||
|
|
@ -127,6 +127,32 @@ export function ConnectorsPopover({ children, tooltip }: ConnectorsPopoverProps)
|
|||
}
|
||||
}, [open, providers, refreshAllStatuses])
|
||||
|
||||
// Listen for OAuth completion events
|
||||
useEffect(() => {
|
||||
const cleanup = window.ipc.on('oauth:didConnect', (event) => {
|
||||
const { provider, success, error } = event
|
||||
|
||||
setProviderStates(prev => ({
|
||||
...prev,
|
||||
[provider]: {
|
||||
isConnected: success,
|
||||
isLoading: false,
|
||||
isConnecting: false,
|
||||
}
|
||||
}))
|
||||
|
||||
if (success) {
|
||||
toast(`Successfully connected to ${provider}`, 'success')
|
||||
// Refresh status to ensure consistency
|
||||
refreshAllStatuses()
|
||||
} else {
|
||||
toast(error || `Failed to connect to ${provider}`, 'error')
|
||||
}
|
||||
})
|
||||
|
||||
return cleanup
|
||||
}, [refreshAllStatuses])
|
||||
|
||||
// Connect to a provider
|
||||
const handleConnect = useCallback(async (provider: string) => {
|
||||
setProviderStates(prev => ({
|
||||
|
|
@ -138,18 +164,10 @@ export function ConnectorsPopover({ children, tooltip }: ConnectorsPopoverProps)
|
|||
const result = await window.ipc.invoke('oauth:connect', { provider })
|
||||
|
||||
if (result.success) {
|
||||
toast(`Successfully connected to ${provider}`, 'success')
|
||||
// Refresh the status after successful connection
|
||||
const checkResult = await window.ipc.invoke('oauth:is-connected', { provider })
|
||||
setProviderStates(prev => ({
|
||||
...prev,
|
||||
[provider]: {
|
||||
isConnected: checkResult.isConnected,
|
||||
isLoading: false,
|
||||
isConnecting: false,
|
||||
}
|
||||
}))
|
||||
// OAuth flow started - keep isConnecting state, wait for event
|
||||
// Event listener will handle the actual completion
|
||||
} else {
|
||||
// Immediate failure (e.g., couldn't start flow)
|
||||
toast(result.error || `Failed to connect to ${provider}`, 'error')
|
||||
setProviderStates(prev => ({
|
||||
...prev,
|
||||
|
|
|
|||
|
|
@ -9,11 +9,6 @@ export function useOAuth(provider: string) {
|
|||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
const [isConnecting, setIsConnecting] = useState<boolean>(false);
|
||||
|
||||
// Check connection status on mount and when provider changes
|
||||
useEffect(() => {
|
||||
checkConnection();
|
||||
}, [provider]);
|
||||
|
||||
const checkConnection = useCallback(async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
|
@ -27,23 +22,52 @@ export function useOAuth(provider: string) {
|
|||
}
|
||||
}, [provider]);
|
||||
|
||||
// Check connection status on mount and when provider changes
|
||||
useEffect(() => {
|
||||
checkConnection();
|
||||
}, [provider, checkConnection]);
|
||||
|
||||
// Listen for OAuth completion events
|
||||
useEffect(() => {
|
||||
const cleanup = window.ipc.on('oauth:didConnect', (event) => {
|
||||
if (event.provider !== provider) {
|
||||
return; // Ignore events for other providers
|
||||
}
|
||||
|
||||
setIsConnected(event.success);
|
||||
setIsConnecting(false);
|
||||
setIsLoading(false);
|
||||
|
||||
if (event.success) {
|
||||
toast(`Successfully connected to ${provider}`, 'success');
|
||||
// Refresh connection status to ensure consistency
|
||||
checkConnection();
|
||||
} else {
|
||||
toast(event.error || `Failed to connect to ${provider}`, 'error');
|
||||
}
|
||||
});
|
||||
|
||||
return cleanup;
|
||||
}, [provider, checkConnection]);
|
||||
|
||||
const connect = useCallback(async () => {
|
||||
try {
|
||||
setIsConnecting(true);
|
||||
const result = await window.ipc.invoke('oauth:connect', { provider });
|
||||
if (result.success) {
|
||||
toast(`Successfully connected to ${provider}`, 'success');
|
||||
await checkConnection();
|
||||
// OAuth flow started - keep isConnecting state, wait for event
|
||||
// Event listener will handle the actual completion
|
||||
} else {
|
||||
// Immediate failure (e.g., couldn't start flow)
|
||||
toast(result.error || `Failed to connect to ${provider}`, 'error');
|
||||
setIsConnecting(false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to connect:', error);
|
||||
toast(`Failed to connect to ${provider}`, 'error');
|
||||
} finally {
|
||||
setIsConnecting(false);
|
||||
}
|
||||
}, [provider, checkConnection]);
|
||||
}, [provider]);
|
||||
|
||||
const disconnect = useCallback(async () => {
|
||||
try {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue