guix-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[no subject]


From: Mathieu Othacehe
Date: Wed, 7 Apr 2021 05:55:02 -0400 (EDT)

branch: master
commit ec0be96407f039a7a2f7daf4baf1d26e47773753
Author: Mathieu Othacehe <othacehe@gnu.org>
AuthorDate: Wed Apr 7 11:47:48 2021 +0200

    Add dashboard display.
    
    * src/cuirass/http.scm (url-handler): New "/eval/id/dashboard" route.
    * src/cuirass/templates.scm (evaluation-dashboard): New procedure.
    * src/static/css/cuirass.css (content-fixed-margin, dashboard, div.tooltip):
    New sections.
---
 src/cuirass/http.scm       |  19 ++++++
 src/cuirass/templates.scm  | 144 +++++++++++++++++++++++++++++++++++++++++++--
 src/static/css/cuirass.css |  25 ++++++++
 3 files changed, 184 insertions(+), 4 deletions(-)

diff --git a/src/cuirass/http.scm b/src/cuirass/http.scm
index 84f5490..a5f282e 100644
--- a/src/cuirass/http.scm
+++ b/src/cuirass/http.scm
@@ -812,6 +812,25 @@ into a specification record and return it."
            (respond-compressed-file log)
            (respond-not-found (uri->string (request-uri request))))))
 
