fix(FN-2714): restore task timer chip to footer metadata row

- Move TaskCard time indicator rendering from the header back into the footer metadata row
- Render timer and files-changed metadata together in the shared footer row layout
- Update timer chip CSS to stay right-aligned with margin-left:auto and prevent shrinking
- Update TaskCard and mobile board tests to assert footer placement and alignment behavior
This commit is contained in:
Fusion
2026-04-27 12:45:53 -07:00
committed by gsxdsm
parent fce5eb490d
commit 3e43477dc8
4 changed files with 19 additions and 17 deletions

View File

@@ -482,6 +482,8 @@
display: inline-flex;
align-items: center;
gap: var(--space-xs);
margin-left: auto;
flex-shrink: 0;
padding: var(--space-xs) var(--space-sm);
border: 1px solid color-mix(in srgb, var(--text-muted) 30%, transparent);
border-radius: var(--radius-pill);

View File

@@ -1208,16 +1208,6 @@ function TaskCardComponent({
{abbreviateMissionTitle(missionTitle ?? task.missionId)}
</span>
)}
{timeIndicator && (
<span
className="card-time-indicator"
title={timeIndicator.title}
aria-label={timeIndicator.ariaLabel}
>
<Clock size={12} />
<span>{timeIndicator.label}</span>
</span>
)}
<div className="card-header-actions">
{canEdit && (
<button
@@ -1394,9 +1384,19 @@ function TaskCardComponent({
</>
);
})()}
{filesChangedButton && (
{(filesChangedButton || timeIndicator) && (
<div className="card-footer-row">
{filesChangedButton}
{timeIndicator && (
<span
className="card-time-indicator"
title={timeIndicator.title}
aria-label={timeIndicator.ariaLabel}
>
<Clock size={12} />
<span>{timeIndicator.label}</span>
</span>
)}
</div>
)}
{((task.dependencies && task.dependencies.length > 0) || queued || task.status === "queued" || task.blockedBy) && (

View File

@@ -503,7 +503,7 @@ describe("TaskCard", () => {
expect(timer?.getAttribute("aria-label")).toContain("Completed processing duration 2h");
});
it("renders files-changed metadata in footer row and timer chip in header", () => {
it("renders files-changed metadata and timer chip in footer row", () => {
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-04-25T18:00:00.000Z"));
@@ -539,9 +539,9 @@ describe("TaskCard", () => {
expect(filesChanged).not.toBeNull();
expect(timer).not.toBeNull();
expect(footerRow?.contains(filesChanged)).toBe(true);
expect(footerRow?.contains(timer)).toBe(false);
expect(header?.contains(timer)).toBe(true);
expect(Array.from(footerRow?.children ?? [])).toEqual([filesChanged]);
expect(footerRow?.contains(timer)).toBe(true);
expect(header?.contains(timer)).toBe(false);
expect(Array.from(footerRow?.children ?? [])).toEqual([filesChanged, timer]);
});
it.each(["triage", "todo", "in-review", "archived"] as const)(
"does not render timer chip for %s cards",

View File

@@ -274,9 +274,9 @@ describe("TaskCard mobile", () => {
expectRuleToContain(css, ".card-footer-row", "flex-wrap: nowrap;");
});
it("keeps TaskCard timer chip in-flow and reserves right alignment for header actions", () => {
it("keeps TaskCard timer chip in-flow and right-aligned in footer metadata row", () => {
const css = loadAllAppCss();
expectRuleNotToContain(css, ".card-time-indicator", "margin-left: auto;");
expectRuleToContain(css, ".card-time-indicator", "margin-left: auto;");
expectRuleToContain(css, ".card-header-actions", "margin-left: auto;");
});