templating: Move actions into template

This commit is contained in:
Tom Wiesing 2023-01-12 13:55:07 +01:00
parent 313af2b9e3
commit 202599aaeb
No known key found for this signature in database
23 changed files with 153 additions and 105 deletions

View file

@ -30,9 +30,11 @@ type componentContext struct {
}
func (admin *Admin) components(r *http.Request) (cp componentContext, err error) {
admin.Dependencies.Custom.Update(&cp, r, []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
{Title: "Components", Path: "/admin/components/"},
admin.Dependencies.Custom.Update(&cp, r, custom.BaseContextGaps{
Crumbs: []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
{Title: "Components", Path: "/admin/components/"},
},
})
cp.Analytics = *admin.Analytics
@ -56,10 +58,12 @@ type ingredientsContext struct {
func (admin *Admin) ingredients(r *http.Request) (cp ingredientsContext, err error) {
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
admin.Dependencies.Custom.Update(&cp, r, []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
{Title: "Instance", Path: template.URL("/admin/instance/" + slug)},
{Title: "Ingredients", Path: template.URL("/admin/instance/" + slug + "/ingredients/")},
admin.Dependencies.Custom.Update(&cp, r, custom.BaseContextGaps{
Crumbs: []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
{Title: "Instance", Path: template.URL("/admin/instance/" + slug)},
{Title: "Ingredients", Path: template.URL("/admin/instance/" + slug + "/ingredients/")},
},
})
// find the instance itself!

View file

@ -40,10 +40,12 @@ type grantsContext struct {
}
func (gc *grantsContext) use(r *http.Request, slug string, admin *Admin) (err error) {
admin.Dependencies.Custom.Update(gc, r, []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
{Title: "Instance", Path: template.URL("/admin/instance/" + slug)},
{Title: "Grants", Path: template.URL("/admin/instance/" + slug + "/grants/")},
admin.Dependencies.Custom.Update(gc, r, custom.BaseContextGaps{
Crumbs: []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
{Title: "Instance", Path: template.URL("/admin/instance/" + slug)},
{Title: "Grants", Path: template.URL("/admin/instance/" + slug + "/grants/")},
},
})
// find the instance itself

View file

@ -1,15 +1,6 @@
{{ template "_base.html" . }}
{{ define "title" }}Admin{{ end }}
{{ define "header" }}
<p>
<div class="pure-button-group" role="group" aria-label="Actions">
<a class="pure-button" href="/admin/users">Users</a>
<a class="pure-button pure-button-small" href="/admin/components">Components</a>
</div>
</p>
{{ end }}
{{ define "content" }}
<div class="pure-u-1-1">
<h2 id="overview">Distillery Configuration</h2>

View file

@ -1,15 +1,6 @@
{{ template "_base.html" . }}
{{ define "title" }}{{ .Instance.Slug }}{{ end }}
{{ define "header" }}
<p>
<div class="pure-button-group" role="group" aria-label="Actions">
<a class="pure-button" href="/admin/grants/{{ .Info.Slug }}">Grants</a>
<a class="pure-button pure-button-small" href="/admin/ingredients/{{ .Instance.Slug }}">Ingredients</a>
</div>
</p>
{{ end }}
{{ define "content" }}
<div class="pure-u-1-1">
<h2 id="overview">Info &amp; Status</h2>

View file

@ -1,13 +1,5 @@
{{ template "_base.html" . }}
{{ define "title" }}Admin Users{{ end }}
{{ define "header" }}
<p>
<div class="pure-button-group" role="group" aria-label="Actions">
<a class="pure-button" href="/admin/users/create">Create New</a>
</div>
</p>
{{ end }}
{{ define "title" }}Users{{ end }}
{{ define "content" }}

View file

@ -87,8 +87,14 @@ type indexContext struct {
}
func (admin *Admin) index(r *http.Request) (idx indexContext, err error) {
admin.Dependencies.Custom.Update(&idx, r, []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
admin.Dependencies.Custom.Update(&idx, r, custom.BaseContextGaps{
Crumbs: []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
},
Actions: []component.MenuItem{
{Title: "Users", Path: "/admin/users/"},
{Title: "Components", Path: "/admin/components/", Priority: component.SmallButton},
},
})
idx.Distillery, idx.Instances, err = admin.Status(r.Context(), true)
return

View file

@ -32,9 +32,15 @@ type instanceContext struct {
func (admin *Admin) instance(r *http.Request) (is instanceContext, err error) {
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
admin.Dependencies.Custom.Update(&is, r, []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
{Title: "Instance", Path: template.URL("/admin/instance/" + slug)},
admin.Dependencies.Custom.Update(&is, r, custom.BaseContextGaps{
Crumbs: []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
{Title: "Instance", Path: template.URL("/admin/instance/" + slug)},
},
Actions: []component.MenuItem{
{Title: "Grants", Path: template.URL("/admin/grants/" + slug)},
{Title: "Ingredients", Path: template.URL("/admin/ingredients/" + slug), Priority: component.SmallButton},
},
})
// find the instance itself!

View file

@ -32,9 +32,11 @@ type userContext struct {
}
func (admin *Admin) users(r *http.Request) (uc userContext, err error) {
admin.Dependencies.Custom.Update(&uc, r, []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
{Title: "Users", Path: "/admin/users/"},
admin.Dependencies.Custom.Update(&uc, r, custom.BaseContextGaps{
Crumbs: []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
{Title: "Users", Path: "/admin/users/"},
},
})
uc.Error = r.URL.Query().Get("error")
@ -62,10 +64,15 @@ type createUserResult struct {
func (admin *Admin) createUser(ctx context.Context) http.Handler {
userCreateTemplate := admin.Dependencies.Custom.Template(userCreateTemplate)
crumbs := []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
{Title: "Users", Path: "/admin/users"},
{Title: "Create", Path: "/admin/users/create"},
gaps := custom.BaseContextGaps{
Crumbs: []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
{Title: "Users", Path: "/admin/users"},
{Title: "Create", Path: "/admin/users/create"},
},
Actions: []component.MenuItem{
{Title: "Create New", Path: "/admin/users/create/"},
},
}
return &httpx.Form[createUserResult]{
@ -78,7 +85,7 @@ func (admin *Admin) createUser(ctx context.Context) http.Handler {
RenderTemplate: userCreateTemplate,
RenderTemplateContext: func(ctx httpx.FormContext, r *http.Request) any {
return admin.Dependencies.Custom.NewForm(ctx, r, crumbs)
return admin.Dependencies.Custom.NewForm(ctx, r, gaps)
},
Validate: func(r *http.Request, values map[string]string) (cu createUserResult, err error) {

View file

@ -25,8 +25,10 @@ type publicContext struct {
}
func (home *Home) publicHandler(ctx context.Context) http.Handler {
crumbs := []component.MenuItem{
{Title: "WissKI Distillery", Path: "/"},
gaps := custom.BaseContextGaps{
Crumbs: []component.MenuItem{
{Title: "WissKI Distillery", Path: "/"},
},
}
return httpx.HTMLHandler[publicContext]{
Handler: func(r *http.Request) (pc publicContext, err error) {
@ -35,7 +37,7 @@ func (home *Home) publicHandler(ctx context.Context) http.Handler {
return pc, httpx.ErrNotFound
}
home.Dependencies.Custom.Update(&pc, r, crumbs)
home.Dependencies.Custom.Update(&pc, r, gaps)
pc.Instances = home.homeInstances.Get(nil)
pc.SelfRedirect = home.Config.SelfRedirect.String()

View file

@ -59,8 +59,10 @@ type legalContext struct {
}
func (legal *Legal) context(r *http.Request) (lc legalContext, err error) {
legal.Dependencies.Custom.Update(&lc, r, []component.MenuItem{
{Title: "Legal", Path: "/legal/"},
legal.Dependencies.Custom.Update(&lc, r, custom.BaseContextGaps{
Crumbs: []component.MenuItem{
{Title: "Legal", Path: "/legal/"},
},
})
lc.LegalNotices = cli.LegalNotices

View file

@ -123,8 +123,10 @@ type newsContext struct {
// HandleRoute returns the handler for the requested path
func (news *News) HandleRoute(ctx context.Context, path string) (http.Handler, error) {
crumbs := []component.MenuItem{
{Title: "News", Path: "/news/"},
gaps := custom.BaseContextGaps{
Crumbs: []component.MenuItem{
{Title: "News", Path: "/news/"},
},
}
items, itemsErr := Items()
@ -134,7 +136,7 @@ func (news *News) HandleRoute(ctx context.Context, path string) (http.Handler, e
return httpx.HTMLHandler[newsContext]{
Handler: func(r *http.Request) (nc newsContext, err error) {
news.Dependencies.Custom.Update(&nc, r, crumbs)
news.Dependencies.Custom.Update(&nc, r, gaps)
nc.Items, err = items, itemsErr
return

View file

@ -27,8 +27,8 @@ type BaseContext struct {
GeneratedAt time.Time // time this page was generated at
// Menu and breadcrumbs
Menu []component.MenuItem
Crumbs []component.MenuItem
Menu []component.MenuItem
BaseContextGaps
CSRF template.HTML // CSRF Field
}
@ -43,12 +43,24 @@ const (
requestNilError template.HTML = errorPrefix + "<code>BaseContext.use()</code> called with nil request" + errorSuffix
)
type BaseContextGaps struct {
Crumbs []component.MenuItem
Actions []component.MenuItem
}
func (bcg BaseContextGaps) Clone() BaseContextGaps {
return BaseContextGaps{
Crumbs: slices.Clone(bcg.Crumbs),
Actions: slices.Clone(bcg.Actions),
}
}
// Use updates this context to use the values from the given base.
//
// The given request *must not* be nil.
//
// For convenience the passed context is also returned.
func (tc *BaseContext) use(custom *Custom, r *http.Request, crumbs []component.MenuItem) *BaseContext {
func (tc *BaseContext) use(custom *Custom, r *http.Request, gaps BaseContextGaps) *BaseContext {
// tc.custom = custom
tc.inited = true
tc.requestWasNil = r == nil
@ -65,7 +77,7 @@ func (tc *BaseContext) use(custom *Custom, r *http.Request, crumbs []component.M
tc.Menu = custom.BuildMenu(r)
// build the breadcrumbs
tc.Crumbs = slices.Clone(crumbs)
tc.BaseContextGaps = gaps.Clone()
last := len(tc.Crumbs) - 1
for i := range tc.Crumbs {
tc.Crumbs[i].Active = i == last
@ -86,9 +98,9 @@ func (bc BaseContext) DoInitCheck() template.HTML {
}
// NewForm is like New, but returns a new BaseFormContext
func (custom *Custom) NewForm(context httpx.FormContext, r *http.Request, crumbs []component.MenuItem) (ctx BaseFormContext) {
func (custom *Custom) NewForm(context httpx.FormContext, r *http.Request, bcg BaseContextGaps) (ctx BaseFormContext) {
ctx.FormContext = context
ctx.use(custom, r, crumbs)
ctx.use(custom, r, bcg)
return
}
@ -96,11 +108,11 @@ func (custom *Custom) NewForm(context httpx.FormContext, r *http.Request, crumbs
//
// Assumes that context is a pointer to a struct type.
// If this is not the case, might call panic().
func (custom *Custom) Update(context any, r *http.Request, crumbs []component.MenuItem) *BaseContext {
func (custom *Custom) Update(context any, r *http.Request, bcg BaseContextGaps) *BaseContext {
ctx := reflect.ValueOf(context).
Elem().FieldByName(baseContextName).Addr().
Interface().(*BaseContext)
ctx.use(custom, r, crumbs)
ctx.use(custom, r, bcg)
return ctx
}

View file

@ -1,5 +1,5 @@
<div class="pure-u-1-1">
<h2 id="components">Components</h2>
<h2 id="structs">Structs</h2>
</div>
{{ range $name, $comp := .Components }}

View file

@ -11,7 +11,7 @@
<body>
{{ .BaseContext.DoInitCheck }}
<nav class="pure-menu pure-menu-horizontal">
<ul class="pure-menu-list">
<ul class="pure-menu-list" role="menubar">
{{ range .BaseContext.Menu }}
<li class="pure-menu-item{{ if .Active }} pure-menu-selected{{ end }}">
<a href="{{ .Path }}" class="pure-menu-link">{{ .Title }}</a>
@ -27,7 +27,13 @@
<header>
<h1 id="top">{{ template "title" . }}</h1>
{{ block "header" . }}<!-- no header by default -->{{ end }}
{{ if .BaseContext.Actions }}
<div class="pure-button-group" role="group" aria-label="Actions">
{{ range .BaseContext.Actions }}
<a href="{{ .Path }}" class="pure-button{{ if eq .Priority -1 }} pure-button-small{{end}}">{{ .Title }}</a>
{{ end }}
</div>
{{ end }}
</header>
<main>
<div class="pure-g">