Email page (#561)

* email view

* render html emails

* match unread and read status

* move to accordian

* faster loads

* iframe mounted across toggle and cached height

* prefetch on hover

* fix iframe caching

* split inbox

* email processing agent

* summary

* rich text

* email drafts

* add pagination, watcher and separation from gmail sync

* fix first load issue

* handle drafts

* send button opens the thread

* simplify renderer and fix flickering issue

* remove rended driven email path

* support attachments in incoming emails

* fix white background as well as dark mode
This commit is contained in:
arkml 2026-05-18 21:46:26 +05:30 committed by GitHub
parent af618155e1
commit 7dcf8eea70
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 3139 additions and 72 deletions

View file

@ -88,12 +88,13 @@ export type CalendarBlock = z.infer<typeof CalendarBlockSchema>;
export const EmailBlockSchema = z.object({
threadId: z.string().optional(),
threadUrl: z.string().url().optional(),
summary: z.string().optional(),
subject: z.string().optional(),
from: z.string().optional(),
to: z.string().optional(),
date: z.string().optional(),
latest_email: z.string(),
latest_email: z.string().optional(),
past_summary: z.string().optional(),
draft_response: z.string().optional(),
response_mode: z.enum(['inline', 'assistant', 'both']).optional(),
@ -101,6 +102,42 @@ export const EmailBlockSchema = z.object({
export type EmailBlock = z.infer<typeof EmailBlockSchema>;
export const GmailAttachmentSchema = z.object({
filename: z.string(),
mimeType: z.string().optional(),
sizeBytes: z.number().int().nonnegative().optional(),
savedPath: z.string(),
});
export type GmailAttachment = z.infer<typeof GmailAttachmentSchema>;
export const GmailThreadMessageSchema = z.object({
id: z.string().optional(),
from: z.string().optional(),
to: z.string().optional(),
cc: z.string().optional(),
date: z.string().optional(),
subject: z.string().optional(),
body: z.string().optional(),
bodyHtml: z.string().optional(),
unread: z.boolean().optional(),
bodyHeight: z.number().int().positive().optional(),
attachments: z.array(GmailAttachmentSchema).optional(),
});
export type GmailThreadMessage = z.infer<typeof GmailThreadMessageSchema>;
export const GmailThreadSchema = EmailBlockSchema.extend({
threadId: z.string(),
threadUrl: z.string().url(),
unread: z.boolean().optional(),
importance: z.enum(['important', 'other']).optional(),
gmail_draft: z.string().optional(),
messages: z.array(GmailThreadMessageSchema),
});
export type GmailThread = z.infer<typeof GmailThreadSchema>;
export const EmailsBlockSchema = z.object({
title: z.string().optional(),
emails: z.array(EmailBlockSchema),

View file

@ -18,6 +18,7 @@ import { RowboatApiConfig } from './rowboat-account.js';
import { ZListToolkitsResponse } from './composio.js';
import { BrowserStateSchema } from './browser-control.js';
import { BillingInfoSchema } from './billing.js';
import { EmailBlockSchema, GmailThreadSchema } from './blocks.js';
// ============================================================================
// Runtime Validation Schemas (Single Source of Truth)
@ -123,6 +124,38 @@ const ipcSchemas = {
req: WorkspaceChangeEvent,
res: z.null(),
},
'gmail:getImportant': {
req: z.object({
cursor: z.string().optional(),
limit: z.number().int().min(1).max(100).optional(),
}),
res: z.object({
threads: z.array(GmailThreadSchema),
nextCursor: z.string().nullable(),
}),
},
'gmail:getEverythingElse': {
req: z.object({
cursor: z.string().optional(),
limit: z.number().int().min(1).max(100).optional(),
}),
res: z.object({
threads: z.array(GmailThreadSchema),
nextCursor: z.string().nullable(),
}),
},
'gmail:triggerSync': {
req: z.object({}),
res: z.object({}),
},
'gmail:saveMessageHeight': {
req: z.object({
threadId: z.string().min(1),
messageId: z.string().min(1),
height: z.number().int().positive(),
}),
res: z.object({}),
},
'mcp:listTools': {
req: z.object({
serverName: z.string(),