feat(ui): UI shell with repo list, boxes [1]-[3], details and demo mode #30

Merged
deadstyle merged 16 commits from feature/8-ui-shell into develop 2026-10-02 13:29:09 -05:00
Owner

Summary

The UI shell for #8: lazyforge now opens a real terminal UI. You get the repo list on the left with ★ Renovate pinned at the top (still a placeholder), the boxes [1] Pull requests, [2] Issues and [3] Actions (Actions only when the forge has them), and a details pane with the Overview tab. Navigation is h/l, j/k, 1–5, tab, gg/G, with a breadcrumb, status-bar hints and ? help, all driven by one keymap. lazyforge --demo runs the whole UI on built-in demo data seeded from the mockup. It's read-only: actions come in #9.

Changes

  • internal/ui + internal/ui/style: Bubble Tea v2 (charm.land/bubbletea/v2 v2.0.10, bubbles/v2 v2.2.1, lipgloss/v2 v2.0.6).
    • The root model routes between the repo list, boxes and details. The focused box grows.
    • The layout comes from the window size and fits 80×24.
    • Screens render from the core cache at once, then refresh in the background: every five minutes, and on r as wired in #9. Results for a repo you've moved away from are dropped.
  • Box [1]'s title follows the host's term ("Pull requests" or "Merge requests"). A breadcrumb that's too long shortens in the middle.
  • Details show only tabs that have content, so Overview for now. q quits, and ctrl+c quits from anywhere.
  • forgetest.NewDemo: demo data matching the mockup.
  • cmd/lazyforge:
    • --demo starts the UI on the demo data.
    • With a real config, it signs in to the selected host through the Forgejo/Gitea adapter and starts the UI.
    • The startup update check still runs before the UI, and --demo skips it.
  • .golangci.yml: a depguard rule. Only cmd/ (and tests) may import the concrete adapter or the test fake, which enforces the layering in CI.
  • ADR 0010 and a ## UI section in docs/architecture.md.

Screens (lazyforge --demo, 80×24, captured in tmux)

