Add Tag view including required changes.

This commit is contained in:
Jan Eitzinger 2022-02-10 18:48:58 +01:00
parent 27fd3c4e5a
commit 14693ad32b
6 changed files with 170 additions and 2 deletions

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"database/sql" "database/sql"
"errors" "errors"
"fmt"
"strconv" "strconv"
"github.com/ClusterCockpit/cc-backend/auth" "github.com/ClusterCockpit/cc-backend/auth"
@ -123,6 +124,42 @@ func (r *JobRepository) CreateTag(tagType string, tagName string) (tagId int64,
return res.LastInsertId() 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`. // 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. // 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) { func (r *JobRepository) AddTagOrCreate(jobId int64, tagType string, tagName string) (tagId int64, err error) {

78
repository/job_test.go Normal file
View 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"])
// }
}

View File

@ -38,6 +38,7 @@ import (
) )
var db *sqlx.DB var db *sqlx.DB
var jobRepo *repository.JobRepository
// Format of the configurartion (file). See below for the defaults. // Format of the configurartion (file). See below for the defaults.
type ProgramConfig struct { type ProgramConfig struct {
@ -162,11 +163,29 @@ func setupAnalysisRoute(i InfoType, r *http.Request) InfoType {
return i 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{ var routes []Route = []Route{
{"/monitoring/jobs/", "monitoring/jobs.tmpl", "Jobs - ClusterCockpit", true, func(i InfoType, r *http.Request) InfoType { return i }}, {"/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/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/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/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/user/{id}", "monitoring/user.tmpl", "User <ID> - ClusterCockpit", true, setupUserRoute},
{"/monitoring/systems/{cluster}", "monitoring/systems.tmpl", "Cluster <ID> - ClusterCockpit", false, setupClusterRoute}, {"/monitoring/systems/{cluster}", "monitoring/systems.tmpl", "Cluster <ID> - ClusterCockpit", false, setupClusterRoute},
{"/monitoring/node/{cluster}/{hostname}", "monitoring/node.tmpl", "Node <ID> - ClusterCockpit", false, setupNodeRoute}, {"/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") graphQLPlayground := playground.Handler("GraphQL playground", "/query")
api := &api.RestApi{ api := &api.RestApi{
JobRepository: &repository.JobRepository{DB: db}, JobRepository: jobRepo,
AsyncArchiving: programConfig.AsyncArchiving, AsyncArchiving: programConfig.AsyncArchiving,
Resolver: resolver, Resolver: resolver,
MachineStateDir: programConfig.MachineStateDir, MachineStateDir: programConfig.MachineStateDir,

View File

@ -58,6 +58,14 @@
</a> </a>
</li> </li>
{{end}} {{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}} {{else}}
{{block "navitem_stats" .}} {{block "navitem_stats" .}}
<li class="nav-item"> <li class="nav-item">

View 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}}

View File

@ -22,13 +22,20 @@ type Page struct {
} }
func init() { func init() {
templatesDir = "./templates/" bp := "./"
ebp := os.Getenv("BASEPATH")
if ebp != "" {
bp = ebp
}
templatesDir = bp + "templates/"
base := template.Must(template.ParseFiles(templatesDir + "base.tmpl")) base := template.Must(template.ParseFiles(templatesDir + "base.tmpl"))
files := []string{ files := []string{
"home.tmpl", "404.tmpl", "login.tmpl", "home.tmpl", "404.tmpl", "login.tmpl",
"imprint.tmpl", "privacy.tmpl", "imprint.tmpl", "privacy.tmpl",
"monitoring/jobs.tmpl", "monitoring/jobs.tmpl",
"monitoring/job.tmpl", "monitoring/job.tmpl",
"monitoring/taglist.tmpl",
"monitoring/list.tmpl", "monitoring/list.tmpl",
"monitoring/user.tmpl", "monitoring/user.tmpl",
"monitoring/systems.tmpl", "monitoring/systems.tmpl",