feat: Add Google Mail thread list item

This commit is contained in:
2024-01-26 22:50:13 +01:00
parent 3df827ebd7
commit e0f90b0c42
12 changed files with 185 additions and 72 deletions

View File

@@ -1,29 +0,0 @@
import { NotificationActions } from "../../action/NotificationActions";
import { NotificationListItemProps } from "../../notification";
import { Detail, List, environment } from "@raycast/api";
import { useMemo } from "react";
export function GoogleMailNotificationListItem({ notification, mutate }: NotificationListItemProps) {
const icon = useMemo(() => {
if (environment.appearance === "dark") {
return "google-mail-logo-light.svg";
}
return "google-mail-logo-dark.svg";
}, [environment]);
return (
<List.Item
key={notification.id}
title={notification.title}
icon={icon}
subtitle={`#${notification.source_id}`}
actions={
<NotificationActions
notification={notification}
detailsTarget={<Detail markdown="# To be implemented 👋" />}
mutate={mutate}
/>
}
/>
);
}

View File

@@ -0,0 +1,24 @@
import { GoogleMailThreadListItem } from "./GoogleMailThreadListItem";
import { NotificationListItemProps } from "../../../notification";
import { environment } from "@raycast/api";
import { useMemo } from "react";
export function GoogleMailNotificationListItem({ notification, mutate }: NotificationListItemProps) {
const icon = useMemo(() => {
if (environment.appearance === "dark") {
return "google-mail-logo-light.svg";
}
return "google-mail-logo-dark.svg";
}, [environment]);
if (notification.metadata.type !== "GoogleMail") return null;
return (
<GoogleMailThreadListItem
icon={icon}
notification={notification}
googleMailThread={notification.metadata.content}
mutate={mutate}
/>
);
}

View File

@@ -0,0 +1,65 @@
import { GoogleMailThreadPreview } from "../preview/GoogleMailThreadPreview";
import { NotificationActions } from "../../../action/NotificationActions";
//import { getLinearUserAccessory } from "../accessories";
import { Notification } from "../../../notification";
import { Icon, Color, List } from "@raycast/api";
import { MutatePromise } from "@raycast/utils";
import { GoogleMailThread } from "../types";
import { Page } from "../../../types";
interface GoogleMailThreadListItemProps {
icon: string;
notification: Notification;
googleMailThread: GoogleMailThread;
mutate: MutatePromise<Page<Notification> | undefined>;
}
export function GoogleMailThreadListItem({
icon,
notification,
googleMailThread,
mutate,
}: GoogleMailThreadListItemProps) {
const isStarred = googleMailThread.messages.some((message) => message.labelIds?.includes("STARRED"));
const isImportant = googleMailThread.messages.some((message) => message.labelIds?.includes("IMPORTANT"));
const fromAddress = googleMailThread.messages[0].payload.headers.find((header) => header.name === "From")?.value;
const subtitle = fromAddress;
const accessories: List.Item.Accessory[] = [
{
date: new Date(notification.updated_at),
tooltip: `Updated at ${notification.updated_at}`,
},
];
if (isStarred) {
accessories.unshift({
icon: { source: Icon.Star, tintColor: Color.Yellow },
tooltip: "Starred",
});
}
if (isImportant) {
accessories.unshift({
icon: { source: Icon.Exclamationmark, tintColor: Color.Red },
tooltip: "Important",
});
}
return (
<List.Item
key={notification.id}
title={notification.title}
icon={icon}
accessories={accessories}
subtitle={subtitle}
actions={
<NotificationActions
notification={notification}
detailsTarget={<GoogleMailThreadPreview notification={notification} googleMailThread={googleMailThread} />}
mutate={mutate}
/>
}
/>
);
}

View File

@@ -0,0 +1,26 @@
import { Notification, getNotificationHtmlUrl } from "../../../notification";
import { Detail, ActionPanel, Action } from "@raycast/api";
import { GoogleMailThread } from "../types";
import { useMemo } from "react";
interface GoogleMailThreadPreviewProps {
notification: Notification;
googleMailThread: GoogleMailThread;
}
export function GoogleMailThreadPreview({ notification }: GoogleMailThreadPreviewProps) {
const notification_html_url = useMemo(() => {
return getNotificationHtmlUrl(notification);
}, [notification]);
return (
<Detail
markdown={`# ${notification.title}`}
actions={
<ActionPanel>
<Action.OpenInBrowser url={notification_html_url} />
</ActionPanel>
}
/>
);
}