+    (('GET "eval" (= string->number id) "dashboard")
+     (let* ((params (request-parameters request))
+            (system (assq-ref params 'system))
+            (default-system "x86_64-linux")
+            (spec-name (db-get-evaluation-specification id))
+            (spec (db-get-specification spec-name))
+            (systems (specification-systems spec)))
+       (respond-html
+        (html-page
+         "Dashboard"
+         (evaluation-dashboard id systems
+                               #:current-system
+                               (or system default-system))
+         `(((#:name . ,spec-name)
+            (#:link . ,(string-append "/jobset/" spec-name)))
+           ((#:name . ,(string-append "Evaluation " (number->string id)))
+            (#:link . ,(string-append "/eval/" (number->string id)))))
+         #:margin? #f))))
+
     (('GET "search")
      (let* ((params (request-parameters request))
             (query (and=> (assq-ref params 'query) uri-decode))
diff --git a/src/cuirass/templates.scm b/src/cuirass/templates.scm
index b172c40..8b6d0a1 100644
--- a/src/cuirass/templates.scm
+++ b/src/cuirass/templates.scm
@@ -52,7 +52,8 @@
             running-builds-table
             global-metrics-content
             workers-status
-            machine-status))
+            machine-status
+            evaluation-dashboard))
 
 (define (navigation-items navigation)
   (match navigation
@@ -104,7 +105,9 @@ the " (code "guix-master") " specification for the " (code 
"i686-linux") "
 system whose names start with " (code "guile-") ":" (br)
 (code "spec:guix-master system:i686-linux status:success guile-")))))
 
-(define* (html-page title body navigation #:optional query)
+(define* (html-page title body navigation
+                    #:optional query
+                    #:key (margin? #t))
   "Return HTML page with given TITLE and BODY."
   `(html (@ (xmlns "http://www.w3.org/1999/xhtml";)
             (xml:lang "en")
@@ -198,7 +201,10 @@ columnDefs: [
                                Home))
                         ,@(navigation-items navigation)))
                ,(search-form query))
-          (div (@ (class "container content"))
+          (div (@ (id "content")
+                  (class ,(if margin?
+                              "container content"
+                              "content-fixed-margin")))
                ,body)
           (footer
            (@ (class "footer text-center"))
@@ -844,8 +850,15 @@ if ($('.param-select-row').is(':visible')) {
                         (td ,(input-changes (assq-ref row #:checkouts)))
                         (td ,@(evaluation-badges row))
                         (td
+                         (a (@ (href "/eval/" ,(assq-ref row #:id)
+                                     "/dashboard"))
+                            (div
+                             (@ (class "oi oi-monitor d-inline-block")
+                                (title "Dashboard")
+                                (aria-hidden "true"))
+                             ""))
                          (div
-                          (@ (class "dropdown"))
+                          (@ (class "dropdown d-inline-block ml-2"))
                           (a (@ (class "oi oi-menu dropdown-toggle 
no-dropdown-arrow")
                                 (href "#")
                                 (data-toggle "dropdown")
@@ -1148,6 +1161,10 @@ $(document).ready(function() {
                 status
                 id)
        "  "
+       (a (@ (class "oi oi-monitor mr-2")
+             (style "font-size:0.8em")
+             (href "/eval/" ,id "/dashboard")
+             (role "button")))
        (a (@ (id "paginate")
              (class "oi oi-collapse-down")
              (style "font-size:0.7em")
@@ -1707,3 +1724,122 @@ text-dark d-flex position-absolute w-100"))
                                      #:labels
                                      '("Free store disk space percentage")
                                      #:colors (list "#3e95cd"))))))))
+
+(define* (evaluation-dashboard evaluation systems
+                               #:key current-system)
+  (let ((jobs
+         (format #f "/api/jobs?evaluation=~a&system=~a"
+                 evaluation current-system)))
+    `((p (@ (class "lead"))
+         ,(format #f "Dasboard evaluation #~a" evaluation))
+      (form (@ (id "get-dashboard")
+               (class "row g-3 mb-3")
+               (action "/eval/" ,evaluation "/dashboard")
+               (method "GET"))
+            (div (@ (class "col-auto"))
+                 (select (@ (id "system")
+                            (name "system")
+                            (class "form-control"))
+                         ,@(map (lambda (system)
+                                  `(option
+                                    (@ (value ,system)
+                                       ,@(if (string=? system current-system)
+                                             '((selected))
+                                             '()))
+                                    ,system))
+                                systems)))
+            (div (@ (class "col-auto"))
+                 (button
+                  (@ (type "submit")
+                     (class "btn btn-primary"))
+                  " Go")))
+      (script ,(format #f "
+      function radius(count) {
+          if (count < 100)
+              return 15;
+          else if (count < 1000)
+              return 10;
+          else
+              return 5;
+      }
+
+      function color(status) {
+          switch (status) {
+          case -3:
+          case -2:
+              return 'gray';
+          case -1:
+              return 'orange';
+          case 0:
+              return 'green';
+          case 1:
+          case 2:
+          case 3:
+          case 4:
+              return 'red';
+          }
+      }
+
+      function svgWidth() {
+          var width = d3.select('#content').style('width').slice(0, -2);
+          return Math.round(Number(width));
+      }
+
+      d3.json('~a').then(function (data) {
+          var width = svgWidth();
+          var circle_radius = radius(data.length);
+          var margin_x = circle_radius;
+          var margin_y = circle_radius;
+          var margin_circle_x = 3;
+          var margin_circle_y = (2.5 * circle_radius);
+          var circle_count_x =
+              Math.floor((width - 2 * margin_x) /
+                         ((2 * circle_radius) + margin_circle_x));
+          var height = ((data.length / circle_count_x) *
+                        margin_circle_y) +
+              circle_radius + 2 * margin_y;
+
+          console.log(width);
+          console.log(height);
+
+          var div = d3.select('body').append('div')
+                        .attr('class', 'tooltip')
+                        .style('opacity', 0);
+          var svg = d3.select('#content').append('svg')
+              .attr('width', width)
+              .attr('height', height);
+          var circles = svg.append('g')
+              .selectAll('circle')
+              .data(data)
+              .enter()
+              .append('a')
+              .attr('xlink:href', d => '/build/' + d.build + '/details')
+              .append('circle')
+              .attr('r', circle_radius)
+              .attr('cx', function(d, i) {
+                  return margin_x +
+                      (i % circle_count_x)
+                      * (circle_radius * 2 + margin_circle_x);
+              })
+              .attr('cy', function (d, i) {
+                  return margin_y + Math.floor(i / circle_count_x)
+                      * margin_circle_y;
+              })
+              .style('fill', d => color(d.status))
+              .on('mouseover', function(event, d) {
+                  var circle = d3.select(this)
+                      .style('fill', 'steelblue');
+                  div.style('opacity', .9);
+                  div.html(d.name)
+                      .style('left', (event.pageX + 30) + 'px')
+                      .style('top', (event.pageY - 30) + 'px');
+              })
+              .on('mouseout', function(event, d) {
+                  var circle = d3.select(this)
+                      .style('fill', color(d.status));
+                  div.style('opacity', 0);
+                  div.html('')
+                      .style('left', '0px')
+                      .style('top', '0px');
+              })
+      });" jobs)))))
diff --git a/src/static/css/cuirass.css b/src/static/css/cuirass.css
index 14a7b29..6022f9e 100644
--- a/src/static/css/cuirass.css
+++ b/src/static/css/cuirass.css
@@ -15,6 +15,10 @@ body {
     padding: 1em 0em 1em;
 }
 
+.content-fixed-margin {
+    margin: 1em 3em;
+}
+
 #search input:focus {
     width: 500px;
 }
@@ -66,3 +70,24 @@ a.dropdown-toggle:focus + .dropdown-menu {
     background-color: #f5f5f5;
 }
 
+
+#dashboard {
+    display: block;
+    margin: auto;
+}
+
+div.tooltip {
+    position: absolute;
+    opacity:0.8;
+    z-index:1000;
+    text-align:left;
+    border-radius:4px;
+    -moz-border-radius:4px;
+    -webkit-border-radius:4px;
+    padding:8px;
+    color:#fff;
+    background-color:#000;
+    font: 12px sans-serif;
+    max-width: 1000px;
+    height: 30px;
+}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]