Removes the mobile stacked-card override for the Summary tab's per-model token/cost table so it stays a real, horizontally-scrollable table matching the Command Center pattern, and updates the covering tests/changeset accordingly. - Drop the @media (max-width: 768px) block in TaskDetailModal.css that converted .task-summary-token-table rows into stacked cards (display:block, thead hidden, td::before labels), so the wrapper's overflow-x: auto and table min-width now govern mobile layout. - Update FNXC:TaskDetailSummaryTokenCost comments to document the new horizontal-scroll contract instead of the removed stacked-card behavior, and refresh the TaskCostTab.css FNXC comment to match. - Add a new regression test (token-table-mobile-scroll.test.ts) asserting the task-detail token table wrapper keeps overflow-x: auto, the mobile media block no longer stacks rows into cards, and the Command Center .cc-table-wrap stays scrollable. - Update the existing TaskDetailModal summary-tab test to assert the stacked-card CSS is absent from the mobile block instead of asserting its presence. - Add a patch changeset describing the fix for end users. Files changed: .changeset/mobile-token-table-scroll.md | 7 +++ .../__tests__/token-table-mobile-scroll.test.ts | 70 +++++++++++++++++++++ packages/dashboard/app/components/TaskCostTab.css | 2 +- .../dashboard/app/components/TaskDetailModal.css | 73 ++-------------------- .../__tests__/TaskDetailModal.summary-tab.test.tsx | 13 ++-- 5 files changed, 90 insertions(+), 75 deletions(-) Fusion-Task-Id: FN-7843 Fusion-Task-Lineage: bb6dde7c-f205-45f3-984a-0fc52be5d547 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
71 lines
2.6 KiB
TypeScript
71 lines
2.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { readFileSync } from "fs";
|
|
import { resolve } from "path";
|
|
|
|
function readCss(relativePath: string): string {
|
|
return readFileSync(resolve(__dirname, relativePath), "utf-8");
|
|
}
|
|
|
|
function extractFirstMediaBlock(css: string, pattern: RegExp): string {
|
|
const match = pattern.exec(css);
|
|
expect(match, `missing media block for ${pattern}`).toBeTruthy();
|
|
|
|
const start = match!.index + match![0].length;
|
|
let index = start;
|
|
let depth = 1;
|
|
while (index < css.length && depth > 0) {
|
|
if (css[index] === "{") depth += 1;
|
|
if (css[index] === "}") depth -= 1;
|
|
index += 1;
|
|
}
|
|
|
|
expect(depth).toBe(0);
|
|
return css.slice(start, index - 1);
|
|
}
|
|
|
|
function ruleBlock(css: string, selector: string): string {
|
|
const escaped = selector.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
const match = css.match(new RegExp(`${escaped}\\s*\\{[^}]*\\}`, "s"));
|
|
expect(match, `missing CSS rule for ${selector}`).toBeTruthy();
|
|
return match![0];
|
|
}
|
|
|
|
describe("FN-7843 token table mobile scroll contract", () => {
|
|
const taskDetailCss = readCss("../components/TaskDetailModal.css");
|
|
const commandCenterAreasCss = readCss("../components/command-center/areas/areas.css");
|
|
const mobileTaskDetailCss = extractFirstMediaBlock(
|
|
taskDetailCss,
|
|
/@media\s*\(max-width:\s*768px\)\s*\{/,
|
|
);
|
|
|
|
it("keeps the task-detail token table overflow owned by its wrapper", () => {
|
|
const wrapperRule = ruleBlock(taskDetailCss, ".task-summary-token-table-wrap");
|
|
const tableRule = ruleBlock(taskDetailCss, ".task-summary-token-table");
|
|
|
|
expect(wrapperRule).toContain("overflow-x: auto;");
|
|
expect(tableRule).toMatch(/min-width:\s*[^;]+;/);
|
|
});
|
|
|
|
it("does not convert task-detail token tables into stacked mobile cards", () => {
|
|
expect(mobileTaskDetailCss).not.toMatch(
|
|
/\.task-summary-token-table-wrap\s*\{[^}]*overflow-x:\s*visible\s*;/s,
|
|
);
|
|
expect(mobileTaskDetailCss).not.toMatch(
|
|
/\.task-summary-token-table(?:\s|,|\{|[^{}]*\{[^}]*)display:\s*block\s*;/s,
|
|
);
|
|
expect(mobileTaskDetailCss).not.toMatch(
|
|
/\.task-summary-token-table\s+(?:thead|tbody|tfoot|tr|th|td)(?:\s|,|\{|[^{}]*\{[^}]*)display:\s*block\s*;/s,
|
|
);
|
|
expect(mobileTaskDetailCss).not.toMatch(
|
|
/\.task-summary-token-table\s+thead\s*\{[^}]*display:\s*none\s*;/s,
|
|
);
|
|
expect(mobileTaskDetailCss).not.toContain(".task-summary-token-table td::before");
|
|
});
|
|
|
|
it("keeps the Command Center per-model table wrapper scrollable", () => {
|
|
const commandCenterTableWrapRule = ruleBlock(commandCenterAreasCss, ".cc-table-wrap");
|
|
|
|
expect(commandCenterTableWrapRule).toContain("overflow-x: auto;");
|
|
});
|
|
});
|