mirror of
				https://github.com/ClusterCockpit/cc-backend
				synced 2025-10-31 07:55:06 +01:00 
			
		
		
		
	Implement UI config handling
This commit is contained in:
		
							
								
								
									
										177
									
								
								web/configSchema.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								web/configSchema.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | ||||
| // Copyright (C) NHR@FAU, University Erlangen-Nuremberg. | ||||
| // All rights reserved. This file is part of cc-backend. | ||||
| // Use of this source code is governed by a MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| package web | ||||
|  | ||||
| var configSchema = ` | ||||
| 	{ | ||||
|   "type": "object", | ||||
|   "properties": { | ||||
|     "jobList": { | ||||
|       "description": "Job list defaults. Applies to user- and jobs views.", | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|         "usePaging": { | ||||
|           "description": "If classic paging is used instead of continuous scrolling by default.", | ||||
|           "type": "boolean" | ||||
|         }, | ||||
|         "showFootprint": { | ||||
|           "description": "If footprint bars are shown as first column by default.", | ||||
|           "type": "boolean" | ||||
|         } | ||||
|       }, | ||||
|       "required": ["usePaging", "showFootprint"] | ||||
|     }, | ||||
|     "nodeList": { | ||||
|       "description": "Node list defaults. Applies to node list view.", | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|         "usePaging": { | ||||
|           "description": "If classic paging is used instead of continuous scrolling by default.", | ||||
|           "type": "boolean" | ||||
|         } | ||||
|       }, | ||||
|       "required": ["usePaging"] | ||||
|     }, | ||||
|     "jobView": { | ||||
|       "description": "Job view defaults.", | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|         "showPolarPlot": { | ||||
|           "description": "If the job metric footprints polar plot is shown by default.", | ||||
|           "type": "boolean" | ||||
|         }, | ||||
|         "showFootprint": { | ||||
|           "description": "If the annotated job metric footprint bars are shown by default.", | ||||
|           "type": "boolean" | ||||
|         }, | ||||
|         "showRoofline": { | ||||
|           "description": "If the job roofline plot is shown by default.", | ||||
|           "type": "boolean" | ||||
|         }, | ||||
|         "showStatTable": { | ||||
|           "description": "If the job metric statistics table is shown by default.", | ||||
|           "type": "boolean" | ||||
|         } | ||||
|       }, | ||||
|       "required": ["showFootprint"] | ||||
|     }, | ||||
|     "metricConfig": { | ||||
|       "description": "Global initial metric selections for primary views of all clusters.", | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|         "jobListMetrics": { | ||||
|           "description": "Initial metrics shown for new users in job lists (User and jobs view).", | ||||
|           "type": "array", | ||||
|           "items": { | ||||
|             "type": "string", | ||||
|             "minItems": 1 | ||||
|           } | ||||
|         }, | ||||
|         "jobViewPlotMetrics": { | ||||
|           "description": "Initial metrics shown for new users as job view metric plots.", | ||||
|           "type": "array", | ||||
|           "items": { | ||||
|             "type": "string", | ||||
|             "minItems": 1 | ||||
|           } | ||||
|         }, | ||||
|         "jobViewTableMetrics": { | ||||
|           "description": "Initial metrics shown for new users in job view statistics table.", | ||||
|           "type": "array", | ||||
|           "items": { | ||||
|             "type": "string", | ||||
|             "minItems": 1 | ||||
|           } | ||||
|         }, | ||||
|         "clusters": { | ||||
|           "description": "Overrides for global defaults by cluster and subcluster.", | ||||
|           "type": "array", | ||||
|           "items": { | ||||
|             "type": "object", | ||||
|             "properties": { | ||||
|               "name": { | ||||
|                 "description": "The name of the cluster.", | ||||
|               "kind": { | ||||
|                 "type": "string", | ||||
|                 "enum": ["influxdb", "prometheus", "cc-metric-store", "cc-metric-store-internal", "test"] | ||||
|               }, | ||||
|               "url": { | ||||
|                 "type": "string" | ||||
|               }, | ||||
|               "subClusters" { | ||||
|                 "description": "The array of overrides per subcluster.", | ||||
|                 "type":"array", | ||||
|                 "items": { | ||||
|                   "type": "object", | ||||
|                   "properties": { | ||||
|                     "name": { | ||||
|                       "description": "The name of the subcluster.", | ||||
|                       "type": "string" | ||||
|                     }, | ||||
|                     "jobListMetrics": { | ||||
|                       "description": "Initial metrics shown for new users in job lists (User and jobs view) for subcluster.", | ||||
|                       "type": "array", | ||||
|                       "items": { | ||||
|                         "type": "string", | ||||
|                         "minItems": 1 | ||||
|                       } | ||||
|                     }, | ||||
|                     "jobViewPlotMetrics": { | ||||
|                       "description": "Initial metrics shown for new users as job view timeplots for subcluster.", | ||||
|                       "type": "array", | ||||
|                       "items": { | ||||
|                         "type": "string", | ||||
|                         "minItems": 1 | ||||
|                       } | ||||
|                     }, | ||||
|                     "jobViewTableMetrics": { | ||||
|                       "description": "Initial metrics shown for new users in job view statistics table for subcluster.", | ||||
|                       "type": "array", | ||||
|                       "items": { | ||||
|                         "type": "string", | ||||
|                         "minItems": 1 | ||||
|                       } | ||||
|                     } | ||||
|                   }, | ||||
|                   "required": ["name"], | ||||
|                   "minItems": 1 | ||||
|                 } | ||||
|               } | ||||
|             }, | ||||
|             "required": ["name", "subClusters"], | ||||
|             "minItems": 1 | ||||
|           } | ||||
|         }, | ||||
|         "required": ["jobListMetrics", "jobViewPlotMetrics", "jobViewTableMetrics"] | ||||
|       } | ||||
|     }, | ||||
|     "plotConfiguration": { | ||||
|       "description": "Initial settings for plot render options.", | ||||
|       "type": "object", | ||||
|       "properties": { | ||||
|         "colorBackground": { | ||||
|           "description": "If the metric plot backgrounds are initially colored by threshold limits.", | ||||
|           "type": "boolean" | ||||
|         }, | ||||
|         "plotsPerRow": { | ||||
|           "description": "How many plots are initially rendered in per row. Applies to job, single node, and analysis views.", | ||||
|           "type": "integer" | ||||
|         }, | ||||
|         "lineWidth": { | ||||
|           "description": "Initial thickness of rendered plotlines. Applies to metric plot, job compare plot and roofline.", | ||||
|           "type": "integer" | ||||
|         }, | ||||
|         "colorScheme": { | ||||
|           "description": "Initial colorScheme to be used for metric plots.", | ||||
|           "type": "array", | ||||
|           "items": { | ||||
|             "type": "string" | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|       "required": ["colorBackground", "plotsPerRow", "lineWidth"] | ||||
|     } | ||||
|   }` | ||||
							
								
								
									
										120
									
								
								web/web.go
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								web/web.go
									
									
									
									
									
								
							| @@ -1,15 +1,19 @@ | ||||
