Add optional Parent Issue column to inbox show/hide columns

Adds a "parent" column option to the inbox column toggle dropdown.
When enabled, sub-issues display the parent's identifier (e.g. PAP-123)
with the parent title as a tooltip. Uses the existing issueById lookup
map to resolve parent info without additional API calls.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta 2026-04-06 15:38:02 -05:00
parent c414790404
commit b3b9d99519
4 changed files with 33 additions and 3 deletions

View file

@ -515,13 +515,14 @@ describe("inbox helpers", () => {
});
it("hides the workspace column option unless isolated workspaces are enabled", () => {
expect(getAvailableInboxIssueColumns(false)).toEqual(["status", "id", "assignee", "project", "labels", "updated"]);
expect(getAvailableInboxIssueColumns(false)).toEqual(["status", "id", "assignee", "project", "parent", "labels", "updated"]);
expect(getAvailableInboxIssueColumns(true)).toEqual([
"status",
"id",
"assignee",
"project",
"workspace",
"parent",
"labels",
"updated",
]);

View file

@ -9,7 +9,7 @@ export const INBOX_LAST_TAB_KEY = "paperclip:inbox:last-tab";
export const INBOX_ISSUE_COLUMNS_KEY = "paperclip:inbox:issue-columns";
export type InboxTab = "mine" | "recent" | "unread" | "all";
export type InboxApprovalFilter = "all" | "actionable" | "resolved";
export const inboxIssueColumns = ["status", "id", "assignee", "project", "workspace", "labels", "updated"] as const;
export const inboxIssueColumns = ["status", "id", "assignee", "project", "workspace", "parent", "labels", "updated"] as const;
export type InboxIssueColumn = (typeof inboxIssueColumns)[number];
export const DEFAULT_INBOX_ISSUE_COLUMNS: InboxIssueColumn[] = ["status", "id", "updated"];
export type InboxWorkItem =

View file

@ -205,6 +205,8 @@ describe("InboxIssueTrailingColumns", () => {
workspaceName={null}
assigneeName={null}
currentUserId={null}
parentIdentifier={null}
parentTitle={null}
/>,
);
});
@ -229,6 +231,8 @@ describe("InboxIssueTrailingColumns", () => {
workspaceName={null}
assigneeName={null}
currentUserId={null}
parentIdentifier={null}
parentTitle={null}
/>,
);
});

View file

@ -141,13 +141,14 @@ function readIssueIdFromRun(run: HeartbeatRun): string | null {
type NonIssueUnreadState = "visible" | "fading" | "hidden" | null;
const trailingIssueColumns: InboxIssueColumn[] = ["assignee", "project", "workspace", "labels", "updated"];
const trailingIssueColumns: InboxIssueColumn[] = ["assignee", "project", "workspace", "parent", "labels", "updated"];
const inboxIssueColumnLabels: Record<InboxIssueColumn, string> = {
status: "Status",
id: "ID",
assignee: "Assignee",
project: "Project",
workspace: "Workspace",
parent: "Parent issue",
labels: "Tags",
updated: "Last updated",
};
@ -157,6 +158,7 @@ const inboxIssueColumnDescriptions: Record<InboxIssueColumn, string> = {
assignee: "Assigned agent or board user.",
project: "Linked project pill with its color.",
workspace: "Execution or project workspace used for the issue.",
parent: "Parent issue identifier and title.",
labels: "Issue labels and tags.",
updated: "Latest visible activity time.",
};
@ -224,6 +226,7 @@ function issueTrailingGridTemplate(columns: InboxIssueColumn[]): string {
if (column === "assignee") return "minmax(7.5rem, 9.5rem)";
if (column === "project") return "minmax(6.5rem, 8.5rem)";
if (column === "workspace") return "minmax(9rem, 12rem)";
if (column === "parent") return "minmax(8rem, 12rem)";
if (column === "labels") return "minmax(8rem, 10rem)";
return "minmax(6rem, 7rem)";
})
@ -238,6 +241,8 @@ export function InboxIssueTrailingColumns({
workspaceName,
assigneeName,
currentUserId,
parentIdentifier,
parentTitle,
}: {
issue: Issue;
columns: InboxIssueColumn[];
@ -246,6 +251,8 @@ export function InboxIssueTrailingColumns({
workspaceName: string | null;
assigneeName: string | null;
currentUserId: string | null;
parentIdentifier: string | null;
parentTitle: string | null;
}) {
const activityText = timeAgo(issue.lastActivityAt ?? issue.lastExternalCommentAt ?? issue.updatedAt);
const userLabel = formatAssigneeUserLabel(issue.assigneeUserId, currentUserId) ?? "User";
@ -348,6 +355,22 @@ export function InboxIssueTrailingColumns({
);
}
if (column === "parent") {
if (!issue.parentId) {
return <span key={column} className="min-w-0" aria-hidden="true" />;
}
return (
<span key={column} className="min-w-0 truncate text-xs text-muted-foreground" title={parentTitle ?? undefined}>
{parentIdentifier ? (
<span className="font-mono">{parentIdentifier}</span>
) : (
<span className="italic">Sub-issue</span>
)}
</span>
);
}
return (
<span key={column} className="min-w-0 truncate text-right text-[11px] font-medium text-muted-foreground">
{activityText}
@ -1979,6 +2002,8 @@ export function Inbox() {
})}
assigneeName={agentName(issue.assigneeAgentId)}
currentUserId={currentUserId}
parentIdentifier={issue.parentId ? (issueById.get(issue.parentId)?.identifier ?? null) : null}
parentTitle={issue.parentId ? (issueById.get(issue.parentId)?.title ?? null) : null}
/>
) : undefined
}