2024-04-11 23:04:30 +02:00
|
|
|
// Copyright (C) NHR@FAU, University Erlangen-Nuremberg.
|
2022-07-29 06:29:21 +02:00
|
|
|
// All rights reserved.
|
|
|
|
// Use of this source code is governed by a MIT-style
|
|
|
|
// license that can be found in the LICENSE file.
|
2022-07-06 14:55:39 +02:00
|
|
|
package web
|
|
|
|
|
|
|
|
import (
|
|
|
|
"embed"
|
|
|
|
"html/template"
|
|
|
|
"io/fs"
|
|
|
|
"net/http"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/ClusterCockpit/cc-backend/internal/config"
|
2023-07-19 08:25:14 +02:00
|
|
|
"github.com/ClusterCockpit/cc-backend/internal/util"
|
2022-07-06 14:55:39 +02:00
|
|
|
"github.com/ClusterCockpit/cc-backend/pkg/log"
|
2022-09-12 13:35:42 +02:00
|
|
|
"github.com/ClusterCockpit/cc-backend/pkg/schema"
|
2022-07-06 14:55:39 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
/// Go's embed is only allowed to embed files in a subdirectory of the embedding package ([see here](https://github.com/golang/go/issues/46056)).
|
|
|
|
|
|
|
|
//go:embed frontend/public/*
|
|
|
|
var frontendFiles embed.FS
|
|
|
|
|
|
|
|
func ServeFiles() http.Handler {
|
|
|
|
publicFiles, err := fs.Sub(frontendFiles, "frontend/public")
|
|
|
|
if err != nil {
|
2023-01-19 16:59:14 +01:00
|
|
|
log.Fatalf("WEB/WEB > cannot find frontend public files")
|
2022-07-06 14:55:39 +02:00
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return http.FileServer(http.FS(publicFiles))
|
|
|
|
}
|
|
|
|
|
|
|
|
//go:embed templates/*
|
|
|
|
var templateFiles embed.FS
|
|
|
|
|
|
|
|
var templates map[string]*template.Template = map[string]*template.Template{}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
base := template.Must(template.ParseFS(templateFiles, "templates/base.tmpl"))
|
|
|
|
if err := fs.WalkDir(templateFiles, "templates", func(path string, d fs.DirEntry, err error) error {
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if d.IsDir() || path == "templates/base.tmpl" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-06-22 07:01:29 +02:00
|
|
|
if path == "templates/login.tmpl" {
|
2023-07-19 08:25:14 +02:00
|
|
|
if util.CheckFileExists("./var/login.tmpl") {
|
2023-06-22 07:01:29 +02:00
|
|
|
log.Info("overwrite login.tmpl with local file")
|
|
|
|
templates[strings.TrimPrefix(path, "templates/")] =
|
|
|
|
template.Must(template.Must(base.Clone()).ParseFiles("./var/login.tmpl"))
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
2023-06-12 16:45:23 +02:00
|
|
|
if path == "templates/imprint.tmpl" {
|
2023-07-19 08:25:14 +02:00
|
|
|
if util.CheckFileExists("./var/imprint.tmpl") {
|
2023-06-12 16:45:23 +02:00
|
|
|
log.Info("overwrite imprint.tmpl with local file")
|
|
|
|
templates[strings.TrimPrefix(path, "templates/")] =
|
|
|
|
template.Must(template.Must(base.Clone()).ParseFiles("./var/imprint.tmpl"))
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if path == "templates/privacy.tmpl" {
|
2023-07-19 08:25:14 +02:00
|
|
|
if util.CheckFileExists("./var/privacy.tmpl") {
|
2023-06-12 16:45:23 +02:00
|
|
|
log.Info("overwrite privacy.tmpl with local file")
|
|
|
|
templates[strings.TrimPrefix(path, "templates/")] =
|
|
|
|
template.Must(template.Must(base.Clone()).ParseFiles("./var/privacy.tmpl"))
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-06 14:55:39 +02:00
|
|
|
templates[strings.TrimPrefix(path, "templates/")] = template.Must(template.Must(base.Clone()).ParseFS(templateFiles, path))
|
|
|
|
return nil
|
|
|
|
}); err != nil {
|
2023-01-19 16:59:14 +01:00
|
|
|
log.Fatalf("WEB/WEB > cannot find frontend template files")
|
2022-07-06 14:55:39 +02:00
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_ = base
|
|
|
|
}
|
|
|
|
|
2022-09-27 09:56:17 +02:00
|
|
|
type Build struct {
|
2023-02-17 15:45:31 +01:00
|
|
|
Version string
|
|
|
|
Hash string
|
2022-09-27 09:56:17 +02:00
|
|
|
Buildtime string
|
|
|
|
}
|
|
|
|
|
2022-07-06 14:55:39 +02:00
|
|
|
type Page struct {
|
|
|
|
Title string // Page title
|
2023-06-22 18:09:40 +02:00
|
|
|
MsgType string // For generic use in message boxes
|
|
|
|
Message string // For generic use in message boxes
|
2023-08-17 10:29:00 +02:00
|
|
|
User schema.User // Information about the currently logged in user (Full User Info)
|
|
|
|
Roles map[string]schema.Role // Available roles for frontend render checks
|
2023-02-17 15:45:31 +01:00
|
|
|
Build Build // Latest information about the application
|
2022-09-12 13:35:42 +02:00
|
|
|
Clusters []schema.ClusterConfig // List of all clusters for use in the Header
|
2022-07-06 14:55:39 +02:00
|
|
|
FilterPresets map[string]interface{} // For pages with the Filter component, this can be used to set initial filters.
|
|
|
|
Infos map[string]interface{} // For generic use (e.g. username for /monitoring/user/<id>, job id for /monitoring/job/<id>)
|
|
|
|
Config map[string]interface{} // UI settings for the currently logged in user (e.g. line width, ...)
|
2024-09-24 11:13:39 +02:00
|
|
|
Resampling *schema.ResampleConfig // If not nil, defines resampling trigger and resolutions
|
2022-07-06 14:55:39 +02:00
|
|
|
}
|
|
|
|
|
2023-08-17 10:29:00 +02:00
|
|
|
func RenderTemplate(rw http.ResponseWriter, file string, page *Page) {
|
2022-07-06 14:55:39 +02:00
|
|
|
t, ok := templates[file]
|
|
|
|
if !ok {
|
2023-06-22 16:26:09 +02:00
|
|
|
log.Errorf("WEB/WEB > template '%s' not found", file)
|
2022-07-06 14:55:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if page.Clusters == nil {
|
2022-09-05 17:46:38 +02:00
|
|
|
for _, c := range config.Keys.Clusters {
|
2022-09-12 13:35:42 +02:00
|
|
|
page.Clusters = append(page.Clusters, schema.ClusterConfig{Name: c.Name, FilterRanges: c.FilterRanges, MetricDataRepository: nil})
|
2022-07-06 14:55:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-22 16:26:09 +02:00
|
|
|
log.Debugf("Page config : %v\n", page.Config)
|
2022-07-06 14:55:39 +02:00
|
|
|
if err := t.Execute(rw, page); err != nil {
|
2023-02-01 11:58:27 +01:00
|
|
|
log.Errorf("Template error: %s", err.Error())
|
2022-07-06 14:55:39 +02:00
|
|
|
}
|
|
|
|
}
|