FN-7836: fix Task Documents sidebar cards collapsing to blank rows under flex shrink

Fixes the Task Documents view rendering blank/border-only rows once many task-card groups load in the scrolling sidebar; each card now opts out of flex shrink so overflow clipping no longer compresses group content out of view.

- DocumentsView.css: add `flex: 0 0 auto` to `.documents-task-sidebar-group` so cards keep their natural height instead of being shrunk by the flex column when many groups are loaded
- DocumentsView.test.tsx: add regression test rendering 54 loaded task-document groups, asserting `flex-shrink: 0` and that group heading/content text remains visible and interactive
- Add changeset documenting the patch-level fix

Files changed:
 .changeset/fn-7836-task-documents-rendering.md     |  7 +++
 .../dashboard/app/components/DocumentsView.css     |  4 ++
 .../components/__tests__/DocumentsView.test.tsx    | 71 ++++++++++++++++++++++
 3 files changed, 82 insertions(+)

Fusion-Task-Id: FN-7836

Fusion-Task-Lineage: f07bad59-c6b9-41e3-9475-5a4339044bb4

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-07-11 21:15:13 -07:00
parent 1540473db8
commit b3ed63dae9
3 changed files with 82 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: Fix the Artifacts Task Documents list rendering as blank rows when documents are loaded.
category: fix
dev: Root cause was flex-shrinking task cards in DocumentsView.css; cards now opt out of shrink and DocumentsView.test.tsx covers loaded 50+ group rendering.

View File

@@ -373,6 +373,9 @@ FN-7811 reuses the Project Files shell for Task Documents, while task-scoped sid
FNXC:DocumentsView 2026-07-11-19:03:
FN-7834 requires task-document groups to scan as discrete task containers, not a flat sequence of peer rows. Keep the stronger card/header hierarchy and inter-group gap scoped under .documents-task-documents-sidebar so Project Files' shared .markdown-file-item list and the Artifacts gallery remain visually unchanged.
FNXC:DocumentsView 2026-07-11-21:12:
FN-7836 requires loaded Task Documents to render visible task-card groups even when 50+ tasks exist. The sidebar is a scrolling flex column; each card must opt out of flex shrink before overflow is clipped, otherwise browser layout compresses every group into border-only lines while the DOM/text still exists.
*/
.documents-task-documents-sidebar {
display: flex;
@@ -383,6 +386,7 @@ FN-7834 requires task-document groups to scan as discrete task containers, not a
}
.documents-task-sidebar-group {
flex: 0 0 auto;
overflow: hidden;
border: thin solid var(--border);
border-radius: var(--radius-lg);

View File

@@ -439,6 +439,77 @@ describe("DocumentsView", () => {
expect(legacyGroup.querySelector(".documents-group-status")).not.toBeInTheDocument();
});
/*
FNXC:DocumentsView 2026-07-11-21:12:
FN-7836 regression coverage targets the browser-only failure mode: real data can load while 50+ flexed task-card groups shrink under overflow clipping into border-only lines. Keep the test tied to the task-scoped CSS contract (`flex-shrink: 0`) plus visible group/row content so a loaded-but-blank sidebar cannot recur without failing close to the defect.
*/
it("renders many loaded task-document groups without flex-shrinking cards into blank lines", async () => {
const manyTaskDocuments: TaskDocumentWithTask[] = Array.from({ length: 54 }, (_, index) => {
const taskNumber = String(index + 1).padStart(3, "0");
return {
id: `many-doc-${taskNumber}`,
taskId: `FN-MANY-${taskNumber}`,
key: index === 0 ? "plan" : "notes",
content: `Document content ${taskNumber}`,
revision: index + 1,
author: "agent",
createdAt: `2026-04-19T10:${String(index % 60).padStart(2, "0")}:00.000Z`,
updatedAt: `2026-04-19T12:${String(index % 60).padStart(2, "0")}:00.000Z`,
taskTitle: index === 53 ? undefined : `Loaded task ${taskNumber}`,
taskColumn: index === 52 || index === 53 ? undefined : index % 2 === 0 ? "done" : "todo",
};
});
manyTaskDocuments.push({
id: "many-doc-001-notes",
taskId: "FN-MANY-001",
key: "notes",
content: "Second document content",
revision: 2,
author: "agent",
createdAt: "2026-04-19T09:00:00.000Z",
updatedAt: "2026-04-19T11:59:00.000Z",
taskTitle: "Loaded task 001",
taskColumn: "done",
});
mockUseProjectMarkdownFiles.mockReturnValue({
files: [],
loading: false,
error: null,
refresh: vi.fn().mockResolvedValue(undefined),
});
mockUseDocuments.mockReturnValue({
documents: manyTaskDocuments,
projectFiles: [],
loading: false,
error: null,
refresh: vi.fn().mockResolvedValue(undefined),
});
render(<DocumentsView addToast={addToast} onOpenDetail={onOpenDetail} />);
fireEvent.click(screen.getByRole("tab", { name: /show task documents/i }));
const sidebar = screen.getByLabelText("Task documents");
const groups = Array.from(sidebar.querySelectorAll<HTMLElement>(".documents-task-sidebar-group"));
expect(groups).toHaveLength(54);
expect(screen.queryByText("Loading task documents…")).not.toBeInTheDocument();
expect(screen.queryByText("No task documents yet.")).not.toBeInTheDocument();
expect(screen.getByText("Select a task document to view its content.")).toBeInTheDocument();
const firstGroup = screen.getByRole("heading", { name: /FN-MANY-001.*Loaded task 001/i }).closest(".documents-task-sidebar-group") as HTMLElement;
expect(getComputedStyle(firstGroup).flexShrink).toBe("0");
expect(within(firstGroup).getByText("FN-MANY-001")).toHaveTextContent("FN-MANY-001");
expect(within(firstGroup).getByText("Loaded task 001")).toHaveTextContent("Loaded task 001");
expect(within(firstGroup).getAllByRole("button", { name: /open FN-MANY-001/i })).toHaveLength(2);
const legacyGroup = screen.getByRole("heading", { name: /FN-MANY-054.*Untitled/i }).closest(".documents-task-sidebar-group") as HTMLElement;
expect(within(legacyGroup).getByText("Untitled")).toBeInTheDocument();
expect(legacyGroup.querySelector(".documents-group-status")).not.toBeInTheDocument();
fireEvent.click(within(firstGroup).getByRole("button", { name: "Open FN-MANY-001 plan" }));
expect(await screen.findByText("Document content 001")).toBeInTheDocument();
});
it("selecting a task document loads content and marks the sidebar entry current", () => {
render(<DocumentsView addToast={addToast} onOpenDetail={onOpenDetail} />);