feat(dev): lab ⋯ menu — repo link + auto-close #99

Closed
opened 2026-06-05 21:14:38 +02:00 by dominik.polakovics · 0 comments

Summary

Two improvements to the lab's per-project menu (the per-card menu where AFK runs are handled), in hosts/fw/vms/dev/modules/lab:

  1. Repository link — jump to the project's Forgejo repo from the menu.
  2. Auto-close — the menu should dismiss itself like a normal dropdown.

Single PR, commit scope feat(dev): (lab is vendored under the dev microVM, ADR-0004).

  • Add a Repository ↗ row at the bottom of the menu, below a 1px divider, after the existing AFK controls (Start AFK run / Auto / Reset).
  • Links to the repo home https://git.cloonar.com/<Owner>/<Repo>, opening in a new tab (target="_blank" rel="noopener").
  • Forgejo projects only. Non-Forgejo cards are unchanged — they keep just the disabled "needs a git.cloonar.com repo" line (no git.cloonar.com URL to offer).
  • Available for Forgejo projects regardless of Claude login state (navigation, not an AFK action).

Implementation:

  • forgejo.go: add func (f forgejoInfo) RepoURL() string building https://<forgejoHost>/<Owner>/<Repo> (keeps forgejoHost the single source of the host); returns "" when !IsForgejo.
  • handlers.go: add RepoURL string to projectGroup; populate at the snapshot site (~:697) from forgejoFor(p.Path).RepoURL().
  • templates/index.html: render <a class="menu-item" href="{{.RepoURL}}" target="_blank" rel="noopener">Repository ↗</a> inside the {{if .Forgejo}} block, after the AFK forms, preceded by a .menu-sep divider.
  • CSS: add a.menu-item:hover { background: var(--hover); } (current hover rule is button-scoped); add a .menu-sep rule (1px var(--border)). The existing .menu-item base already supplies the 44px tap target.

2. Auto-close

The menu (<details class="menu">) currently never closes on its own: the DOM-morph deliberately preserves the open attribute across the ~4s poll (patchAttrs skips open). Add explicit, event-driven auto-close without touching that morph rule, so a background refresh still never snaps an open menu shut:

  • Close the menu on (a) click/tap outside any open menu, (b) click of any item inside (Start AFK / Auto / Reset / Repository) — uniform immediate close, and (c) Escape.
  • Implement in the existing delegated document click handler (+ a keydown for Escape). For each open details.menu: click on its own <summary> → do nothing (native toggle owns it); click inside its .menu-list → close; click outside the menu → close. Gives accordion behavior for free (opening one closes another).
  • Race-safe: we only ever close (never reopen), so it can't fight the native <summary> toggle; and since we close via JS while the morph leaves open untouched, a later morph keeps it closed.
  • No-JS: native <details> still opens/closes by tapping (graceful degradation; auto-close is a JS-only enhancement).

Testing

  • Go (forgejo_test.go for RepoURL(), plus snapshot/handlers rendering): run go test ./... && go vet ./... && go build ./... locally — the pre-commit hook is eval-only (nix-instantiate) and does not run Go tests.
  • Inline JS: verify with ephemeral jsdom in /tmp (ADR-0004, no committed JS harness) — assert outside-click, action-click, and Escape each close the menu; summary-click still toggles; and a simulated apply() morph neither reopens a closed menu nor closes an open one.

Acceptance criteria

  • Forgejo project's menu shows Repository ↗ at the bottom under a divider; opens https://git.cloonar.com/<owner>/<repo> in a new tab.
  • Non-Forgejo project's menu is unchanged (no repo link).
  • Clicking any menu item closes the menu immediately.
  • Tapping/clicking outside the menu closes it.
  • Escape closes the menu.
  • Clicking still opens/closes normally; the background poll never opens or closes the menu on its own.
  • go test ./... && go vet ./... && go build ./... pass; JS behavior verified via jsdom.
  • Single PR, feat(dev): scope.
