Header in svelte

This commit is contained in:
Lou Knauer 2022-02-15 10:03:09 +01:00
parent 6d0a4a91a3
commit df3c806ab7
15 changed files with 63 additions and 134 deletions

@ -1 +1 @@
Subproject commit 42f56f0a0a162bec0871949cade791590bea6a89
Subproject commit cb0447516b5102b7869eb6068df3de08b7736caf

View File

@ -86,27 +86,20 @@ func setupRoutes(router *mux.Router, routes []Route) {
return
}
infos := map[string]interface{}{
"admin": true,
}
if user := auth.GetUser(r.Context()); user != nil {
infos["loginId"] = user.Username
infos["admin"] = user.HasRole(auth.RoleAdmin)
} else {
infos["loginId"] = false
infos["admin"] = false
}
infos = route.Setup(infos, r)
infos := route.Setup(map[string]interface{}{}, r)
if id, ok := infos["id"]; ok {
route.Title = strings.Replace(route.Title, "<ID>", id.(string), 1)
}
infos["clusters"] = config.Clusters
username, isAdmin := "", true
if user := auth.GetUser(r.Context()); user != nil {
username = user.Username
isAdmin = user.HasRole(auth.RoleAdmin)
}
page := templates.Page{
Title: route.Title,
User: templates.User{Username: username, IsAdmin: isAdmin},
Config: conf,
Infos: infos,
}

View File

@ -95,15 +95,9 @@ var programConfig ProgramConfig = ProgramConfig{
JobArchive: "./var/job-archive",
AsyncArchiving: true,
DisableArchive: false,
LdapConfig: &auth.LdapConfig{
Url: "ldap://localhost",
UserBase: "ou=hpc,dc=rrze,dc=uni-erlangen,dc=de",
SearchDN: "cn=admin,dc=rrze,dc=uni-erlangen,dc=de",
UserBind: "uid={username},ou=hpc,dc=rrze,dc=uni-erlangen,dc=de",
UserFilter: "(&(objectclass=posixAccount)(uid=*))",
},
HttpsCertFile: "",
HttpsKeyFile: "",
LdapConfig: nil,
HttpsCertFile: "",
HttpsKeyFile: "",
UiDefaults: map[string]interface{}{
"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"}},
@ -407,22 +401,19 @@ func main() {
return
}
infos := map[string]interface{}{
"clusters": config.Clusters,
}
username, isAdmin := "", true
if user := auth.GetUser(r.Context()); user != nil {
infos["loginId"] = user.Username
infos["admin"] = user.HasRole(auth.RoleAdmin)
} else {
infos["loginId"] = false
infos["admin"] = false
username = user.Username
isAdmin = user.HasRole(auth.RoleAdmin)
}
templates.Render(rw, r, "home.tmpl", &templates.Page{
Title: "ClusterCockpit",
User: templates.User{Username: username, IsAdmin: isAdmin},
Config: conf,
Infos: infos,
Infos: map[string]interface{}{
"clusters": config.Clusters,
},
})
})

View File

@ -13,101 +13,16 @@
{{block "stylesheets" .}}
{{end}}
<script>
const header = {
"username": "{{ .User.Username }}",
"isAdmin": "{{ .User.IsAdmin }}",
"clusters": {{ .Clusters }},
};
</script>
</head>
<body class="Site">
<header>
<nav class="navbar navbar-expand-lg navbar-light fixed-top bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="/">
{{block "brand" .}}
<img alt="ClusterCockpit Logo" src="/img/logo.png" class="d-inline-block align-top">
{{end}}
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
{{block "navigation" .}}
<ul class="navbar-nav mr-auto">
{{block "navitem_joblist" .}}
<li class="nav-item">
<a class="nav-link fs-5" href="/monitoring/jobs/">
<span class="cc-nav-text">Joblist</span>
<i class="bi-card-list"></i>
</a>
</li>
{{end}}
{{if .Infos.admin }}
{{block "navitem_analysis" .}}
<li class="nav-item ">
<a class="nav-link disabled fs-5" href="/monitoring/analysis/">
<span class="cc-nav-text">Analysis</span>
<i class="bi-graph-up"></i>
</a>
</li>
{{end}}
{{block "navitem_systems" .}}
<li class="nav-item ">
<a class="nav-link disabled fs-5" href="/monitoring/systems/">
<span class="cc-nav-text">Systems</span>
<i class="bi-graph-up"></i>
</a>
</li>
{{end}}
{{block "navitem_users" .}}
<li class="nav-item">
<a class="nav-link fs-5" href="/monitoring/users/">
<span class="cc-nav-text">Users</span>
<i class="bi-people-fill"></i>
</a>
</li>
{{end}}
{{block "navitem_tags" .}}
<li class="nav-item">
<a class="nav-link fs-5" href="/monitoring/tags/">
<span class="cc-nav-text">Tags</span>
<i class="bi-tag-fill"></i>
</a>
</li>
{{end}}
{{else}}
{{block "navitem_stats" .}}
<li class="nav-item">
<a class="nav-link fs-5" href="/monitoring/user/admin">
<span class="cc-nav-text">Statistics</span>
<i class="bi-bar-chart-line-fill"></i>
</a>
</li>
{{end}}
{{end}}
</ul>
</div>
{{if .Infos.loginId }}
<div class="d-flex align-items-end">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<form method="post" action="/logout">
<button type="submit" class="btn btn-link nav-link fs-5">
<span class="cc-nav-text">{{ .Infos.loginId }} Logout</span>
<i class="bi-box-arrow-right"></i>
</button>
</form>
</li>
</ul>
<form class="d-flex my-0" onsubmit="this.action='/search';">
{{if .Infos.admin }}
<input class="form-control me-2" type="search" name="searchId" placeholder="jobId / userId" id="searchId" aria-label="Search">
{{else}}
<input class="form-control me-2" type="search" name="searchId" placeholder="jobId" id="searchId" aria-label="Search">
{{end}}
<button class="btn btn-outline-success fs-6" type="submit">Search</button>
</form>
</div>
{{end}}
{{end}}
</div>
</nav>
</header>
<header id="svelte-header"></header>
<main class="Site-content">
<div class="container">
@ -127,6 +42,7 @@
{{end}}
{{block "javascript" .}}
<script src='/build/header.js'></script>
{{end}}
</body>
</html>

