From 3d23385713600db744c8a0f056542d349b07fe8b Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 15 May 2026 11:26:14 +0800 Subject: [PATCH 1/5] Fix 5 UI issues: column visibility, avatar, description editor, dedup labels, breadcrumbs - Add Columns dropdown in board toolbar to toggle column visibility - Replace "?" avatar for unassigned issues with a subtle user outline icon - Replace plain description textarea with MarkdownRenderer view / RichTextEditor edit toggle - Deduplicate labels by id in both BoardPage and IssuePage - Add parent issue breadcrumb navigation in IssuePage header Co-authored-by: Cursor --- packages/web/src/components/IssueCard.tsx | 8 +- packages/web/src/components/Primitives.tsx | 7 +- packages/web/src/routes/BoardPage.tsx | 16 ++- packages/web/src/routes/IssuePage.tsx | 108 +++++++++++++++++++-- 4 files changed, 124 insertions(+), 15 deletions(-) diff --git a/packages/web/src/components/IssueCard.tsx b/packages/web/src/components/IssueCard.tsx index a6d584b..d51d79a 100644 --- a/packages/web/src/components/IssueCard.tsx +++ b/packages/web/src/components/IssueCard.tsx @@ -167,9 +167,11 @@ export function IssueCard({
- + {issue.assignee ? ( + + ) : null} {issue.assignee?.name ?? 'Unassigned'}
diff --git a/packages/web/src/components/Primitives.tsx b/packages/web/src/components/Primitives.tsx index eb399a7..81783ed 100644 --- a/packages/web/src/components/Primitives.tsx +++ b/packages/web/src/components/Primitives.tsx @@ -16,7 +16,12 @@ export function Avatar({ user, size = 20 }: { user?: AvatarUser | null | undefin display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--fg-faint)', fontSize: size * 0.5, flexShrink: 0, - }}>? + }}> + + + + + ); } const initials = user.avatar ?? (user.name ? user.name.trim().split(/\s+/).filter(Boolean).map(w => w[0]).join('').slice(0, 2).toUpperCase() : '?'); diff --git a/packages/web/src/routes/BoardPage.tsx b/packages/web/src/routes/BoardPage.tsx index 483a4d5..64640a8 100644 --- a/packages/web/src/routes/BoardPage.tsx +++ b/packages/web/src/routes/BoardPage.tsx @@ -184,7 +184,9 @@ export function BoardPage() { ); const teams = queryData?.teams.nodes ?? EMPTY_TEAMS; const users = queryData?.users.nodes ?? EMPTY_USERS; - const labels = queryData?.issueLabels.nodes ?? EMPTY_LABELS; + const labels = useMemo(() => Array.from( + new Map((queryData?.issueLabels.nodes ?? EMPTY_LABELS).map(l => [l.id, l])).values() + ), [queryData?.issueLabels.nodes]); const baseIssues = queryData?.issues.nodes ?? EMPTY_ISSUES; const [createdIssues, setCreatedIssues] = useState([]); const [issueOverrides, setIssueOverrides] = useState>({}); @@ -1924,6 +1926,18 @@ export function BoardPage() { +
+ Columns +
+ {(selectedTeam?.states.nodes ?? []).map((state) => ( + + ))} +
+
+
diff --git a/packages/web/src/routes/IssuePage.tsx b/packages/web/src/routes/IssuePage.tsx index cb6c5c9..24ae879 100644 --- a/packages/web/src/routes/IssuePage.tsx +++ b/packages/web/src/routes/IssuePage.tsx @@ -86,6 +86,7 @@ export function IssuePage() { const [selectedLabelIds, setSelectedLabelIds] = useState([]); const [selectedAssigneeId, setSelectedAssigneeId] = useState(''); const [isEditingTitle, setIsEditingTitle] = useState(false); + const [isEditingDescription, setIsEditingDescription] = useState(false); const [commentBody, setCommentBody] = useState(''); const isSavingTitleRef = useRef(false); const titleTextareaRef = useRef(null); @@ -524,7 +525,9 @@ export function IssuePage() { } const activeIssue = issueSnapshot; - const allLabels = data?.issueLabels.nodes ?? []; + const allLabels = Array.from( + new Map((data?.issueLabels.nodes ?? []).map(l => [l.id, l])).values() + ); const allUsers = data?.users.nodes ?? []; // --- Render --- @@ -538,6 +541,31 @@ export function IssuePage() { } onClick={() => navigate(-1)}> {selectedTeam.key} + {activeIssue.parent ? ( + <> + + + + + + ) : null} + + + {activeIssue.identifier} @@ -612,15 +640,75 @@ export function IssuePage() { /> {/* Description */} -