fix(ui): harden issue breadcrumb source routing

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta 2026-03-27 08:02:26 -05:00
parent 0f9faa297b
commit 3986eb615c
6 changed files with 101 additions and 15 deletions

View file

@ -12,7 +12,7 @@ import { heartbeatsApi } from "../api/heartbeats";
import { useCompany } from "../context/CompanyContext";
import { useBreadcrumbs } from "../context/BreadcrumbContext";
import { queryKeys } from "../lib/queryKeys";
import { createIssueDetailLocationState } from "../lib/issueDetailBreadcrumb";
import { createIssueDetailLocationState, createIssueDetailPath } from "../lib/issueDetailBreadcrumb";
import { EmptyState } from "../components/EmptyState";
import { PageSkeleton } from "../components/PageSkeleton";
import { IssueRow } from "../components/IssueRow";
@ -526,6 +526,7 @@ export function Inbox() {
createIssueDetailLocationState(
"Inbox",
`${location.pathname}${location.search}${location.hash}`,
"inbox",
),
[location.pathname, location.search, location.hash],
);
@ -1019,7 +1020,7 @@ export function Inbox() {
const item = workItemsToRender[selectedIndex];
if (item.kind === "issue") {
const pathId = item.issue.identifier ?? item.issue.id;
navigate(`/issues/${pathId}`, { state: issueLinkState });
navigate(createIssueDetailPath(pathId, issueLinkState), { state: issueLinkState });
} else if (item.kind === "approval") {
navigate(`/approvals/${item.approval.id}`);
} else if (item.kind === "failed_run") {

View file

@ -14,7 +14,7 @@ import { useToast } from "../context/ToastContext";
import { useBreadcrumbs } from "../context/BreadcrumbContext";
import { assigneeValueFromSelection, suggestedCommentAssigneeValue } from "../lib/assignees";
import { queryKeys } from "../lib/queryKeys";
import { readIssueDetailBreadcrumb } from "../lib/issueDetailBreadcrumb";
import { createIssueDetailPath, readIssueDetailBreadcrumb } from "../lib/issueDetailBreadcrumb";
import { useProjectOrder } from "../hooks/useProjectOrder";
import { relativeTime, cn, formatTokens, visibleRunCostUsd } from "../lib/utils";
import { InlineEditor } from "../components/InlineEditor";
@ -270,8 +270,8 @@ export function IssueDetail() {
const hasLiveRuns = (liveRuns ?? []).length > 0 || !!activeRun;
const sourceBreadcrumb = useMemo(
() => readIssueDetailBreadcrumb(location.state) ?? { label: "Issues", href: "/issues" },
[location.state],
() => readIssueDetailBreadcrumb(location.state, location.search) ?? { label: "Issues", href: "/issues" },
[location.state, location.search],
);
// Filter out runs already shown by the live widget to avoid duplication
@ -581,9 +581,12 @@ export function IssueDetail() {
// Redirect to identifier-based URL if navigated via UUID
useEffect(() => {
if (issue?.identifier && issueId !== issue.identifier) {
navigate(`/issues/${issue.identifier}`, { replace: true, state: location.state });
navigate(createIssueDetailPath(issue.identifier, location.state, location.search), {
replace: true,
state: location.state,
});
}
}, [issue, issueId, navigate, location.state]);
}, [issue, issueId, navigate, location.state, location.search]);
useEffect(() => {
if (!issue?.id) return;
@ -695,7 +698,7 @@ export function IssueDetail() {
<span key={ancestor.id} className="flex items-center gap-1">
{i > 0 && <ChevronRight className="h-3 w-3 shrink-0" />}
<Link
to={`/issues/${ancestor.identifier ?? ancestor.id}`}
to={createIssueDetailPath(ancestor.identifier ?? ancestor.id, location.state, location.search)}
state={location.state}
className="hover:text-foreground transition-colors truncate max-w-[200px]"
title={ancestor.title}
@ -1063,7 +1066,7 @@ export function IssueDetail() {
{childIssues.map((child) => (
<Link
key={child.id}
to={`/issues/${child.identifier ?? child.id}`}
to={createIssueDetailPath(child.identifier ?? child.id, location.state, location.search)}
state={location.state}
className="flex items-center justify-between px-3 py-2 text-sm hover:bg-accent/20 transition-colors"
>

View file

@ -70,6 +70,7 @@ export function Issues() {
createIssueDetailLocationState(
"Issues",
`${location.pathname}${location.search}${location.hash}`,
"issues",
),
[location.pathname, location.search, location.hash],
);