View File

@ -1,6 +1,6 @@
{{define "content"}}
<div class="row">
<div class="col-8">
<div class="col">
<h2>Clusters</h2>
<table class="table">
<thead>

View File

@ -38,5 +38,7 @@
</div>
</div>
</div>
</div>
</div>
</section>
{{end}}

View File

@ -7,6 +7,7 @@
{{end}}
{{define "javascript"}}
<script>
header.currentView = 'analysis';
const cluster = {{ .Infos.cluster }};
const filterPresets = {{ .FilterPresets }};
const clusterCockpitConfig = {{ .Config }};

View File

@ -7,6 +7,7 @@
{{end}}
{{define "javascript"}}
<script>
header.currentView = 'job';
const jobInfos = {
id: "{{ .Infos.id }}",
jobId: "{{ .Infos.jobId }}",

View File

@ -8,6 +8,7 @@
{{define "javascript"}}
<script>
header.currentView = 'jobs';
const filterPresets = {{ .FilterPresets }};
const clusterCockpitConfig = {{ .Config }};
</script>

View File

@ -7,6 +7,7 @@
{{end}}
{{define "javascript"}}
<script>
header.currentView = {{ .Infos.listType }}.toLowerCase() + 's';
const listType = {{ .Infos.listType }};
const filterPresets = {{ .FilterPresets }};
const clusterCockpitConfig = {{ .Config }};

View File

@ -7,6 +7,7 @@
{{end}}
{{define "javascript"}}
<script>
header.currentView = 'node';
const infos = {{ .Infos }};
const clusterCockpitConfig = {{ .Config }};
</script>

View File

@ -7,6 +7,7 @@
{{end}}
{{define "javascript"}}
<script>
header.currentView = 'system';
const infos = {{ .Infos }};
const clusterCockpitConfig = {{ .Config }};
</script>

View File

@ -1,3 +1,9 @@
{{define "javascript"}}
<script>
header.currentView = 'tags';
</script>
<script src='/build/header.js'></script>
{{end}}
{{define "content"}}
<div class="container">
<div class="row justify-content-center">

View File

@ -7,6 +7,7 @@
{{end}}
{{define "javascript"}}
<script>
header.currentView = 'user';
const userInfos = {{ .Infos }};
const filterPresets = {{ .FilterPresets }};
const clusterCockpitConfig = {{ .Config }};

View File

@ -5,6 +5,7 @@ import (
"net/http"
"os"
"github.com/ClusterCockpit/cc-backend/config"
"github.com/ClusterCockpit/cc-backend/log"
)
@ -12,13 +13,20 @@ var templatesDir string
var debugMode bool = os.Getenv("DEBUG") == "1"
var templates map[string]*template.Template = map[string]*template.Template{}
type User struct {
Username string // Username of the currently logged in user
IsAdmin bool
}
type Page struct {
Title string
Error string
Info string
FilterPresets map[string]interface{}
Infos map[string]interface{}
Config map[string]interface{}
Title string // Page title
Error string // For generic use (e.g. the exact error message on /login)
Info string // For generic use (e.g. "Logout successfull" on /login)
User User // Information about the currently logged in user
Clusters []string // 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.
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, ...)
}
func init() {
@ -58,6 +66,12 @@ func Render(rw http.ResponseWriter, r *http.Request, file string, page *Page) {
t = template.Must(template.ParseFiles(templatesDir+"base.tmpl", templatesDir+file))
}
if page.Clusters == nil {
for _, c := range config.Clusters {
page.Clusters = append(page.Clusters, c.Name)
}
}
if err := t.Execute(rw, page); err != nil {
log.Errorf("template error: %s", err.Error())
}