View File

@@ -0,0 +1,27 @@
export interface GoogleMailThread {
id: string;
user_email_address: string;
history_id: string;
messages: Array<GoogleMailMessage>;
}
export interface GoogleMailMessage {
id: string;
threadId: string;
labelIds?: Array<string>;
snippet: string;
payload: GoogleMailMessagePayload;
sizeEstimate: number;
historyId: string;
internalDate: Date;
}
export interface GoogleMailMessagePayload {
mimeType: string;
headers: Array<GoogleMailMessageHeader>;
}
export interface GoogleMailMessageHeader {
name: string;
value: string;
}

View File

@@ -1,11 +1,12 @@
import { LinearWorkflowStateType, LinearIssueNotification, LinearWorkflowState } from "../types";
import { NotificationActions } from "../../../action/NotificationActions";
import { LinearIssuePreview } from "../preview/LinearIssuePreview";
import { getLinearUserAccessory } from "../accessories";
import { Notification } from "../../../notification";
import { LinearIssueNotification } from "../types";
import { MutatePromise } from "@raycast/utils";
import { Page } from "../../../types";
import { List } from "@raycast/api";
import { match } from "ts-pattern";
interface LinearIssueNotificationListItemProps {
icon: string;
@@ -53,36 +54,18 @@ export function LinearIssueNotificationListItem({
}
export function getLinearIssueStateAccessory(state: LinearWorkflowState): List.Item.Accessory {
switch (state.type) {
case "Triage":
return {
icon: { source: "linear-issue-triage.svg", tintColor: state.color },
tooltip: state.name,
};
case "Backlog":
return {
icon: { source: "linear-issue-backlog.svg", tintColor: state.color },
tooltip: state.name,
};
case "Unstarted":
return {
icon: { source: "linear-issue-unstarted.svg", tintColor: state.color },
tooltip: state.name,
};
case "Started":
return {
icon: { source: "linear-issue-started.svg", tintColor: state.color },
tooltip: state.name,
};
case "Completed":
return {
icon: { source: "linear-issue-completed.svg", tintColor: state.color },
tooltip: state.name,
};
case "Canceled":
return {
icon: { source: "linear-issue-canceled.svg", tintColor: state.color },
tooltip: state.name,
};
}
return {
icon: {
source: match(state)
.with({ type: LinearWorkflowStateType.Triage }, () => "linear-issue-triage.svg")
.with({ type: LinearWorkflowStateType.Backlog }, () => "linear-issue-backlog.svg")
.with({ type: LinearWorkflowStateType.Unstarted }, () => "linear-issue-unstarted.svg")
.with({ type: LinearWorkflowStateType.Started }, () => "linear-issue-started.svg")
.with({ type: LinearWorkflowStateType.Completed }, () => "linear-issue-completed.svg")
.with({ type: LinearWorkflowStateType.Canceled }, () => "linear-issue-canceled.svg")
.exhaustive(),
tintColor: state.color,
},
tooltip: state.name,
};
}

View File

@@ -29,7 +29,7 @@ export function LinearNotificationListItem({ notification, mutate }: Notificatio
<LinearProjectNotificationListItem
icon={icon}
notification={notification}
LinearProjectNotification={notification.metadata.content.content}
linearProjectNotification={notification.metadata.content.content}
mutate={mutate}
/>
);

View File

@@ -43,7 +43,7 @@ export function LinearProjectNotificationListItem({
<NotificationActions
notification={notification}
detailsTarget={
<LinearProjectPreview notification={notification} linearProject={linearProjectNotification.issue} />
<LinearProjectPreview notification={notification} linearProject={linearProjectNotification.project} />
}
mutate={mutate}
/>

View File

@@ -1,3 +1,7 @@
export type LinearNotification =
| { type: "IssueNotification"; content: LinearIssueNotification }
| { type: "ProjectNotification"; content: LinearProjectNotification };
export interface LinearIssueNotification {
id: string;
type: string;