Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions frontend/dummy-pulls.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
"user": {
"login": "BaseInfinity"
},
"assignees": ["danielbeardsley"],
"requested_reviewers": ["ianrohde", "danielbeardsley"],
"cr_req": 2,
"qa_req": 1,
"status": {
Expand Down Expand Up @@ -171,6 +173,8 @@
"user": {
"login": "ianrohde"
},
"assignees": ["danielbeardsley", "ianrohde"],
"requested_reviewers": ["rjmccluskey"],
"cr_req": 2,
"qa_req": 1,
"status": {
Expand Down Expand Up @@ -481,6 +485,7 @@
"user": {
"login": "hackalot805"
},
"assignees": ["ardelato"],
"cr_req": 2,
"qa_req": 1,
"status": {
Expand Down Expand Up @@ -609,6 +614,7 @@
"login": "ardelato"
},
"cr_req": 2,
"requested_reviewers": ["danielbeardsley", "hackalot805"],
"qa_req": 1,
"status": {
"qa_req": 1,
Expand Down Expand Up @@ -697,6 +703,7 @@
"user": {
"login": "rjmccluskey"
},
"assignees": ["hackalot805", "ardelato"],
"cr_req": 2,
"qa_req": 1,
"status": {
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/pull-card/avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { userProfileUrl } from "../utils";
export function Avatar({
user,
linkToProfile,
title,
}: {
user: string;
linkToProfile?: boolean;
title?: string;
}) {
const cleanUsername = user.replace(/\[bot\]$/, "");
return (
Expand All @@ -20,7 +22,7 @@ export function Avatar({
display="inline-block"
borderRadius="full"
verticalAlign="bottom"
title={user}
title={title ?? user}
src={`https://github.com/${cleanUsername}.png?size=20`}
/>
);
Expand Down
17 changes: 13 additions & 4 deletions frontend/src/pull-card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,18 @@ export const PullCard = memo(function PullCard({
isExternal
color="var(--pull-title)"
>
{pull.isMine() ? (
{pull.authoredByMe() ? (
<FontAwesomeIcon
icon={faStar}
className="star"
color="var(--user-icon)"
/>
) : (
<Avatar user={pull.user.login} linkToProfile />
<Avatar
user={pull.authors()[0]}
linkToProfile
title={pull.authors().join(", ")}
/>
)}
<chakra.span fontWeight="bold">
{pull.getRepoName()} #{pull.number}:{" "}
Expand Down Expand Up @@ -120,6 +124,7 @@ export const PullCard = memo(function PullCard({
signatures={pull.cr_signatures}
required={pull.status.cr_req}
title="CR"
showReviewRequest
/>
<Signatures
pull={pull}
Expand Down Expand Up @@ -170,14 +175,18 @@ export const ClosedPullCard = memo(function ClosedPullCard({
textDecoration={wasMerged ? "none" : "line-through"}
color="var(--pull-title)"
>
{pull.isMine() ? (
{pull.authoredByMe() ? (
<FontAwesomeIcon
icon={faStar}
className="star"
color="var(--user-icon)"
/>
) : (
<Avatar user={pull.user.login} linkToProfile />
<Avatar
user={pull.authors()[0]}
linkToProfile
title={pull.authors().join(", ")}
/>
)}
<chakra.span fontWeight="bold">
{pull.getRepoName()} #{pull.number}:{" "}
Expand Down
1 change: 0 additions & 1 deletion frontend/src/pull-card/participants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,3 @@ function tooltip(pull: Pull) {
`${pull.participants.length} participants`;
}
}

13 changes: 12 additions & 1 deletion frontend/src/pull-card/signatures.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ import {
} from "@chakra-ui/react";
import { memo } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCheckCircle } from "@fortawesome/free-solid-svg-icons";
import { faCheckCircle, faStar } from "@fortawesome/free-solid-svg-icons";

interface SignaturesProps {
pull: Pull;
title: string;
signatures: SignatureGroup;
required: number;
// When set (the CR block), show a blue star before the title if a review
// is requested from the current user.
showReviewRequest?: boolean;
}

const SigSectionTitle = Box;
Expand All @@ -34,6 +37,7 @@ function SignaturesFlag({
title,
signatures,
required,
showReviewRequest,
}: SignaturesProps) {
const statusVariant =
signatures.current.length >= required
Expand All @@ -59,6 +63,13 @@ function SignaturesFlag({
sx={styles}
title={noneToShow ? `No ${title} Required` : ""}
>
{showReviewRequest && pull.reviewRequestedFromMe() && (
<FontAwesomeIcon
icon={faStar}
color="var(--user-icon)"
title={`Review requested from ${pull.requested_reviewers.join(", ")}`}
/>
)}
<Box m="2px" mr={noneToShow ? "2px" : 2}>
{title}
</Box>
Expand Down
18 changes: 17 additions & 1 deletion frontend/src/pull.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ export class Pull extends PullData {

isMineViaAffiliation(): boolean {
return (
this.isMine() ||
this.authoredByMe() ||
this.reviewRequestedFromMe() ||
this.hasCurrentSig(getUser()) ||
this.hasOutdatedSig(getUser()) ||
this.hasMyDevBlock() ||
Expand Down Expand Up @@ -84,6 +85,21 @@ export class Pull extends PullData {
return this.participants && this.participants.includes(getUser());
}

// The pull author plus its assignees, treated as a combined author list.
authors(): string[] {
return [this.user.login, ...(this.assignees ?? [])].filter(
(login, i, all) => all.indexOf(login) === i
);
}

authoredByMe(): boolean {
return this.authors().includes(getUser());
}

reviewRequestedFromMe(): boolean {
return this.requested_reviewers?.includes(getUser()) ?? false;
}

hasMyDevBlock(): boolean {
return this.getDevBlock()?.data.user.login == getUser();
}
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,6 @@ export class PullData {
};
labels: Label[];
participants: string[];
assignees: string[];
requested_reviewers: string[];
}
66 changes: 66 additions & 0 deletions frontend/test/named-pulls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,70 @@ export const Participants = <PullData[]>[
}),
];

export const Authors = <PullData[]>[
pullData({
number: 1,
title: "Single author (not me)",
cr_req: 0,
user: { login: "author1" },
}),
pullData({
number: 2,
title: "Author plus two assignees (none is me) — hover lists all",
cr_req: 0,
user: { login: "author1" },
assignees: ["assignee1", "assignee2"],
}),
pullData({
number: 3,
title: "Authored by me",
cr_req: 0,
user: { login: getUser() },
}),
pullData({
number: 4,
title: "Assigned to me (I'm an assignee, not the author)",
cr_req: 0,
user: { login: "author1" },
assignees: [getUser()],
}),
];

export const ReviewRequests = <PullData[]>[
pullData({
number: 1,
title: "Review requested from me",
cr_req: 1,
requested_reviewers: [getUser()],
}),
pullData({
number: 1,
title: "Review requested from me",
cr_req: 1,
requested_reviewers: [getUser()],
status: {
allQA: [],
allCR: [sig(SignatureType.CR, true, getUser())],
},
}),
pullData({
number: 2,
title: "Review requested from me and another",
cr_req: 1,
requested_reviewers: [getUser(), "User 2"],
status: {
allQA: [],
allCR: [sig(SignatureType.CR, true, "User 2")],
},
}),
pullData({
number: 3,
title: "Review requested from someone else",
cr_req: 1,
requested_reviewers: ["User2"],
}),
];

export const KitchenSink = <PullData[]>[
pullData({
title: "Pull With Lots of flags and such and a really long title",
Expand Down Expand Up @@ -462,5 +526,7 @@ export const KitchenSink = <PullData[]>[
}),
],
participants: ["other person", getUser()],
assignees: ["coAuthor"],
requested_reviewers: [getUser()],
}),
];
4 changes: 4 additions & 0 deletions frontend/test/pull-card-demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
Labels,
Draft,
MyOwn,
Authors,
ReviewRequests,
Participants,
KitchenSink,
} from "./named-pulls";
Expand Down Expand Up @@ -51,6 +53,8 @@ function PullCardDemo() {
<Row title="Labels" pullDatas={Labels} />
<Row title="Draft" pullDatas={Draft} />
<Row title="My Own" pullDatas={MyOwn} />
<Row title="Authors (author + assignees)" pullDatas={Authors} />
<Row title="Review Requests" pullDatas={ReviewRequests} />
<Row title="Participants" pullDatas={Participants} />
<Row title="Kitchen Sink (all the things)" pullDatas={KitchenSink} linesChanged={true}/>
</ChakraProvider>
Expand Down
2 changes: 2 additions & 0 deletions frontend/test/pull-data-parts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ export function pullData(p: DeepPartial<PullData>): PullData {
},
labels: p.labels || [],
participants: p.participants || [],
assignees: p.assignees || [],
requested_reviewers: p.requested_reviewers || [],
};
}

Expand Down
1 change: 1 addition & 0 deletions migrations/0020-pulls--add-assignees.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `pulls` ADD COLUMN `assignees` json DEFAULT NULL AFTER `owner`;
1 change: 1 addition & 0 deletions migrations/0021-pulls--add-requested-reviewers.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE `pulls` ADD COLUMN `requested_reviewers` json DEFAULT NULL AFTER `assignees`;
2 changes: 2 additions & 0 deletions migrations/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ CREATE TABLE IF NOT EXISTS `pulls` (
`head_sha` char(40) COLLATE utf8mb4_general_ci NOT NULL,
`base_branch` varchar(255) COLLATE utf8mb4_general_ci NOT NULL,
`owner` varchar(255) COLLATE utf8mb4_general_ci NOT NULL,
`assignees` json DEFAULT NULL,
`requested_reviewers` json DEFAULT NULL,
`cr_req` int NOT NULL DEFAULT '2',
`qa_req` int NOT NULL DEFAULT '1',
`date` int unsigned DEFAULT NULL,
Expand Down
3 changes: 3 additions & 0 deletions models/db_pull.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ function DBPull(pull) {
head_sha: pullData.head.sha,
base_branch: pullData.base.ref,
owner: getLogin(pullData.user),
// Serialize to a JSON string; MySQL parses it into the JSON column.
assignees: JSON.stringify(pullData.assignees || []),
requested_reviewers: JSON.stringify(pullData.requested_reviewers || []),
cr_req: pullData.cr_req,
qa_req: pullData.qa_req,
closes: pullData.closes,
Expand Down
7 changes: 7 additions & 0 deletions models/pull.js
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,10 @@ class Pull {
user: {
login: getLogin(data.user),
},
assignees: (data.assignees || []).map((a) => getLogin(a)),
requested_reviewers: (data.requested_reviewers || []).map((r) =>
getLogin(r)
),
commits: data.commits,
additions: data.additions,
deletions: data.deletions,
Expand Down Expand Up @@ -280,6 +284,9 @@ class Pull {
user: {
login: data.owner,
},
// mysql2 auto-parses the JSON column, so this is already an array (or null).
assignees: data.assignees ?? [],
requested_reviewers: data.requested_reviewers ?? [],
cr_req: data.cr_req,
qa_req: data.qa_req,
};
Expand Down