feat: Add Google Mail thread list item
This commit is contained in:
@@ -24,6 +24,7 @@ export function NotificationActions({ notification, detailsTarget, mutate }: Not
|
|||||||
return getNotificationHtmlUrl(notification);
|
return getNotificationHtmlUrl(notification);
|
||||||
}, [notification]);
|
}, [notification]);
|
||||||
|
|
||||||
|
console.log("notification_html_url", notification_html_url, notification);
|
||||||
return (
|
return (
|
||||||
<ActionPanel>
|
<ActionPanel>
|
||||||
<Action.OpenInBrowser url={notification_html_url} />
|
<Action.OpenInBrowser url={notification_html_url} />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import { GoogleMailNotificationListItem } from "./integrations/google-mail/listitem/GoogleMailNotificationListItem";
|
||||||
import { Action, ActionPanel, Detail, List, getPreferenceValues, openExtensionPreferences } from "@raycast/api";
|
import { Action, ActionPanel, Detail, List, getPreferenceValues, openExtensionPreferences } from "@raycast/api";
|
||||||
import { GoogleMailNotificationListItem } from "./integrations/google-mail/GoogleMailNotificationListItem";
|
|
||||||
import { GithubNotificationListItem } from "./integrations/github/listitem/GithubNotificationListItem";
|
import { GithubNotificationListItem } from "./integrations/github/listitem/GithubNotificationListItem";
|
||||||
import { LinearNotificationListItem } from "./integrations/linear/listitem/LinearNotificationListItem";
|
import { LinearNotificationListItem } from "./integrations/linear/listitem/LinearNotificationListItem";
|
||||||
import { TodoistNotificationListItem } from "./integrations/todoist/TodoistNotificationListItem";
|
import { TodoistNotificationListItem } from "./integrations/todoist/TodoistNotificationListItem";
|
||||||
|
|||||||
@@ -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}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
src/integrations/google-mail/types.ts
Normal file
27
src/integrations/google-mail/types.ts
Normal 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;
|
||||||
|
}
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
|
import { LinearWorkflowStateType, LinearIssueNotification, LinearWorkflowState } from "../types";
|
||||||
import { NotificationActions } from "../../../action/NotificationActions";
|
import { NotificationActions } from "../../../action/NotificationActions";
|
||||||
import { LinearIssuePreview } from "../preview/LinearIssuePreview";
|
import { LinearIssuePreview } from "../preview/LinearIssuePreview";
|
||||||
import { getLinearUserAccessory } from "../accessories";
|
import { getLinearUserAccessory } from "../accessories";
|
||||||
import { Notification } from "../../../notification";
|
import { Notification } from "../../../notification";
|
||||||
import { LinearIssueNotification } from "../types";
|
|
||||||
import { MutatePromise } from "@raycast/utils";
|
import { MutatePromise } from "@raycast/utils";
|
||||||
import { Page } from "../../../types";
|
import { Page } from "../../../types";
|
||||||
import { List } from "@raycast/api";
|
import { List } from "@raycast/api";
|
||||||
|
import { match } from "ts-pattern";
|
||||||
|
|
||||||
interface LinearIssueNotificationListItemProps {
|
interface LinearIssueNotificationListItemProps {
|
||||||
icon: string;
|
icon: string;
|
||||||
@@ -53,36 +54,18 @@ export function LinearIssueNotificationListItem({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getLinearIssueStateAccessory(state: LinearWorkflowState): List.Item.Accessory {
|
export function getLinearIssueStateAccessory(state: LinearWorkflowState): List.Item.Accessory {
|
||||||
switch (state.type) {
|
|
||||||
case "Triage":
|
|
||||||
return {
|
return {
|
||||||
icon: { source: "linear-issue-triage.svg", tintColor: state.color },
|
icon: {
|
||||||
tooltip: state.name,
|
source: match(state)
|
||||||
};
|
.with({ type: LinearWorkflowStateType.Triage }, () => "linear-issue-triage.svg")
|
||||||
case "Backlog":
|
.with({ type: LinearWorkflowStateType.Backlog }, () => "linear-issue-backlog.svg")
|
||||||
return {
|
.with({ type: LinearWorkflowStateType.Unstarted }, () => "linear-issue-unstarted.svg")
|
||||||
icon: { source: "linear-issue-backlog.svg", tintColor: state.color },
|
.with({ type: LinearWorkflowStateType.Started }, () => "linear-issue-started.svg")
|
||||||
tooltip: state.name,
|
.with({ type: LinearWorkflowStateType.Completed }, () => "linear-issue-completed.svg")
|
||||||
};
|
.with({ type: LinearWorkflowStateType.Canceled }, () => "linear-issue-canceled.svg")
|
||||||
case "Unstarted":
|
.exhaustive(),
|
||||||
return {
|
tintColor: state.color,
|
||||||
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,
|
tooltip: state.name,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export function LinearNotificationListItem({ notification, mutate }: Notificatio
|
|||||||
<LinearProjectNotificationListItem
|
<LinearProjectNotificationListItem
|
||||||
icon={icon}
|
icon={icon}
|
||||||
notification={notification}
|
notification={notification}
|
||||||
LinearProjectNotification={notification.metadata.content.content}
|
linearProjectNotification={notification.metadata.content.content}
|
||||||
mutate={mutate}
|
mutate={mutate}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export function LinearProjectNotificationListItem({
|
|||||||
<NotificationActions
|
<NotificationActions
|
||||||
notification={notification}
|
notification={notification}
|
||||||
detailsTarget={
|
detailsTarget={
|
||||||
<LinearProjectPreview notification={notification} linearProject={linearProjectNotification.issue} />
|
<LinearProjectPreview notification={notification} linearProject={linearProjectNotification.project} />
|
||||||
}
|
}
|
||||||
mutate={mutate}
|
mutate={mutate}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
export type LinearNotification =
|
||||||
|
| { type: "IssueNotification"; content: LinearIssueNotification }
|
||||||
|
| { type: "ProjectNotification"; content: LinearProjectNotification };
|
||||||
|
|
||||||
export interface LinearIssueNotification {
|
export interface LinearIssueNotification {
|
||||||
id: string;
|
id: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { GithubDiscussion, GithubPullRequest } from "./integrations/github/types";
|
import { GithubDiscussion, GithubPullRequest } from "./integrations/github/types";
|
||||||
|
import { GoogleMailThread } from "./integrations/google-mail/types";
|
||||||
|
import { LinearNotification } from "./integrations/linear/types";
|
||||||
import { MutatePromise } from "@raycast/utils";
|
import { MutatePromise } from "@raycast/utils";
|
||||||
import { match, P } from "ts-pattern";
|
import { match, P } from "ts-pattern";
|
||||||
import { Page } from "./types";
|
import { Page } from "./types";
|
||||||
@@ -18,11 +20,14 @@ export interface Notification {
|
|||||||
details?: NotificationDetails;
|
details?: NotificationDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NotificationMetadata = {
|
export type NotificationMetadata =
|
||||||
type: "Github" | "Linear" | "GoogleMail" | "Todoist";
|
| {
|
||||||
|
type: "Github" | "Todoist";
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
content: any;
|
content: any;
|
||||||
};
|
}
|
||||||
|
| { type: "Linear"; content: LinearNotification }
|
||||||
|
| { type: "GoogleMail"; content: GoogleMailThread };
|
||||||
|
|
||||||
export type NotificationDetails =
|
export type NotificationDetails =
|
||||||
| { type: "GithubPullRequest"; content: GithubPullRequest }
|
| { type: "GithubPullRequest"; content: GithubPullRequest }
|
||||||
@@ -43,8 +48,8 @@ export type NotificationListItemProps = {
|
|||||||
export function getNotificationHtmlUrl(notification: Notification) {
|
export function getNotificationHtmlUrl(notification: Notification) {
|
||||||
return match(notification)
|
return match(notification)
|
||||||
.with(
|
.with(
|
||||||
{ details: { type: P.union("GithubPullRequest", "GithubDiscussion") } },
|
{ details: { type: P.union("GithubPullRequest", "GithubDiscussion"), content: P.select() } },
|
||||||
() => notification.details.content.url,
|
(notificationDetails) => notificationDetails.url,
|
||||||
)
|
)
|
||||||
.with(
|
.with(
|
||||||
{ metadata: { type: "Linear", content: { type: "IssueNotification", content: P.select() } } },
|
{ metadata: { type: "Linear", content: { type: "IssueNotification", content: P.select() } } },
|
||||||
@@ -54,6 +59,13 @@ export function getNotificationHtmlUrl(notification: Notification) {
|
|||||||
{ metadata: { type: "Linear", content: { type: "ProjectNotification", content: P.select() } } },
|
{ metadata: { type: "Linear", content: { type: "ProjectNotification", content: P.select() } } },
|
||||||
(linearProjectNotification) => linearProjectNotification.project.url,
|
(linearProjectNotification) => linearProjectNotification.project.url,
|
||||||
)
|
)
|
||||||
|
.with(
|
||||||
|
{ metadata: { type: "GoogleMail", content: P.select() } },
|
||||||
|
(googleMailThread) =>
|
||||||
|
`https://mail.google.com/mail/u/${googleMailThread.user_email_address}/#inbox/${googleMailThread.id}`,
|
||||||
|
)
|
||||||
|
.with({ metadata: { type: "Todoist", content: P.select() } }, () => "")
|
||||||
|
.with({ metadata: { type: "Github" } }, () => "https://github.com")
|
||||||
.exhaustive();
|
.exhaustive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user