From 9c5c8a05e258bafc927af5b08a54cfc55d48aaba Mon Sep 17 00:00:00 2001 From: Lou Knauer Date: Thu, 9 Dec 2021 16:27:48 +0100 Subject: [PATCH] Add more views --- README.md | 11 ++- frontend | 2 +- server.go | 108 +++++++++++++++++++++++++++-- templates/home.html | 55 +++++++++++++-- templates/monitoring/analysis.html | 18 +++++ templates/monitoring/jobs.html | 2 +- templates/monitoring/node.html | 21 ++++++ templates/monitoring/systems.html | 19 +++++ templates/templates.go | 33 +++++---- 9 files changed, 245 insertions(+), 24 deletions(-) create mode 100644 templates/monitoring/analysis.html create mode 100644 templates/monitoring/node.html create mode 100644 templates/monitoring/systems.html diff --git a/README.md b/README.md index 2c941af..a3e25aa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ClusterCockpit with a Golang backend (Only supports archived jobs) +# ClusterCockpit with a Golang backend [![Build](https://github.com/ClusterCockpit/cc-jobarchive/actions/workflows/test.yml/badge.svg)](https://github.com/ClusterCockpit/cc-jobarchive/actions/workflows/test.yml) @@ -11,7 +11,12 @@ git clone --recursive git@github.com:ClusterCockpit/cc-jobarchive.git # Prepare frontend cd ./cc-jobarchive/frontend yarn install -CCFRONTEND_ROLLUP_INTRO="" yarn build +export CCFRONTEND_ROLLUP_INTRO=' +const JOBVIEW_URL = job => `/monitoring/job/${job.jobId}`; +const USERVIEW_URL = userId => `/monitoring/user/${userId}`; +const TAG_URL = tag => `/monitoring/jobs/?tag=${tag.id}`; +' +yarn build cd .. go get @@ -45,4 +50,6 @@ This project uses [gqlgen](https://github.com/99designs/gqlgen) for the GraphQL - [ ] Documentation - [ ] Write more TODOs +- [ ] Caching +- [ ] Generate JWTs based on the provided keys diff --git a/frontend b/frontend index 41b8953..cc48461 160000 --- a/frontend +++ b/frontend @@ -1 +1 @@ -Subproject commit 41b8953eb14e52fe9f3c4fe69167202f8002de45 +Subproject commit cc48461a810dbd3565000150fc99332743de92ba diff --git a/server.go b/server.go index 5cd4790..b87c881 100644 --- a/server.go +++ b/server.go @@ -176,8 +176,27 @@ func main() { secured.HandleFunc("/config.json", config.ServeConfig).Methods(http.MethodGet) secured.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) { + conf, err := config.GetUIConfig(r) + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + + infos := map[string]interface{}{ + "clusters": config.Clusters, + "username": "", + "admin": true, + } + + if user := auth.GetUser(r.Context()); user != nil { + infos["username"] = user.Username + infos["admin"] = user.IsAdmin + } + templates.Render(rw, r, "home", &templates.Page{ - Title: "ClusterCockpit", + Title: "ClusterCockpit", + Config: conf, + Infos: infos, }) }) @@ -208,9 +227,34 @@ func monitoringRoutes(router *mux.Router, resolver *graph.Resolver) { return } + filterPresets := map[string]interface{}{} + query := r.URL.Query() + if query.Get("tag") != "" { + filterPresets["tagId"] = query.Get("tag") + } + if query.Get("cluster") != "" { + filterPresets["clusterId"] = query.Get("cluster") + } + if query.Get("project") != "" { + filterPresets["projectId"] = query.Get("project") + } + if query.Get("running") == "true" { + filterPresets["isRunning"] = true + } + if query.Get("running") == "false" { + filterPresets["isRunning"] = false + } + if query.Get("from") != "" && query.Get("to") != "" { + filterPresets["startTime"] = map[string]string{ + "from": query.Get("from"), + "to": query.Get("to"), + } + } + templates.Render(rw, r, "monitoring/jobs/", &templates.Page{ - Title: "Jobs - ClusterCockpit", - Config: conf, + Title: "Jobs - ClusterCockpit", + Config: conf, + FilterPresets: filterPresets, }) }) @@ -266,8 +310,64 @@ func monitoringRoutes(router *mux.Router, resolver *graph.Resolver) { templates.Render(rw, r, "monitoring/user/", &templates.Page{ Title: fmt.Sprintf("User %s - ClusterCockpit", id), Config: conf, + Infos: map[string]interface{}{"userId": id}, + }) + }) + + router.HandleFunc("/monitoring/analysis/", func(rw http.ResponseWriter, r *http.Request) { + conf, err := config.GetUIConfig(r) + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + + filterPresets := map[string]interface{}{} + query := r.URL.Query() + if query.Get("cluster") != "" { + filterPresets["clusterId"] = query.Get("cluster") + } + + templates.Render(rw, r, "monitoring/analysis/", &templates.Page{ + Title: "Analysis View - ClusterCockpit", + Config: conf, + FilterPresets: filterPresets, + }) + }) + + router.HandleFunc("/monitoring/systems/", func(rw http.ResponseWriter, r *http.Request) { + conf, err := config.GetUIConfig(r) + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + + filterPresets := map[string]interface{}{} + query := r.URL.Query() + if query.Get("cluster") != "" { + filterPresets["clusterId"] = query.Get("cluster") + } + + templates.Render(rw, r, "monitoring/systems/", &templates.Page{ + Title: "System View - ClusterCockpit", + Config: conf, + FilterPresets: filterPresets, + }) + }) + + router.HandleFunc("/monitoring/node/{clusterId}/{nodeId}", func(rw http.ResponseWriter, r *http.Request) { + conf, err := config.GetUIConfig(r) + if err != nil { + http.Error(rw, err.Error(), http.StatusInternalServerError) + return + } + + vars := mux.Vars(r) + templates.Render(rw, r, "monitoring/node/", &templates.Page{ + Title: fmt.Sprintf("Node %s - ClusterCockpit", vars["nodeId"]), + Config: conf, Infos: map[string]interface{}{ - "userId": id, + "nodeId": vars["nodeId"], + "clusterId": vars["clusterId"], }, }) }) diff --git a/templates/home.html b/templates/home.html index 7bbee5a..6b23b2f 100644 --- a/templates/home.html +++ b/templates/home.html @@ -1,10 +1,57 @@ {{define "content"}}
- + {{if .Infos.username}} + {{ .Infos.username }} + {{if .Infos.admin}} + Admin + {{end}} + {{end}} +
+
+
+ +
+
+
+
+ {{if .Infos.admin}} +
+ +
+ {{else}} +
+ +
+ {{end}} +
+

