mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2024-12-26 13:29:05 +01:00
Add Tag view including required changes.
This commit is contained in:
parent
27fd3c4e5a
commit
14693ad32b
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/ClusterCockpit/cc-backend/auth"
|
||||
@ -123,6 +124,42 @@ func (r *JobRepository) CreateTag(tagType string, tagName string) (tagId int64,
|
||||
return res.LastInsertId()
|
||||
}
|
||||
|
||||
func (r *JobRepository) GetTags() (tags []schema.Tag, counts map[string]int, err error) {
|
||||
tags = make([]schema.Tag, 0, 100)
|
||||
xrows, err := r.DB.Queryx("SELECT * FROM tag")
|
||||
for xrows.Next() {
|
||||
var t schema.Tag
|
||||
err = xrows.StructScan(&t)
|
||||
tags = append(tags, t)
|
||||
}
|
||||
|
||||
q := sq.Select("t.tag_name, count(jt.tag_id)").
|
||||
From("tag t").
|
||||
LeftJoin("jobtag jt ON t.id = jt.tag_id").
|
||||
GroupBy("t.tag_name")
|
||||
|
||||
qs, _, err := q.ToSql()
|
||||
rows, err := r.DB.Query(qs)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
counts = make(map[string]int)
|
||||
|
||||
for rows.Next() {
|
||||
var tagName string
|
||||
var count int
|
||||
err = rows.Scan(&tagName, &count)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
counts[tagName] = count
|
||||
}
|
||||
err = rows.Err()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// AddTagOrCreate adds the tag with the specified type and name to the job with the database id `jobId`.
|
||||
// If such a tag does not yet exist, it is created.
|
||||
func (r *JobRepository) AddTagOrCreate(jobId int64, tagType string, tagName string) (tagId int64, err error) {
|
||||
|
78
repository/job_test.go
Normal file
78
repository/job_test.go
Normal file
@ -0,0 +1,78 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
var db *sqlx.DB
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
|
||||
if db != nil {
|
||||
panic("prefer using sub-tests (`t.Run`) or implement `cleanup` before calling setup twice.")
|
||||
}
|
||||
db, err = sqlx.Open("sqlite3", "../var/test.db")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func setup(t *testing.T) *JobRepository {
|
||||
return &JobRepository{
|
||||
DB: db,
|
||||
}
|
||||
}
|
||||
|
||||
func TestFind(t *testing.T) {
|
||||
r := setup(t)
|
||||
|
||||
job, err := r.Find(1001789, "emmy", 1540853248)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// fmt.Printf("%+v", job)
|
||||
|
||||
if job.ID != 1245 {
|
||||
t.Errorf("wrong summary for diagnostic 3\ngot: %d \nwant: 1245", job.JobID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindById(t *testing.T) {
|
||||
r := setup(t)
|
||||
|
||||
job, err := r.FindById(1245)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// fmt.Printf("%+v", job)
|
||||
|
||||
if job.JobID != 1001789 {
|
||||
t.Errorf("wrong summary for diagnostic 3\ngot: %d \nwant: 1001789", job.JobID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTags(t *testing.T) {
|
||||
r := setup(t)
|
||||
|
||||
tags, _, err := r.GetTags()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Printf("TAGS %+v \n", tags)
|
||||
// fmt.Printf("COUNTS %+v \n", counts)
|
||||
t.Errorf("wrong summary for diagnostic 3\ngot: %d \nwant: 23", 28)
|
||||
|
||||
// if counts["load-imbalance"] != 23 {
|
||||
// t.Errorf("wrong summary for diagnostic 3\ngot: %d \nwant: 23", counts["load-imbalance"])
|
||||
// }
|
||||
}
|
23
server.go
23
server.go
@ -38,6 +38,7 @@ import (
|
||||
)
|
||||
|
||||
var db *sqlx.DB
|
||||
var jobRepo *repository.JobRepository
|
||||
|
||||
// Format of the configurartion (file). See below for the defaults.
|
||||
type ProgramConfig struct {
|
||||
@ -162,11 +163,29 @@ func setupAnalysisRoute(i InfoType, r *http.Request) InfoType {
|
||||
return i
|
||||
}
|
||||
|
||||
func setupTaglistRoute(i InfoType, r *http.Request) InfoType {
|
||||
tags, counts, _ := jobRepo.GetTags()
|
||||
tagMap := make(map[string][]map[string]interface{})
|
||||
|
||||
for _, tag := range tags {
|
||||
tagItem := map[string]interface{}{
|
||||
"id": tag.ID,
|
||||
"name": tag.Name,
|
||||
"count": counts[tag.Name],
|
||||
}
|
||||
tagMap[tag.Type] = append(tagMap[tag.Type], tagItem)
|
||||
}
|
||||
log.Infof("TAGS %+v", tags)
|
||||
i["tagmap"] = tagMap
|
||||
return i
|
||||
}
|
||||
|
||||
var routes []Route = []Route{
|
||||
{"/monitoring/jobs/", "monitoring/jobs.tmpl", "Jobs - ClusterCockpit", true, func(i InfoType, r *http.Request) InfoType { return i }},
|
||||
{"/monitoring/job/{id:[0-9]+}", "monitoring/job.tmpl", "Job <ID> - ClusterCockpit", false, setupJobRoute},
|
||||
{"/monitoring/users/", "monitoring/list.tmpl", "Users - ClusterCockpit", true, func(i InfoType, r *http.Request) InfoType { i["listType"] = "USER"; return i }},
|
||||
{"/monitoring/projects/", "monitoring/list.tmpl", "Projects - ClusterCockpit", true, func(i InfoType, r *http.Request) InfoType { i["listType"] = "PROJECT"; return i }},
|
||||
{"/monitoring/tags/", "monitoring/taglist.tmpl", "Tags - ClusterCockpit", false, setupTaglistRoute},
|
||||
{"/monitoring/user/{id}", "monitoring/user.tmpl", "User <ID> - ClusterCockpit", true, setupUserRoute},
|
||||
{"/monitoring/systems/{cluster}", "monitoring/systems.tmpl", "Cluster <ID> - ClusterCockpit", false, setupClusterRoute},
|
||||
{"/monitoring/node/{cluster}/{hostname}", "monitoring/node.tmpl", "Node <ID> - ClusterCockpit", false, setupNodeRoute},
|
||||
@ -307,9 +326,11 @@ func main() {
|
||||
})
|
||||
}
|
||||
|
||||
jobRepo = &repository.JobRepository{DB: db}
|
||||
|
||||
graphQLPlayground := playground.Handler("GraphQL playground", "/query")
|
||||
api := &api.RestApi{
|
||||
JobRepository: &repository.JobRepository{DB: db},
|
||||
JobRepository: jobRepo,
|
||||
AsyncArchiving: programConfig.AsyncArchiving,
|
||||
Resolver: resolver,
|
||||
MachineStateDir: programConfig.MachineStateDir,
|
||||
|
@ -58,6 +58,14 @@
|
||||
</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">
|
||||
|
17
templates/monitoring/taglist.tmpl
Normal file
17
templates/monitoring/taglist.tmpl
Normal file
@ -0,0 +1,17 @@
|
||||
{{define "content"}}
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-10">
|
||||
{{ range $tagType, $tagList := .Infos.tagmap }}
|
||||
<div class="my-3 p-2 bg-secondary text-white text-capitalize">
|
||||
{{ $tagType }}
|
||||
</div>
|
||||
{{ range $tagList }}
|
||||
<a class="btn btn-lg btn-warning" href="/monitoring/jobs/?tag={{ .id }}" role="button">
|
||||
{{ .name }} <span class="badge bg-light text-dark">{{ .count }}</span> </a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
@ -22,13 +22,20 @@ type Page struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
templatesDir = "./templates/"
|
||||
bp := "./"
|
||||
ebp := os.Getenv("BASEPATH")
|
||||
|
||||
if ebp != "" {
|
||||
bp = ebp
|
||||
}
|
||||
templatesDir = bp + "templates/"
|
||||
base := template.Must(template.ParseFiles(templatesDir + "base.tmpl"))
|
||||
files := []string{
|
||||
"home.tmpl", "404.tmpl", "login.tmpl",
|
||||
"imprint.tmpl", "privacy.tmpl",
|
||||
"monitoring/jobs.tmpl",
|
||||
"monitoring/job.tmpl",
|
||||
"monitoring/taglist.tmpl",
|
||||
"monitoring/list.tmpl",
|
||||
"monitoring/user.tmpl",
|
||||
"monitoring/systems.tmpl",
|
||||
|
Loading…
Reference in New Issue
Block a user