## Summary Two improvements to the lab's per-project `⋯` menu (the per-card menu where AFK runs are handled), in `hosts/fw/vms/dev/modules/lab`: 1. **Repository link** — jump to the project's Forgejo repo from the menu. 2. **Auto-close** — the menu should dismiss itself like a normal dropdown. Single PR, commit scope `feat(dev):` (lab is vendored under the dev microVM, ADR-0004). ## 1. Repository link (Forgejo-only) - Add a `Repository ↗` row at the **bottom** of the `⋯` menu, below a 1px divider, after the existing AFK controls (Start AFK run / Auto / Reset). - Links to the repo home `https://git.cloonar.com/<Owner>/<Repo>`, opening in a **new tab** (`target="_blank" rel="noopener"`). - **Forgejo projects only.** Non-Forgejo cards are unchanged — they keep just the disabled "needs a git.cloonar.com repo" line (no git.cloonar.com URL to offer). - Available for Forgejo projects regardless of Claude login state (navigation, not an AFK action). Implementation: - `forgejo.go`: add `func (f forgejoInfo) RepoURL() string` building `https://<forgejoHost>/<Owner>/<Repo>` (keeps `forgejoHost` the single source of the host); returns "" when `!IsForgejo`. - `handlers.go`: add `RepoURL string` to `projectGroup`; populate at the snapshot site (~`:697`) from `forgejoFor(p.Path).RepoURL()`. - `templates/index.html`: render `<a class="menu-item" href="{{.RepoURL}}" target="_blank" rel="noopener">Repository ↗</a>` inside the `{{if .Forgejo}}` block, after the AFK forms, preceded by a `.menu-sep` divider. - CSS: add `a.menu-item:hover { background: var(--hover); }` (current hover rule is `button`-scoped); add a `.menu-sep` rule (1px `var(--border)`). The existing `.menu-item` base already supplies the 44px tap target. ## 2. Auto-close The `⋯` menu (`<details class="menu">`) currently never closes on its own: the DOM-morph deliberately preserves the `open` attribute across the ~4s poll (`patchAttrs` skips `open`). Add explicit, event-driven auto-close **without** touching that morph rule, so a background refresh still never snaps an open menu shut: - Close the menu on **(a)** click/tap outside any open menu, **(b)** click of any item inside (Start AFK / Auto / Reset / Repository) — uniform immediate close, and **(c)** Escape. - Implement in the existing delegated `document` click handler (+ a `keydown` for Escape). For each open `details.menu`: click on its own `<summary>` → do nothing (native toggle owns it); click inside its `.menu-list` → close; click outside the menu → close. Gives accordion behavior for free (opening one closes another). - Race-safe: we only ever *close* (never reopen), so it can't fight the native `<summary>` toggle; and since we close via JS while the morph leaves `open` untouched, a later morph keeps it closed. - No-JS: native `<details>` still opens/closes by tapping `⋯` (graceful degradation; auto-close is a JS-only enhancement). ## Testing - **Go** (`forgejo_test.go` for `RepoURL()`, plus snapshot/handlers rendering): run `go test ./... && go vet ./... && go build ./...` **locally** — the pre-commit hook is eval-only (nix-instantiate) and does not run Go tests. - **Inline JS**: verify with ephemeral jsdom in `/tmp` (ADR-0004, no committed JS harness) — assert outside-click, action-click, and Escape each close the menu; summary-click still toggles; and a simulated `apply()` morph neither reopens a closed menu nor closes an open one. ## Acceptance criteria - [ ] Forgejo project's `⋯` menu shows `Repository ↗` at the bottom under a divider; opens `https://git.cloonar.com/<owner>/<repo>` in a new tab. - [ ] Non-Forgejo project's menu is unchanged (no repo link). - [ ] Clicking any menu item closes the menu immediately. - [ ] Tapping/clicking outside the menu closes it. - [ ] Escape closes the menu. - [ ] Clicking `⋯` still opens/closes normally; the background poll never opens or closes the menu on its own. - [ ] `go test ./... && go vet ./... && go build ./...` pass; JS behavior verified via jsdom. - [ ] Single PR, `feat(dev):` scope.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Cloonar/nixos#99
No description provided.