base dashboard and login

This commit is contained in:
2026-05-17 08:28:16 +00:00
parent 64f4f3c5d4
commit 317a7f3f13
40 changed files with 3327 additions and 72 deletions
+30 -13
View File
@@ -5,12 +5,14 @@ import (
"bytes"
"fmt"
"html/template"
"io/fs"
"log"
"net/http"
"path/filepath"
"path"
"strings"
"crowdsec-dashy/internal/crowdsec"
"crowdsec-dashy/internal/middleware"
)
// -----------------------------------------------------------------------
@@ -23,33 +25,46 @@ type Renderer struct {
funcMap template.FuncMap
}
// NewRenderer parses all page templates against the base layout.
func NewRenderer(templateDir string) (*Renderer, error) {
// bareLayoutPages lists page names that use base_bare.html instead of base.html.
var bareLayoutPages = map[string]bool{
"login": true,
}
// NewRenderer parses all page templates. Most pages use the sidebar layout
// (base.html); pages listed in bareLayoutPages use the bare layout (base_bare.html).
func NewRenderer(fsys fs.FS) (*Renderer, error) {
r := &Renderer{
templates: make(map[string]*template.Template),
funcMap: buildFuncMap(),
}
basePath := filepath.Join(templateDir, "layouts", "base.html")
const (
basePath = "templates/layouts/base.html"
barePath = "templates/layouts/base_bare.html"
)
pages, err := filepath.Glob(filepath.Join(templateDir, "pages", "*.html"))
pages, err := fs.Glob(fsys, "templates/pages/*.html")
if err != nil {
return nil, fmt.Errorf("renderer: glob pages: %w", err)
}
if len(pages) == 0 {
return nil, fmt.Errorf("renderer: no page templates found in %s/pages/", templateDir)
return nil, fmt.Errorf("renderer: no page templates found")
}
for _, page := range pages {
name := templateName(page)
tmpl, err := template.New("base").
layout := basePath
if bareLayoutPages[name] {
layout = barePath
}
tmpl, err := template.New(path.Base(page)).
Funcs(r.funcMap).
ParseFiles(basePath, page)
ParseFS(fsys, layout, page)
if err != nil {
return nil, fmt.Errorf("renderer: parse %s: %w", name, err)
}
r.templates[name] = tmpl
log.Printf("renderer: registered template %q", name)
log.Printf("renderer: registered template %q (layout: %s)", name, path.Base(layout))
}
return r, nil
@@ -64,7 +79,7 @@ func (r *Renderer) Render(w http.ResponseWriter, name string, data any) {
}
var buf bytes.Buffer
if err := tmpl.ExecuteTemplate(&buf, "base", data); err != nil {
if err := tmpl.Execute(&buf, data); err != nil {
log.Printf("renderer: execute %q: %v", name, err)
http.Error(w, "internal server error", http.StatusInternalServerError)
return
@@ -84,9 +99,9 @@ func (r *Renderer) RenderError(w http.ResponseWriter, code int, msg string) {
})
}
func templateName(path string) string {
base := filepath.Base(path)
return base[:len(base)-len(filepath.Ext(base))]
func templateName(p string) string {
base := path.Base(p)
return base[:len(base)-len(path.Ext(base))]
}
// -----------------------------------------------------------------------
@@ -206,6 +221,7 @@ type PageData struct {
Flash FlashMessage
CLIAvailable bool
PollInterval int
CSRFToken string
}
// FlashMessage is a one-shot notification shown on the next page load.
@@ -229,6 +245,7 @@ func NewPageData(r *http.Request, title string, cliAvail bool, pollSec int) Page
Nav: SidebarNav,
CLIAvailable: cliAvail,
PollInterval: pollSec,
CSRFToken: middleware.CSRFFromContext(r),
}
}