lazyforge forge.home.arpa › home/homelab › [1] Pull requests › #42
╭─ [1] Pull requests 3 ──────╮╭─ Overview ─────────────────────────────────────╮
│ #42 chore(deps): upd… ✓ 4m ││ chore(deps): update postgres to v17.0          │
│ #41 chore(deps): up… ✗ 25m ││ home/homelab #42 · renovate · 4m ago           │
│ #39 feat: add uptime… ✓ 1d ││ ✓ CI passing · dependencies   │
│                            ││ renovate/postgres-17.x → main   │
│                            ││                                                │
│                            ││ This PR contains the following updates:        │
│                            ││                                                │
│                            ││ | Package | Update | Change |   │
│                            ││ |---|---|---|                                  │
│                            ││ |                                              │
╰────────────────────────────╯│ [postgres](https://hub.docker.com/_/postgres)  │
╭─ [2] Issues 2 ─────────────╮│ | major | `16.4` → `17.0` |   │
│ #12 Dependency Dashboa… 4m ││                                                │
│ #30 Paperless back… 1💬 3d ││ ---                                            │
│                            ││                                                │
╰────────────────────────────╯│                                                │
╭─ [3] Actions 2 ────────────╮│                                                │
│ ✓ deploy main          10m ││                                                │
│ ✗ validate renovate/t… 25m ││                                                │
│                            ││                                                │
╰────────────────────────────╯╰────────────────────────────────────────────────╯
 DETAILS  j/k scroll · [ ] tabs · h back

Test plan

  • Tests drive the UI by sending it messages against the core over the demo fake, plus a few checks on the rendered text with colour codes stripped. They cover navigation, box focus and growth, the details pane, help, quit, dropping stale and cancelled loads, cache hits that skip fetching, the Actions gate, empty boxes, layout at 80×24, 120×40 and 20×5, breadcrumb shortening, and tab and control-character sanitising.
  • Mutation checks: UI 22 killed (2 equivalent), demo and startup 8 of 8 killed.
  • Reviews: spec PASS (opus) and standards PASS after one fix round. Comments and test-quality PASS after three fix rounds, which also removed a flaky-test risk: the test helper now fails on a slow command instead of silently dropping it.
  • make check exit 0 after syncing develop: format, lint (0 issues), go test -race, govulncheck, build, install test.

Rulings

  • Box titles follow design.md ("Pull requests"/"Merge requests"), with the breadcrumb shortened in the middle, overruling the planner's "[1] PRs".
  • Only tabs with content are shown, so no "Not available yet" placeholders ship.
  • q and ctrl+c quit, as in the mockup. Status messages clear on the next key press.
  • No teatest. Golden files would churn on every style change.
  • Dismissed: "tabs misalign the border" is a tmux capture artifact, and the model output lines are exact width. Also dismissed: a suggestion to merge the box and tab key handlers, since they differ in how they move between levels.

Closes #8

🤖 Generated with Claude Code

## Summary The UI shell for #8: lazyforge now opens a real terminal UI. You get the repo list on the left with ★ Renovate pinned at the top (still a placeholder), the boxes [1] Pull requests, [2] Issues and [3] Actions (Actions only when the forge has them), and a details pane with the Overview tab. Navigation is `h`/`l`, `j`/`k`, `1`–`5`, `tab`, `gg`/`G`, with a breadcrumb, status-bar hints and `?` help, all driven by one keymap. `lazyforge --demo` runs the whole UI on built-in demo data seeded from the mockup. It's read-only: actions come in #9. ## Changes - `internal/ui` + `internal/ui/style`: Bubble Tea v2 (`charm.land/bubbletea/v2` v2.0.10, `bubbles/v2` v2.2.1, `lipgloss/v2` v2.0.6). - The root model routes between the repo list, boxes and details. The focused box grows. - The layout comes from the window size and fits 80×24. - Screens render from the core cache at once, then refresh in the background: every five minutes, and on `r` as wired in #9. Results for a repo you've moved away from are dropped. - Box [1]'s title follows the host's term ("Pull requests" or "Merge requests"). A breadcrumb that's too long shortens in the middle. - Details show only tabs that have content, so Overview for now. `q` quits, and `ctrl+c` quits from anywhere. - `forgetest.NewDemo`: demo data matching the mockup. - `cmd/lazyforge`: - `--demo` starts the UI on the demo data. - With a real config, it signs in to the selected host through the Forgejo/Gitea adapter and starts the UI. - The startup update check still runs before the UI, and `--demo` skips it. - `.golangci.yml`: a depguard rule. Only `cmd/` (and tests) may import the concrete adapter or the test fake, which enforces the layering in CI. - ADR 0010 and a `## UI` section in `docs/architecture.md`. ## Screens (`lazyforge --demo`, 80×24, captured in tmux) ``` lazyforge forge.home.arpa › home/homelab › [1] Pull requests › #42 ╭─ [1] Pull requests 3 ──────╮╭─ Overview ─────────────────────────────────────╮ │ #42 chore(deps): upd… ✓ 4m ││ chore(deps): update postgres to v17.0 │ │ #41 chore(deps): up… ✗ 25m ││ home/homelab #42 · renovate · 4m ago │ │ #39 feat: add uptime… ✓ 1d ││ ✓ CI passing · dependencies │ │ ││ renovate/postgres-17.x → main │ │ ││ │ │ ││ This PR contains the following updates: │ │ ││ │ │ ││ | Package | Update | Change | │ │ ││ |---|---|---| │ │ ││ | │ ╰────────────────────────────╯│ [postgres](https://hub.docker.com/_/postgres) │ ╭─ [2] Issues 2 ─────────────╮│ | major | `16.4` → `17.0` | │ │ #12 Dependency Dashboa… 4m ││ │ │ #30 Paperless back… 1💬 3d ││ --- │ │ ││ │ ╰────────────────────────────╯│ │ ╭─ [3] Actions 2 ────────────╮│ │ │ ✓ deploy main 10m ││ │ │ ✗ validate renovate/t… 25m ││ │ │ ││ │ ╰────────────────────────────╯╰────────────────────────────────────────────────╯ DETAILS j/k scroll · [ ] tabs · h back ``` ## Test plan - Tests drive the UI by sending it messages against the core over the demo fake, plus a few checks on the rendered text with colour codes stripped. They cover navigation, box focus and growth, the details pane, help, quit, dropping stale and cancelled loads, cache hits that skip fetching, the Actions gate, empty boxes, layout at 80×24, 120×40 and 20×5, breadcrumb shortening, and tab and control-character sanitising. - Mutation checks: UI 22 killed (2 equivalent), demo and startup 8 of 8 killed. - Reviews: spec PASS (opus) and standards PASS after one fix round. Comments and test-quality PASS after three fix rounds, which also removed a flaky-test risk: the test helper now fails on a slow command instead of silently dropping it. - `make check` exit 0 after syncing develop: format, lint (0 issues), `go test -race`, govulncheck, build, install test. ## Rulings - Box titles follow design.md ("Pull requests"/"Merge requests"), with the breadcrumb shortened in the middle, overruling the planner's "[1] PRs". - Only tabs with content are shown, so no "Not available yet" placeholders ship. - `q` and `ctrl+c` quit, as in the mockup. Status messages clear on the next key press. - No teatest. Golden files would churn on every style change. - Dismissed: "tabs misalign the border" is a tmux capture artifact, and the model output lines are exact width. Also dismissed: a suggestion to merge the box and tab key handlers, since they differ in how they move between levels. Closes #8 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Refs #8. Demo mode data for the UI shell, relative to a caller-supplied now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds internal/ui and internal/ui/style on Charm v2 (bubbletea v2.0.10,
bubbles v2.2.1, lipgloss v2.0.6): two-column layout, repo list with the
pinned Renovate row, boxes [1]-[3], details Overview, breadcrumb, status
bar hints and help overlay, with stale-result and cancellation handling.

#8

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Wires ui.New to the real host (Forgejo/Gitea) and to forgetest.NewDemo.
Adds the architecture UI section and ADR 0010.

#8

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#8

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replaces the hand-built Fake now that S2's demo data exists. Part of #8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fixes phase 6 review findings H1, L1-L5 and spec I2/I3 for #8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #8: onboarding, picker, no-adapter and token_cmd errors (no secret
leak); demo host, repo activity, item numbers/statuses, timestamps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Covers load, stale drop, refresh, navigation, details, help, status bar,
layout and the layering greps. Shared helpers move to helpers_test.go.

#8

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fix wave for #8 phase 9: drop go.mod version pin test, assert AC values
in demo tests, remove redundant tests, add why comment on row().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #8

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The test helper now waits 5s per command and fails instead of silently
dropping a slow load. Refs #8

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
refactor(ui): make the refresh tick a Model field and trim comments
All checks were successful
ci / check (pull_request) Successful in 1m27s
0b22608366
Replaces the package-level tick var with a Model field set like now,
drops TestMain, deletes paraphrase comments, and tidies ui tests.
Refs #8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
deadstyle merged commit ad1710dfa0 into develop 2026-10-02 13:29:09 -05:00
deadstyle deleted branch feature/8-ui-shell 2026-10-02 13:29:09 -05:00
Sign in to join this conversation.
No description provided.