| // Copyright (C) NHR@FAU, University Erlangen-Nuremberg. | ||||
| // All rights reserved. | ||||
| // All rights reserved. This file is part of cc-backend. | ||||
| // Use of this source code is governed by a MIT-style | ||||
| // license that can be found in the LICENSE file. | ||||
|  | ||||
| // Package web implements the HTML templating and web frontend configuration | ||||
| package web | ||||
|  | ||||
| import ( | ||||
| 	"embed" | ||||
| 	"encoding/json" | ||||
| 	"html/template" | ||||
| 	"io/fs" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/ClusterCockpit/cc-backend/internal/config" | ||||
| 	"github.com/ClusterCockpit/cc-backend/pkg/archive" | ||||
| @@ -18,8 +22,114 @@ import ( | ||||
| 	"github.com/ClusterCockpit/cc-lib/util" | ||||
| ) | ||||
|  | ||||
| /// 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)). | ||||
| type WebConfig struct { | ||||
| 	JobList           JobListConfig     `json:"jobList"` | ||||
| 	NodeList          NodeListConfig    `json:"nodeList"` | ||||
| 	JobView           JobViewConfig     `json:"jobView"` | ||||
| 	MetricConfig      MetricConfig      `json:"metricConfig"` | ||||
| 	PlotConfiguration PlotConfiguration `json:"plotConfiguration"` | ||||
| } | ||||
|  | ||||
| type JobListConfig struct { | ||||
| 	UsePaging     bool `json:"usePaging"` | ||||
| 	ShowFootprint bool `json:"showFootprint"` | ||||
| } | ||||
|  | ||||
| type NodeListConfig struct { | ||||
| 	UsePaging bool `json:"usePaging"` | ||||
| } | ||||
|  | ||||
| type JobViewConfig struct { | ||||
| 	ShowPolarPlot bool `json:"showPolarPlot"` | ||||
| 	ShowFootprint bool `json:"showFootprint"` | ||||
| 	ShowRoofline  bool `json:"showRoofline"` | ||||
| 	ShowStatTable bool `json:"showStatTable"` | ||||
| } | ||||
|  | ||||
| type MetricConfig struct { | ||||
| 	JobListMetrics      []string        `json:"jobListMetrics"` | ||||
| 	JobViewPlotMetrics  []string        `json:"jobViewPlotMetrics"` | ||||
| 	JobViewTableMetrics []string        `json:"jobViewTableMetrics"` | ||||
| 	Clusters            []ClusterConfig `json:"clusters"` | ||||
| } | ||||
|  | ||||
| type ClusterConfig struct { | ||||
| 	Name        string             `json:"name"` | ||||
| 	SubClusters []SubClusterConfig `json:"subClusters"` | ||||
| } | ||||
|  | ||||
| type SubClusterConfig struct { | ||||
| 	Name                string   `json:"name"` | ||||
| 	JobListMetrics      []string `json:"jobListMetrics"` | ||||
| 	JobViewPlotMetrics  []string `json:"jobViewPlotMetrics"` | ||||
| 	JobViewTableMetrics []string `json:"jobViewTableMetrics"` | ||||
| } | ||||
|  | ||||
| type PlotConfiguration struct { | ||||
| 	ColorBackground bool     `json:"colorBackground"` | ||||
| 	PlotsPerRow     int      `json:"plotsPerRow"` | ||||
| 	LineWidth       int      `json:"lineWidth"` | ||||
| 	ColorScheme     []string `json:"colorScheme"` | ||||
| } | ||||
|  | ||||
| var initOnce sync.Once | ||||
|  | ||||
| var Keys = WebConfig{ | ||||
| 	JobList: JobListConfig{ | ||||
| 		UsePaging:     false, | ||||
| 		ShowFootprint: true, | ||||
| 	}, | ||||
| 	NodeList: NodeListConfig{ | ||||
| 		UsePaging: true, | ||||
| 	}, | ||||
| 	JobView: JobViewConfig{ | ||||
| 		ShowPolarPlot: true, | ||||
| 		ShowFootprint: true, | ||||
| 		ShowRoofline:  true, | ||||
| 		ShowStatTable: true, | ||||
| 	}, | ||||
| 	MetricConfig: MetricConfig{ | ||||
| 		JobListMetrics:      []string{"flops_any", "mem_bw", "mem_used"}, | ||||
| 		JobViewPlotMetrics:  []string{"flops_any", "mem_bw", "mem_used"}, | ||||
| 		JobViewTableMetrics: []string{"flops_any", "mem_bw", "mem_used"}, | ||||
| 	}, | ||||
| 	PlotConfiguration: PlotConfiguration{ | ||||
| 		ColorBackground: true, | ||||
| 		PlotsPerRow:     3, | ||||
| 		LineWidth:       3, | ||||
| 		ColorScheme:     []string{"#00bfff", "#0000ff", "#ff00ff", "#ff0000", "#ff8000", "#ffff00", "#80ff00"}, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| // | ||||
| // 	map[string]any{ | ||||
| // 	"analysis_view_histogramMetrics":         []string{"flops_any", "mem_bw", "mem_used"}, | ||||
| // 	"analysis_view_scatterPlotMetrics":       [][]string{{"flops_any", "mem_bw"}, {"flops_any", "cpu_load"}, {"cpu_load", "mem_bw"}}, | ||||
| // 	"job_view_nodestats_selectedMetrics":     []string{"flops_any", "mem_bw", "mem_used"}, | ||||
| // 	"plot_list_jobsPerPage":                  50, | ||||
| // 	"system_view_selectedMetric":             "cpu_load", | ||||
| // 	"analysis_view_selectedTopEntity":        "user", | ||||
| // 	"analysis_view_selectedTopCategory":      "totalWalltime", | ||||
| // 	"status_view_selectedTopUserCategory":    "totalJobs", | ||||
| // 	"status_view_selectedTopProjectCategory": "totalJobs", | ||||
| // } | ||||
|  | ||||
| func Init(rawConfig json.RawMessage, disableArchive bool) error { | ||||
| 	var err error | ||||
|  | ||||
| 	initOnce.Do(func() { | ||||
| 		config.Validate(configSchema, rawConfig) | ||||
| 		if err = json.Unmarshal(rawConfig, &Keys); err != nil { | ||||
| 			cclog.Warn("Error while unmarshaling raw config json") | ||||
| 			return | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // / 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 | ||||
|  | ||||
| @@ -92,9 +202,9 @@ type Page struct { | ||||
| 	Build         Build                  // Latest information about the application | ||||
| 	Clusters      []config.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, ...) | ||||
| 	FilterPresets map[string]any         // For pages with the Filter component, this can be used to set initial filters. | ||||
| 	Infos         map[string]any         // For generic use (e.g. username for /monitoring/user/<id>, job id for /monitoring/job/<id>) | ||||
| 	Config        map[string]any         // UI settings for the currently logged in user (e.g. line width, ...) | ||||
| 	Resampling    *config.ResampleConfig // If not nil, defines resampling trigger and resolutions | ||||
| 	Redirect      string                 // The originally requested URL, for intermediate login handling | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user