From 5faa0a4d6cc04b0a045ebd5893e1b224f127f2a9 Mon Sep 17 00:00:00 2001 From: Daniel Beardsley Date: Tue, 10 Jun 2025 11:42:05 -0700 Subject: [PATCH 1/2] frontend: use index.html template for pull-card-demo Turns out, this was generating pull-card-demo.html which isn't' what's used when accessing /pull-card-demo (that is dynamically generated using webpack? and doesn't include the body classes we added for chakra). Now /pull-card-demo should load the generated index.html and thus have the same look and feel as the main page. --- frontend/webpack.dev.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/webpack.dev.config.js b/frontend/webpack.dev.config.js index 9728fa60..c165c109 100644 --- a/frontend/webpack.dev.config.js +++ b/frontend/webpack.dev.config.js @@ -77,7 +77,7 @@ export default { }), new HtmlWebpackPlugin({ template: relative("index.html"), - filename: "./pull-card-demo.html", + filename: "./pull-card-demo/index.html", chunks: ["pull-card-demo"], }), new ESLintPlugin({ From 27cbb50692690a0eb93ffa6099d93712c63fbe5b Mon Sep 17 00:00:00 2001 From: Daniel Beardsley Date: Tue, 10 Jun 2025 12:52:36 -0700 Subject: [PATCH 2/2] Pull cards: add "participants" UI component This indicates how many unique participants have left a comment or review. This also allows the "personal view" filter to include pulls you've commented on. Note: participants doesn't include the Author because I found myself having to explicitly exclude the Author every time I was checking for participants. --- frontend/dummy-pulls.json | 4 +++ frontend/src/pull-card/index.tsx | 2 ++ frontend/src/pull-card/participants.tsx | 37 +++++++++++++++++++++++++ frontend/src/pull.ts | 7 ++++- frontend/src/theme/day_theme.less | 3 ++ frontend/src/theme/night_theme.less | 3 ++ frontend/src/types.ts | 1 + frontend/test/named-pulls.ts | 34 +++++++++++++++++++++++ frontend/test/pull-card-demo.tsx | 2 ++ frontend/test/pull-data-parts.ts | 3 +- models/pull.js | 12 ++++++++ 11 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 frontend/src/pull-card/participants.tsx diff --git a/frontend/dummy-pulls.json b/frontend/dummy-pulls.json index f269022b..3511efd0 100644 --- a/frontend/dummy-pulls.json +++ b/frontend/dummy-pulls.json @@ -167,6 +167,7 @@ "base": { "ref": "master" }, + "participants": ["ianrohde", "Another"], "user": { "login": "ianrohde" }, @@ -457,6 +458,7 @@ "body": "pull request dummy body", "created_at": "2020-10-28T01:02:33.000Z", "updated_at": "2020-11-10T22:16:17.000Z", + "participants": ["danielbeardsley", "someone else"], "closed_at": null, "merged_at": null, "difficulty": null, @@ -4702,6 +4704,7 @@ "base": { "ref": "master" }, + "participants": ["BaseInfinity", "other", "another"], "user": { "login": "BaseInfinity" }, @@ -4991,6 +4994,7 @@ "base": { "ref": "master" }, + "participants": ["evannoronha", "someone else"], "user": { "login": "evannoronha" }, diff --git a/frontend/src/pull-card/index.tsx b/frontend/src/pull-card/index.tsx index 43d006e7..cf8aa21d 100644 --- a/frontend/src/pull-card/index.tsx +++ b/frontend/src/pull-card/index.tsx @@ -1,5 +1,6 @@ import { Pull } from "../pull"; import { CommitStatuses } from "./commit-statuses"; +import { Participants } from "./participants"; import { Age } from "./age"; import { Flags } from "./flags"; import { Avatar } from "./avatar"; @@ -68,6 +69,7 @@ export const PullCard = memo(function PullCard({ return ( + diff --git a/frontend/src/pull-card/participants.tsx b/frontend/src/pull-card/participants.tsx new file mode 100644 index 00000000..d999ee25 --- /dev/null +++ b/frontend/src/pull-card/participants.tsx @@ -0,0 +1,37 @@ +import { Pull } from "../pull"; +import { + Box +} from "@chakra-ui/react"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { + faUser, + faUsers, +} from "@fortawesome/free-solid-svg-icons"; + +export function Participants({ pull }: { pull: Pull }) { + if (!pull.participants?.length) { + return null; + } + return ( + + 1 ? faUsers : faUser} + title={tooltip(pull)} + color={pull.participating() ? "var(--participants-including-me)" : "var(--participants-without-me)"} + /> + + ); +} + +function tooltip(pull: Pull) { + if (pull.participants.length == 1) { + return pull.participating() ? + "Only you participating" : + "1 participant" + } else { + return pull.participating() ? + `${pull.participants.length} participants (including you)` : + `${pull.participants.length} participants`; + } +} + diff --git a/frontend/src/pull.ts b/frontend/src/pull.ts index 47bfad8d..38236b2f 100644 --- a/frontend/src/pull.ts +++ b/frontend/src/pull.ts @@ -49,7 +49,8 @@ export class Pull extends PullData { this.hasCurrentSig(getUser()) || this.hasOutdatedSig(getUser()) || this.hasMyDevBlock() || - this.hasMyDeployBlock() + this.hasMyDeployBlock() || + this.participating() ); } @@ -79,6 +80,10 @@ export class Pull extends PullData { ); } + participating(): boolean { + return this.participants && this.participants.includes(getUser()); + } + hasMyDevBlock(): boolean { return this.getDevBlock()?.data.user.login == getUser(); } diff --git a/frontend/src/theme/day_theme.less b/frontend/src/theme/day_theme.less index 7b71689c..cd9887be 100644 --- a/frontend/src/theme/day_theme.less +++ b/frontend/src/theme/day_theme.less @@ -175,6 +175,9 @@ body[data-theme="day_theme"] { --refresh-background: @white; --refresh-hover: @blue; + --participants-without-me: @grey; + --participants-including-me: @blue; + // Lines Changed --additions: darken(@green, 10%); --deletions: @red; diff --git a/frontend/src/theme/night_theme.less b/frontend/src/theme/night_theme.less index 8d60d7c0..4f29943c 100644 --- a/frontend/src/theme/night_theme.less +++ b/frontend/src/theme/night_theme.less @@ -168,6 +168,9 @@ body[data-theme="night_theme"] { --refresh-background: @steel; --refresh-hover: @blue; + --participants-without-me: darken(@grey, 15%); + --participants-including-me: @blue; + --copy-branch: darken(@grey, 15%); --copy-branch-hover: @blue; diff --git a/frontend/src/types.ts b/frontend/src/types.ts index 20e1494c..75d605c3 100644 --- a/frontend/src/types.ts +++ b/frontend/src/types.ts @@ -124,4 +124,5 @@ export class PullData { commit_statuses: CommitStatus[]; }; labels: Label[]; + participants: string[]; } diff --git a/frontend/test/named-pulls.ts b/frontend/test/named-pulls.ts index 222545e3..428ffb1c 100644 --- a/frontend/test/named-pulls.ts +++ b/frontend/test/named-pulls.ts @@ -390,6 +390,39 @@ export const MyOwn = [ }), ]; +export const Participants = [ + pullData({ + number: 1, + title: "No participants", + cr_req: 0, + participants: [], + }), + pullData({ + number: 2, + title: "One participant", + cr_req: 0, + participants: ["Other"], + }), + pullData({ + number: 3, + title: "Multiple participants", + cr_req: 0, + participants: ["User2", "User3"], + }), + pullData({ + number: 4, + title: "Only me participating", + cr_req: 0, + participants: [getUser()], + }), + pullData({ + number: 5, + title: "multiple participants (including me)", + cr_req: 0, + participants: ["User2", "User3", getUser()], + }), +]; + export const KitchenSink = [ pullData({ title: "Pull With Lots of flags and such and a really long title", @@ -428,5 +461,6 @@ export const KitchenSink = [ created_at: daysAgo(1 / 24), }), ], + participants: ["other person", getUser()], }), ]; diff --git a/frontend/test/pull-card-demo.tsx b/frontend/test/pull-card-demo.tsx index 976a31da..c89c4731 100644 --- a/frontend/test/pull-card-demo.tsx +++ b/frontend/test/pull-card-demo.tsx @@ -17,6 +17,7 @@ import { Labels, Draft, MyOwn, + Participants, KitchenSink, } from "./named-pulls"; import { PullCard } from "../src/pull-card"; @@ -50,6 +51,7 @@ function PullCardDemo() { + ); diff --git a/frontend/test/pull-data-parts.ts b/frontend/test/pull-data-parts.ts index b16a2221..a0d57186 100644 --- a/frontend/test/pull-data-parts.ts +++ b/frontend/test/pull-data-parts.ts @@ -77,7 +77,7 @@ export function pullData(p: DeepPartial): PullData { return { repo: repo, repoSpec: p.repoSpec || null, - number: pullNumber(), + number: p.number || pullNumber(), state: "open", draft: p.draft, title: p.title || "Young pull with no CR / QA", @@ -113,6 +113,7 @@ export function pullData(p: DeepPartial): PullData { commit_statuses: p.status?.commit_statuses || [], }, labels: p.labels || [], + participants: p.participants || [], }; } diff --git a/models/pull.js b/models/pull.js index f1602fd7..60ed4c2a 100644 --- a/models/pull.js +++ b/models/pull.js @@ -32,6 +32,7 @@ class Pull { this.data.closes = data.closes; this.data.connects = data.connects; } + this.data.participants = this.collectParticipants(); this.identifySignatures(); } @@ -70,6 +71,17 @@ class Pull { }); } + collectParticipants() { + const participants = new Set(); + this.comments.forEach((comment) => { + participants.add(comment.data.user.login); + }); + this.reviews.forEach((review) => { + participants.add(review.data.user.login); + }); + return Array.from(participants); + } + syncToIssue() { return Promise.resolve(this); /* The below needs to be rethought a bit and possibly the causal direction