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.
This commit is contained in:
M3gA-Mind
2026-03-05 20:55:45 +05:30
parent cc4fd44843
commit 05581d9d85
2 changed files with 44 additions and 18 deletions
+28 -11
View File
@@ -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<string, unknown> = {
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 };
+16 -7
View File
@@ -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<typeof useAppDispatch>
): Promise<void> {
async function syncNotionUserOnConnect(dispatch: ReturnType<typeof useAppDispatch>): Promise<void> {
try {
const toolResult = await skillManager.callTool('notion', 'get-user', { user_id: 'me' });
if (!toolResult || toolResult.isError || toolResult.content.length === 0) {