197 lines
6.0 KiB
TypeScript
197 lines
6.0 KiB
TypeScript
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;
|
|
}
|
|
}
|