~bigbes/sr-ht-dolt

ref: f88846acf59598f9d235819608ba4d9ac7cc26c8 sr-ht-dolt/web/views.go -rw-r--r-- 2.6 KiB
f88846ac — Eugene Blikh web: serve the static tree through ecore's assets 9 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package web

import (
	"context"
	"net/url"

	"sourcecraft.dev/bigbes/sr-ht-dolt/browse"
	"sourcecraft.dev/bigbes/sr-ht-dolt/core"
)

// View is a specialized, read-only rendering of a repository whose table shape
// it recognizes. Views are registered at init time via RegisterView and chosen
// per-repo by Applies. The generic table browser is always available too, so a
// View never has to be exhaustive.
//
// A View pulls all of its data through the BrowseSession surface only (Tables,
// Rows, Branches, Log, ...); there is no SQL engine behind a bare store. Build
// returns an opaque value handed to the view's Template as its .Data field.
type View interface {
	Name() string                           // URL slug, e.g. "beads"; must be a valid path segment, unique
	Label() string                          // human tab label, e.g. "Beads"
	Template() string                       // page template filename in templates/, e.g. "beads.html"
	Applies(tables []browse.TableInfo) bool // fingerprint by table names/columns
	// Build produces the opaque .Data value for the view's Template. query is the
	// request URL's query string, so a view can offer sub-modes (e.g. beads'
	// ?issue=<id> detail pane) without a new route.
	Build(ctx context.Context, sess BrowseSession, repo *core.Repo, ref string, query url.Values) (any, error)
}

// registeredViews is the package-global registry populated at init time by
// RegisterView. It is read once per process: loadTemplates parses each view's
// Template() at startup, and Register snapshots it into app.views so handlers
// (and tests, which set app.views directly) never touch the global at request
// time.
var registeredViews []View

// RegisterView adds v to the global registry. It is meant to be called from an
// init() in the file that defines a concrete view, so the registry is fully
// populated before loadTemplates runs and the first request arrives. If a view
// with the same Name() is already registered it is replaced, so double
// registration (e.g. from a duplicated init) is safe.
func RegisterView(v View) {
	for i, existing := range registeredViews {
		if existing.Name() == v.Name() {
			registeredViews[i] = v
			return
		}
	}
	registeredViews = append(registeredViews, v)
}

// applicableViews returns the subset of views whose Applies reports true for
// tables, preserving registration order. It is pure: handlers pass their own
// snapshot (app.views) so the result is deterministic and testable.
func applicableViews(views []View, tables []browse.TableInfo) []View {
	out := make([]View, 0, len(views))
	for _, v := range views {
		if v.Applies(tables) {
			out = append(out, v)
		}
	}
	return out
}