templates: Add a proper menu and navigation

This commit is contained in:
Tom Wiesing 2023-01-11 14:24:13 +01:00
parent 0bb7f99fa3
commit a00195be16
No known key found for this signature in database
76 changed files with 336 additions and 233 deletions

View file

@ -40,6 +40,7 @@ type Admin struct {
var (
_ component.DistilleryFetcher = (*Admin)(nil)
_ component.Routeable = (*Admin)(nil)
_ component.Menuable = (*Admin)(nil)
)
func (admin *Admin) Routes() component.Routes {
@ -50,6 +51,19 @@ func (admin *Admin) Routes() component.Routes {
}
}
func (admin *Admin) Menu(r *http.Request) []component.MenuItem {
if !admin.Dependencies.Auth.Has(auth.Admin, r) {
return nil
}
return []component.MenuItem{
{
Title: "Admin",
Path: "/admin/",
Priority: component.MenuAdmin,
},
}
}
func (admin *Admin) HandleRoute(ctx context.Context, route string) (handler http.Handler, err error) {
router := httprouter.New()
@ -62,17 +76,17 @@ func (admin *Admin) HandleRoute(ctx context.Context, route string) (handler http
}
}
// handle everything
router.HandlerFunc(http.MethodGet, route, func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, route+"index", http.StatusTemporaryRedirect)
})
// add a handler for the index page
router.Handler(http.MethodGet, route+"index", httpx.HTMLHandler[indexContext]{
router.Handler(http.MethodGet, route, httpx.HTMLHandler[indexContext]{
Handler: admin.index,
Template: admin.Dependencies.Custom.Template(indexTemplate),
})
// fallback to the "/" page
router.HandlerFunc(http.MethodGet, route+"index", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, route, http.StatusTemporaryRedirect)
})
// add a handler for the user page
router.Handler(http.MethodGet, route+"users", httpx.HTMLHandler[userContext]{
Handler: admin.users,

View file

@ -1,10 +1,12 @@
package admin
import (
"html/template"
"net/http"
_ "embed"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/static"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/static/custom"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
@ -28,7 +30,10 @@ type componentContext struct {
}
func (admin *Admin) components(r *http.Request) (cp componentContext, err error) {
admin.Dependencies.Custom.Update(&cp, r)
admin.Dependencies.Custom.Update(&cp, r, []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
{Title: "Components", Path: "/admin/components/"},
})
cp.Analytics = *admin.Analytics
return
@ -49,10 +54,15 @@ type ingredientsContext struct {
}
func (admin *Admin) ingredients(r *http.Request) (cp ingredientsContext, err error) {
admin.Dependencies.Custom.Update(&cp, r)
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/")},
})
// find the instance itself!
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
instance, err := admin.Dependencies.Instances.WissKI(r.Context(), slug)
if err == instances.ErrWissKINotFound {
return cp, httpx.ErrNotFound

View file

@ -3,8 +3,10 @@ package admin
import (
_ "embed"
"fmt"
"html/template"
"net/http"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/static"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/static/custom"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
@ -38,7 +40,11 @@ type grantsContext struct {
}
func (gc *grantsContext) use(r *http.Request, slug string, admin *Admin) (err error) {
admin.Dependencies.Custom.Update(gc, r)
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/")},
})
// find the instance itself
gc.instance, err = admin.Dependencies.Instances.WissKI(r.Context(), slug)

View file

@ -1,13 +1,6 @@
{{ template "_base.html" . }}
{{ define "title" }}Distillery Admin - Components Page{{ end }}
{{ define "header"}}
<p>
<a class="pure-button" href="/admin/index">Admin</a> &gt;
<a class="pure-button pure-button-primary" href="/admin/components">Components</a>
</p>
{{ end }}
{{ define "content" }}
{{ template "_anal.html" .Analytics }}
{{ end }}

View file

@ -1,14 +1,6 @@
{{ template "_base.html" . }}
{{ define "title" }}Distillery Admin - {{ .Instance.Slug }} - Grants{{ end }}
{{ define "header"}}
<p>
<a class="pure-button" href="/admin/index">Admin</a> &gt;
<a class="pure-button" href="/admin/instance/{{ .Instance.Slug }}">Instance</a> &gt;
<a class="pure-button pure-button-primary" href="/admin/grants/{{ .Instance.Slug }}">Grants</a>
</p>
{{ end }}
{{ define "content" }}
{{ $csrf := .CSRF }}
{{ $slug := .Instance.Slug }}

View file

@ -1,10 +1,7 @@
{{ template "_base.html" . }}
{{ define "title" }}Distillery Admin{{ end }}
{{ define "header"}}
<p>
<a class="pure-button pure-button-primary" href="/admin/index">Admin</a>
</p>
{{ define "header" }}
<p>
<div class="pure-button-group" role="group" aria-label="Actions">
<a class="pure-button" href="/admin/users">Users</a>

View file

@ -1,14 +1,6 @@
{{ template "_base.html" . }}
{{ define "title" }}Distillery Admin - {{ .Instance.Slug }} - Ingredients{{ end }}
{{ define "header"}}
<p>
<a class="pure-button" href="/admin/index">Admin</a> &gt;
<a class="pure-button" href="/admin/instance/{{ .Instance.Slug }}">Instance</a> &gt;
<a class="pure-button pure-button-primary" href="/admin/ingredients/{{ .Instance.Slug }}">Ingredients</a>
</p>
{{ end }}
{{ define "content" }}
{{ template "_anal.html" .Analytics }}
{{ end }}

View file

@ -1,11 +1,7 @@
{{ template "_base.html" . }}
{{ define "title" }}Distillery Admin - {{ .Instance.Slug }}{{ end }}
{{ define "header"}}
<p>
<a class="pure-button" href="/admin/index">Admin</a> &gt;
<a class="pure-button pure-button-primary" href="/admin/instance/{{ .Instance.Slug }}">Instance</a>
</p>
{{ define "header" }}
<p>
<div class="pure-button-group" role="group" aria-label="Actions">
<a class="pure-button" href="/admin/grants/{{ .Info.Slug }}">Grants</a>

View file

@ -2,10 +2,3 @@
{{ define "form/title" }}Distillery Admin - Create User{{ end }}
{{ define "form/button" }}Create{{ end }}
{{ define "header"}}
<p>
<a class="pure-button" href="/admin/index">Admin</a> &gt;
<a class="pure-button" href="/admin/users">Users</a> &gt;
<a class="pure-button pure-button-primary" href="/admin/users/create">Create</a>
</p>
{{ end }}

View file

@ -1,11 +1,7 @@
{{ template "_base.html" . }}
{{ define "title" }}Distillery Admin - Users{{ end }}
{{ define "header"}}
<p>
<a class="pure-button" href="/admin/index">Admin</a> &gt;
<a class="pure-button pure-button-primary" href="/admin/users">Users</a>
</p>
{{ define "header" }}
<p>
<div class="pure-button-group" role="group" aria-label="Actions">
<a class="pure-button" href="/admin/users/create">Create New</a>

View file

@ -87,7 +87,9 @@ type indexContext struct {
}
func (admin *Admin) index(r *http.Request) (idx indexContext, err error) {
admin.Dependencies.Custom.Update(&idx, r)
admin.Dependencies.Custom.Update(&idx, r, []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
})
idx.Distillery, idx.Instances, err = admin.Status(r.Context(), true)
return
}

View file

@ -2,8 +2,10 @@ package admin
import (
_ "embed"
"html/template"
"net/http"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/static"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/static/custom"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/instances"
@ -28,10 +30,14 @@ type instanceContext struct {
}
func (admin *Admin) instance(r *http.Request) (is instanceContext, err error) {
admin.Dependencies.Custom.Update(&is, r)
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)},
})
// find the instance itself!
slug := httprouter.ParamsFromContext(r.Context()).ByName("slug")
instance, err := admin.Dependencies.Instances.WissKI(r.Context(), slug)
if err == instances.ErrWissKINotFound {
return is, httpx.ErrNotFound

View file

@ -8,6 +8,7 @@ import (
_ "embed"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/auth"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/static"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component/control/static/custom"
@ -31,7 +32,10 @@ type userContext struct {
}
func (admin *Admin) users(r *http.Request) (uc userContext, err error) {
admin.Dependencies.Custom.Update(&uc, r)
admin.Dependencies.Custom.Update(&uc, r, []component.MenuItem{
{Title: "Admin", Path: "/admin/"},
{Title: "Users", Path: "/admin/users/"},
})
uc.Error = r.URL.Query().Get("error")
uc.Users, err = admin.Dependencies.Auth.Users(r.Context())
@ -58,6 +62,11 @@ 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"},
}
return &httpx.Form[createUserResult]{
Fields: []field.Field{
@ -67,8 +76,10 @@ func (admin *Admin) createUser(ctx context.Context) http.Handler {
},
FieldTemplate: field.PureCSSFieldTemplate,
RenderTemplate: userCreateTemplate,
RenderTemplateContext: admin.Dependencies.Custom.RenderContext,
RenderTemplate: userCreateTemplate,
RenderTemplateContext: func(ctx httpx.FormContext, r *http.Request) any {
return admin.Dependencies.Custom.NewForm(ctx, r, crumbs)
},
Validate: func(r *http.Request, values map[string]string) (cu createUserResult, err error) {
cu.User, cu.Passsword, cu.Admin = values["username"], values["password"], values["admin"] == field.CheckboxChecked