feat(FN-2311): default dashboard TUI to system section

- Reorder dashboard TUI sections so System is tab [1] and the initial active view
- Update header rendering across wide, medium, and narrow terminal layouts to reflect the new tab order
- Expand dashboard TUI tests to assert system-first labels and default active section behavior
- Document system-first startup behavior in CLI reference and add a patch changeset for @runfusion/fusion
This commit is contained in:
Fusion
2026-04-23 10:33:56 -07:00
committed by gsxdsm
parent ad9224c9b9
commit e59adc5125
6 changed files with 36 additions and 15 deletions

View File

@@ -166,26 +166,34 @@ describe("renderHeaderToString", () => {
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");
expect(header).toContain("[1] System");
expect(header).toContain("[2] Logs");
});
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
expect(header).toContain("[1]S"); // Short label for System
expect(header).toContain("[2]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("[1]System");
expect(header).toContain("[n/p]nav");
});
});
// ── Type exports verification ─────────────────────────────────────────────
describe("DashboardTUI default section", () => {
it("starts on the system section by default", () => {
const tui = new DashboardTUI();
expect((tui as any).activeSection).toBe("system");
});
});
describe("Type exports", () => {
it("exports LogEntry type", () => {
const entry = {

View File

@@ -2,8 +2,8 @@
* Dashboard TUI Renderer
*
* An interactive terminal user interface for `fn dashboard` with five sections:
* - logs: real-time log entries with ring buffer
* - system: host, port, URL, auth mode, token, engine mode
* - logs: real-time log entries with ring buffer
* - utilities: action list with keybindings
* - stats: task counts, active task count, agent state counts
* - settings: real key/value settings from TaskStore
@@ -257,10 +257,10 @@ function visibleTruncate(text: string, maxWidth: number): string {
// ── Dashboard TUI Renderer ───────────────────────────────────────────────────
const SECTION_ORDER: SectionId[] = ["logs", "system", "utilities", "stats", "settings"];
const SECTION_ORDER: SectionId[] = ["system", "logs", "utilities", "stats", "settings"];
export class DashboardTUI {
private activeSection: SectionId = "logs";
private activeSection: SectionId = "system";
private logBuffer: LogRingBuffer;
private systemInfo: SystemInfo | null = null;
private taskStats: TaskStats | null = null;
@@ -684,8 +684,8 @@ export class DashboardTUI {
process.stdout.write(title);
// Responsive header modes based on terminal width:
// - Wide (>= 70 cols): Full labels "[1] Logs [2] System [3] Utilities [4] Stats [5] Settings"
// - Medium (>= 40 cols): Short labels "[1] L [2] S [3] U [4] St [5] Se"
// - Wide (>= 70 cols): Full labels "[1] System [2] Logs [3] Utilities [4] Stats [5] Settings"
// - Medium (>= 40 cols): Short labels "[1] S [2] L [3] U [4] St [5] Se"
// - Narrow (< 40 cols): Only active tab with navigation hint "[n/p] Previous/Next"
if (cols >= 70) {
@@ -1331,7 +1331,7 @@ export function renderHeaderToString(cols: number): string {
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 isActive = section === "system"; // Default active section for test
const num = (i + 1).toString();
const label = section.charAt(0).toUpperCase() + section.slice(1);
const tabText = `[${num}] ${label}`;
@@ -1348,7 +1348,7 @@ export function renderHeaderToString(cols: number): string {
};
for (let i = 0; i < SECTION_ORDER.length; i++) {
const section = SECTION_ORDER[i];
const isActive = section === "logs";
const isActive = section === "system";
const num = (i + 1).toString();
const shortLabel = shortLabels[section];
const tabText = `[${num}]${shortLabel}`;
@@ -1356,7 +1356,7 @@ export function renderHeaderToString(cols: number): string {
output += colorize(` ${tabText} `, style);
}
} else {
output += colorize(" [1]Logs ", "brightBlue");
output += colorize(" [1]System ", "brightBlue");
output += colorize(" [n/p]nav ", "dim");
}

View File

@@ -240,7 +240,7 @@ export async function runDashboard(port: number, opts: { paused?: boolean; dev?:
//
// When both stdout and stdin are TTY, we activate the interactive TUI
// instead of plain console output. The TUI provides 5 sections:
// logs, system, utilities, stats, settings with keyboard navigation.
// system, logs, utilities, stats, settings with keyboard navigation.
//
// In non-TTY mode (CI, piped output), we fall back to plain console
// output to maintain compatibility with automated workflows.