Skip to content

Commit 601afd3

Browse files
committed
feat(dashboard): adds "Involved" role badge for upstream items
- adds "involved" fallback role when upstream item has no specific author/assignee/reviewer match (ghost badge-sm styling) - settings repo count now includes upstream repos with breakdown
1 parent 9bf9ec6 commit 601afd3

File tree

5 files changed

+20
-6
lines changed

5 files changed

+20
-6
lines changed

src/app/components/dashboard/IssuesTab.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ export default function IssuesTab(props: IssuesTabProps) {
6262
new Map(props.trackedUsers?.map(u => [u.login, u]) ?? [])
6363
);
6464

65+
const upstreamRepoSet = createMemo(() =>
66+
new Set((config.upstreamRepos ?? []).map(r => r.fullName))
67+
);
68+
6569
const filterGroups = createMemo<FilterChipGroupDef[]>(() => {
6670
const users = props.allUsers;
6771
if (!users || users.length <= 1) return issueFilterGroups;
@@ -96,7 +100,7 @@ export default function IssuesTab(props: IssuesTabProps) {
96100
if (filter.repo && issue.repoFullName !== filter.repo) return false;
97101
if (filter.org && !issue.repoFullName.startsWith(filter.org + "/")) return false;
98102

99-
const roles = deriveInvolvementRoles(props.userLogin, issue.userLogin, issue.assigneeLogins, []);
103+
const roles = deriveInvolvementRoles(props.userLogin, issue.userLogin, issue.assigneeLogins, [], upstreamRepoSet().has(issue.repoFullName));
100104

101105
if (tabFilter.role !== "all") {
102106
if (!roles.includes(tabFilter.role as "author" | "assignee")) return false;

src/app/components/dashboard/PullRequestsTab.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ export default function PullRequestsTab(props: PullRequestsTabProps) {
127127
new Map(props.trackedUsers?.map(u => [u.login, u]) ?? [])
128128
);
129129

130+
const upstreamRepoSet = createMemo(() =>
131+
new Set((config.upstreamRepos ?? []).map(r => r.fullName))
132+
);
133+
130134
const filterGroups = createMemo<FilterChipGroupDef[]>(() => {
131135
const users = props.allUsers;
132136
if (!users || users.length <= 1) return prFilterGroups;
@@ -161,7 +165,7 @@ export default function PullRequestsTab(props: PullRequestsTabProps) {
161165
if (filter.repo && pr.repoFullName !== filter.repo) return false;
162166
if (filter.org && !pr.repoFullName.startsWith(filter.org + "/")) return false;
163167

164-
const roles = deriveInvolvementRoles(props.userLogin, pr.userLogin, pr.assigneeLogins, pr.reviewerLogins);
168+
const roles = deriveInvolvementRoles(props.userLogin, pr.userLogin, pr.assigneeLogins, pr.reviewerLogins, upstreamRepoSet().has(pr.repoFullName));
165169
const sizeCategory = prSizeCategory(pr.additions, pr.deletions);
166170

167171
// Tab filters — light-field filters always apply; heavy-field filters

src/app/components/settings/SettingsPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ export default function SettingsPage() {
295295
<div>
296296
<p class="text-sm font-medium text-base-content">Repositories</p>
297297
<p class="text-xs text-base-content/60">
298-
{localRepos().length} selected
298+
{localRepos().length + localUpstream().length} selected{localUpstream().length > 0 ? ` (${localUpstream().length} upstream)` : ""}
299299
</p>
300300
<Show when={localRepos().length > 50}>
301301
<p class="text-xs text-warning">

src/app/components/shared/RoleBadge.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { For, Show } from "solid-js";
22

33
interface RoleBadgeProps {
4-
roles: ("author" | "reviewer" | "assignee")[];
4+
roles: ("author" | "reviewer" | "assignee" | "involved")[];
55
}
66

77
const ROLE_CONFIG = {
@@ -17,6 +17,10 @@ const ROLE_CONFIG = {
1717
label: "Assignee",
1818
class: "badge badge-accent badge-sm",
1919
},
20+
involved: {
21+
label: "Involved",
22+
class: "badge badge-ghost badge-sm",
23+
},
2024
} as const;
2125

2226
export default function RoleBadge(props: RoleBadgeProps) {

src/app/lib/format.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,15 @@ export function deriveInvolvementRoles(
7575
authorLogin: string,
7676
assigneeLogins: string[],
7777
reviewerLogins: string[],
78-
): ("author" | "reviewer" | "assignee")[] {
78+
isUpstream?: boolean,
79+
): ("author" | "reviewer" | "assignee" | "involved")[] {
7980
if (!userLogin) return [];
8081
const login = userLogin.toLowerCase();
81-
const roles: ("author" | "reviewer" | "assignee")[] = [];
82+
const roles: ("author" | "reviewer" | "assignee" | "involved")[] = [];
8283
if (authorLogin.toLowerCase() === login) roles.push("author");
8384
if (reviewerLogins.some((r) => r.toLowerCase() === login)) roles.push("reviewer");
8485
if (assigneeLogins.some((a) => a.toLowerCase() === login)) roles.push("assignee");
86+
if (roles.length === 0 && isUpstream) roles.push("involved");
8587
return roles;
8688
}
8789

0 commit comments

Comments
 (0)