feat(FN-2285): rebrand dashboard TUI header to Fusion

- Update dashboard TUI header copy from "fn board" to "fusion" branding
- Add CLI tests that validate the new header text and related rendering behavior
- Include a changeset documenting the published @runfusion/fusion patch for the branding update
This commit is contained in:
Fusion
2026-04-22 23:49:49 -07:00
committed by gsxdsm
parent b5129ff968
commit 0bb0100072
3 changed files with 119 additions and 1 deletions

View File

@@ -3,6 +3,7 @@ import {
LogRingBuffer,
DashboardLogSink,
isTTYAvailable,
renderHeaderToString,
type SystemInfo,
type TaskStats,
type SettingsValues,
@@ -148,6 +149,40 @@ describe("isTTYAvailable", () => {
});
});
// ── Header Branding Tests ───────────────────────────────────────────────
describe("renderHeaderToString", () => {
it("includes 'fusion' in header title", () => {
const header = renderHeaderToString(80);
expect(header).toContain("fusion");
});
it("does not include old 'fn board' branding", () => {
const header = renderHeaderToString(80);
expect(header).not.toContain("fn board");
});
it("renders correctly at wide terminal width (>= 70 cols)", () => {
const header = renderHeaderToString(80);
expect(header).toContain("fusion");
expect(header).toContain("Logs");
expect(header).toContain("System");
});
it("renders correctly at medium terminal width (>= 40 cols)", () => {
const header = renderHeaderToString(50);
expect(header).toContain("fusion");
expect(header).toContain("[1]L"); // Short label for Logs
});
it("renders correctly at narrow terminal width (< 40 cols)", () => {
const header = renderHeaderToString(30);
expect(header).toContain("fusion");
expect(header).toContain("Logs");
expect(header).toContain("[n/p]nav");
});
});
// ── Type exports verification ─────────────────────────────────────────────
describe("Type exports", () => {

View File

@@ -556,7 +556,7 @@ export class DashboardTUI {
private renderHeader(): void {
const cols = process.stdout.columns || 80;
const title = colorize(" fn board ", "cyan");
const title = colorize(" fusion ", "cyan");
const titleLen = visibleLength(title);
process.stdout.write(title);
@@ -1012,3 +1012,81 @@ function padRight(text: string, width: number): string {
export function isTTYAvailable(): boolean {
return Boolean(process.stdout.isTTY && process.stdin.isTTY);
}
// ── Header String Helper (for testing) ─────────────────────────────────────
/**
* Render the header to a string using the given column width.
* Used for testing without requiring TTY mode.
*/
export function renderHeaderToString(cols: number): string {
const title = colorize(" fusion ", "cyan");
const titleLen = visibleLength(title);
let output = title;
// Build tabs based on column width (same logic as renderHeader)
if (cols >= 70) {
for (let i = 0; i < SECTION_ORDER.length; i++) {
const section = SECTION_ORDER[i];
const isActive = section === "logs"; // Default active section for test
const num = (i + 1).toString();
const label = section.charAt(0).toUpperCase() + section.slice(1);
const tabText = `[${num}] ${label}`;
const style = isActive ? "brightBlue" : "dim";
output += colorize(` ${tabText} `, style);
}
} else if (cols >= 40) {
const shortLabels: Record<SectionId, string> = {
logs: "L",
system: "S",
utilities: "U",
stats: "St",
settings: "Se",
};
for (let i = 0; i < SECTION_ORDER.length; i++) {
const section = SECTION_ORDER[i];
const isActive = section === "logs";
const num = (i + 1).toString();
const shortLabel = shortLabels[section];
const tabText = `[${num}]${shortLabel}`;
const style = isActive ? "brightBlue" : "dim";
output += colorize(` ${tabText} `, style);
}
} else {
output += colorize(" [1]Logs ", "brightBlue");
output += colorize(" [n/p]nav ", "dim");
}
// Calculate tabs length for padding
const tabsLength = SECTION_ORDER.reduce((acc, s, i) => {
let label: string;
if (cols >= 70) {
label = s.charAt(0).toUpperCase() + s.slice(1);
} else if (cols >= 40) {
const shortLabels: Record<SectionId, string> = {
logs: "L",
system: "S",
utilities: "U",
stats: "St",
settings: "Se",
};
label = shortLabels[s];
} else {
label = s.charAt(0).toUpperCase() + s.slice(1);
}
const tabText = `[${i + 1}]${label} `;
return acc + tabText.length;
}, 0);
const headerLen = titleLen + tabsLength;
const remaining = cols - headerLen;
if (remaining > 0) {
output += " ".repeat(remaining);
}
output += "\n";
output += colorize("─".repeat(Math.max(20, cols)), "dim") + "\n";
return output;
}