From e473ba68fb23d5e25a18e04113dfb8c16f9db6c2 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Wed, 24 Jun 2026 22:29:19 -0700 Subject: [PATCH] FN-6997: widen task changes diff panel Reclaims task detail padding so inline diffs have more readable width on compact screens. - Expand the compact Changes file list to consume detail-body padding without page overflow. - Add mobile breakpoint coverage that matches the detail-body padding contract. - Add regression tests for the phone-width inline diff surface and CSS rules. - Add a patch changeset for the published Fusion CLI package. Files changed: .changeset/fn-6997-diff-panel-width.md | 7 ++ .../dashboard/app/components/TaskChangesTab.css | 20 ++++- .../components/__tests__/TaskChangesTab.test.tsx | 98 +++++++++++++++++++++- 3 files changed, 121 insertions(+), 4 deletions(-) Fusion-Task-Id: FN-6997 Fusion-Task-Lineage: a7f21c0d-89a8-430e-a84c-341a10af4a4a --- .changeset/fn-6997-diff-panel-width.md | 7 ++ .../app/components/TaskChangesTab.css | 20 +++- .../__tests__/TaskChangesTab.test.tsx | 98 ++++++++++++++++++- 3 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 .changeset/fn-6997-diff-panel-width.md diff --git a/.changeset/fn-6997-diff-panel-width.md b/.changeset/fn-6997-diff-panel-width.md new file mode 100644 index 0000000000..9172ddabae --- /dev/null +++ b/.changeset/fn-6997-diff-panel-width.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Make the task Changes tab inline diff panel wider on narrow screens. +category: fix +dev: Reclaims task-detail body padding for compact inline diff lists with mobile CSS contract coverage. diff --git a/packages/dashboard/app/components/TaskChangesTab.css b/packages/dashboard/app/components/TaskChangesTab.css index cac5a74a1a..2d006bef63 100644 --- a/packages/dashboard/app/components/TaskChangesTab.css +++ b/packages/dashboard/app/components/TaskChangesTab.css @@ -2,10 +2,24 @@ gap: var(--space-xs); } -/* Pull the file list wider to reclaim horizontal space from .detail-body padding */ +/* +FNXC:TaskChangesDiff 2026-06-25-22:12: +The inline task Changes diff should reclaim safe horizontal padding from the task detail body, especially on Android-width viewports, without changing the expanded diff modal or allowing page-level horizontal overflow. +Keep the negative margins matched to the active .detail-body padding at desktop/tablet and mobile breakpoints. +*/ .task-changes-tab .changes-file-list.task-changes-file-list--compact { - margin-left: calc(-1 * var(--space-md)); - margin-right: calc(-1 * var(--space-md)); + margin-left: calc(-1 * calc(var(--space-lg) + var(--space-xs))); + margin-right: calc(-1 * calc(var(--space-lg) + var(--space-xs))); + max-width: calc(100% + (calc(var(--space-lg) + var(--space-xs)) * 2)); + box-sizing: border-box; +} + +@media (max-width: 768px) { + .task-changes-tab .changes-file-list.task-changes-file-list--compact { + margin-left: calc(-1 * calc(var(--space-md) + var(--space-xs) / 2)); + margin-right: calc(-1 * calc(var(--space-md) + var(--space-xs) / 2)); + max-width: calc(100% + (calc(var(--space-md) + var(--space-xs) / 2) * 2)); + } } .task-changes-file-list--compact .changes-file-header { diff --git a/packages/dashboard/app/components/__tests__/TaskChangesTab.test.tsx b/packages/dashboard/app/components/__tests__/TaskChangesTab.test.tsx index 11e944261c..1d9896c8ae 100644 --- a/packages/dashboard/app/components/__tests__/TaskChangesTab.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskChangesTab.test.tsx @@ -1,6 +1,6 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { render, screen, fireEvent, waitFor } from "@testing-library/react"; -import { loadAllAppCss } from "../../test/cssFixture"; +import { loadAllAppCss, loadAllAppCssBaseOnly } from "../../test/cssFixture"; import { TaskChangesTab } from "../TaskChangesTab"; import type { MergeDetails, Column } from "@fusion/core"; @@ -1115,6 +1115,102 @@ describe("TaskChangesTab — expand button", () => { }); describe("TaskChangesTab — compact spacing class", () => { + it("reproduces the mobile inline diff surface inside a phone-width detail body", async () => { + const longPath = "packages/dashboard/app/components/task-detail/mobile/VeryLongInlineDiffPanelRegressionFile.tsx"; + mockFetchTaskDiff.mockResolvedValue({ + files: [ + { + path: longPath, + status: "modified", + additions: 47, + deletions: 5, + patch: [ + "diff --git a/packages/dashboard/app/components/task-detail/mobile/VeryLongInlineDiffPanelRegressionFile.tsx b/packages/dashboard/app/components/task-detail/mobile/VeryLongInlineDiffPanelRegressionFile.tsx", + "@@ -1,3 +1,6 @@", + "-const cramped = true;", + "+const inlineChangesPanelReclaimsTaskDetailPaddingWithoutPageOverflow = true;", + "+export const androidChromeWidthRepresentativeLine = inlineChangesPanelReclaimsTaskDetailPaddingWithoutPageOverflow;", + ].join("\n"), + }, + { + path: "packages/dashboard/app/components/TaskChangesTab.css", + status: "modified", + additions: 3, + deletions: 0, + patch: "@@ -1 +1,3 @@\n+.task-changes-tab {}", + }, + ], + stats: { filesChanged: 2, additions: 50, deletions: 5 }, + }); + + const { container } = render( +
+ +
, + ); + + await waitFor(() => { + expect(screen.getByText(longPath)).toBeTruthy(); + }); + + const mobileDetailBody = screen.getByTestId("mobile-detail-body"); + const taskTab = container.querySelector(".detail-body > .task-changes-tab"); + const fileList = taskTab?.querySelector(".changes-file-list.task-changes-file-list--compact"); + const diffPatch = fileList?.querySelector(".changes-diff-patch.changes-diff-patch--wrap"); + + expect(mobileDetailBody.style.maxInlineSize).toBe("430px"); + expect(mobileDetailBody.style.overflowX).toBe("hidden"); + expect(taskTab).toBeTruthy(); + expect(fileList).toBeTruthy(); + expect(diffPatch).toBeTruthy(); + expect(diffPatch?.textContent).toContain("inlineChangesPanelReclaimsTaskDetailPaddingWithoutPageOverflow"); + expect(fileList?.getAttribute("style")).toBeNull(); + expect(diffPatch?.getAttribute("style")).toBeNull(); + }); + + it("widens the desktop inline file list by reclaiming detail-body padding without inline styles", () => { + const css = loadAllAppCssBaseOnly(); + const ruleMatch = css.match(/\.task-changes-tab\s+\.changes-file-list\.task-changes-file-list--compact\s*\{([^}]*)\}/); + + expect(ruleMatch).toBeTruthy(); + const rule = ruleMatch![1]; + expect(rule).toContain("margin-left: calc(-1 * calc(var(--space-lg) + var(--space-xs)));"); + expect(rule).toContain("margin-right: calc(-1 * calc(var(--space-lg) + var(--space-xs)));"); + expect(rule).toContain("max-width: calc(100% + (calc(var(--space-lg) + var(--space-xs)) * 2));"); + }); + + it("uses a 768px mobile breakpoint to reclaim the narrower mobile detail-body padding safely", () => { + const css = loadAllAppCss(); + const mobileRuleMatch = css.match(/@media\s*\(max-width:\s*768px\)\s*\{\s*\.task-changes-tab\s+\.changes-file-list\.task-changes-file-list--compact\s*\{([\s\S]*?)\}/); + + expect(mobileRuleMatch).toBeTruthy(); + const rule = mobileRuleMatch![1]; + expect(rule).toContain("margin-left: calc(-1 * calc(var(--space-md) + var(--space-xs) / 2));"); + expect(rule).toContain("margin-right: calc(-1 * calc(var(--space-md) + var(--space-xs) / 2));"); + expect(rule).toContain("max-width: calc(100% + (calc(var(--space-md) + var(--space-xs) / 2) * 2));"); + }); + + it("keeps mobile widening equal and opposite to detail-body padding while preserving overflow containment", () => { + const css = loadAllAppCss(); + const detailBodyMobileRuleMatch = css.match(/\.detail-body\s*\{\s*padding:\s*calc\(var\(--space-md\) \+ var\(--space-xs\) \/ 2\);([\s\S]*?)\}/); + const compactListMobileRuleMatch = css.match(/@media\s*\(max-width:\s*768px\)\s*\{\s*\.task-changes-tab\s+\.changes-file-list\.task-changes-file-list--compact\s*\{([\s\S]*?)\}/); + + expect(detailBodyMobileRuleMatch).toBeTruthy(); + expect(compactListMobileRuleMatch).toBeTruthy(); + + const mobilePadding = "calc(var(--space-md) + var(--space-xs) / 2)"; + expect(css).toContain("@media (max-width: 768px)"); + expect(detailBodyMobileRuleMatch![0]).toContain(`padding: ${mobilePadding};`); + expect(detailBodyMobileRuleMatch![1]).toContain("overflow-x: hidden;"); + expect(compactListMobileRuleMatch![1]).toContain(`margin-left: calc(-1 * ${mobilePadding});`); + expect(compactListMobileRuleMatch![1]).toContain(`margin-right: calc(-1 * ${mobilePadding});`); + expect(compactListMobileRuleMatch![1]).toContain(`max-width: calc(100% + (${mobilePadding} * 2));`); + }); + it("renders the file list with the compact modifier class", async () => { mockFetchTaskDiff.mockResolvedValue(DONE_TASK_DIFF);