diff --git a/src/EmailArea.tsx b/src/EmailArea.tsx index b9c6254..3d3c049 100644 --- a/src/EmailArea.tsx +++ b/src/EmailArea.tsx @@ -4,7 +4,7 @@ import Stack from "react-bootstrap/Stack"; import { IAccount, IEmail, IMailbox } from "./client/types"; import Client from "./client/Client"; import EmailContent from "./EmailContent"; -import Mailbox from "./Mailbox"; +import EmailList from "./EmailList"; type EmailAreaProps = { account: IAccount | null; @@ -17,7 +17,7 @@ type EmailAreaProps = { const EmailArea: React.FC = (props) => { if (props.emailId === "") { return ( - = (props) => { } else { return ( - = ({ accountId, id, name }) => { + const href = "#" + accountId + "/" + id; -class Mailbox extends React.Component { - componentDidUpdate() { - if (this.props.account == null) return; - if (this.props.client == null) return; - if (this.props.mailbox == null) return; - this.props.client.ensureMailbox( - this.props.account.id, - this.props.mailbox.id, - ); - } - - render() { - return ( - - ); - } -} + return ( + + {name} + + ); +}; export default Mailbox; diff --git a/src/MailboxList.tsx b/src/MailboxList.tsx index 8d8e847..3bbe6a6 100644 --- a/src/MailboxList.tsx +++ b/src/MailboxList.tsx @@ -3,7 +3,7 @@ import Stack from "react-bootstrap/Stack"; import Client from "./client/Client"; import { IAccount } from "./client/types"; -import MailboxSummary from "./MailboxSummary"; +import Mailbox from "./Mailbox"; type MailboxListProps = { account: IAccount | null; @@ -25,8 +25,8 @@ class MailboxList extends React.Component { ) : ( - {Object.values(this.props.account.mailboxes).map((m) => ( - ( + = ({ accountId, id, name }) => { - const href = "#" + accountId + "/" + id; - - return ( - - {name} - - ); -}; - -export default Mailbox; diff --git a/src/client/Client.tsx b/src/client/Client.tsx index 9f35f35..e67bd71 100644 --- a/src/client/Client.tsx +++ b/src/client/Client.tsx @@ -13,7 +13,6 @@ import { IEmailStub, IMailbox, ISession, - MailboxIdMap, MailboxRole, PushMessage, } from "./types"; @@ -26,7 +25,6 @@ export interface IAuth { } export interface ClientState { - emailState: string | null; inFlight: { emailContents: Set; emailStubs: Set; @@ -35,9 +33,7 @@ export interface ClientState { mailboxes: { trash: IMailbox; } | null; - mailboxState: string | null; session: ISession | null; - threadState: string | null; } class Account implements IAccount { @@ -46,7 +42,7 @@ class Account implements IAccount { accountCapabilities: { [key: string]: jmaptypes.IMailCapabilities }; isPersonal: boolean; isReadOnly: boolean; - mailboxes: MailboxIdMap | null; + mailboxes: Array | null; name: string; constructor(id: string, props: jmaptypes.IAccount) { @@ -59,9 +55,10 @@ class Account implements IAccount { } mailboxByRole(role: MailboxRole): IMailbox | null { if (this.mailboxes === null) return null; - for (const mailbox of Object.values(this.mailboxes)) { - if (mailbox.role === role) { - return mailbox; + for (let i = 0; i < this.mailboxes.length; i++) { + const m = this.mailboxes[i]; + if (m.role === role) { + return m; } } return null; @@ -72,16 +69,13 @@ export default class Client { callbacks: Array = []; jclient: jmapclient.Client | null = null; state: ClientState = { - emailState: null, inFlight: { emailContents: new Set(), emailStubs: new Set(), mailboxes: new Set(), }, mailboxes: null, - mailboxState: null, session: null, - threadState: null, }; // Get the currently active account @@ -180,14 +174,6 @@ export default class Client { this.doLogin(auth); } - // Ensure we have the full email content - ensureMailbox(accountId: string, mailboxId: string) { - if (this.state.session == null) return; - const existing = this.state.session.mailboxes[mailboxId]; - if (existing != null) return; - this.mailboxList(accountId, [mailboxId]); - } - email(emailId: string): IEmail | null { if (this.state.session == null) return null; const result = this.state.session.emails[emailId]; @@ -261,10 +247,8 @@ export default class Client { receivedAt: e.receivedAt, subject: e.subject, }; + this._triggerChange(msg + e.id); }); - this._triggerChange(msg); - //this.state.session.state = response.sessionState; - this.state.emailState = response.state; }) .catch((x) => { console.error("Failed to get email stub", emailId, x); @@ -311,39 +295,12 @@ export default class Client { if (this.state.session == null) return null; const account = this.state.session.accounts[accountId]; if (account.mailboxes == null) return null; - const mailbox = account.mailboxes[mailboxId]; - return mailbox; - } - mailboxGet(accountId: string, id: string) { - if (this.jclient == null) return; - if (this.state.session == null) return; - // TODO: do this in a single request with 2 queries when the client can handle it. - this.jclient - .mailbox_get({ - accountId: accountId, - ids: [id], - }) - .then((response) => { - if (this.state.session == null) return; - const account = this.state.session.accounts[response.accountId]; - if (response.list.length !== 1) { - console.error( - "Should only get 1 mailbox in mailboxGet. Got ", - response.list, - ); - return; - } - const m = response.list[0]; - if (account.mailboxes === null) { - account.mailboxes = {}; - } - account.mailboxes[m.id] = { - ...m, - emailIds: null, - }; - this.state.mailboxState = response.state; - this.emailList(accountId, id, []); - }); + for (let i = 0; i < account.mailboxes.length; i++) { + if (account.mailboxes[i].id === mailboxId) { + return account.mailboxes[i]; + } + } + return null; } mailboxList(accountId: string, ids: Array) { if (this.jclient == null) return; @@ -358,18 +315,14 @@ export default class Client { .then((response) => { if (this.state.session == null) return; const account = this.state.session.accounts[response.accountId]; - const mailboxes: MailboxIdMap = {}; + const mailboxes: Array = []; response.list.forEach((m) => { - // If we already have a mailbox with emails then don't throw that data away - const existing = - account.mailboxes === null ? null : account.mailboxes[m.id]; - mailboxes[m.id] = { + mailboxes.push({ ...m, - emailIds: existing === null ? null : existing.emailIds, - }; + emailIds: null, + }); }); account.mailboxes = mailboxes; - this.state.mailboxState = response.state; this._triggerChange("Mailboxes " + accountId); }); } @@ -384,70 +337,13 @@ export default class Client { c(); }); } - _onChangedEmail(accountId: string, state: string) { - console.log("Email changed", state); - if (this.jclient === null) return; - if (this.state.session === null) return; - const account = this.account(accountId); - if (account === null) return; - if (this.state.emailState === null) return; - const args = { - accountId: accountId, - sinceState: this.state.emailState, - }; - this.jclient.email_changes(args).then((r) => { - console.log("Handle email changes ", r); - }); - } - _onChangedMailbox(accountId: string, state: string) { - console.log("Mailbox changed", state); - if (this.jclient === null) return; - if (this.state.session === null) return; - const account = this.account(accountId); - if (account === null) return; - if (this.state.mailboxState === null) return; - const args = { - accountId: accountId, - sinceState: this.state.mailboxState, - }; - this.jclient.mailbox_changes(args).then((response) => { - console.log("Handle mailbox changes ", response); - for (let i = 0; i < response.created.length; i++) { - const mailboxId = response.created[i]; - this.mailboxGet(accountId, mailboxId); - } - for (let i = 0; i < response.updated.length; i++) { - const mailboxId = response.updated[i]; - this.mailboxGet(accountId, mailboxId); - } - if (this.state.session === null) return; - for (let i = 0; i < response.destroyed.length; i++) { - const mailboxId = response.destroyed[i]; - delete this.state.session.mailboxes[mailboxId]; - } - }); - } - _onChangedThread(accountId: string, state: string) { - console.log("Thread changed", state); - if (this.jclient === null) return; - if (this.state.session === null) return; - const account = this.account(accountId); - if (account === null) return; - if (this.state.threadState === null) return; - const args = { - accountId: accountId, - sinceState: this.state.threadState, - }; - this.jclient.thread_changes(args).then((r) => { - console.log("Handle thread changes ", r); - }); - } _onSession() { + console.log("Session received"); + // For the type checker if (!this.jclient) return; const session = this.jclient.getSession(); - console.log("Session received: ", session); // Subscribe to server-pushed events if (session.eventSourceUrl) { this._subscribeToEventSource(session.eventSourceUrl); @@ -462,7 +358,6 @@ export default class Client { ), emails: {}, emailStubs: {}, - mailboxes: {}, }; if (!this.state.session) return; this._triggerChange("Session"); @@ -478,28 +373,7 @@ export default class Client { this.jclient.subscribeToEvents( eventSourceUrl, (type: string, message: PushMessage) => { - if (type === "ping") { - return; - } - if (type === "state") { - console.log("Got an event!", type, message); - const stateChange = message as jmaptypes.IStateChange; - for (const [accountId, changes] of Object.entries( - stateChange.changed, - )) { - for (const [changeType, state] of Object.entries(changes)) { - if (changeType === "Email") { - this._onChangedEmail(accountId, state); - } else if (changeType === "Mailbox") { - this._onChangedMailbox(accountId, state); - } else if (changeType === "Thread") { - this._onChangedThread(accountId, state); - } - } - } - } else { - console.log("Not sure what to do with event", type); - } + console.log("Got an event!", type, message); }, ); } diff --git a/src/client/jmap-client-ts b/src/client/jmap-client-ts index ee2af71..5cf6129 160000 --- a/src/client/jmap-client-ts +++ b/src/client/jmap-client-ts @@ -1 +1 @@ -Subproject commit ee2af71a8e764c1a8153a7dcd71f4085f970243f +Subproject commit 5cf6129a517224b90f79cb96f212d57c5bceb51f diff --git a/src/client/types.tsx b/src/client/types.tsx index 1b0e56f..a251cd0 100644 --- a/src/client/types.tsx +++ b/src/client/types.tsx @@ -1,10 +1,10 @@ import * as client from "./jmap-client-ts/src/types"; -export type MailboxIdMapPresence = { [mailboxId: string]: boolean }; +export type MailboxIdMap = { [mailboxId: string]: boolean }; export interface IEmailStub { from: Array; id: string; - mailboxIds: MailboxIdMapPresence; + mailboxIds: MailboxIdMap; receivedAt: string; subject: string; } @@ -12,7 +12,6 @@ export interface IEmailStub { export interface IMailbox extends client.IMailboxProperties { emailIds: Array | null; } -export type MailboxIdMap = { [mailboxId: string]: IMailbox }; export interface IEmail extends client.IEmailProperties { //sentAt: IutcDate|null, @@ -20,7 +19,7 @@ export interface IEmail extends client.IEmailProperties { export interface IAccount extends client.IAccount { id: string; - mailboxes: MailboxIdMap | null; + mailboxes: Array | null; mailboxByRole(role: MailboxRole): IMailbox | null; } @@ -43,5 +42,4 @@ export interface ISession extends client.ISession { accounts: AccountIdMap; emails: EmailIdMap; emailStubs: EmailStubIdMap; - mailboxes: MailboxIdMap; }