# A full-screen dashboard

> The reference dashboard: tabs, a checklist with progress, a log tail and a status line that collapses, in the alternate screen — and clean lines in a pipe and NDJSON under --json, from the same program.

Source: https://controlroom.interlace.tools/docs/recipes/dashboard

[`examples/dashboard`](https://github.com/ofri-peretz/burgee/tree/main/examples/dashboard) is a
boilerplate in the shape of a setup wizard: two tabs, a checklist with progress, a log tail and a
status line that collapses, in the alternate screen. Copy it to start your own:

```bash
npx degit ofri-peretz/burgee/examples/dashboard my-dashboard
cd my-dashboard && npm install && node dashboard.mjs
```

| Key | What it does |
| :-- | :-- |
| `←` `→` | switch tab |
| `s` | collapse or expand the status line |
| `q`, `Ctrl+C` | quit, and hand the terminal back as it was |

## How it is built

**One layout per tab.** `layout` is a function of the screen's state, so the status tab shows
the learn panel beside the checklist and the logs tab shows the tail:

```js
function layout(state) {
  const body =
    state.active === 0
      ? { direction: 'row', parts: [{ size: { fr: 1, min: 20 }, content: 'learn' }, { size: { fr: 2 }, content: 'tasks' }] }
      : 'log';
  return {
    direction: 'column',
    parts: [
      { size: 1, content: 'tabs' },
      { size: 'fit', content: 'status' },
      { content: body },
      { size: 1, content: 'hints' },
    ],
  };
}
```

**Keys are data.** The keymap binds the arrows to the reducer's `tab.prev` and `tab.next`, `s` to
`toggle:status`, which collapses the status pane, and `q` to the program's own `quit`. The hint
line at the bottom is `hints(KEYMAP, LABELS)`, so it lists exactly those keys:

```js
const KEYMAP = { left: 'tab.prev', right: 'tab.next', s: 'toggle:status', q: 'quit', 'ctrl+c': 'quit' };
const LABELS = { 'tab.prev': 'switch tab', 'tab.next': 'switch tab', 'toggle:status': 'toggle status', quit: 'quit' };
```

**Panes are flagstaff components.** `tabBar()`, `tasks()` and `logTail()` are flagstaff's; the
status and learn panes are a one-line text component. The tab bar and the hint line are
`liveOnly`, because tabs and keys mean nothing off a terminal.

**The work drives the screen.** Each step marks itself running, pushes its log lines, and
updates three panes; the last one commits a summary and closes. In the alternate screen the
commit is held and printed to the main screen as the program exits, so the summary is what is
left in the terminal.

## Every caller

On a terminal it is a full screen. Piped, each pane prints under its label, and then each
change is one line:

```text title="node dashboard.mjs" in="examples/dashboard"
Status
Progress: 0/4 completed
Learn
The wizard installs the SDK
and checks the first event.
Tasks

Log

◆ Detect the framework
┊ found package.json
┊ framework: next
✔ Detect the framework
◆ Install the SDK
┊ npm install posthog-js
┊ added 1 package
Progress: 1/4 completed
✔ Install the SDK
◆ Write the config
┊ wrote posthog.config.js
Progress: 2/4 completed
✔ Write the config
◆ Check the setup
┊ sent a test event
┊ event received
Progress: 3/4 completed
✔ Check the setup
Progress: 4/4 completed
Done: Progress: 4/4 completed
```

`node dashboard.mjs --json` writes one NDJSON event per update to stderr, `{"event":"tasks",
"state":{…}}` and so on, ending with the commit and each pane's last state. The example's own
`npm test` checks the pipe, `--json`, and the keys on a simulated terminal: `→` to the log tab,
`s` to collapse the status line, `q` to leave the alternate screen.

## What to change first

1. **`STEPS`**, the work: a `title` and the `log` lines each step produces. In your program, run
   the real work where `advance()` marks a step running, and push its output into `lines`.
2. **`layout()`**, the arrangement per tab ([Layout](/docs/guides/layout)).
3. **`KEYMAP` and `LABELS`**, the keys ([Tabs, focus and keys](/docs/guides/tabs-and-keys)).
