feat: List Github notifications
This commit is contained in:
35
src/integrations/github/GithubNotificationListItem.tsx
Normal file
35
src/integrations/github/GithubNotificationListItem.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import { environment } from "@raycast/api";
|
||||
import { useMemo } from "react";
|
||||
import { NotificationListItemProps } from "../../types";
|
||||
import { GithubDiscussionNotificationListItem } from "./listitem/GithubDiscussionNotificationListItem";
|
||||
import { GithubPullRequestNotificationListItem } from "./listitem/GithubPullRequestNotificationListItem";
|
||||
|
||||
export function GithubNotificationListItem({ notification }: NotificationListItemProps) {
|
||||
const icon = useMemo(() => {
|
||||
if (environment.appearance === "dark") {
|
||||
return "github-logo-light.svg";
|
||||
}
|
||||
return "github-logo-dark.svg";
|
||||
}, [environment]);
|
||||
|
||||
switch (notification.details?.type) {
|
||||
case "GithubPullRequest":
|
||||
return (
|
||||
<GithubPullRequestNotificationListItem
|
||||
icon={icon}
|
||||
notification={notification}
|
||||
githubPullRequest={notification.details.content}
|
||||
/>
|
||||
);
|
||||
case "GithubDiscussion":
|
||||
return (
|
||||
<GithubDiscussionNotificationListItem
|
||||
icon={icon}
|
||||
notification={notification}
|
||||
githubDiscussion={notification.details.content}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import { Color, Icon, List } from "@raycast/api";
|
||||
import { NotificationActions } from "../../../NotificationActions";
|
||||
import { Notification } from "../../../types";
|
||||
import { getGithubActorAccessory } from "../misc";
|
||||
import { GithubDiscussion, GithubDiscussionStateReason } from "../types";
|
||||
import { GithubDiscussionPreview } from "../preview/GithubDiscussionPreview";
|
||||
|
||||
interface GithubDiscussionNotificationListItemProps {
|
||||
icon: string;
|
||||
notification: Notification;
|
||||
githubDiscussion: GithubDiscussion;
|
||||
}
|
||||
|
||||
export function GithubDiscussionNotificationListItem({
|
||||
icon,
|
||||
notification,
|
||||
githubDiscussion,
|
||||
}: GithubDiscussionNotificationListItemProps) {
|
||||
const subtitle = `${githubDiscussion.repository.name_with_owner}`;
|
||||
|
||||
const author = getGithubActorAccessory(githubDiscussion.author);
|
||||
const discussionStatus = getGithubDiscussionStatusAccessory(githubDiscussion.state_reason);
|
||||
|
||||
const accessories: List.Item.Accessory[] = [
|
||||
author,
|
||||
{ date: new Date(githubDiscussion.updated_at), tooltip: `Updated at ${githubDiscussion.updated_at}` },
|
||||
];
|
||||
|
||||
if (discussionStatus) {
|
||||
accessories.unshift(discussionStatus);
|
||||
}
|
||||
if (githubDiscussion.comments_count > 0) {
|
||||
accessories.unshift({
|
||||
text: githubDiscussion.comments_count.toString(),
|
||||
icon: Icon.Bubble,
|
||||
tooltip: `${githubDiscussion.comments_count} comments`,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<List.Item
|
||||
key={notification.id}
|
||||
title={notification.title}
|
||||
icon={icon}
|
||||
subtitle={subtitle}
|
||||
accessories={accessories}
|
||||
actions={
|
||||
<NotificationActions
|
||||
notification={notification}
|
||||
detailsTarget={<GithubDiscussionPreview notification={notification} githubDiscussion={githubDiscussion} />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function getGithubDiscussionStatusAccessory(stateReason?: GithubDiscussionStateReason): List.Item.Accessory {
|
||||
switch (stateReason) {
|
||||
case GithubDiscussionStateReason.Duplicate:
|
||||
return {
|
||||
icon: { source: "github-discussion-duplicate.svg", tintColor: Color.SecondaryText },
|
||||
tooltip: "Answered",
|
||||
};
|
||||
case GithubDiscussionStateReason.Outdated:
|
||||
return {
|
||||
icon: { source: "github-discussion-outdated.svg", tintColor: Color.SecondaryText },
|
||||
tooltip: "Answered",
|
||||
};
|
||||
case GithubDiscussionStateReason.Reopened:
|
||||
return { icon: { source: "github-discussion-opened.svg", tintColor: Color.Green }, tooltip: "Answered" };
|
||||
case GithubDiscussionStateReason.Resolved:
|
||||
return { icon: { source: "github-discussion-closed.svg", tintColor: Color.Magenta }, tooltip: "Answered" };
|
||||
default:
|
||||
return { icon: { source: "github-discussion-opened.svg", tintColor: Color.Green }, tooltip: "Answered" };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
import { Color, Icon, List } from "@raycast/api";
|
||||
import { NotificationActions } from "../../../NotificationActions";
|
||||
import { Notification } from "../../../types";
|
||||
import { GithubPullRequestPreview } from "../preview/GithubPullRequestPreview";
|
||||
import {
|
||||
GithubPullRequestState,
|
||||
GithubPullRequestReviewDecision,
|
||||
GithubCheckConclusionState,
|
||||
GithubPullRequest,
|
||||
GithubCommitChecks,
|
||||
GithubCheckStatusState,
|
||||
GithubCheckSuite,
|
||||
} from "../types";
|
||||
import { getGithubActorAccessory } from "../misc";
|
||||
|
||||
interface GithubPullRequestNotificationListItemProps {
|
||||
icon: string;
|
||||
notification: Notification;
|
||||
githubPullRequest: GithubPullRequest;
|
||||
}
|
||||
|
||||
export function GithubPullRequestNotificationListItem({
|
||||
icon,
|
||||
notification,
|
||||
githubPullRequest,
|
||||
}: GithubPullRequestNotificationListItemProps) {
|
||||
const subtitle = `${githubPullRequest.head_repository?.name_with_owner} #${githubPullRequest.number}`;
|
||||
|
||||
const author = getGithubActorAccessory(githubPullRequest.author);
|
||||
const prChecks = getGithubPullRequestChecksAccessory(githubPullRequest.latest_commit);
|
||||
const review = getGithubPullRequestReviewAccessory(githubPullRequest.review_decision);
|
||||
const prStatus = getGithubPullRequestStateAccessory(githubPullRequest);
|
||||
|
||||
const accessories: List.Item.Accessory[] = [
|
||||
author,
|
||||
{
|
||||
date: new Date(githubPullRequest.updated_at),
|
||||
tooltip: `Updated at ${githubPullRequest.updated_at}`,
|
||||
},
|
||||
];
|
||||
|
||||
if (prStatus) {
|
||||
accessories.unshift(prStatus);
|
||||
}
|
||||
if (githubPullRequest.comments_count > 0) {
|
||||
accessories.unshift({
|
||||
text: githubPullRequest.comments_count.toString(),
|
||||
icon: Icon.Bubble,
|
||||
tooltip: `${githubPullRequest.comments_count} comments`,
|
||||
});
|
||||
}
|
||||
if (review) {
|
||||
accessories.unshift(review);
|
||||
}
|
||||
if (prChecks) {
|
||||
accessories.unshift(prChecks);
|
||||
}
|
||||
|
||||
return (
|
||||
<List.Item
|
||||
key={notification.id}
|
||||
title={notification.title}
|
||||
icon={icon}
|
||||
accessories={accessories}
|
||||
subtitle={subtitle}
|
||||
actions={
|
||||
<NotificationActions
|
||||
notification={notification}
|
||||
detailsTarget={<GithubPullRequestPreview notification={notification} githubPullRequest={githubPullRequest} />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function getGithubPullRequestChecksAccessory(latestCommit: GithubCommitChecks): List.Item.Accessory | null {
|
||||
const progress = computePullRequestChecksProgress(latestCommit.check_suites);
|
||||
if (!progress) {
|
||||
return null;
|
||||
}
|
||||
switch (progress.status()) {
|
||||
case GithubCheckStatusState.Pending:
|
||||
return { icon: Icon.Pause, tooltip: "Pending" };
|
||||
case GithubCheckStatusState.InProgress:
|
||||
return { icon: Icon.Pause, tooltip: "In progress" }; // TODO Spinner
|
||||
case GithubCheckStatusState.Completed:
|
||||
switch (progress.conclusion()) {
|
||||
case GithubCheckConclusionState.Success:
|
||||
return { icon: Icon.CheckCircle, tooltip: "Success" };
|
||||
case GithubCheckConclusionState.Failure:
|
||||
return { icon: Icon.XMarkCircle, tooltip: "Failure" };
|
||||
default:
|
||||
return { icon: Icon.QuestionMarkCircle, tooltip: "Neutral" };
|
||||
}
|
||||
default:
|
||||
return { icon: Icon.QuestionMarkCircle, tooltip: "Neutral" };
|
||||
}
|
||||
}
|
||||
|
||||
class GithubChecksProgress {
|
||||
checksCount = 0;
|
||||
completedChecksCount = 0;
|
||||
failedChecksCount = 0;
|
||||
|
||||
status(): GithubCheckStatusState {
|
||||
if (this.completedChecksCount === 0) {
|
||||
return GithubCheckStatusState.Pending;
|
||||
}
|
||||
if (this.completedChecksCount === this.checksCount) {
|
||||
return GithubCheckStatusState.Completed;
|
||||
}
|
||||
return GithubCheckStatusState.InProgress;
|
||||
}
|
||||
|
||||
conclusion(): GithubCheckConclusionState {
|
||||
if (this.status() === GithubCheckStatusState.InProgress) {
|
||||
return GithubCheckConclusionState.Neutral;
|
||||
}
|
||||
if (this.failedChecksCount > 0) {
|
||||
return GithubCheckConclusionState.Failure;
|
||||
}
|
||||
return GithubCheckConclusionState.Success;
|
||||
}
|
||||
}
|
||||
|
||||
function computePullRequestChecksProgress(checkSuites?: Array<GithubCheckSuite>): GithubChecksProgress | null {
|
||||
if (checkSuites) {
|
||||
const progress = new GithubChecksProgress();
|
||||
|
||||
for (const checkSuite of checkSuites) {
|
||||
if (checkSuite.status !== GithubCheckStatusState.Queued) {
|
||||
for (const checkRun of checkSuite.check_runs) {
|
||||
progress.checksCount += 1;
|
||||
if (checkRun.status === GithubCheckStatusState.Completed) {
|
||||
progress.completedChecksCount += 1;
|
||||
if (checkRun.conclusion && checkRun.conclusion !== GithubCheckConclusionState.Success) {
|
||||
progress.failedChecksCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (progress.checksCount === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getGithubPullRequestReviewAccessory(
|
||||
reviewDecision?: GithubPullRequestReviewDecision,
|
||||
): List.Item.Accessory | null {
|
||||
switch (reviewDecision) {
|
||||
case GithubPullRequestReviewDecision.Approved:
|
||||
return { tag: { value: "Approved", color: Color.Green } };
|
||||
case GithubPullRequestReviewDecision.ChangesRequested:
|
||||
return { tag: { value: "Changes requested", color: Color.Red } };
|
||||
case GithubPullRequestReviewDecision.ReviewRequired:
|
||||
return { tag: { value: "Review required", color: Color.Orange } };
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getGithubPullRequestStateAccessory(githubPullRequest: GithubPullRequest): List.Item.Accessory | null {
|
||||
switch (githubPullRequest.state) {
|
||||
case GithubPullRequestState.Open:
|
||||
if (githubPullRequest.is_draft) {
|
||||
return {
|
||||
icon: {
|
||||
source: "github-pullrequest-draft.svg",
|
||||
tintColor: Color.SecondaryText,
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
icon: { source: "github-pullrequest.svg", tintColor: Color.Green },
|
||||
};
|
||||
case GithubPullRequestState.Closed:
|
||||
return {
|
||||
icon: {
|
||||
source: "github-pullrequest-closed.svg",
|
||||
tintColor: Color.SecondaryText,
|
||||
},
|
||||
};
|
||||
case GithubPullRequestState.Merged:
|
||||
return {
|
||||
icon: { source: "github-pullrequest.svg", tintColor: Color.Magenta },
|
||||
};
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
12
src/integrations/github/misc.tsx
Normal file
12
src/integrations/github/misc.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Icon, Image, List } from "@raycast/api";
|
||||
import { GithubActor, getGithubActorName } from "./types";
|
||||
|
||||
export function getGithubActorAccessory(actor?: GithubActor): List.Item.Accessory {
|
||||
if (actor) {
|
||||
return {
|
||||
icon: actor.content.avatar_url ? { source: actor.content.avatar_url, mask: Image.Mask.Circle } : Icon.Person,
|
||||
tooltip: getGithubActorName(actor),
|
||||
};
|
||||
}
|
||||
return { icon: Icon.Person, tooltip: "Unknown" };
|
||||
}
|
||||
27
src/integrations/github/preview/GithubDiscussionPreview.tsx
Normal file
27
src/integrations/github/preview/GithubDiscussionPreview.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Detail, ActionPanel, Action } from "@raycast/api";
|
||||
import { Notification } from "../../../types";
|
||||
import { GithubDiscussion } from "../types";
|
||||
import { useMemo } from "react";
|
||||
import { getNotificationHtmlUrl } from "../../../notification";
|
||||
|
||||
interface GithubDiscussionPreviewProps {
|
||||
notification: Notification;
|
||||
githubDiscussion: GithubDiscussion;
|
||||
}
|
||||
|
||||
export function GithubDiscussionPreview({ notification, githubDiscussion }: GithubDiscussionPreviewProps) {
|
||||
const notification_html_url = useMemo(() => {
|
||||
return getNotificationHtmlUrl(notification);
|
||||
}, [notification]);
|
||||
|
||||
return (
|
||||
<Detail
|
||||
markdown={`# ${githubDiscussion.title}`}
|
||||
actions={
|
||||
<ActionPanel>
|
||||
<Action.OpenInBrowser url={notification_html_url} />
|
||||
</ActionPanel>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
27
src/integrations/github/preview/GithubPullRequestPreview.tsx
Normal file
27
src/integrations/github/preview/GithubPullRequestPreview.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { Detail, ActionPanel, Action } from "@raycast/api";
|
||||
import { Notification } from "../../../types";
|
||||
import { GithubPullRequest } from "../types";
|
||||
import { useMemo } from "react";
|
||||
import { getNotificationHtmlUrl } from "../../../notification";
|
||||
|
||||
interface GithubPullRequestPreviewProps {
|
||||
notification: Notification;
|
||||
githubPullRequest: GithubPullRequest;
|
||||
}
|
||||
|
||||
export function GithubPullRequestPreview({ notification, githubPullRequest }: GithubPullRequestPreviewProps) {
|
||||
const notification_html_url = useMemo(() => {
|
||||
return getNotificationHtmlUrl(notification);
|
||||
}, [notification]);
|
||||
|
||||
return (
|
||||
<Detail
|
||||
markdown={`# ${githubPullRequest.title}`}
|
||||
actions={
|
||||
<ActionPanel>
|
||||
<Action.OpenInBrowser url={notification_html_url} />
|
||||
</ActionPanel>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
221
src/integrations/github/types.ts
Normal file
221
src/integrations/github/types.ts
Normal file
@@ -0,0 +1,221 @@
|
||||
export interface GithubPullRequest {
|
||||
id: string;
|
||||
number: number;
|
||||
url: string;
|
||||
title: string;
|
||||
body: string;
|
||||
state: GithubPullRequestState;
|
||||
is_draft: boolean;
|
||||
closed_at?: Date;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
merged_at?: Date;
|
||||
mergeable_state: GithubMergeableState;
|
||||
merge_state_status: GithubMergeStateStatus;
|
||||
merged_by?: GithubActor;
|
||||
deletions: number;
|
||||
additions: number;
|
||||
changed_files: number;
|
||||
labels: Array<GithubLabel>;
|
||||
comments_count: number;
|
||||
comments: Array<GithubIssueComment>;
|
||||
latest_commit: GithubCommitChecks;
|
||||
base_ref_name: string;
|
||||
base_repository?: GithubRepositorySummary;
|
||||
head_ref_name: string;
|
||||
head_repository?: GithubRepositorySummary;
|
||||
author?: GithubActor;
|
||||
assignees: Array<GithubActor>;
|
||||
review_decision?: GithubPullRequestReviewDecision;
|
||||
reviews: Array<GithubPullRequestReview>;
|
||||
review_requests: Array<GithubReviewer>;
|
||||
}
|
||||
|
||||
export enum GithubPullRequestState {
|
||||
Open = "Open",
|
||||
Closed = "Closed",
|
||||
Merged = "Merged",
|
||||
}
|
||||
|
||||
export enum GithubMergeableState {
|
||||
Unknown = "Unknown",
|
||||
Mergeable = "Mergeable",
|
||||
Conflicting = "Conflicting",
|
||||
}
|
||||
|
||||
export enum GithubMergeStateStatus {
|
||||
Behind = "Behind",
|
||||
Blocked = "Blocked",
|
||||
Clean = "Clean",
|
||||
Dirty = "Dirty",
|
||||
Draft = "Draft",
|
||||
HasHooks = "HasHooks",
|
||||
Unknown = "Unknown",
|
||||
Unstable = "Unstable",
|
||||
}
|
||||
|
||||
export type GithubActor =
|
||||
| { type: "GithubUserSummary"; content: GithubUserSummary }
|
||||
| { type: "GithubBotSummary"; content: GithubBotSummary };
|
||||
|
||||
export function getGithubActorName(actor?: GithubActor): string {
|
||||
if (!actor) {
|
||||
return "Unknown";
|
||||
}
|
||||
switch (actor.type) {
|
||||
case "GithubUserSummary":
|
||||
return actor.content.name ? actor.content.name : actor.content.login;
|
||||
case "GithubBotSummary":
|
||||
return actor.content.login;
|
||||
}
|
||||
}
|
||||
|
||||
export interface GithubUserSummary {
|
||||
name?: string;
|
||||
login: string;
|
||||
avatar_url: string;
|
||||
}
|
||||
|
||||
export interface GithubBotSummary {
|
||||
login: string;
|
||||
avatar_url: string;
|
||||
}
|
||||
|
||||
export interface GithubTeamSummary {
|
||||
avatar_url?: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface GithubMannequinSummary {
|
||||
avatar_url: string;
|
||||
login: string;
|
||||
}
|
||||
|
||||
export interface GithubLabel {
|
||||
name: string;
|
||||
color: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
export interface GithubIssueComment {
|
||||
url: string;
|
||||
body: string;
|
||||
created_at: Date;
|
||||
author?: GithubActor;
|
||||
}
|
||||
|
||||
export interface GithubCommitChecks {
|
||||
git_commit_id: string;
|
||||
check_suites?: Array<GithubCheckSuite>;
|
||||
}
|
||||
|
||||
export interface GithubCheckSuite {
|
||||
check_runs: Array<GithubCheckRun>;
|
||||
conclusion?: GithubCheckConclusionState;
|
||||
status: GithubCheckStatusState;
|
||||
workflow?: GithubWorkflow;
|
||||
app: GithubCheckSuiteApp;
|
||||
}
|
||||
|
||||
export interface GithubCheckRun {
|
||||
name: string;
|
||||
conclusion?: GithubCheckConclusionState;
|
||||
status: GithubCheckStatusState;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
export enum GithubCheckConclusionState {
|
||||
ActionRequired = "ActionRequired",
|
||||
Cancelled = "Cancelled",
|
||||
Failure = "Failure",
|
||||
Neutral = "Neutral",
|
||||
Skipped = "Skipped",
|
||||
Stale = "Stale",
|
||||
StartupFailure = "StartupFailure",
|
||||
Success = "Success",
|
||||
TimedOut = "TimedOut",
|
||||
}
|
||||
|
||||
export enum GithubCheckStatusState {
|
||||
Completed = "Completed",
|
||||
InProgress = "InProgress",
|
||||
Pending = "Pending",
|
||||
Queued = "Queued",
|
||||
Requested = "Requested",
|
||||
Waiting = "Waiting",
|
||||
}
|
||||
|
||||
export interface GithubWorkflow {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface GithubCheckSuiteApp {
|
||||
name: string;
|
||||
logo_url?: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface GithubRepositorySummary {
|
||||
name_with_owner: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export enum GithubPullRequestReviewDecision {
|
||||
Approved = "Approved",
|
||||
ChangesRequested = "ChangesRequested",
|
||||
ReviewRequired = "ReviewRequired",
|
||||
}
|
||||
|
||||
export interface GithubPullRequestReview {
|
||||
author?: GithubActor;
|
||||
body: string;
|
||||
state: GithubPullRequestReviewState;
|
||||
}
|
||||
|
||||
export enum GithubPullRequestReviewState {
|
||||
Approved = "Approved",
|
||||
ChangesRequested = "ChangesRequested",
|
||||
Commented = "Commented",
|
||||
Dismissed = "Dismissed",
|
||||
Pending = "Pending",
|
||||
}
|
||||
|
||||
export type GithubReviewer =
|
||||
| { type: "GithubUserSummary"; content: GithubUserSummary }
|
||||
| { type: "GithubTeamSummary"; content: GithubTeamSummary }
|
||||
| { type: "GithubBotSummary"; content: GithubBotSummary }
|
||||
| { type: "GithubMannequinSummary"; content: GithubMannequinSummary };
|
||||
|
||||
export interface GithubDiscussion {
|
||||
id: string;
|
||||
number: number;
|
||||
url: string;
|
||||
title: string;
|
||||
body: string;
|
||||
repository: GithubRepositorySummary;
|
||||
state_reason?: GithubDiscussionStateReason;
|
||||
closed_at?: Date;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
labels: Array<GithubLabel>;
|
||||
comments_count: number;
|
||||
author?: GithubActor;
|
||||
answer_chosen_at?: Date;
|
||||
answer_chosen_by?: GithubActor;
|
||||
answer?: GithubDiscussionComment;
|
||||
}
|
||||
|
||||
export enum GithubDiscussionStateReason {
|
||||
Duplicate = "Duplicate",
|
||||
Outdated = "Outdated",
|
||||
Reopened = "Reopened",
|
||||
Resolved = "Resolved",
|
||||
}
|
||||
|
||||
export interface GithubDiscussionComment {
|
||||
url: string;
|
||||
body: string;
|
||||
created_at: Date;
|
||||
author?: GithubActor;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { Detail, List, environment } from "@raycast/api";
|
||||
import { useMemo } from "react";
|
||||
import { NotificationActions } from "../../NotificationActions";
|
||||
import { NotificationListItemProps } from "../../types";
|
||||
|
||||
export function GoogleMailNotificationListItem({ notification }: 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 👋" />} />
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
25
src/integrations/linear/LinearNotificationListItem.tsx
Normal file
25
src/integrations/linear/LinearNotificationListItem.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Detail, List, environment } from "@raycast/api";
|
||||
import { useMemo } from "react";
|
||||
import { NotificationActions } from "../../NotificationActions";
|
||||
import { NotificationListItemProps } from "../../types";
|
||||
|
||||
export function LinearNotificationListItem({ notification }: 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 👋" />} />
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
28
src/integrations/todoist/TodoistNotificationListItem.tsx
Normal file
28
src/integrations/todoist/TodoistNotificationListItem.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Detail, List, environment } from "@raycast/api";
|
||||
import { useMemo } from "react";
|
||||
import { NotificationTaskActions } from "../../NotificationTaskActions";
|
||||
import { NotificationListItemProps } from "../../types";
|
||||
|
||||
export function TodoistNotificationListItem({ notification }: NotificationListItemProps) {
|
||||
const icon = useMemo(() => {
|
||||
if (environment.appearance === "dark") {
|
||||
return "todoist-icon-light.svg";
|
||||
}
|
||||
return "todoist-icon-dark.svg";
|
||||
}, [environment]);
|
||||
|
||||
return (
|
||||
<List.Item
|
||||
key={notification.id}
|
||||
title={notification.title}
|
||||
icon={icon}
|
||||
subtitle={`#${notification.source_id}`}
|
||||
actions={
|
||||
<NotificationTaskActions
|
||||
notification={notification}
|
||||
detailsTarget={<Detail markdown="# To be implemented 👋" />}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user