Show email subject lines.
This includes a bunch of new things. I've introduced "ensureEmail..." to indicate that the UI would like some data to be populated, but if it is already present we don't need to do anything. I've also introduced a cache for emails that is keyed on the email ID. I don't know if email IDs are unique. They look like they should be globally unique within a given server, but I'm not sure and the standard is unclear. It'll need some experimentation.
This commit is contained in:
parent
5c7e67a2bd
commit
a34d8f53b3
|
@ -3,6 +3,7 @@ import Stack from "react-bootstrap/Stack";
|
|||
|
||||
import Client from "./client/Client";
|
||||
import { IAccount, IMailbox } from "./client/types";
|
||||
import EmailSummary from "./EmailSummary";
|
||||
|
||||
type EmailListProps = {
|
||||
account: IAccount | null;
|
||||
|
@ -17,37 +18,31 @@ class EmailList extends React.Component<EmailListProps, EmailListState> {
|
|||
if (this.props.account == null) return;
|
||||
if (this.props.client == null) return;
|
||||
if (this.props.mailbox == null) return;
|
||||
this.props.client.emailList(
|
||||
this.props.client.ensureEmailList(
|
||||
this.props.account.id,
|
||||
this.props.mailbox.id,
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (
|
||||
this.props.account == null ||
|
||||
this.props.client == null ||
|
||||
this.props.mailbox == null ||
|
||||
this.props.mailbox.emailIds == null
|
||||
) {
|
||||
return <Stack />;
|
||||
} else if (this.props.mailbox.emails == null) {
|
||||
return (
|
||||
<Stack>
|
||||
{this.props.mailbox.emailIds.map((e) => (
|
||||
<div className="p-2" key={e}>
|
||||
Email {e}
|
||||
</div>
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Stack>
|
||||
{this.props.mailbox.emails.map((m) => (
|
||||
<div className="p-2" key={m.id}>
|
||||
{m.subject}
|
||||
</div>
|
||||
{this.props.mailbox.emailIds.slice(0, 5).map((e) => (
|
||||
<EmailSummary
|
||||
account={this.props.account}
|
||||
client={this.props.client}
|
||||
emailId={e}
|
||||
email={this.props.client!.email(e)}
|
||||
key={e}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import React from "react";
|
||||
import Client from "./client/Client";
|
||||
import { IAccount, IEmail } from "./client/types";
|
||||
|
||||
type EmailSummaryProps = {
|
||||
account: IAccount | null;
|
||||
client: Client | null;
|
||||
email: IEmail | null;
|
||||
emailId: string;
|
||||
};
|
||||
type EmailSummaryState = {};
|
||||
|
||||
class EmailSummary extends React.Component<
|
||||
EmailSummaryProps,
|
||||
EmailSummaryState
|
||||
> {
|
||||
componentDidMount() {
|
||||
this.ensureData();
|
||||
}
|
||||
componentDidUpdate() {
|
||||
this.ensureData();
|
||||
}
|
||||
|
||||
ensureData() {
|
||||
if (this.props.account == null) return;
|
||||
if (this.props.client == null) return;
|
||||
this.props.client.ensureEmailGet(this.props.account.id, this.props.emailId);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="p-2" key={this.props.emailId}>
|
||||
{this.props.email != null
|
||||
? this.props.email.subject
|
||||
: this.props.emailId}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default EmailSummary;
|
|
@ -6,7 +6,7 @@ import * as base64 from "base-64";
|
|||
import * as jmapclient from "jmap-client-ts";
|
||||
import { FetchTransport } from "jmap-client-ts/lib/utils/fetch-transport";
|
||||
|
||||
import { IAccount, IMailbox, ISession } from "./types";
|
||||
import { IAccount, IEmail, IMailbox, ISession } from "./types";
|
||||
|
||||
type Callback = () => void;
|
||||
|
||||
|
@ -36,11 +36,27 @@ export default class Client {
|
|||
this.callbacks.push(f);
|
||||
}
|
||||
|
||||
// Ensure we have the fully-fleshed email
|
||||
ensureEmailGet(accountId: string, emailId: string) {
|
||||
if (this.state.session == null) return;
|
||||
const existing = this.state.session.emails[emailId];
|
||||
if (existing != null) return;
|
||||
this.emailGet(accountId, emailId);
|
||||
}
|
||||
|
||||
// Ensure we have the list of emails for the provided account and mailbox
|
||||
ensureEmailList(accountId: string, mailboxId: string) {
|
||||
const mailbox = this.mailbox(accountId, mailboxId);
|
||||
if (mailbox != null && mailbox.emailIds != null) return;
|
||||
this.emailList(accountId, mailboxId, []);
|
||||
}
|
||||
|
||||
// Ensure that login happens. If this is called many times, only login once.
|
||||
ensureLogin(auth: IAuth) {
|
||||
if (this.jclient != null) return;
|
||||
this.doLogin(auth);
|
||||
}
|
||||
|
||||
// Make the request to get system metadata
|
||||
doLogin(auth: IAuth) {
|
||||
const domain = auth.email.split("@")[1];
|
||||
|
@ -65,13 +81,41 @@ export default class Client {
|
|||
return;
|
||||
}
|
||||
|
||||
email(emailId: string): IEmail | null {
|
||||
if (this.state.session == null) return null;
|
||||
return this.state.session.emails[emailId];
|
||||
}
|
||||
|
||||
emailGet(accountId: string, emailId: string) {
|
||||
if (this.jclient == null) return;
|
||||
|
||||
this.jclient
|
||||
.email_get({
|
||||
accountId: accountId,
|
||||
ids: [emailId],
|
||||
properties: ["mailboxIds", "subject"],
|
||||
})
|
||||
.then((response) => {
|
||||
console.log("Email response", response);
|
||||
response.list.forEach((e) => {
|
||||
if (this.state.session == null) return;
|
||||
const existing = this.state.session.emails[e.id];
|
||||
if (existing !== undefined && existing.subject !== e.subject) {
|
||||
console.error(
|
||||
"Expectations violation: email ID is not unique within the server!",
|
||||
);
|
||||
}
|
||||
this.state.session.emails[e.id] = e;
|
||||
this._triggerChange();
|
||||
});
|
||||
})
|
||||
.catch((x) => {
|
||||
console.error("Failed to get email", emailId, x);
|
||||
});
|
||||
}
|
||||
|
||||
emailList(accountId: string, mailboxId: string, ids: Array<string>) {
|
||||
if (this.jclient == null) return;
|
||||
/*this.jclient.email_get({
|
||||
accountId: accountId,
|
||||
ids: [],
|
||||
properties: ["threadId"]
|
||||
});*/
|
||||
this.jclient
|
||||
.email_query({
|
||||
accountId: accountId,
|
||||
|
@ -84,7 +128,7 @@ export default class Client {
|
|||
this._triggerChange();
|
||||
})
|
||||
.catch(() => {
|
||||
console.error("OH NOES");
|
||||
console.error("Failed to get email list from mailbox", mailboxId);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -145,6 +189,7 @@ export default class Client {
|
|||
{ ...account, id: key.toString(), mailboxes: null },
|
||||
]),
|
||||
),
|
||||
emails: {},
|
||||
};
|
||||
if (!this.state.session) return;
|
||||
this._triggerChange();
|
||||
|
|
|
@ -5,13 +5,17 @@ export interface IMailbox extends client.IMailboxProperties {
|
|||
emails: Array<client.IEmailProperties> | null;
|
||||
}
|
||||
|
||||
export interface IEmail extends client.IEmailProperties {}
|
||||
|
||||
export interface IAccount extends client.IAccount {
|
||||
id: string;
|
||||
mailboxes: Array<IMailbox> | null;
|
||||
}
|
||||
|
||||
export type AccountIdMap = { [accountId: string]: IAccount };
|
||||
export type EmailIdMap = { [emailId: string]: IEmail };
|
||||
|
||||
export interface ISession extends client.ISession {
|
||||
accounts: AccountIdMap;
|
||||
emails: EmailIdMap;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue