From 05581d9d85f0e91cd1e2cb874b0d7834382d6b61 Mon Sep 17 00:00:00 2001 From: M3gA-Mind Date: Thu, 5 Mar 2026 20:55:45 +0530 Subject: [PATCH] Refactor Gmail metadata synchronization logic - Updated the `syncGmailMetadataToBackend` function to accept a new `GmailStateForSync` interface, enhancing type safety and clarity. - Introduced a new `GmailEmailSummaryLike` interface to represent email summaries in the synchronization process. - Adjusted the handling of Gmail profile data to ensure proper extraction and emission of metadata to the backend. - Updated the `SkillProvider` to dispatch Gmail emails to the Redux store and synchronize the Gmail state effectively. --- src/lib/gmail/services/metadataSync.ts | 39 ++++++++++++++++++-------- src/providers/SkillProvider.tsx | 23 ++++++++++----- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/src/lib/gmail/services/metadataSync.ts b/src/lib/gmail/services/metadataSync.ts index 7efc2528d..b8e0850a7 100644 --- a/src/lib/gmail/services/metadataSync.ts +++ b/src/lib/gmail/services/metadataSync.ts @@ -6,34 +6,51 @@ import { emitViaRustSocket } from '../../../utils/tauriSocket'; const INTEGRATION_METADATA_SYNC_EVENT = 'integration:metadata-sync'; -const PROVIDER_GOOGLE = 'gmail'; +const PROVIDER_GOOGLE = 'google'; /** Gmail profile shape from skill state (snake_case). */ -export interface GmailProfileLike { +interface GmailProfileLike { email_address: string; messages_total: number; threads_total: number; history_id: string; } +/** Single email summary from skill state. */ +interface GmailEmailSummaryLike { + id: string; + threadId: string; + snippet?: string; + subject?: string; + from?: string; + date?: string; +} + +/** Gmail skill state slice we care about for metadata sync. */ +export interface GmailStateForSync { + profile?: GmailProfileLike | null; + emails?: GmailEmailSummaryLike[] | null; +} + /** * Emit `integration:metadata-sync` with Gmail profile and emails so the * backend can merge them into the user's Google OAuth integration. * No-op when profile is missing or not in Tauri. */ -export function syncGmailMetadataToBackend(gmailState: GmailProfileLike | undefined): void { - if (!gmailState) return; +export function syncGmailMetadataToBackend(gmailState: GmailStateForSync | undefined): void { + if (!gmailState?.profile || typeof gmailState.profile !== 'object') return; + const profile = gmailState.profile as GmailProfileLike; const metadata: Record = { - email_address: gmailState.email_address, - messages_total: gmailState.messages_total, - threads_total: gmailState.threads_total, - history_id: gmailState.history_id, + email_address: profile.email_address, + messages_total: profile.messages_total, + threads_total: profile.threads_total, + history_id: profile.history_id, }; - // if (Array.isArray(gmailState.emails) && gmailState.emails.length > 0) { - // metadata.emails = gmailState.emails as GmailEmailSummaryLike[]; - // } + if (Array.isArray(gmailState.emails) && gmailState.emails.length > 0) { + metadata.emails = gmailState.emails as GmailEmailSummaryLike[]; + } const payload = { requestId: crypto.randomUUID(), provider: PROVIDER_GOOGLE, metadata }; diff --git a/src/providers/SkillProvider.tsx b/src/providers/SkillProvider.tsx index 66a8d9be1..aea64b40e 100644 --- a/src/providers/SkillProvider.tsx +++ b/src/providers/SkillProvider.tsx @@ -9,16 +9,21 @@ import { listen } from '@tauri-apps/api/event'; import { type ReactNode, useEffect, useRef } from 'react'; import { - type GmailProfileLike, + type GmailStateForSync, syncGmailMetadataToBackend, } from '../lib/gmail/services/metadataSync'; import { syncNotionMetadataToBackend } from '../lib/notion/services/metadataSync'; import { skillManager } from '../lib/skills/manager'; import type { SkillManifest } from '../lib/skills/types'; import { buildManualSentryEvent, enqueueError } from '../services/errorReportQueue'; -import { type GmailProfile, setGmailProfile } from '../store/gmailSlice'; -import { setNotionProfile, type NotionUserProfile } from '../store/notionSlice'; +import { + GmailEmailSummary, + type GmailProfile, + setGmailEmails, + setGmailProfile, +} from '../store/gmailSlice'; import { useAppDispatch, useAppSelector } from '../store/hooks'; +import { type NotionUserProfile, setNotionProfile } from '../store/notionSlice'; import { setSkillError, setSkillState, setSkillStatus } from '../store/skillsSlice'; import { DEV_AUTO_LOAD_SKILL, IS_DEV } from '../utils/config'; @@ -85,12 +90,16 @@ function syncGmailStateToSlice( : null ) ); - syncGmailMetadataToBackend(gmailState.profile as GmailProfileLike); + dispatch( + setGmailEmails( + Array.isArray(gmailState.emails) ? (gmailState.emails as GmailEmailSummary[]) : [] + ) + ); + + syncGmailMetadataToBackend(gmailState as GmailStateForSync); } -async function syncNotionUserOnConnect( - dispatch: ReturnType -): Promise { +async function syncNotionUserOnConnect(dispatch: ReturnType): Promise { try { const toolResult = await skillManager.callTool('notion', 'get-user', { user_id: 'me' }); if (!toolResult || toolResult.isError || toolResult.content.length === 0) {