Clusters

+ + + + + + + + + + + {{range .Infos.clusters}} + + + + + + + {{end}} + +
Name/IDJobsSystem ViewAnalysis View
{{.ClusterID}}JobsSystem ViewAnalysis View
{{end}} diff --git a/templates/monitoring/analysis.html b/templates/monitoring/analysis.html new file mode 100644 index 0000000..d6c0b80 --- /dev/null +++ b/templates/monitoring/analysis.html @@ -0,0 +1,18 @@ +{{define "content"}} +
+{{end}} + +{{define "stylesheets"}} + +{{end}} +{{define "javascript"}} + + +{{end}} diff --git a/templates/monitoring/jobs.html b/templates/monitoring/jobs.html index e6382c2..1d70968 100644 --- a/templates/monitoring/jobs.html +++ b/templates/monitoring/jobs.html @@ -7,7 +7,7 @@ {{end}} {{define "javascript"}} + +{{end}} diff --git a/templates/monitoring/systems.html b/templates/monitoring/systems.html new file mode 100644 index 0000000..b8e6ccf --- /dev/null +++ b/templates/monitoring/systems.html @@ -0,0 +1,19 @@ +{{define "content"}} +
+{{end}} + +{{define "stylesheets"}} + +{{end}} +{{define "javascript"}} + + +{{end}} diff --git a/templates/templates.go b/templates/templates.go index 6b0a267..327ef19 100644 --- a/templates/templates.go +++ b/templates/templates.go @@ -9,10 +9,11 @@ import ( var templates map[string]*template.Template type Page struct { - Title string - Login *LoginPage - Infos map[string]interface{} - Config map[string]interface{} + Title string + Login *LoginPage + FilterPresets map[string]interface{} + Infos map[string]interface{} + Config map[string]interface{} } type LoginPage struct { @@ -23,18 +24,26 @@ type LoginPage struct { func init() { base := template.Must(template.ParseFiles("./templates/base.html")) templates = map[string]*template.Template{ - "home": template.Must(template.Must(base.Clone()).ParseFiles("./templates/home.html")), - "404": template.Must(template.Must(base.Clone()).ParseFiles("./templates/404.html")), - "login": template.Must(template.Must(base.Clone()).ParseFiles("./templates/login.html")), - "monitoring/jobs/": template.Must(template.Must(base.Clone()).ParseFiles("./templates/monitoring/jobs.html")), - "monitoring/job/": template.Must(template.Must(base.Clone()).ParseFiles("./templates/monitoring/job.html")), - "monitoring/users/": template.Must(template.Must(base.Clone()).ParseFiles("./templates/monitoring/users.html")), - "monitoring/user/": template.Must(template.Must(base.Clone()).ParseFiles("./templates/monitoring/user.html")), + "home": template.Must(template.Must(base.Clone()).ParseFiles("./templates/home.html")), + "404": template.Must(template.Must(base.Clone()).ParseFiles("./templates/404.html")), + "login": template.Must(template.Must(base.Clone()).ParseFiles("./templates/login.html")), + "monitoring/jobs/": template.Must(template.Must(base.Clone()).ParseFiles("./templates/monitoring/jobs.html")), + "monitoring/job/": template.Must(template.Must(base.Clone()).ParseFiles("./templates/monitoring/job.html")), + "monitoring/users/": template.Must(template.Must(base.Clone()).ParseFiles("./templates/monitoring/users.html")), + "monitoring/user/": template.Must(template.Must(base.Clone()).ParseFiles("./templates/monitoring/user.html")), + "monitoring/analysis/": template.Must(template.Must(base.Clone()).ParseFiles("./templates/monitoring/analysis.html")), + "monitoring/systems/": template.Must(template.Must(base.Clone()).ParseFiles("./templates/monitoring/systems.html")), + "monitoring/node/": template.Must(template.Must(base.Clone()).ParseFiles("./templates/monitoring/node.html")), } } func Render(rw http.ResponseWriter, r *http.Request, name string, page *Page) { - if err := templates[name].Execute(rw, page); err != nil { + t, ok := templates[name] + if !ok { + panic("templates must be predefinied!") + } + + if err := t.Execute(rw, page); err != nil { log.Printf("template error: %s\n", err.Error()) } }