diff --git a/ui/src/components/IssueProperties.test.tsx b/ui/src/components/IssueProperties.test.tsx
index 3c92683a7b0..2069d76b1bf 100644
--- a/ui/src/components/IssueProperties.test.tsx
+++ b/ui/src/components/IssueProperties.test.tsx
@@ -323,6 +323,9 @@ describe("IssueProperties", () => {
const selectedParentTrigger = Array.from(container.querySelectorAll("button"))
.find((button) => button.textContent?.includes("PAP-2 Candidate parent"));
expect(selectedParentTrigger).not.toBeUndefined();
+ const parentLink = container.querySelector('a[href="/issues/PAP-2"]');
+ expect(parentLink).not.toBeNull();
+ expect(selectedParentTrigger!.contains(parentLink)).toBe(false);
await act(async () => {
selectedParentTrigger!.dispatchEvent(new MouseEvent("click", { bubbles: true }));
diff --git a/ui/src/components/IssueProperties.tsx b/ui/src/components/IssueProperties.tsx
index 32592a885fd..0deebe6376d 100644
--- a/ui/src/components/IssueProperties.tsx
+++ b/ui/src/components/IssueProperties.tsx
@@ -708,17 +708,19 @@ export function IssueProperties({
{parentIdentifier ? `${parentIdentifier} ` : ""}
{parentTitle}
- e.stopPropagation()}
- >
-
-
) : (
No parent
);
+ const parentLink = issue.parentId ? (
+ e.stopPropagation()}
+ >
+
+
+ ) : undefined;
const parentOptions = (allIssues ?? [])
.filter((candidate) => candidate.id !== issue.id)
.filter((candidate) => !descendantIssueIds.has(candidate.id))
@@ -944,6 +946,7 @@ export function IssueProperties({
triggerContent={parentTrigger}
triggerClassName="min-w-0 max-w-full"
popoverClassName="w-72"
+ extra={parentLink}
>
{parentContent}
diff --git a/ui/src/components/IssuesList.test.tsx b/ui/src/components/IssuesList.test.tsx
index 9dee6d6b91b..4c263f96ed5 100644
--- a/ui/src/components/IssuesList.test.tsx
+++ b/ui/src/components/IssuesList.test.tsx
@@ -421,6 +421,47 @@ describe("IssuesList", () => {
});
});
+ it("skips deferred row sizing for expanded parent rows with visible children", async () => {
+ const parentIssue = createIssue({
+ id: "issue-parent",
+ identifier: "PAP-1",
+ title: "Parent issue",
+ });
+ const childIssue = createIssue({
+ id: "issue-child",
+ identifier: "PAP-2",
+ title: "Child issue",
+ parentId: "issue-parent",
+ });
+
+ const { root } = renderWithQueryClient(
+ undefined}
+ />,
+ container,
+ );
+
+ await waitForAssertion(() => {
+ const rows = Array.from(container.querySelectorAll('[data-testid="issue-row"]'));
+ const parentRow = rows.find((row) => row.textContent?.includes("Parent issue"));
+ const childRow = rows.find((row) => row.textContent?.includes("Child issue"));
+ expect(parentRow).not.toBeUndefined();
+ expect(childRow).not.toBeUndefined();
+ expect((parentRow?.parentElement as HTMLDivElement | null)?.style.contentVisibility).toBe("");
+ expect((parentRow?.parentElement as HTMLDivElement | null)?.style.containIntrinsicSize).toBe("");
+ expect((childRow?.parentElement as HTMLDivElement | null)?.style.contentVisibility).toBe("auto");
+ expect((childRow?.parentElement as HTMLDivElement | null)?.style.containIntrinsicSize).toBe("44px");
+ });
+
+ act(() => {
+ root.unmount();
+ });
+ });
+
it("uses context-scoped persisted column visibility", async () => {
localStorage.setItem("paperclip:test-issues:company-1:issue-columns", JSON.stringify(["id", "assignee"]));
diff --git a/ui/src/components/IssuesList.tsx b/ui/src/components/IssuesList.tsx
index 5b8a562a28c..1f8ebcdcba7 100644
--- a/ui/src/components/IssuesList.tsx
+++ b/ui/src/components/IssuesList.tsx
@@ -835,6 +835,7 @@ export function IssuesList({
const hasChildren = children.length > 0;
const totalDescendants = hasChildren ? countDescendants(issue.id, childMap) : 0;
const isExpanded = !viewState.collapsedParents.includes(issue.id);
+ const useDeferredRowRendering = !(hasChildren && isExpanded);
const issueProject = issue.projectId ? projectById.get(issue.projectId) ?? null : null;
const parentIssue = issue.parentId ? issueById.get(issue.parentId) ?? null : null;
const toggleCollapse = (e: { preventDefault: () => void; stopPropagation: () => void }) => {
@@ -852,8 +853,12 @@ export function IssuesList({
key={issue.id}
style={{
...(depth > 0 ? { paddingLeft: `${depth * 16}px` } : {}),
- contentVisibility: "auto",
- containIntrinsicSize: "44px",
+ ...(useDeferredRowRendering
+ ? {
+ contentVisibility: "auto",
+ containIntrinsicSize: "44px",
+ }
+ : {}),
}}
>
{
);
expect(html).toContain("world");
- expect(html).toContain("first");
- expect(html).toContain("second");
+ expect(html).toMatch(/]*>first<\/li>/);
+ expect(html).toMatch(/]*>second<\/li>/);
});
it("hides saved-session resume skip stderr from nice mode normalization", () => {
@@ -106,8 +106,8 @@ describe("RunTranscriptView", () => {
);
expect(html).toContain("Summary
");
- expect(html).toContain("fixed deploy config");
- expect(html).toContain("posted issue update");
+ expect(html).toMatch(/]*>fixed deploy config<\/li>/);
+ expect(html).toMatch(/]*>posted issue update<\/li>/);
expect(html).not.toContain("result");
});
});