From 429e7e4f03db90f2dcedc3a19088debfd31e2583 Mon Sep 17 00:00:00 2001 From: tusharmagar Date: Mon, 16 Mar 2026 16:17:33 +0530 Subject: [PATCH] Implement Gmail integration with Composio, enhancing onboarding flow to support Gmail connection status and API key management. Update ConnectorsPopover and SettingsDialog components to reflect new functionality, including dynamic tab visibility based on Rowboat connection status. --- .../src/components/connectors-popover.tsx | 26 +++- .../src/components/onboarding/index.tsx | 7 ++ .../onboarding/steps/completion-step.tsx | 15 ++- .../steps/connect-accounts-step.tsx | 40 +++++-- .../onboarding/steps/welcome-step.tsx | 5 +- .../onboarding/use-onboarding-state.ts | 111 +++++++++++++++++- .../src/components/settings-dialog.tsx | 27 ++++- 7 files changed, 205 insertions(+), 26 deletions(-) diff --git a/apps/x/apps/renderer/src/components/connectors-popover.tsx b/apps/x/apps/renderer/src/components/connectors-popover.tsx index 268fcfe7..ec3cd8cd 100644 --- a/apps/x/apps/renderer/src/components/connectors-popover.tsx +++ b/apps/x/apps/renderer/src/components/connectors-popover.tsx @@ -75,7 +75,7 @@ export function ConnectorsPopover({ children, tooltip, open: openProp, onOpenCha const [gmailLoading, setGmailLoading] = useState(true) const [gmailConnecting, setGmailConnecting] = useState(false) - // Load available providers and composio-for-google flag on mount + // Load available providers on mount useEffect(() => { async function loadProviders() { try { @@ -89,6 +89,12 @@ export function ConnectorsPopover({ children, tooltip, open: openProp, onOpenCha setProvidersLoading(false) } } + loadProviders() + }, []) + + // Re-check composio-for-google flag every time the popover opens + useEffect(() => { + if (!open) return async function loadComposioForGoogleFlag() { try { const result = await window.ipc.invoke('composio:use-composio-for-google', null) @@ -97,9 +103,8 @@ export function ConnectorsPopover({ children, tooltip, open: openProp, onOpenCha console.error('Failed to check composio-for-google flag:', error) } } - loadProviders() loadComposioForGoogleFlag() - }, []) + }, [open]) // Load Granola config const refreshGranolaConfig = useCallback(async () => { @@ -339,9 +344,9 @@ export function ConnectorsPopover({ children, tooltip, open: openProp, onOpenCha // Listen for OAuth completion events useEffect(() => { - const cleanup = window.ipc.on('oauth:didConnect', (event) => { + const cleanup = window.ipc.on('oauth:didConnect', async (event) => { const { provider, success, error } = event - + setProviderStates(prev => ({ ...prev, [provider]: { @@ -362,6 +367,17 @@ export function ConnectorsPopover({ children, tooltip, open: openProp, onOpenCha } else { toast.success(`Connected to ${displayName}`) } + + // When Rowboat account connects, re-check composio flag so Gmail uses the right flow + if (provider === 'rowboat') { + try { + const result = await window.ipc.invoke('composio:use-composio-for-google', null) + setUseComposioForGoogle(result.enabled) + } catch (err) { + console.error('Failed to re-check composio-for-google flag:', err) + } + } + // Refresh status to ensure consistency refreshAllStatuses() } else { diff --git a/apps/x/apps/renderer/src/components/onboarding/index.tsx b/apps/x/apps/renderer/src/components/onboarding/index.tsx index 8cb10700..d37cdf0f 100644 --- a/apps/x/apps/renderer/src/components/onboarding/index.tsx +++ b/apps/x/apps/renderer/src/components/onboarding/index.tsx @@ -8,6 +8,7 @@ import { DialogContent, } from "@/components/ui/dialog" import { GoogleClientIdModal } from "@/components/google-client-id-modal" +import { ComposioApiKeyModal } from "@/components/composio-api-key-modal" import { useOnboardingState } from "./use-onboarding-state" import { StepIndicator } from "./step-indicator" import { WelcomeStep } from "./steps/welcome-step" @@ -44,6 +45,12 @@ export function OnboardingModal({ open, onComplete }: OnboardingModalProps) { onSubmit={state.handleGoogleClientIdSubmit} isSubmitting={state.providerStates.google?.isConnecting ?? false} /> + {}}> 0 || granolaEnabled || slackEnabled + const { connectedProviders, granolaEnabled, slackEnabled, gmailConnected, handleComplete } = state + const hasConnections = connectedProviders.length > 0 || granolaEnabled || slackEnabled || gmailConnected return (
@@ -65,6 +65,17 @@ export function CompletionStep({ state }: CompletionStepProps) { >

Connected

+ {gmailConnected && ( + + + Gmail (Email) + + )} {connectedProviders.includes('google') && ( ) : (
- {/* Email & Calendar */} - {providers.includes('google') && ( + {/* Email / Email & Calendar */} + {(useComposioForGoogle || providers.includes('google')) && (
- Email & Calendar + {useComposioForGoogle ? 'Email' : 'Email & Calendar'} - } - iconBg="bg-red-500/10" - iconColor="text-red-500" - providerState={providerStates['google']} - onConnect={() => handleConnect('google')} - index={cardIndex++} - /> + {useComposioForGoogle ? ( + } + iconBg="bg-red-500/10" + iconColor="text-red-500" + providerState={{ isConnected: gmailConnected, isLoading: gmailLoading, isConnecting: gmailConnecting }} + onConnect={handleConnectGmail} + index={cardIndex++} + /> + ) : ( + } + iconBg="bg-red-500/10" + iconColor="text-red-500" + providerState={providerStates['google']} + onConnect={() => handleConnect('google')} + index={cardIndex++} + /> + )}
)} diff --git a/apps/x/apps/renderer/src/components/onboarding/steps/welcome-step.tsx b/apps/x/apps/renderer/src/components/onboarding/steps/welcome-step.tsx index 08a0f9cb..90bbcd02 100644 --- a/apps/x/apps/renderer/src/components/onboarding/steps/welcome-step.tsx +++ b/apps/x/apps/renderer/src/components/onboarding/steps/welcome-step.tsx @@ -41,7 +41,10 @@ export function WelcomeStep({ state }: WelcomeStepProps) { Connected to Rowboat