From 3717bab673857c2695e6531d58a51e5efe5981f6 Mon Sep 17 00:00:00 2001 From: Forgotten Date: Wed, 25 Feb 2026 17:40:13 -0600 Subject: [PATCH] fix(ui): prevent top bar and header rows from overflowing on mobile - BreadcrumbBar: add min-w-0/overflow-hidden to container, truncate last breadcrumb item - IssueDetail: add flex-wrap and min-w-0 to header row, shrink-0 on buttons, truncate project name - Companies: add flex-wrap and tighter gap on stats row for mobile Co-Authored-By: Claude Opus 4.6 --- ui/src/components/BreadcrumbBar.tsx | 14 +++++----- ui/src/pages/Companies.tsx | 2 +- ui/src/pages/IssueDetail.tsx | 40 +++++++++++++++++++++-------- 3 files changed, 38 insertions(+), 18 deletions(-) diff --git a/ui/src/components/BreadcrumbBar.tsx b/ui/src/components/BreadcrumbBar.tsx index 55438b2c..e627099e 100644 --- a/ui/src/components/BreadcrumbBar.tsx +++ b/ui/src/components/BreadcrumbBar.tsx @@ -33,9 +33,9 @@ export function BreadcrumbBar() { // Single breadcrumb = page title (uppercase) if (breadcrumbs.length === 1) { return ( -
+
{menuButton} -

+

{breadcrumbs[0].label}

@@ -44,18 +44,18 @@ export function BreadcrumbBar() { // Multiple breadcrumbs = breadcrumb trail return ( -
+
{menuButton} - - + + {breadcrumbs.map((crumb, i) => { const isLast = i === breadcrumbs.length - 1; return ( {i > 0 && } - + {isLast || !crumb.href ? ( - {crumb.label} + {crumb.label} ) : ( {crumb.label} diff --git a/ui/src/pages/Companies.tsx b/ui/src/pages/Companies.tsx index abf73e0b..6d1ff8f0 100644 --- a/ui/src/pages/Companies.tsx +++ b/ui/src/pages/Companies.tsx @@ -231,7 +231,7 @@ export function Companies() {
{/* Stats row */} -
+
diff --git a/ui/src/pages/IssueDetail.tsx b/ui/src/pages/IssueDetail.tsx index 2431f1fb..73b978ab 100644 --- a/ui/src/pages/IssueDetail.tsx +++ b/ui/src/pages/IssueDetail.tsx @@ -3,6 +3,7 @@ import { useParams, Link, useNavigate } from "react-router-dom"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { issuesApi } from "../api/issues"; import { activityApi } from "../api/activity"; +import { heartbeatsApi } from "../api/heartbeats"; import { agentsApi } from "../api/agents"; import { projectsApi } from "../api/projects"; import { useCompany } from "../context/CompanyContext"; @@ -186,6 +187,15 @@ export function IssueDetail() { enabled: !!issueId, }); + const { data: liveRuns } = useQuery({ + queryKey: queryKeys.issues.liveRuns(issueId!), + queryFn: () => heartbeatsApi.liveRunsForIssue(issueId!), + enabled: !!issueId && !!selectedCompanyId, + refetchInterval: 3000, + }); + + const hasLiveRuns = (liveRuns ?? []).length > 0; + const { data: allIssues } = useQuery({ queryKey: queryKeys.issues.list(selectedCompanyId!), queryFn: () => issuesApi.list(selectedCompanyId!), @@ -423,7 +433,7 @@ export function IssueDetail() { )}
-
+
updateIssue.mutate({ status })} @@ -432,15 +442,25 @@ export function IssueDetail() { priority={issue.priority} onChange={(priority) => updateIssue.mutate({ priority })} /> - {issue.identifier ?? issue.id.slice(0, 8)} + {issue.identifier ?? issue.id.slice(0, 8)} + + {hasLiveRuns && ( + + + + + + Live + + )} {issue.projectId ? ( - {(projects ?? []).find((p) => p.id === issue.projectId)?.name ?? issue.projectId.slice(0, 8)} + {(projects ?? []).find((p) => p.id === issue.projectId)?.name ?? issue.projectId.slice(0, 8)} ) : ( @@ -473,7 +493,7 @@ export function IssueDetail() { @@ -599,10 +619,6 @@ export function IssueDetail() { - - - - @@ -632,6 +648,10 @@ export function IssueDetail() { const attachment = await uploadAttachment.mutateAsync(file); return attachment.contentPath; }} + onAttachImage={async (file) => { + await uploadAttachment.mutateAsync(file); + }} + liveRunSlot={} />