mirror of
				https://github.com/ClusterCockpit/cc-backend
				synced 2025-11-04 01:25:06 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			131 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			131 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (C) NHR@FAU, University Erlangen-Nuremberg.
 | 
						|
// All rights reserved.
 | 
						|
// Use of this source code is governed by a MIT-style
 | 
						|
// license that can be found in the LICENSE file.
 | 
						|
package web
 | 
						|
 | 
						|
import (
 | 
						|
	"embed"
 | 
						|
	"html/template"
 | 
						|
	"io/fs"
 | 
						|
	"net/http"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"github.com/ClusterCockpit/cc-backend/internal/config"
 | 
						|
	"github.com/ClusterCockpit/cc-backend/internal/util"
 | 
						|
	"github.com/ClusterCockpit/cc-backend/pkg/archive"
 | 
						|
	"github.com/ClusterCockpit/cc-backend/pkg/log"
 | 
						|
	"github.com/ClusterCockpit/cc-backend/pkg/schema"
 | 
						|
)
 | 
						|
 | 
						|
/// 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 {
 | 
						|
		log.Abortf("Serve Files: Could not find 'frontend/public' file directory.\nError: %s\n", err.Error())
 | 
						|
	}
 | 
						|
	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
 | 
						|
		}
 | 
						|
 | 
						|
		if path == "templates/login.tmpl" {
 | 
						|
			if util.CheckFileExists("./var/login.tmpl") {
 | 
						|
				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
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if path == "templates/imprint.tmpl" {
 | 
						|
			if util.CheckFileExists("./var/imprint.tmpl") {
 | 
						|
				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" {
 | 
						|
			if util.CheckFileExists("./var/privacy.tmpl") {
 | 
						|
				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
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		templates[strings.TrimPrefix(path, "templates/")] = template.Must(template.Must(base.Clone()).ParseFS(templateFiles, path))
 | 
						|
		return nil
 | 
						|
	}); err != nil {
 | 
						|
		log.Abortf("Web init(): Could not find frontend template files.\nError: %s\n", err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	_ = base
 | 
						|
}
 | 
						|
 | 
						|
type Build struct {
 | 
						|
	Version   string
 | 
						|
	Hash      string
 | 
						|
	Buildtime string
 | 
						|
}
 | 
						|
 | 
						|
type Page struct {
 | 
						|
	Title         string                 // Page title
 | 
						|
	MsgType       string                 // For generic use in message boxes
 | 
						|
	Message       string                 // For generic use in message boxes
 | 
						|
	User          schema.User            // Information about the currently logged in user (Full User Info)
 | 
						|
	Roles         map[string]schema.Role // Available roles for frontend render checks
 | 
						|
	Build         Build                  // Latest information about the application
 | 
						|
	Clusters      []schema.ClusterConfig // List of all clusters for use in the Header
 | 
						|
	SubClusters   map[string][]string    // Map per cluster of all subClusters for use in the Header
 | 
						|
	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, ...)
 | 
						|
	Resampling    *schema.ResampleConfig // If not nil, defines resampling trigger and resolutions
 | 
						|
	Redirect      string                 // The originally requested URL, for intermediate login handling
 | 
						|
}
 | 
						|
 | 
						|
func RenderTemplate(rw http.ResponseWriter, file string, page *Page) {
 | 
						|
	t, ok := templates[file]
 | 
						|
	if !ok {
 | 
						|
		log.Errorf("WEB/WEB > template '%s' not found", file)
 | 
						|
	}
 | 
						|
 | 
						|
	if page.Clusters == nil {
 | 
						|
		for _, c := range config.Keys.Clusters {
 | 
						|
			page.Clusters = append(page.Clusters, schema.ClusterConfig{Name: c.Name, FilterRanges: c.FilterRanges, MetricDataRepository: nil})
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if page.SubClusters == nil {
 | 
						|
		page.SubClusters = make(map[string][]string)
 | 
						|
		for _, cluster := range archive.Clusters {
 | 
						|
			for _, sc := range cluster.SubClusters {
 | 
						|
				page.SubClusters[cluster.Name] = append(page.SubClusters[cluster.Name], sc.Name)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	log.Debugf("Page config : %v\n", page.Config)
 | 
						|
	if err := t.Execute(rw, page); err != nil {
 | 
						|
		log.Errorf("Template error: %s", err.Error())
 | 
						|
	}
 | 
						|
}
 |