diff --git a/.changeset/fn-8527-themed-stats-link.md b/.changeset/fn-8527-themed-stats-link.md new file mode 100644 index 0000000000..d3921b57f2 --- /dev/null +++ b/.changeset/fn-8527-themed-stats-link.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Make imported task links in Stats follow the active dashboard theme. +category: fix +dev: The shared Stats provenance link now uses the --accent token. diff --git a/packages/dashboard/app/components/TaskTokenStatsPanel.css b/packages/dashboard/app/components/TaskTokenStatsPanel.css index a465402da1..eaec49913c 100644 --- a/packages/dashboard/app/components/TaskTokenStatsPanel.css +++ b/packages/dashboard/app/components/TaskTokenStatsPanel.css @@ -132,6 +132,21 @@ font-size: calc(var(--space-sm) + var(--space-xs)); } +.task-token-stats-panel__imported-source-link { + color: var(--accent); + overflow-wrap: anywhere; +} + +.task-token-stats-panel__imported-source-link:hover { + text-decoration: underline; +} + +.task-token-stats-panel__imported-source-link:focus-visible { + outline: none; + box-shadow: var(--focus-ring-strong); + border-radius: var(--radius-sm); +} + .task-token-stats-panel__cache-ratio { color: var(--text); font-size: calc(var(--space-sm) + var(--space-xs)); diff --git a/packages/dashboard/app/components/TaskTokenStatsPanel.tsx b/packages/dashboard/app/components/TaskTokenStatsPanel.tsx index c6f5f73e20..89ef4e3e45 100644 --- a/packages/dashboard/app/components/TaskTokenStatsPanel.tsx +++ b/packages/dashboard/app/components/TaskTokenStatsPanel.tsx @@ -317,7 +317,12 @@ export function TaskTokenStatsPanel({ tokenUsage, loading, task }: TaskTokenStat
{t("taskDetail.provenance.importedFrom", "Imported from")}
{/^https?:\/\//i.test(task.sourceMetadata.issueUrl) ? ( - + /* + FNXC:TaskStatsProvenance 2026-07-22-21:47: + Imported-source links use the active accent rather than the browser default so the + shared Stats panel remains theme-aware on desktop and narrow/mobile task detail. + */ + {task.sourceMetadata.issueUrl} ) : ( diff --git a/packages/dashboard/app/components/__tests__/TaskTokenStatsPanel.test.tsx b/packages/dashboard/app/components/__tests__/TaskTokenStatsPanel.test.tsx index 8277ffb811..53d8351c11 100644 --- a/packages/dashboard/app/components/__tests__/TaskTokenStatsPanel.test.tsx +++ b/packages/dashboard/app/components/__tests__/TaskTokenStatsPanel.test.tsx @@ -1,3 +1,5 @@ +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; import { describe, expect, it, vi } from "vitest"; import { render, screen } from "@testing-library/react"; import { createInstance } from "i18next"; @@ -6,6 +8,8 @@ import { TaskTokenStatsPanel } from "../TaskTokenStatsPanel"; import type { Task } from "@fusion/core"; import realEnApp from "../../../../i18n/locales/en/app.json"; +const taskTokenStatsPanelCss = readFileSync(resolve(__dirname, "../TaskTokenStatsPanel.css"), "utf8"); + function makeTask(overrides: Partial = {}): Task { return { id: "FN-400", @@ -311,6 +315,32 @@ describe("TaskTokenStatsPanel", () => { .toHaveAttribute("href", "https://github.com/Runfusion/Fusion/issues/2356"); }); + /* + FNXC:TaskStatsProvenance 2026-07-22-21:47: + The desktop and narrow/mobile task detail both mount this shared Stats panel. A populated + imported task must keep its safe external-link contract while component CSS binds its color to + the active theme accent instead of browser-default blue. + */ + it("uses the active theme accent for populated imported-source links across shared Stats surfaces", () => { + const issueUrl = "https://github.com/Runfusion/Fusion/issues/2410"; + render(); + + const importedSource = screen.getByRole("link", { name: issueUrl }); + expect(importedSource).toHaveClass("task-token-stats-panel__imported-source-link"); + expect(importedSource).toHaveAttribute("href", issueUrl); + expect(importedSource).toHaveAttribute("target", "_blank"); + expect(importedSource).toHaveAttribute("rel", "noreferrer"); + expect(taskTokenStatsPanelCss).toMatch( + /\.task-token-stats-panel__imported-source-link\s*\{[^}]*color:\s*var\(--accent\);[^}]*\}/, + ); + expect(taskTokenStatsPanelCss).not.toMatch( + /\.task-token-stats-panel__imported-source-link\s*\{[^}]*color:\s*(?:blue|#[0-9a-f]{3,8}|rgb)/i, + ); + }); + it("renders a non-http issueUrl as plain text, never as a link", () => { render(