feat: Add Linear notification list item
This commit is contained in:
1
assets/linear-issue-backlog.svg
Normal file
1
assets/linear-issue-backlog.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="14" height="14" viewBox="0 0 14 14" aria-label="Backlog" fill="#D2D3E0"><path d="M13.9408 7.91426L11.9576 7.65557C11.9855 7.4419 12 7.22314 12 7C12 6.77686 11.9855 6.5581 11.9576 6.34443L13.9408 6.08573C13.9799 6.38496 14 6.69013 14 7C14 7.30987 13.9799 7.61504 13.9408 7.91426ZM13.4688 4.32049C13.2328 3.7514 12.9239 3.22019 12.5538 2.73851L10.968 3.95716C11.2328 4.30185 11.4533 4.68119 11.6214 5.08659L13.4688 4.32049ZM11.2615 1.4462L10.0428 3.03204C9.69815 2.76716 9.31881 2.54673 8.91341 2.37862L9.67951 0.531163C10.2486 0.767153 10.7798 1.07605 11.2615 1.4462ZM7.91426 0.0591659L7.65557 2.04237C7.4419 2.01449 7.22314 2 7 2C6.77686 2 6.5581 2.01449 6.34443 2.04237L6.08574 0.059166C6.38496 0.0201343 6.69013 0 7 0C7.30987 0 7.61504 0.0201343 7.91426 0.0591659ZM4.32049 0.531164L5.08659 2.37862C4.68119 2.54673 4.30185 2.76716 3.95716 3.03204L2.73851 1.4462C3.22019 1.07605 3.7514 0.767153 4.32049 0.531164ZM1.4462 2.73851L3.03204 3.95716C2.76716 4.30185 2.54673 4.68119 2.37862 5.08659L0.531164 4.32049C0.767153 3.7514 1.07605 3.22019 1.4462 2.73851ZM0.0591659 6.08574C0.0201343 6.38496 0 6.69013 0 7C0 7.30987 0.0201343 7.61504 0.059166 7.91426L2.04237 7.65557C2.01449 7.4419 2 7.22314 2 7C2 6.77686 2.01449 6.5581 2.04237 6.34443L0.0591659 6.08574ZM0.531164 9.67951L2.37862 8.91341C2.54673 9.31881 2.76716 9.69815 3.03204 10.0428L1.4462 11.2615C1.07605 10.7798 0.767153 10.2486 0.531164 9.67951ZM2.73851 12.5538L3.95716 10.968C4.30185 11.2328 4.68119 11.4533 5.08659 11.6214L4.32049 13.4688C3.7514 13.2328 3.22019 12.9239 2.73851 12.5538ZM6.08574 13.9408L6.34443 11.9576C6.5581 11.9855 6.77686 12 7 12C7.22314 12 7.4419 11.9855 7.65557 11.9576L7.91427 13.9408C7.61504 13.9799 7.30987 14 7 14C6.69013 14 6.38496 13.9799 6.08574 13.9408ZM9.67951 13.4688L8.91341 11.6214C9.31881 11.4533 9.69815 11.2328 10.0428 10.968L11.2615 12.5538C10.7798 12.9239 10.2486 13.2328 9.67951 13.4688ZM12.5538 11.2615L10.968 10.0428C11.2328 9.69815 11.4533 9.31881 11.6214 8.91341L13.4688 9.67951C13.2328 10.2486 12.924 10.7798 12.5538 11.2615Z" stroke="none"></path></svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
1
assets/linear-issue-canceled.svg
Normal file
1
assets/linear-issue-canceled.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="14" height="14" fill="none"><circle cx="7" cy="7" r="6" fill="none" stroke="#95a2b3" stroke-width="2" stroke-dasharray="3.14 0" stroke-dashoffset="-0.7"></circle><circle class="progress" cx="7" cy="7" r="3" fill="none" stroke="#95a2b3" rotate="20" stroke-width="6" stroke-dasharray="18.84955592153876 100" transform="rotate(-90 7 7)"></circle><path class="icon" stroke="none" d="M4.21967 4.21967C4.51256 3.92678 4.98743 3.92678 5.28032 4.21967L6.26516 5.2045L7.25 6.18934L9.21966 4.21967C9.51255 3.92678 9.98743 3.92678 10.2803 4.21967C10.5732 4.51256 10.5732 4.98744 10.2803 5.28033L8.31065 7.25L10.2803 9.21967C10.5732 9.51257 10.5732 9.98744 10.2803 10.2803C9.98743 10.5732 9.51255 10.5732 9.21966 10.2803L7.25 8.31066L5.28032 10.2803C4.98743 10.5732 4.51256 10.5732 4.21967 10.2803C3.92678 9.98744 3.92678 9.51257 4.21967 9.21967L5.2045 8.23484L6.18934 7.25L4.21967 5.28033C3.92678 4.98744 3.92678 4.51256 4.21967 4.21967Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 954 B |
1
assets/linear-issue-completed.svg
Normal file
1
assets/linear-issue-completed.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="14" height="14" viewBox="0 0 14 14" aria-label="Done" fill="#5e6ad2"><path fill-rule="evenodd" clip-rule="evenodd" d="M7 0C3.13401 0 0 3.13401 0 7C0 10.866 3.13401 14 7 14C10.866 14 14 10.866 14 7C14 3.13401 10.866 0 7 0ZM11.101 5.10104C11.433 4.76909 11.433 4.23091 11.101 3.89896C10.7691 3.56701 10.2309 3.56701 9.89896 3.89896L5.5 8.29792L4.10104 6.89896C3.7691 6.56701 3.2309 6.56701 2.89896 6.89896C2.56701 7.2309 2.56701 7.7691 2.89896 8.10104L4.89896 10.101C5.2309 10.433 5.7691 10.433 6.10104 10.101L11.101 5.10104Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 551 B |
1
assets/linear-issue-started.svg
Normal file
1
assets/linear-issue-started.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="1" y="1" width="12" height="12" rx="6" stroke="#F2C94C" stroke-width="2" fill="none"></rect><path fill="#F2C94C" stroke="none" d="M 3.5,3.5 L3.5,0 A3.5,3.5 0 1,1 0, 3.5 z" transform="translate(3.5,3.5)"></path></svg>
|
||||||
|
After Width: | Height: | Size: 286 B |
1
assets/linear-issue-triage.svg
Normal file
1
assets/linear-issue-triage.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="14" height="14" fill="none"><circle cx="7" cy="7" r="3.5" fill="none" stroke="#fc7839" stroke-width="7" stroke-dasharray="2 0" stroke-dashoffset="3.2"></circle><circle class="progress" cx="6" cy="7" r="2" fill="none" stroke="#fc7840" rotate="20" stroke-width="4" stroke-dasharray="0 100" transform="rotate(-90 7 7)"></circle><path class="icon" stroke="none" d="M8.0126 7.98223V9.50781C8.0126 9.92901 8.52329 10.1548 8.85102 9.87854L11.8258 7.37066C12.0581 7.17486 12.0581 6.82507 11.8258 6.62927L8.85102 4.12139C8.52329 3.84509 8.0126 4.07092 8.0126 4.49212V6.01763H5.98739V4.49218C5.98739 4.07098 5.4767 3.84515 5.14897 4.12146L2.17419 6.62933C1.94194 6.82513 1.94194 7.17492 2.17419 7.37072L5.14897 9.8786C5.4767 10.1549 5.98739 9.92907 5.98739 9.50787V7.98223H8.0126Z"></path></svg>
|
||||||
|
After Width: | Height: | Size: 798 B |
1
assets/linear-issue-unstarted.svg
Normal file
1
assets/linear-issue-unstarted.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><rect x="1" y="1" width="12" height="12" rx="6" stroke="#858699" stroke-width="2" fill="none"></rect><path fill="#858699" stroke="none" d="M 3.5,3.5 L3.5,0 A3.5,3.5 0 0,1 3.5, 0 z" transform="translate(3.5,3.5)"></path></svg>
|
||||||
|
After Width: | Height: | Size: 286 B |
@@ -1,8 +1,8 @@
|
|||||||
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 { 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 { TodoistNotificationListItem } from "./integrations/todoist/TodoistNotificationListItem";
|
import { TodoistNotificationListItem } from "./integrations/todoist/TodoistNotificationListItem";
|
||||||
import { LinearNotificationListItem } from "./integrations/linear/LinearNotificationListItem";
|
|
||||||
import { Notification, NotificationListItemProps } from "./notification";
|
import { Notification, NotificationListItemProps } from "./notification";
|
||||||
import { NotificationActions } from "./action/NotificationActions";
|
import { NotificationActions } from "./action/NotificationActions";
|
||||||
import { Page, UniversalInboxPreferences } from "./types";
|
import { Page, UniversalInboxPreferences } from "./types";
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ function getGithubPullRequestChecksAccessory(latestCommit: GithubCommitChecks):
|
|||||||
case GithubCheckStatusState.Pending:
|
case GithubCheckStatusState.Pending:
|
||||||
return { icon: Icon.Pause, tooltip: "Pending" };
|
return { icon: Icon.Pause, tooltip: "Pending" };
|
||||||
case GithubCheckStatusState.InProgress:
|
case GithubCheckStatusState.InProgress:
|
||||||
return { icon: Icon.Pause, tooltip: "In progress" }; // TODO Spinner
|
return { icon: Icon.CircleProgress, tooltip: "In progress" };
|
||||||
case GithubCheckStatusState.Completed:
|
case GithubCheckStatusState.Completed:
|
||||||
switch (progress.conclusion()) {
|
switch (progress.conclusion()) {
|
||||||
case GithubCheckConclusionState.Success:
|
case GithubCheckConclusionState.Success:
|
||||||
|
|||||||
@@ -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 LinearNotificationListItem({ notification, mutate }: NotificationListItemProps) {
|
|
||||||
const icon = useMemo(() => {
|
|
||||||
if (environment.appearance === "dark") {
|
|
||||||
return "linear-logo-light.svg";
|
|
||||||
}
|
|
||||||
return "linear-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}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
12
src/integrations/linear/accessories.ts
Normal file
12
src/integrations/linear/accessories.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Icon, Image, List } from "@raycast/api";
|
||||||
|
import { LinearUser } from "./types";
|
||||||
|
|
||||||
|
export function getLinearUserAccessory(user?: LinearUser): List.Item.Accessory {
|
||||||
|
if (user) {
|
||||||
|
return {
|
||||||
|
icon: user.avatar_url ? { source: user.avatar_url, mask: Image.Mask.Circle } : Icon.Person,
|
||||||
|
tooltip: user.name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return { icon: Icon.Person, tooltip: "Unknown" };
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
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";
|
||||||
|
|
||||||
|
interface LinearIssueNotificationListItemProps {
|
||||||
|
icon: string;
|
||||||
|
notification: Notification;
|
||||||
|
linearIssueNotification: LinearIssueNotification;
|
||||||
|
mutate: MutatePromise<Page<Notification> | undefined>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LinearIssueNotificationListItem({
|
||||||
|
icon,
|
||||||
|
notification,
|
||||||
|
linearIssueNotification,
|
||||||
|
mutate,
|
||||||
|
}: LinearIssueNotificationListItemProps) {
|
||||||
|
const subtitle = `${linearIssueNotification.issue.team.name} #${linearIssueNotification.issue.identifier}`;
|
||||||
|
|
||||||
|
const state = getLinearIssueStateAccessory(linearIssueNotification.issue.state);
|
||||||
|
const assignee = getLinearUserAccessory(linearIssueNotification.issue.assignee);
|
||||||
|
|
||||||
|
const accessories: List.Item.Accessory[] = [
|
||||||
|
state,
|
||||||
|
assignee,
|
||||||
|
{
|
||||||
|
date: new Date(linearIssueNotification.updated_at),
|
||||||
|
tooltip: `Updated at ${linearIssueNotification.updated_at}`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List.Item
|
||||||
|
key={notification.id}
|
||||||
|
title={notification.title}
|
||||||
|
icon={icon}
|
||||||
|
accessories={accessories}
|
||||||
|
subtitle={subtitle}
|
||||||
|
actions={
|
||||||
|
<NotificationActions
|
||||||
|
notification={notification}
|
||||||
|
detailsTarget={<LinearIssuePreview notification={notification} linearIssue={linearIssueNotification.issue} />}
|
||||||
|
mutate={mutate}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { LinearProjectNotificationListItem } from "./LinearProjectNotificationListItem";
|
||||||
|
import { LinearIssueNotificationListItem } from "./LinearIssueNotificationListItem";
|
||||||
|
import { NotificationListItemProps } from "../../../notification";
|
||||||
|
import { environment } from "@raycast/api";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
export function LinearNotificationListItem({ notification, mutate }: NotificationListItemProps) {
|
||||||
|
const icon = useMemo(() => {
|
||||||
|
if (environment.appearance === "dark") {
|
||||||
|
return "linear-logo-light.svg";
|
||||||
|
}
|
||||||
|
return "linear-logo-dark.svg";
|
||||||
|
}, [environment]);
|
||||||
|
|
||||||
|
if (notification.metadata.type !== "Linear") return null;
|
||||||
|
|
||||||
|
switch (notification.metadata.content.type) {
|
||||||
|
case "IssueNotification":
|
||||||
|
return (
|
||||||
|
<LinearIssueNotificationListItem
|
||||||
|
icon={icon}
|
||||||
|
notification={notification}
|
||||||
|
linearIssueNotification={notification.metadata.content.content}
|
||||||
|
mutate={mutate}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case "ProjectNotification":
|
||||||
|
return (
|
||||||
|
<LinearProjectNotificationListItem
|
||||||
|
icon={icon}
|
||||||
|
notification={notification}
|
||||||
|
LinearProjectNotification={notification.metadata.content.content}
|
||||||
|
mutate={mutate}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { NotificationActions } from "../../../action/NotificationActions";
|
||||||
|
import { LinearProjectPreview } from "../preview/LinearProjectPreview";
|
||||||
|
import { getLinearUserAccessory } from "../accessories";
|
||||||
|
import { Notification } from "../../../notification";
|
||||||
|
import { LinearProjectNotification } from "../types";
|
||||||
|
import { MutatePromise } from "@raycast/utils";
|
||||||
|
import { Page } from "../../../types";
|
||||||
|
import { List } from "@raycast/api";
|
||||||
|
|
||||||
|
interface LinearProjectNotificationListItemProps {
|
||||||
|
icon: string;
|
||||||
|
notification: Notification;
|
||||||
|
linearProjectNotification: LinearProjectNotification;
|
||||||
|
mutate: MutatePromise<Page<Notification> | undefined>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LinearProjectNotificationListItem({
|
||||||
|
icon,
|
||||||
|
notification,
|
||||||
|
linearProjectNotification,
|
||||||
|
mutate,
|
||||||
|
}: LinearProjectNotificationListItemProps) {
|
||||||
|
const subtitle = linearProjectNotification.project.name;
|
||||||
|
|
||||||
|
const lead = getLinearUserAccessory(linearProjectNotification.project.lead);
|
||||||
|
|
||||||
|
const accessories: List.Item.Accessory[] = [
|
||||||
|
lead,
|
||||||
|
{
|
||||||
|
date: new Date(linearProjectNotification.updated_at),
|
||||||
|
tooltip: `Updated at ${linearProjectNotification.updated_at}`,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<List.Item
|
||||||
|
key={notification.id}
|
||||||
|
title={notification.title}
|
||||||
|
icon={icon}
|
||||||
|
accessories={accessories}
|
||||||
|
subtitle={subtitle}
|
||||||
|
actions={
|
||||||
|
<NotificationActions
|
||||||
|
notification={notification}
|
||||||
|
detailsTarget={
|
||||||
|
<LinearProjectPreview notification={notification} linearProject={linearProjectNotification.issue} />
|
||||||
|
}
|
||||||
|
mutate={mutate}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
26
src/integrations/linear/preview/LinearIssuePreview.tsx
Normal file
26
src/integrations/linear/preview/LinearIssuePreview.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { Notification, getNotificationHtmlUrl } from "../../../notification";
|
||||||
|
import { Detail, ActionPanel, Action } from "@raycast/api";
|
||||||
|
import { LinearIssue } from "../types";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
interface LinearIssuePreviewProps {
|
||||||
|
notification: Notification;
|
||||||
|
linearIssue: LinearIssue;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LinearIssuePreview({ notification, linearIssue }: LinearIssuePreviewProps) {
|
||||||
|
const notification_html_url = useMemo(() => {
|
||||||
|
return getNotificationHtmlUrl(notification);
|
||||||
|
}, [notification]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Detail
|
||||||
|
markdown={`# ${linearIssue.title}`}
|
||||||
|
actions={
|
||||||
|
<ActionPanel>
|
||||||
|
<Action.OpenInBrowser url={notification_html_url} />
|
||||||
|
</ActionPanel>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
26
src/integrations/linear/preview/LinearProjectPreview.tsx
Normal file
26
src/integrations/linear/preview/LinearProjectPreview.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { Notification, getNotificationHtmlUrl } from "../../../notification";
|
||||||
|
import { Detail, ActionPanel, Action } from "@raycast/api";
|
||||||
|
import { LinearProject } from "../types";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
interface LinearProjectPreviewProps {
|
||||||
|
notification: Notification;
|
||||||
|
linearProject: LinearProject;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LinearProjectPreview({ notification, linearProject }: LinearProjectPreviewProps) {
|
||||||
|
const notification_html_url = useMemo(() => {
|
||||||
|
return getNotificationHtmlUrl(notification);
|
||||||
|
}, [notification]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Detail
|
||||||
|
markdown={`# ${linearProject.name}`}
|
||||||
|
actions={
|
||||||
|
<ActionPanel>
|
||||||
|
<Action.OpenInBrowser url={notification_html_url} />
|
||||||
|
</ActionPanel>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
116
src/integrations/linear/types.ts
Normal file
116
src/integrations/linear/types.ts
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
export interface LinearIssueNotification {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
read_at?: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
snoozed_until_at?: Date;
|
||||||
|
organization: LinearOrganization;
|
||||||
|
issue: LinearIssue;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LinearOrganization {
|
||||||
|
name: string;
|
||||||
|
key: string;
|
||||||
|
logo_url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LinearIssue {
|
||||||
|
id: string;
|
||||||
|
created_at: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
completed_at?: Date;
|
||||||
|
canceled_at?: Date;
|
||||||
|
due_date?: Date;
|
||||||
|
identifier: string;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
priority: LinearIssuePriority;
|
||||||
|
project?: LinearProject;
|
||||||
|
project_milestone?: LinearProjectMilestone;
|
||||||
|
creator?: LinearUser;
|
||||||
|
assignee?: LinearUser;
|
||||||
|
state: LinearWorkflowState;
|
||||||
|
labels: Array<LinearLabel>;
|
||||||
|
description: string;
|
||||||
|
team: LinearTeam;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum LinearIssuePriority {
|
||||||
|
NoPriority = 0,
|
||||||
|
Urgent = 1,
|
||||||
|
High = 2,
|
||||||
|
Normal = 3,
|
||||||
|
Low = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LinearProject {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
description: string;
|
||||||
|
icon?: string;
|
||||||
|
color: string;
|
||||||
|
state: LinearProjectState;
|
||||||
|
progress: number; // percentage between 0 and 100
|
||||||
|
start_date?: Date;
|
||||||
|
target_date?: Date;
|
||||||
|
lead?: LinearUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum LinearProjectState {
|
||||||
|
Planned = "Planned",
|
||||||
|
Backlog = "Backlog",
|
||||||
|
Started = "Started",
|
||||||
|
Paused = "Paused",
|
||||||
|
Completed = "Completed",
|
||||||
|
Canceled = "Canceled",
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LinearProjectMilestone {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LinearUser {
|
||||||
|
name: string;
|
||||||
|
avatar_url?: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LinearWorkflowState {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
color: string;
|
||||||
|
type: LinearWorkflowStateType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum LinearWorkflowStateType {
|
||||||
|
Triage = "Triage",
|
||||||
|
Backlog = "Backlog",
|
||||||
|
Unstarted = "Unstarted",
|
||||||
|
Started = "Started",
|
||||||
|
Completed = "Completed",
|
||||||
|
Canceled = "Canceled",
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LinearLabel {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LinearTeam {
|
||||||
|
id: string;
|
||||||
|
key: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LinearProjectNotification {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
read_at?: Date;
|
||||||
|
updated_at: Date;
|
||||||
|
snoozed_until_at?: Date;
|
||||||
|
organization: LinearOrganization;
|
||||||
|
project: LinearProject;
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { GithubDiscussion, GithubPullRequest } from "./integrations/github/types";
|
import { GithubDiscussion, GithubPullRequest } from "./integrations/github/types";
|
||||||
import { MutatePromise } from "@raycast/utils";
|
import { MutatePromise } from "@raycast/utils";
|
||||||
|
import { match, P } from "ts-pattern";
|
||||||
import { Page } from "./types";
|
import { Page } from "./types";
|
||||||
import { Task } from "./task";
|
import { Task } from "./task";
|
||||||
|
|
||||||
@@ -40,16 +41,20 @@ export type NotificationListItemProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function getNotificationHtmlUrl(notification: Notification) {
|
export function getNotificationHtmlUrl(notification: Notification) {
|
||||||
switch (notification.details?.type) {
|
return match(notification)
|
||||||
case "GithubPullRequest":
|
.with(
|
||||||
return notification.details.content.url;
|
{ details: { type: P.union("GithubPullRequest", "GithubDiscussion") } },
|
||||||
case "GithubDiscussion":
|
() => notification.details.content.url,
|
||||||
return notification.details.content.url;
|
)
|
||||||
default: {
|
.with(
|
||||||
// TODO
|
{ metadata: { type: "Linear", content: { type: "IssueNotification", content: P.select() } } },
|
||||||
return "https://github.com";
|
(linearIssueNotification) => linearIssueNotification.issue.url,
|
||||||
}
|
)
|
||||||
}
|
.with(
|
||||||
|
{ metadata: { type: "Linear", content: { type: "ProjectNotification", content: P.select() } } },
|
||||||
|
(linearProjectNotification) => linearProjectNotification.project.url,
|
||||||
|
)
|
||||||
|
.exhaustive();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isNotificationBuiltFromTask(notification: Notification) {
|
export function isNotificationBuiltFromTask(notification: Notification) {
|
||||||
|
|||||||
Reference in New Issue
Block a user