Add buildInfo to frontend footer

This commit is contained in:
Christoph Kluge 2022-09-27 09:56:17 +02:00
parent d1fefe16a3
commit 24f9d4f934
5 changed files with 46 additions and 11 deletions

View File

@ -226,18 +226,19 @@ func main() {
} }
r := mux.NewRouter() r := mux.NewRouter()
buildInfo := web.Build{Version: version, Hash: hash, Buildtime: buildTime}
r.HandleFunc("/login", func(rw http.ResponseWriter, r *http.Request) { r.HandleFunc("/login", func(rw http.ResponseWriter, r *http.Request) {
rw.Header().Add("Content-Type", "text/html; charset=utf-8") rw.Header().Add("Content-Type", "text/html; charset=utf-8")
web.RenderTemplate(rw, r, "login.tmpl", &web.Page{Title: "Login"}) web.RenderTemplate(rw, r, "login.tmpl", &web.Page{Title: "Login", Build: buildInfo})
}).Methods(http.MethodGet) }).Methods(http.MethodGet)
r.HandleFunc("/imprint", func(rw http.ResponseWriter, r *http.Request) { r.HandleFunc("/imprint", func(rw http.ResponseWriter, r *http.Request) {
rw.Header().Add("Content-Type", "text/html; charset=utf-8") rw.Header().Add("Content-Type", "text/html; charset=utf-8")
web.RenderTemplate(rw, r, "imprint.tmpl", &web.Page{Title: "Imprint"}) web.RenderTemplate(rw, r, "imprint.tmpl", &web.Page{Title: "Imprint", Build: buildInfo})
}) })
r.HandleFunc("/privacy", func(rw http.ResponseWriter, r *http.Request) { r.HandleFunc("/privacy", func(rw http.ResponseWriter, r *http.Request) {
rw.Header().Add("Content-Type", "text/html; charset=utf-8") rw.Header().Add("Content-Type", "text/html; charset=utf-8")
web.RenderTemplate(rw, r, "privacy.tmpl", &web.Page{Title: "Privacy"}) web.RenderTemplate(rw, r, "privacy.tmpl", &web.Page{Title: "Privacy", Build: buildInfo})
}) })
// Some routes, such as /login or /query, should only be accessible to a user that is logged in. // Some routes, such as /login or /query, should only be accessible to a user that is logged in.
@ -256,6 +257,7 @@ func main() {
web.RenderTemplate(rw, r, "login.tmpl", &web.Page{ web.RenderTemplate(rw, r, "login.tmpl", &web.Page{
Title: "Login failed - ClusterCockpit", Title: "Login failed - ClusterCockpit",
Error: err.Error(), Error: err.Error(),
Build: buildInfo,
}) })
})).Methods(http.MethodPost) })).Methods(http.MethodPost)
@ -265,6 +267,7 @@ func main() {
web.RenderTemplate(rw, r, "login.tmpl", &web.Page{ web.RenderTemplate(rw, r, "login.tmpl", &web.Page{
Title: "Bye - ClusterCockpit", Title: "Bye - ClusterCockpit",
Info: "Logout sucessful", Info: "Logout sucessful",
Build: buildInfo,
}) })
}))).Methods(http.MethodPost) }))).Methods(http.MethodPost)
@ -279,6 +282,7 @@ func main() {
web.RenderTemplate(rw, r, "login.tmpl", &web.Page{ web.RenderTemplate(rw, r, "login.tmpl", &web.Page{
Title: "Authentication failed - ClusterCockpit", Title: "Authentication failed - ClusterCockpit",
Error: err.Error(), Error: err.Error(),
Build: buildInfo,
}) })
}) })
}) })
@ -287,7 +291,7 @@ func main() {
if flagDev { if flagDev {
r.Handle("/playground", playground.Handler("GraphQL playground", "/query")) r.Handle("/playground", playground.Handler("GraphQL playground", "/query"))
r.PathPrefix("/swagger/").Handler(httpSwagger.Handler( r.PathPrefix("/swagger/").Handler(httpSwagger.Handler(
httpSwagger.URL("http://localhost:8080/swagger/doc.json"))).Methods(http.MethodGet) httpSwagger.URL("http://clustercockpit.localhost:8082/swagger/doc.json"))).Methods(http.MethodGet)
} }
secured.Handle("/query", graphQLEndpoint) secured.Handle("/query", graphQLEndpoint)
@ -316,7 +320,7 @@ func main() {
}) })
// Mount all /monitoring/... and /api/... routes. // Mount all /monitoring/... and /api/... routes.
routerConfig.SetupRoutes(secured) routerConfig.SetupRoutes(secured, version, hash, buildTime)
api.MountRoutes(secured) api.MountRoutes(secured)
if config.Keys.EmbedStaticFiles { if config.Keys.EmbedStaticFiles {

View File

@ -253,7 +253,7 @@ func buildFilterPresets(query url.Values) map[string]interface{} {
return filterPresets return filterPresets
} }
func SetupRoutes(router *mux.Router) { func SetupRoutes(router *mux.Router, version string, hash string, buildTime string) {
userCfgRepo := repository.GetUserCfgRepo() userCfgRepo := repository.GetUserCfgRepo()
for _, route := range routes { for _, route := range routes {
route := route route := route
@ -281,6 +281,7 @@ func SetupRoutes(router *mux.Router) {
page := web.Page{ page := web.Page{
Title: title, Title: title,
User: web.User{Username: username, IsAdmin: isAdmin, IsSupporter: isSupporter}, User: web.User{Username: username, IsAdmin: isAdmin, IsSupporter: isSupporter},
Build: web.Build{Version: version, Hash: hash, Buildtime: buildTime},
Config: conf, Config: conf,
Infos: infos, Infos: infos,
} }

View File

@ -52,3 +52,21 @@ footer {
margin: 0rem 0.8rem; margin: 0rem 0.8rem;
white-space: nowrap; white-space: nowrap;
} }
.build-list {
color: gray;
font-size: 12px;
list-style-type: none;
padding-left: 0;
width: 100%;
display: flex;
flex-wrap: wrap;
justify-content: right;
margin-top: 0px;
margin-bottom: 5px;
}
.build-list-item {
margin: 0rem 0.8rem;
white-space: nowrap;
}

View File

@ -40,6 +40,11 @@
<li class="footer-list-item"><a class="link-secondary fs-5" href="/imprint" title="Imprint" rel="nofollow">Imprint</a></li> <li class="footer-list-item"><a class="link-secondary fs-5" href="/imprint" title="Imprint" rel="nofollow">Imprint</a></li>
<li class="footer-list-item"><a class="link-secondary fs-5" href="/privacy" title="Privacy Policy" rel="nofollow">Privacy Policy</a></li> <li class="footer-list-item"><a class="link-secondary fs-5" href="/privacy" title="Privacy Policy" rel="nofollow">Privacy Policy</a></li>
</ul> </ul>
<ul class="build-list">
<li class="build-list-item">Version {{ .Build.Version }}</li>
<li class="build-list-item">Hash {{ .Build.Hash }}</li>
<li class="build-list-item">Built {{ .Build.Buildtime }}</li>
</ul>
</footer> </footer>
{{end}} {{end}}

View File

@ -59,11 +59,18 @@ type User struct {
IsSupporter bool IsSupporter bool
} }
type Build struct {
Version string
Hash string
Buildtime string
}
type Page struct { type Page struct {
Title string // Page title Title string // Page title
Error string // For generic use (e.g. the exact error message on /login) Error string // For generic use (e.g. the exact error message on /login)
Info string // For generic use (e.g. "Logout successfull" on /login) Info string // For generic use (e.g. "Logout successfull" on /login)
User User // Information about the currently logged in user User User // Information about the currently logged in user
Build Build // Latest information about the application
Clusters []schema.ClusterConfig // List of all clusters for use in the Header Clusters []schema.ClusterConfig // List of all clusters for use in the Header
FilterPresets map[string]interface{} // For pages with the Filter component, this can be used to set initial filters. 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>) Infos map[string]interface{} // For generic use (e.g. username for /monitoring/user/<id>, job id for /monitoring/job/<id>)