From 4b48d573869af657d12002ceb85a2f631823c559 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 15 May 2026 17:07:05 +0800 Subject: [PATCH 1/7] Fix non-functional UI elements and label deduplication - Wire Filter button in BoardPage to toggle filter bar visibility (default hidden); remove redundant Sort button - Fix label dedup to use name instead of id to prevent same-name duplicates from imports (BoardPage, IssuePage, BacklogPage, Drawer) - Wire "Link to issue" button in IssuePage to copy markdown link - Wire "Invite members" button in SettingsPage to navigate to /members Co-authored-by: Cursor --- .../web/src/components/IssueDetailDrawer.tsx | 2 +- packages/web/src/routes/BacklogPage.tsx | 2 +- packages/web/src/routes/BoardPage.tsx | 18 +++++++------ packages/web/src/routes/IssuePage.tsx | 25 ++++++++++++++----- packages/web/src/routes/SettingsPage.tsx | 3 ++- 5 files changed, 34 insertions(+), 16 deletions(-) diff --git a/packages/web/src/components/IssueDetailDrawer.tsx b/packages/web/src/components/IssueDetailDrawer.tsx index 401355c..aec0ea3 100644 --- a/packages/web/src/components/IssueDetailDrawer.tsx +++ b/packages/web/src/components/IssueDetailDrawer.tsx @@ -151,7 +151,7 @@ export function IssueDetailDrawer({ id: `${issue.id}-labels`, meta: issue.updatedAt, title: 'Labels updated', - body: issue.labels.nodes.map((label) => label.name).join(', '), + body: [...new Set(issue.labels.nodes.map((label) => label.name))].join(', '), }); } diff --git a/packages/web/src/routes/BacklogPage.tsx b/packages/web/src/routes/BacklogPage.tsx index 826cfb3..3bfecdd 100644 --- a/packages/web/src/routes/BacklogPage.tsx +++ b/packages/web/src/routes/BacklogPage.tsx @@ -399,7 +399,7 @@ export function BacklogPage({ {issue.state.name} {issue.labels.nodes.length > 0 - ? issue.labels.nodes.map((label) => label.name).join(', ') + ? [...new Set(issue.labels.nodes.map((label) => label.name))].join(', ') : '—'} {issue.assignee?.name ?? issue.assignee?.email ?? 'Unassigned'} diff --git a/packages/web/src/routes/BoardPage.tsx b/packages/web/src/routes/BoardPage.tsx index 81e6cf7..2b3de06 100644 --- a/packages/web/src/routes/BoardPage.tsx +++ b/packages/web/src/routes/BoardPage.tsx @@ -87,7 +87,7 @@ import { IssueCard } from '../components/IssueCard'; import { IssueDetailDrawer } from '../components/IssueDetailDrawer'; import { KanbanView } from '../components/KanbanView'; import { BacklogPage } from './BacklogPage'; -import { IcoFilter, IcoSort, IcoPlus, IcoList, IcoBoard, IcoClose, IcoChevR } from '../components/Icons'; +import { IcoFilter, IcoPlus, IcoList, IcoBoard, IcoClose, IcoChevR } from '../components/Icons'; import { Btn, PriorityIcon } from '../components/Primitives'; const ISSUE_PAGE_SIZE = 200; @@ -205,9 +205,13 @@ export function BoardPage() { ); const teams = queryData?.teams.nodes ?? EMPTY_TEAMS; const users = queryData?.users.nodes ?? EMPTY_USERS; - const labels = useMemo(() => Array.from( - new Map((queryData?.issueLabels.nodes ?? EMPTY_LABELS).map(l => [l.id, l])).values() - ), [queryData?.issueLabels.nodes]); + const labels = useMemo(() => { + const seen = new Map(); + for (const l of queryData?.issueLabels.nodes ?? EMPTY_LABELS) { + if (!seen.has(l.name)) seen.set(l.name, l); + } + return Array.from(seen.values()); + }, [queryData?.issueLabels.nodes]); const baseIssues = queryData?.issues.nodes ?? EMPTY_ISSUES; const [createdIssues, setCreatedIssues] = useState([]); const [issueOverrides, setIssueOverrides] = useState>({}); @@ -236,6 +240,7 @@ export function BoardPage() { const [activeSavedBoardViewId, setActiveSavedBoardViewId] = useState(''); const boardSearchInputRef = useRef(null); const [inlineCreateGroupId, setInlineCreateGroupId] = useState(null); + const [filterBarVisible, setFilterBarVisible] = useState(false); const [collapsedColumns, setCollapsedColumns] = useState>(() => { try { const stored = localStorage.getItem('involute:collapsed-columns'); @@ -1727,8 +1732,7 @@ export function BoardPage() { ))} ) : null} - } size="sm">Filter - } size="sm">Sort + } size="sm" onClick={() => setFilterBarVisible((v) => !v)}>{filterBarVisible ? 'Hide filters' : 'Filter'}
) : null} - {!isBacklogView ? ( + {!isBacklogView && filterBarVisible ? ( <>
l.name).join(', '), + body: [...new Set(issueSnapshot.labels.nodes.map((l) => l.name))].join(', '), }); } @@ -525,9 +525,15 @@ export function IssuePage() { } const activeIssue = issueSnapshot; - const allLabels = Array.from( - new Map((data?.issueLabels.nodes ?? []).map(l => [l.id, l])).values() - ); + const allLabels = (() => { + const raw = data?.issueLabels.nodes ?? []; + const namesSeen = new Set(); + return raw.filter((l) => { + if (namesSeen.has(l.name)) return false; + namesSeen.add(l.name); + return true; + }); + })(); const allUsers = data?.users.nodes ?? []; // --- Render --- @@ -968,9 +974,16 @@ export function IssuePage() { -