FN-7681: Fix undefined --space-2xs token references in dashboard component CSS
Replaces undefined --space-2xs CSS custom property references with the smallest defined spacing token, --space-xs, across several dashboard component stylesheets, and hardens the regression test that guards against reintroducing --space-2xs by scanning components recursively. - Replace var(--space-2xs) with var(--space-xs) in NewTaskModal.css, QuickEntryBox.css, TaskReviewTab.css, and McpServersCard.css - Update QuickEntryBox.test.tsx assertion to expect --space-xs instead of --space-2xs - Make space-token-defined.test.ts recursively walk components directory (previously only scanned the top level, missing nested files like settings/sections/McpServersCard.css) - Add FNXC:DashboardTokens comments documenting the --space-2xs is-intentionally-undefined decision (FN-5934) and the recursive-scan fix rationale (FN-7681) Files changed: .../app/__tests__/space-token-defined.test.ts | 33 ++++++++++++++++++---- packages/dashboard/app/components/NewTaskModal.css | 2 +- .../dashboard/app/components/QuickEntryBox.css | 18 ++++++++---- .../dashboard/app/components/TaskReviewTab.css | 2 +- .../components/__tests__/QuickEntryBox.test.tsx | 2 +- .../settings/sections/McpServersCard.css | 4 +-- 6 files changed, 44 insertions(+), 17 deletions(-) Fusion-Task-Id: FN-7681 Fusion-Task-Lineage: 59850d5c-09cc-4178-ac45-9792fa9aca59 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
@@ -7,24 +7,45 @@ const componentsDir = resolve(appDir, "components");
|
||||
const stylesPath = resolve(appDir, "styles.css");
|
||||
const themeDataPath = resolve(appDir, "public/theme-data.css");
|
||||
|
||||
/*
|
||||
* FNXC:DashboardTokens 2026-07-08-00:00:
|
||||
* FN-7681 found --space-2xs references escaping this guard inside a
|
||||
* subdirectory stylesheet (settings/sections/McpServersCard.css) because the
|
||||
* original scan was non-recursive. Walk componentsDir recursively (bounded,
|
||||
* no temp-root traversal) so every component CSS file is covered, while
|
||||
* skipping __tests__ directories and non-.css files.
|
||||
*/
|
||||
function listComponentCssFiles(): string[] {
|
||||
return readdirSync(componentsDir)
|
||||
.filter((name) => name.endsWith(".css"))
|
||||
.sort();
|
||||
const results: string[] = [];
|
||||
|
||||
function walk(dir: string): void {
|
||||
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
||||
if (entry.name === "__tests__") continue;
|
||||
const entryPath = join(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
walk(entryPath);
|
||||
} else if (entry.isFile() && entry.name.endsWith(".css")) {
|
||||
results.push(entryPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
walk(componentsDir);
|
||||
return results.sort();
|
||||
}
|
||||
|
||||
describe("dashboard spacing token hygiene", () => {
|
||||
it("does not reference undefined --space-2xs in any component stylesheet", () => {
|
||||
const violations: string[] = [];
|
||||
|
||||
for (const fileName of listComponentCssFiles()) {
|
||||
const filePath = join(componentsDir, fileName);
|
||||
for (const filePath of listComponentCssFiles()) {
|
||||
const relativePath = filePath.slice(componentsDir.length + 1);
|
||||
const source = readFileSync(filePath, "utf8");
|
||||
const lines = source.split(/\r?\n/);
|
||||
|
||||
for (let index = 0; index < lines.length; index += 1) {
|
||||
if (lines[index].includes("var(--space-2xs)")) {
|
||||
violations.push(`${fileName}:${index + 1}:${lines[index].trim()}`);
|
||||
violations.push(`${relativePath}:${index + 1}:${lines[index].trim()}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,7 +492,7 @@ The New Task create workflow selector is a real dropdown so workflow identity ic
|
||||
.task-workflow-option-copy {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-2xs);
|
||||
gap: var(--space-xs);
|
||||
min-width: 0;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
@@ -12,9 +12,15 @@
|
||||
border-color: var(--todo);
|
||||
}
|
||||
|
||||
/*
|
||||
FNXC:DashboardTokens 2026-07-08-00:00:
|
||||
--space-2xs is intentionally undefined (FN-5934 decision); the guard in
|
||||
app/__tests__/space-token-defined.test.ts asserts it stays undefined. Use the
|
||||
smallest defined token, --space-xs (4px), instead of reintroducing --space-2xs.
|
||||
*/
|
||||
.quick-entry-box--drag-over {
|
||||
border-color: var(--triage);
|
||||
box-shadow: 0 0 0 var(--space-2xs) color-mix(in srgb, var(--triage) 35%, transparent);
|
||||
box-shadow: 0 0 0 var(--space-xs) color-mix(in srgb, var(--triage) 35%, transparent);
|
||||
}
|
||||
|
||||
.quick-entry-drop-target {
|
||||
@@ -26,7 +32,7 @@
|
||||
justify-content: center;
|
||||
gap: var(--space-xs);
|
||||
padding: var(--space-sm);
|
||||
border: var(--space-2xs) dashed var(--triage);
|
||||
border: var(--space-xs) dashed var(--triage);
|
||||
border-radius: var(--radius-sm);
|
||||
background: color-mix(in srgb, var(--card) 86%, var(--triage));
|
||||
color: var(--text);
|
||||
@@ -38,12 +44,12 @@
|
||||
.quick-entry-attach-button {
|
||||
position: relative;
|
||||
min-width: calc(var(--space-xl) + var(--space-xs));
|
||||
gap: var(--space-2xs);
|
||||
gap: var(--space-xs);
|
||||
}
|
||||
|
||||
.quick-entry-attach-count {
|
||||
min-width: var(--space-md);
|
||||
padding: 0 var(--space-2xs);
|
||||
padding: 0 var(--space-xs);
|
||||
border-radius: calc(var(--radius) * 4);
|
||||
background: var(--triage);
|
||||
color: var(--provider-icon-contrast);
|
||||
@@ -54,7 +60,7 @@
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.quick-entry-drop-target {
|
||||
inset: var(--space-2xs);
|
||||
inset: var(--space-xs);
|
||||
padding: var(--space-xs);
|
||||
text-align: center;
|
||||
}
|
||||
@@ -288,7 +294,7 @@ FN-7677 — the workflow trigger shares `.btn.btn-sm.dep-trigger` classes with o
|
||||
.quick-entry-workflow-option-copy {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-2xs);
|
||||
gap: var(--space-xs);
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ The Review tab mirrors the Import-from-GitHub comment provenance model: avatar,
|
||||
.task-review-tab__comment-type-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--space-2xs);
|
||||
gap: var(--space-xs);
|
||||
padding: 0 var(--space-xs);
|
||||
min-height: var(--space-lg);
|
||||
border-radius: var(--radius-pill);
|
||||
|
||||
@@ -1780,7 +1780,7 @@ describe("QuickEntryBox", () => {
|
||||
expect(menuRule).not.toContain("inset-inline-start: 0");
|
||||
expect(menuRule).toContain("width: min(calc(var(--space-xl) * 16), calc(100vw - var(--space-lg)))");
|
||||
expect(menuRule).toContain("min-width: min(calc(var(--space-xl) * 14), calc(100vw - var(--space-lg)))");
|
||||
expect(optionCopyRule).toContain("gap: var(--space-2xs)");
|
||||
expect(optionCopyRule).toContain("gap: var(--space-xs)");
|
||||
expect(optionNameRule).toContain("overflow-wrap: anywhere");
|
||||
expect(optionNameRule).toContain("white-space: normal");
|
||||
expect(optionNameRule).not.toContain("text-overflow: ellipsis");
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border-radius: var(--radius-full);
|
||||
padding: var(--space-2xs) var(--space-xs);
|
||||
padding: var(--space-xs) var(--space-xs);
|
||||
font-size: var(--font-size-xs);
|
||||
line-height: var(--line-height-tight);
|
||||
border: var(--border-width) solid var(--border);
|
||||
@@ -128,7 +128,7 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
border-radius: var(--radius-full);
|
||||
padding: var(--space-2xs) var(--space-xs);
|
||||
padding: var(--space-xs) var(--space-xs);
|
||||
border: var(--border-width) solid var(--border);
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user