From 7715a83e6f6d31ef29892efafac2490cc3c55c60 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Sun, 26 Jul 2026 19:45:47 -0700 Subject: [PATCH] FN-8624: fix task detail activity right padding Keep Task Detail activity insets symmetric while reserving overlay clearance only for first-row content. - Move Live/Feed overlay clearance from the activity container to first-row elements. - Preserve responsive overlay spacing and the full-width Interventions timeline. - Cover modal, pop-out, embedded, and responsive activity layouts with updated tests. - Add a patch changeset for the Task Detail padding fix. Files changed: .changeset/fn-8624-task-detail-inset.md | 7 ++++ .../dashboard/app/components/TaskDetailModal.css | 41 ++++++++++------------ .../TaskDetailModal.attachments-and-tabs.test.tsx | 6 ++-- .../__tests__/TaskDetailModal.css.test.ts | 21 ++++++----- ...etailModal.responsive-and-dependencies.test.tsx | 25 +++++++------ 5 files changed, 54 insertions(+), 46 deletions(-) Fusion-Task-Id: FN-8624 Fusion-Task-Lineage: 578cfe86-3021-421d-841b-2670efc10a5d Co-authored-by: Fusion (runfusion.ai) --- .changeset/fn-8624-task-detail-inset.md | 7 ++++ .../app/components/TaskDetailModal.css | 41 +++++++++---------- ...kDetailModal.attachments-and-tabs.test.tsx | 6 ++- .../__tests__/TaskDetailModal.css.test.ts | 21 +++++----- ...Modal.responsive-and-dependencies.test.tsx | 25 ++++++----- 5 files changed, 54 insertions(+), 46 deletions(-) create mode 100644 .changeset/fn-8624-task-detail-inset.md diff --git a/.changeset/fn-8624-task-detail-inset.md b/.changeset/fn-8624-task-detail-inset.md new file mode 100644 index 0000000000..7a67defb2d --- /dev/null +++ b/.changeset/fn-8624-task-detail-inset.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Fix asymmetric right padding in Task Detail activity content. +category: fix +dev: Overlay clearance now applies only to Activity first rows at every breakpoint. diff --git a/packages/dashboard/app/components/TaskDetailModal.css b/packages/dashboard/app/components/TaskDetailModal.css index c64cb01b5f..2513f7173b 100644 --- a/packages/dashboard/app/components/TaskDetailModal.css +++ b/packages/dashboard/app/components/TaskDetailModal.css @@ -3258,20 +3258,27 @@ The body-portaled menu must paint above the owning task-detail modal/popup while font-weight: 600; } +/* +FNXC:TaskDetailActivity 2026-07-27-02:15: +FN-8624 requires Task Detail content insets to stay symmetric at every breakpoint, +including modal, pop-out, and embedded surfaces. The fixed Live/Feed overlay can cover +only the first row, so its tokenized clearance belongs there rather than on this container; +this generalizes FN-8166's mobile-only correction to desktop and tablet. +*/ .detail-activity { position: relative; + padding-inline-end: 0; +} + +.detail-activity:not(.detail-activity--interventions) > h4, +.detail-activity:not(.detail-activity--interventions) > .detail-log-truncated, +.detail-activity:not(.detail-activity--interventions) > .detail-log-loading, +.detail-activity:not(.detail-activity--interventions) > .detail-log-empty, +.detail-activity:not(.detail-activity--interventions) > .detail-activity-list > .detail-log-entry:first-child { padding-inline-end: calc(var(--space-2xl) + var(--space-md)); } -/* -FNXC:PlannerOversight 2026-07-05-00:00: -The Interventions Activity segment (FN-7571) renders no `.activity-expand-toggle--overlay` -button, so it must not reserve the shared `.detail-activity` padding-inline-end that exists -solely to keep that overlay toggle from covering Live/Feed content. Without this override the -FN-7519 Intervention Timeline is inset from the right edge (worse on mobile, where the base -reserved padding grows). FN-7581 zeroes the reserved padding for this segment only; Live/Feed/ -Raw keep the base rule unchanged. -*/ +/* FNXC:PlannerOversight 2026-07-27-02:15: Retain the explicit zero inset for the overlay-free Interventions segment; it documents the FN-7581 full-width timeline contract even though the shared container is now symmetric. */ .detail-activity--interventions { padding-inline-end: 0; } @@ -3315,15 +3322,10 @@ Live and Feed Activity expansion overlays the content instead of reserving a too } /* - FNXC:TaskDetailActivity 2026-07-16-00:00: - FN-8166 removes the residual mobile Feed container right inset so `.detail-body` - provides equal left and right insets. Reserve overlay-toggle clearance only on - top-of-panel first-row elements, keeping the first visible row uncovered. + FNXC:TaskDetailActivity 2026-07-27-02:15: + FN-8624 keeps the base container symmetric; at mobile sizes the smaller fixed + overlay needs correspondingly smaller first-row clearance without covering log text. */ - .detail-activity { - padding-inline-end: 0; - } - .detail-activity:not(.detail-activity--interventions) > h4, .detail-activity:not(.detail-activity--interventions) > .detail-log-truncated, .detail-activity:not(.detail-activity--interventions) > .detail-log-loading, @@ -3332,11 +3334,6 @@ Live and Feed Activity expansion overlays the content instead of reserving a too padding-inline-end: calc(var(--space-2xl) + var(--space-sm)); } - /* FNXC:PlannerOversight 2026-07-05-00:00: mobile reserves more padding for the overlay toggle; neutralize it for Interventions too so FN-7519's timeline stays full width on mobile per FN-7581. */ - .detail-activity--interventions { - padding-inline-end: 0; - } - .activity-expand-toggle { min-inline-size: calc(var(--space-2xl) + var(--space-sm)); min-block-size: calc(var(--space-2xl) + var(--space-sm)); diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.attachments-and-tabs.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.attachments-and-tabs.test.tsx index 0e53f2dcb5..cc8378a05e 100644 --- a/packages/dashboard/app/components/__tests__/TaskDetailModal.attachments-and-tabs.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.attachments-and-tabs.test.tsx @@ -928,12 +928,14 @@ describe("TaskDetailModal", () => { expect(css).not.toContain(".activity-toolbar"); expect(css).not.toContain("activity-toolbar--expand-only"); - expect(css).toContain(".detail-activity {\n position: relative;\n padding-inline-end: calc(var(--space-2xl) + var(--space-md));\n}"); + expect(css).toContain(".detail-activity {\n position: relative;\n padding-inline-end: 0;\n}"); + expect(css).toContain(".detail-activity:not(.detail-activity--interventions) > h4,"); + expect(css).toContain("padding-inline-end: calc(var(--space-2xl) + var(--space-md));"); expect(activityOverlayRule).toContain("position: absolute"); expect(activityOverlayRule).toContain("top: var(--space-md)"); expect(activityOverlayRule).toContain("right: var(--space-md)"); expect(activityOverlayRule).toContain("z-index: 3"); - expect(mobileCss).toContain(" .detail-activity {\n padding-inline-end: 0;\n }"); + expect(mobileCss).not.toContain(" .detail-activity {\n padding-inline-end:"); expect(mobileCss).toContain(" .activity-expand-toggle--overlay {\n top: var(--space-sm);\n right: var(--space-sm);\n }"); expect(expandedTitleRule).not.toContain("display: none"); expect(expandedMetaRule).toContain("display: none"); diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.css.test.ts b/packages/dashboard/app/components/__tests__/TaskDetailModal.css.test.ts index 50d58cc200..4573db6638 100644 --- a/packages/dashboard/app/components/__tests__/TaskDetailModal.css.test.ts +++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.css.test.ts @@ -45,13 +45,12 @@ describe("TaskDetailModal CSS contract", () => { }); /* - FNXC:TaskDetailActivity 2026-07-18-07:25: - FN-8166 zeroed mobile `.detail-activity` padding-inline-end (equal insets from - `.detail-body`); overlay clearance lives only on first-row selectors. Keep the - contract aligned with TaskDetailModal.css so full-suite does not assert the - pre-8166 `var(--space-md)` residual inset. + FNXC:TaskDetailActivity 2026-07-27-02:15: + FN-8624 extends FN-8166's symmetric Activity container inset from mobile to + desktop and tablet. Only possible overlay-covered first rows may reserve tokenized + clearance, so modal, pop-out, and embedded task-detail renders share this CSS contract. */ - it("FN-8154 keeps the mobile Feed inset narrow while clearing its overlay toggle from first rows", async () => { + it("FN-8624 keeps Activity container insets symmetric while clearing the overlay from first rows", async () => { const css = await loadAllAppCss(); const baseCss = await loadAllAppCssBaseOnly(); const mobileCss = css.slice(css.indexOf("@media (max-width: 768px)")); @@ -63,13 +62,13 @@ describe("TaskDetailModal CSS contract", () => { ".detail-activity:not(.detail-activity--interventions) > .detail-activity-list > .detail-log-entry:first-child", ]; - expect(baseCss).toContain(".detail-activity {\n position: relative;\n padding-inline-end: calc(var(--space-2xl) + var(--space-md));\n}"); - expect(mobileCss).toContain(" .detail-activity {\n padding-inline-end: 0;\n }"); - expect(mobileCss).not.toContain(" .detail-activity {\n padding-inline-end: calc(var(--space-2xl) + var(--space-lg));\n }"); - expect(mobileCss).not.toContain(" .detail-activity {\n padding-inline-end: var(--space-md);\n }"); - expect(mobileCss).toContain(" .detail-activity--interventions {\n padding-inline-end: 0;\n }"); + expect(baseCss).toContain(".detail-activity {\n position: relative;\n padding-inline-end: 0;\n}"); + expect(baseCss).toContain(".detail-activity--interventions {\n padding-inline-end: 0;\n}"); + expect(baseCss).not.toContain(".detail-activity {\n position: relative;\n padding-inline-end: calc(var(--space-2xl) + var(--space-md));\n}"); + expect(mobileCss).not.toContain(" .detail-activity {\n padding-inline-end:"); for (const selector of firstRowSelectors) { const escapedSelector = selector.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + expect(baseCss, selector).toMatch(new RegExp(`${escapedSelector}(?:\\s*,\\s*[^{}]+)*\\s*\\{[^}]*padding-inline-end: calc\\(var\\(--space-2xl\\) \\+ var\\(--space-md\\)\\);`)); expect(mobileCss, selector).toMatch(new RegExp(`${escapedSelector}(?:\\s*,\\s*[^{}]+)*\\s*\\{[^}]*padding-inline-end: calc\\(var\\(--space-2xl\\) \\+ var\\(--space-sm\\)\\);`)); } }); diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx index 13b252b032..0d1a8cacac 100644 --- a/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx @@ -729,23 +729,24 @@ describe("TaskDetailModal", () => { expect(css).not.toContain(".activity-toolbar"); expect(css).not.toContain("activity-toolbar--expand-only"); - expect(css).toContain(".detail-activity {\n position: relative;\n padding-inline-end: calc(var(--space-2xl) + var(--space-md));\n}"); + expect(css).toContain(".detail-activity {\n position: relative;\n padding-inline-end: 0;\n}"); + expect(css).toContain(".detail-activity:not(.detail-activity--interventions) > h4,"); + expect(css).toContain("padding-inline-end: calc(var(--space-2xl) + var(--space-md));"); expect(overlayBlock).toContain("position: absolute;"); expect(overlayBlock).toContain("top: var(--space-md);"); expect(overlayBlock).toContain("right: var(--space-md);"); - expect(mobileBlock).toContain(" .detail-activity {\n padding-inline-end: 0;\n }"); + expect(mobileBlock).not.toContain(" .detail-activity {\n padding-inline-end:"); expect(mobileOverlayBlock).toContain("top: var(--space-sm);"); expect(mobileOverlayBlock).toContain("right: var(--space-sm);"); /* - FNXC:TaskDetailActivity 2026-07-16-00:00: - FN-8166 requires Feed to inherit the symmetric mobile `.detail-body` inset, - while only its first visible row reserves space for the opaque overlay toggle. - This contract also prevents non-Feed task-detail surfaces from adding a - container-level right-only inset or mobile horizontal overflow. + FNXC:TaskDetailActivity 2026-07-27-02:15: + FN-8624 requires Feed to inherit the symmetric `.detail-body` inset at every + breakpoint, while only its first visible row reserves space for the opaque overlay. + This contract covers modal, pop-out, embedded, and mobile task-detail surfaces. */ const mobileDetailBodyBlock = getExactCssRuleBlock(mobileBlock, ".detail-body"); - const mobileInterventionsBlock = getExactCssRuleBlock(mobileBlock, ".detail-activity--interventions"); + const baseInterventionsBlock = getExactCssRuleBlock(css, ".detail-activity--interventions"); const mobilePrBlock = getExactCssRuleBlock( getCssAtRuleBlockContainingExactRule(css, "@media (max-width: 768px)", ".detail-pr-tab"), ".detail-pr-tab", @@ -758,7 +759,7 @@ describe("TaskDetailModal", () => { expect(mobileDetailBodyBlock).toContain("padding: calc(var(--space-md) + var(--space-xs) / 2);"); expect(mobileDetailBodyBlock).toContain("overflow-x: hidden;"); - expect(mobileInterventionsBlock).toContain("padding-inline-end: 0;"); + expect(baseInterventionsBlock).toContain("padding-inline-end: 0;"); expect(mobileBlock).toContain(".detail-activity:not(.detail-activity--interventions) > h4,"); expect(mobileBlock).toContain(".detail-activity:not(.detail-activity--interventions) > .detail-log-loading,"); expect(mobileBlock).toContain(".detail-activity:not(.detail-activity--interventions) > .detail-log-empty,"); @@ -797,6 +798,7 @@ describe("TaskDetailModal", () => { const mobileScrollbarBlock = getExactCssRuleBlock(mobileBlock, ".detail-body::-webkit-scrollbar"); const mobileActivityBlock = getExactCssRuleBlock(mobileBlock, ".detail-activity"); const mobileInterventionsBlock = getExactCssRuleBlock(mobileBlock, ".detail-activity--interventions"); + const baseInterventionsBlock = getExactCssRuleBlock(css, ".detail-activity--interventions"); const mobilePrBlock = getExactCssRuleBlock( getCssAtRuleBlockContainingExactRule(css, "@media (max-width: 768px)", ".detail-pr-tab"), ".detail-pr-tab", @@ -815,9 +817,10 @@ describe("TaskDetailModal", () => { expect(mobileDetailBodyBlock).toContain("scrollbar-width: none;"); expect(mobileScrollbarBlock).toContain("display: none;"); - expect(mobileActivityBlock).toContain("padding-inline-end: 0;"); + expect(mobileActivityBlock).toBe(""); expect(mobileBlock).toContain("padding-inline-end: calc(var(--space-2xl) + var(--space-sm));"); - expect(mobileInterventionsBlock).toContain("padding-inline-end: 0;"); + expect(mobileInterventionsBlock).toBe(""); + expect(baseInterventionsBlock).toContain("padding-inline-end: 0;"); expect(mobilePrBlock.trim()).toBe("gap: var(--space-md);"); expect(allMobileCss).not.toMatch(/\.task-changes-tab\s*\{[^}]*\bpadding(?:-[\w-]+)?\s*:/); expect(embeddedBodyBlock).toContain("width: 100%;");