web: draw the chrome from sr-ht-ecore
The brand, the service switcher, the login block, the environment banner
and the database listing were a local port of core.sr.ht's nav — one of
five such ports on this instance, and they had already drifted. They are
now sourcecraft.dev/bigbes/sr-ht-ecore/chrome, the one copy every custom
service draws from.
Deleted: web/chrome.go entire (navEntry, networkOrder, networkExcluded,
buildNetwork, basePage, loginURL, logoutURL), templates/nav.html,
templates/icons/circle.svg (ecore inlines the identical SVG), the
repoList partial, and the local dict/shortHash duplicates.
Added: one chrome.Service built in newApp from our config section with
the hashed stylesheet href set on it, a chrome.Page per request through
app.page, chrome.Attach on every template set, and chrome.Funcs as the
base of the funcmap. Handlers embed chrome.Page in their view structs
instead of copying its fields; the row browser sets ContainerClass to
container-fluid, since its column count is the table's and not ours.
Three behaviour changes come with ecore's policy, all deliberate: the
profile link now prefers hub's ~username page when hub.sr.ht is
configured (it was always meta's /profile), the brand carries a fixed
15rem min-width so the switcher starts at the same x on every service,
and a binary built without a stylesheet renders bare rather than linking
an empty href. The nav test went with the code it tested — ordering,
exclusions and login URLs are ecore's to cover — and what replaced it
asserts only what is ours: that pages are drawn through the chrome at
all, and that the row browser is full-bleed.
The auth path is untouched: a foreign bearer token is still accepted as
a meta.sr.ht PAT.
gitignore the in-repo git worktree directories
Agent worktrees are created under .worktrees/<branch> (and, in the older
repos of this family, .claude/worktrees/<branch>) so that they never
scatter as sibling directories next to the checkout. Neither path was
ignored here, so a worktree showed up as untracked in every git status
taken from the main checkout.
web: restyle dashboard and database lists after git.sr.ht
Replace the bare 'Your databases' heading and compact grid with the
git.sr.ht dashboard layout: a sidebar column with a welcome blurb plus
block buttons (create database, configure dolt credentials), and the
shared event-list cards for the database list. The repoList partial now
renders each database as an event card — name, visibility as small
muted text (non-public only, like git.sr.ht), description below — and
the profile page picks the same partial up automatically.
Adds a 'lower' template func for the visibility label and drops the now
unused .repo-list grid from main.scss (.event-list ships with the core
theme already).
feat(web/beads): hierarchy in the milestone view
Arrange each milestone as a shallow hierarchy instead of a flat list.
- Put the milestone-typed issue(s) on top as the milestone's heads.
- Nest tasks under their epics via parent-child dependency edges,
with a done/total rollup on the epic row; membership stays label-based.
- Keep remaining members as a loose tail; blocks edges are ignored.
- Read the dependencies table optionally, degrading to a flat list.
- Extend fixtures and real-data logging to cover the hierarchy.
feat(web/beads): promote milestones to their own view/tab
Move the milestone rollup off the board and into a dedicated "Milestones" tab
(a registered View, companion to Beads via the same fingerprint). The tab is
richer than the old board panel: per-milestone progress bar, done/open/in-progress
counts, and the issue list under each milestone (open-work first, closed struck
through), each linking to its beads detail. Issues with no milestone label are
summarized in a footnote. A beads DB with no milestone labels still gets the tab,
showing an empty-state hint.
Removes the board's inline milestone panel and the collectMilestones/BeadMilestone
helpers it used; the grouping now lives in the milestones view.
feat(web/beads): ready markers, milestone rollup, transitive dependency tree
Three additions surfacing more of the bd data model:
- Ready: a ⚡ marker on actionable-now cards and a "Ready only" board filter.
"Ready" mirrors bd's ready set exactly — open, unblocked, not template/
ephemeral. As part of this, parent-child edges no longer count as blockers
(a subtask is not blocked by its open epic), which was over-filling Stalled
and under-counting ready; the board now matches bd's is_blocked/ready
accounting (verified: 111 ready on tarantool-etcd, == ready_issues).
- Milestone rollup: a board panel with per-"milestone:<name>" label progress
bars (done/total), each linking to that label's filtered board.
- Transitive dependency tree on the detail page: the full prerequisite chain
("everything this waits on") and the reverse ("everything this unblocks"),
walked from the edge set with depth/'node caps and cycle guard, indented by
depth. Shown only when it reaches past the direct edges, so it never just
repeats the flat Depends-on / Depended-on-by lists.
feat(web/beads): filters for the parade board
Add a filter bar to the beads board: text search (id/title), issue type,
priority, assignee, and label. Filters are query-param based (GET, sticky
across submits) and applied server-side before lane bucketing, so the marquee
counts reflect the filtered set. Dropdown options are collected from the full
issue set (they don't shrink as filters narrow the board); a Clear link shows
when any filter is active. Verified on the 143-issue tarantool-etcd board
(type=bug → 30).
feat(web/beads): close reason in Comments tab; synthesize subtask-add history
- Close reason placement: show it as a block at the end of the Comments tab
(which carries no closed event), while the History tab shows it inline as the
closed event — so it appears in whichever tab you're on, without duplication
within a tab. (Reverts the outright removal.)
- History now includes dependency/subtask additions. beads logs no audit event
for a link, but the dependencies row records created_at/created_by, so
buildDetail synthesizes "added subtask X" / "added dependency on X" timeline
entries (Kind "dep", own accent). On an epic this surfaces when each child was
linked. Guarded on created_at so older schemas without it emit nothing.
- pre.field-body style de-scoped from .bead-detail so the Comments-tab close
reason wraps (overflow-wrap: anywhere) instead of overflowing.
refine(web/beads): concise label events, drop standalone close reason, wrap long lines
- Label audit events collapse to one line ("added label milestone:m3") instead
of a "label added" header plus a redundant "Added label: …" body. The label
name is taken after the first colon so namespaced labels survive.
- Remove the standalone Close reason block below the activity: the reason
already shows as the History tab's `closed` event, so it was a duplicate.
- Add overflow-wrap: anywhere to the timeline body, comment body, and
field-body pre so a very long single-line reason wraps instead of overflowing.
feat(web/beads): epic view with subtask rollup, tabbed Comments/History
Three additions to the beads issue detail:
- Epic mode: when the viewed issue is issue_type=epic, render a Subtasks panel
— its parent-child children (deps pointing at the epic) with a done/total
progress meter, sorted open-work-first with closed sinking to the bottom.
- Activity is now a two-tab strip (pure-CSS, no JS): Comments keeps the plain
thread; History merges comments and the audit-log events table into one
time-sorted timeline with humanized change lines ("changed status to
in_progress", "updated priority to 0", "closed the issue" + reason).
- Close reason moved from the top metadata table to its own block at the very
bottom, after the activity — it reads as a closing note, not a header field.
Verified end-to-end against a real 143-issue beads store (tarantool-etcd) via
the env-guarded TestRealBeadsStore smoke test; unit-covered with a dedicated
epic/history fixture.
feat(web): Overview/Tables/Beads tab bar + full issue fields on beads detail
Give every database page a consistent three-tab bar — Overview, Tables,
then the applicable views (Beads) — in that order. Previously the bar only
carried [views, Tables] and the Overview page marked Tables active, so there
was no way to tell you were on the overview. viewtabs now takes an explicit
Current sentinel ("overview" | "tables" | view slug) and the tree/table row
pages render the bar too (handlers compute applicable views for the ref).
Surface the issue fields the beads detail pane was dropping. The closure
reason (close_reason) recorded by `bd close -r` was never shown; auditing
against bd's own field set also turned up estimated_minutes, external_ref,
spec_id, and started_at. All render conditionally, so issues that don't set
them stay uncluttered.
style(web): restyle the beads parade in the todo.sr.ht idiom
The board still read as a rounded-card kanban from another app. Re-skin
every surface in sourcehut's own issue-tracker language (todo.sr.ht):
flat and square — no border-radius, no shadows, no tints — hairline gray
borders, monospace ids, striped-on-hover rows instead of cards, and
squared bordered labels (the sourcehut .label: 1px border, no radius).
The summary becomes a flat hairline strip and each lane a squared column
with a 2px accent cap. The Mardi Gras hues survive only as small square
swatches and the lane cap, never as fills, so the view looks like a
native sourcehut tracker in both the light and dark themes. Verified via
a headless light/dark render. Test asserts the renamed summary class.
fix(web): make the beads view inherit the SourceHut theme
The beads board shipped its own Mardi Gras palette — a purple→green
marquee gradient and saturated solid lane fills — that clashed with
SourceHut's flat, utilitarian dark theme, and the detail pane's field
labels were a hardcoded dark purple with no dark-mode override, leaving
"Created by / Owner / Description" unreadable on the dark background.
Drive everything from CSS variables that mirror core.sr.ht's Bootstrap
palette for both the light default and the prefers-color-scheme: dark
variant sourcehut ships (the same media query it uses), so the view
inherits the host theme instead of fighting it. Lane hues become muted
Mardi Gras accents (gold/green/violet/gray) used only as thin borders and
low-alpha tints — never as body text — so contrast holds on either theme.
The marquee is now a flat stat row, lanes an understated panel with an
accent underline, and detail labels a readable muted caption. Verified
light and dark via a headless render.
feat(web): Mardi Gras beads view
Render a beads (bd) issue database as a Mardi Gras parade board: four
lanes — Rolling (in progress), Lined Up (open & ready), Stalled (open &
blocked), Past Stand (done) — plus a marquee of per-lane counts. Cards
show id/title/type/priority/assignee/labels and blocked-by/blocks counts;
an issue-detail pane (?issue=<id>) shows the full issue with its
dependency edges in both directions and its comments thread.
Fingerprints on the issues + dependencies tables and reads everything
through the browse layer (column-name-keyed, so column order is
irrelevant), capped at 2000 rows/table. Status is bucketed via
custom_statuses with name heuristics as a fallback; "blocked" means
is_blocked or an open blocking dependency. Plugs into the view registry
via init()+RegisterView with no framework edits. Purple/gold/green
palette scoped in the template (no scss rebuild needed).
feat(web): pluggable alternative-view registry for repositories
A repository can now expose specialized, read-only "views" chosen by the
shape of its tables, while the generic table browser stays available as a
fallback. A View fingerprints the tables (Applies), builds a model from
the browse layer (Build), and renders its own template; views register at
init time via RegisterView and are dispatched by slug at
/~user/db/view/{slug}. The overview shows a tab per applicable view.
The template loader parses each registered view's template with the
shared chrome, so a new view plugs in by adding two files (its .go with
init()+RegisterView and its .html) plus nothing else — no edits to the
registry, router, loader, or handlers. Build receives the request query
values so a view can offer sub-modes (e.g. a detail pane). No SQL engine
is involved; views read through the existing BrowseSession surface.
web: router, handlers, and sourcehut chrome
Chi route table per plan, SourceHut chrome port (nav/layout from
core.sr.ht Bootstrap structure), dual-flow clone box, dolt-key
association page with hash-fragment prefill, same-origin CSRF checks.
Handlers depend on small injected interfaces (StoreManager, RepoStore,
BrowseOpener, UserResolver) with production adapters included.