guix-commits
[Top][All Lists]
Advanced

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

[no subject]


From: Tatiana
Date: Sun, 27 May 2018 17:35:13 -0400 (EDT)

branch: web-interface
commit 501d15b27d16f0ef0c1f808bf97e1340a62ac5f5
Author: TSholokhova <address@hidden>
Date:   Mon May 28 00:25:22 2018 +0300

    Add specification builds page.
    
    * src/cuirass/http.scm: Add handler for "/status/<repo_name>" query. Static 
files serving. Fix codestyle.
    * src/cuirass/templates.scm: Add builds tables (latest and queue). Add 
hyperref from the main page to the builds pages.
    * src/static/style.css: New file. Example style file.
---
 src/cuirass/http.scm      |  72 ++++++++++++++++++----
 src/cuirass/templates.scm | 104 +++++++++++++++++++++++++-------
 src/static/style.css      | 150 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 295 insertions(+), 31 deletions(-)

diff --git a/src/cuirass/http.scm b/src/cuirass/http.scm
index f5e3ac1..3d4f4c2 100644
--- a/src/cuirass/http.scm
+++ b/src/cuirass/http.scm
@@ -3,6 +3,7 @@
 ;;; Copyright © 2016 Mathieu Lirzin <address@hidden>
 ;;; Copyright © 2017 Mathieu Othacehe <address@hidden>
 ;;; Copyright © 2018 Ludovic Courtès <address@hidden>
+;;; Copyright © 2018 Tatiana Sholokhova <address@hidden>
 ;;;
 ;;; This file is part of Cuirass.
 ;;;
@@ -23,8 +24,10 @@
   #:use-module (cuirass database)
   #:use-module (cuirass utils)
   #:use-module (cuirass logging)
+  #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-11)
   #:use-module (srfi srfi-26)
+  #:use-module (ice-9 binary-ports)
   #:use-module (ice-9 match)
   #:use-module (json)
   #:use-module (web request)
@@ -37,6 +40,25 @@
   #:use-module (cuirass templates)
   #:export (run-cuirass-server))
 
+(define %static-directory
+  ;; Define to the static file directory.
+  (string-append (or (getenv "CUIRASS_DATADIR")
+                     (string-append %datadir "/" %package))
+                 "/static/"))
+
+(define file-mime-types
+  '(("css" . (text/css))
+    ("js"  . (text/javascript))
+    ("png" . (image/png))
+    ("gif" . (image/gif))
+    ("html" . (text/html))))
+
+(define (file-extension file-name)
+  (last (string-split file-name #\.)))
+
+(define (directory? filename)
+  (string=? filename (dirname filename)))
+
 (define (build->hydra-build build)
   "Convert BUILD to an assoc list matching hydra API format."
   (define (bool->int bool)
@@ -143,8 +165,18 @@ Hydra format."
   (define (respond-html body)
     (respond '((content-type . (text/html)))
              #:body (lambda (port)
-                      (sxml->xml body port)
-                      )))
+                      (sxml->xml body port))))
+  
+  (define (respond-static-file path)
+    ;; PATH is a list of path components
+    (let ((file-name (string-join (cons* %static-directory path) "/")))
+      (if (and (not (any (cut string-contains <> "..") path))
+               (file-exists? file-name)
+               (not (directory? file-name)))
+          (respond 
+            `((content-type . ,(assoc-ref file-mime-types (file-extension 
file-name))))
+            #:body (call-with-input-file file-name get-bytevector-all))
+          (respond-not-found file-name))))
 
   (define (respond-build-not-found build-id)
     (respond-json-with-error
@@ -157,6 +189,11 @@ Hydra format."
        404
        (format #f "The build log of derivation ~a is not available." drv))))
 
+  (define (respond-not-found resource_name)
+    (respond (build-response #:code 404)
+             #:body (string-append "Resource not found: "
+                                   resource_name)))
+
   (log-message "~a ~a" (request-method request)
                (uri-path (request-uri request)))
 
@@ -233,18 +270,33 @@ Hydra format."
                                       ,@params
                                       (order status+submission-time)))))
            (respond-json-with-error 500 "Parameter not defined!"))))
-    (("status")
-     (respond-html (templatize 
-                   "Status" 
-                   (specifications-table 
-                    (with-critical-section db-channel (db) 
(db-get-specifications db))))))
+    (("status") 
+     (respond-html (html-page
+                     "Status" 
+                     (specifications-table 
+                      (with-critical-section db-channel (db) 
(db-get-specifications db))))))
+    (("status" name)
+      (respond-html (html-page
+                      name 
+                      (build-table 
+                        (handle-builds-request db-channel
+                          `((status done)
+                          (project ,name)
+                          (nr 10)
+                          (order finish-time)))
+                        (handle-builds-request db-channel
+                          `((status pending)
+                          (project ,name)
+                          (nr 10)
+                          (order status+submission-time)))))))
+    (("static" path ...)
+     ;(display (request-uri request))
+     (respond-static-file path))
     ('method-not-allowed
      ;; 405 "Method Not Allowed"
      (values (build-response #:code 405) #f db-channel))
     (_
-     (respond (build-response #:code 404)
-              #:body (string-append "Resource not found: "
-                                    (uri->string (request-uri request)))))))
+     (respond-not-found  (uri->string (request-uri request))))))
 
 (define* (run-cuirass-server db #:key (host "localhost") (port 8080))
   (let* ((host-info  (gethostbyname host))
diff --git a/src/cuirass/templates.scm b/src/cuirass/templates.scm
index ff63469..f882e98 100644
--- a/src/cuirass/templates.scm
+++ b/src/cuirass/templates.scm
@@ -1,32 +1,94 @@
+
+;;;; http.scm -- HTTP API
+;;; Copyright © 2018 Tatiana Sholokhova <address@hidden>
+;;;
+;;; This file is part of Cuirass.
+;;;
+;;; Cuirass is free software: you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation, either version 3 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; Cuirass is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Cuirass.  If not, see <http://www.gnu.org/licenses/>.
+
 (define-module (cuirass templates)
-  #:export (templatize
-            specifications-table))
+  #:export (html-page
+            specifications-table
+            build-table))
 
 
-(define (templatize title body)
+(define (html-page title body)
+  "Return html page with given title and body"
   `(html 
-    ,(head title)
+    (head 
+      (meta (@ (charset "utf-8")))
+      (link (@ (rel "stylesheet") 
+               (type "text/css")
+               (href "/static/style.css")))
+      (title ,title))
     (body ,body)))
 
 
-(define (head title)
-  `(head 
-    (meta (@ (charset "utf-8"))) 
-    (title ,title)))
-
-
 (define (specifications-table specs)
+  "Return body for main (Status) html-page"
   `(table
     (@ (class "table-fill"))
-    (thead
-     (tr
-      (th (@ (class "text-left")) Name)
-      (th (@ (class "text-left")) Branch)))
-    (tbody
+    (caption  "Status")
+     ,@(if (null? specs)
+        `((th (@ (class "text-left")) "No elements here."))
+        `((thead
+            (tr
+             (th (@ (class "text-left")) Name)
+             (th (@ (class "text-left")) Branch)))
+           (tbody
+            (@ (class "table-fill"))
+            ,@(map
+             (lambda (spec)
+              `(tr
+                (td (a (@ (href ,(string-append "/status/" (assq-ref spec 
#:name))))) ,(assq-ref spec #:name))
+                (td ,(assq-ref spec #:branch))))
+            specs))))))
+
+(define (build-table done pending)
+  "Return body for project's html-page"
+  (define (table-row build)
+    `(tr
+      (td ,(assq-ref build #:project))
+      (td ,(assq-ref build #:jobset))
+      (td ,(assq-ref build #:job))
+      (td ,(assq-ref build #:nixname))
+      (td ,(assq-ref build #:buildstatus))))
+  (define (table-header)
+    `(thead
+      (tr
+       (th (@ (class "text-left")) Project)
+       (th (@ (class "text-left")) Jobset)
+       (th (@ (class "text-left")) Job)
+       (th (@ (class "text-left")) Nixname)
+       (th (@ (class "text-left")) Buildstatus))))
+  `(
+    (table 
+     (@ (class "table-fill"))
+     (caption  "Latest builds")
+     ,@(if (null? done)
+       `((th (@ (class "text-left")) "No elements here."))
+       `(,(table-header)
+         (tbody
+          (@ (class "table-fill"))
+          ,@(map table-row done)))))
+    (table
      (@ (class "table-fill"))
-     ,@(map
-        (lambda (spec)
-          `(tr
-            (td ,(assq-ref spec #:name))
-            (td ,(assq-ref spec #:branch))))
-        specs))))
+     (caption "Queue")
+     ,@(if (null? pending)
+       `((th (@ (class "text-left")) "No elements here."))
+       `(,(table-header)
+         (tbody
+          (@ (class "table-fill"))
+          ,@(map table-row pending)))))))
+
diff --git a/src/static/style.css b/src/static/style.css
new file mode 100644
index 0000000..2d4b243
--- /dev/null
+++ b/src/static/style.css
@@ -0,0 +1,150 @@
address@hidden 
url(https://fonts.googleapis.com/css?family=Roboto:400,500,700,300,100);
+
+body {
+  background-color: #aec4fc;
+  font-family: "Roboto", helvetica, arial, sans-serif;
+  font-size: 16px;
+  font-weight: 400;
+  text-rendering: optimizeLegibility;
+}
+caption {
+   color: #111144;
+   font-size: 30px;
+   font-weight: 400;
+   font-style:normal;
+   font-family: "Roboto", helvetica, arial, sans-serif;
+   text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.1);
+}
+div.table-title {
+   display: block;
+  margin: auto;
+  max-width: 1000px;
+  padding:5px;
+  width: 100%;
+}
+
+.table-title h3 {
+   color: #fafafa;
+   font-size: 30px;
+   font-weight: 400;
+   font-style:normal;
+   font-family: "Roboto", helvetica, arial, sans-serif;
+   text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.1);
+   text-transform:uppercase;
+}
+
+
+/*** Table Styles **/
+
+.table-fill {
+  background: white;
+  border-radius:3px;
+  border-collapse: collapse;
+  height: 60px;
+  margin: auto;
+  max-width: 1000px;
+  padding:5px;
+  width: 100%;
+  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
+  animation: float 5s infinite;
+}
+ 
+th {
+  color:#D5DDE5;;
+  background:#1b1e24;
+  border-bottom:4px solid #9ea7af;
+  border-right: 1px solid #343a45;
+  font-size:23px;
+  font-weight: 100;
+  padding:24px;
+  text-align:left;
+  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+  vertical-align:middle;
+}
+
+th:first-child {
+  border-top-left-radius:3px;
+}
+ 
+th:last-child {
+  border-top-right-radius:3px;
+  border-right:none;
+}
+  
+tr {
+  border-top: 1px solid #C1C3D1;
+  border-bottom-: 1px solid #C1C3D1;
+  color:#666B85;
+  font-size:16px;
+  font-weight:normal;
+  text-shadow: 0 1px 1px rgba(256, 256, 256, 0.1);
+}
+ 
+tr:hover td {
+  background:#4E5066;
+  color:#FFFFFF;
+  border-top: 1px solid #22262e;
+}
+ 
+tr:first-child {
+  border-top:none;
+}
+
+tr:last-child {
+  border-bottom:none;
+}
+ 
+tr:nth-child(odd) td {
+  background:#EBEBEB;
+}
+ 
+tr:nth-child(odd):hover td {
+  background:#4E5066;
+}
+
+tr:last-child td:first-child {
+  border-bottom-left-radius:3px;
+}
+ 
+tr:last-child td:last-child {
+  border-bottom-right-radius:3px;
+}
+ 
+td {
+  background:#FFFFFF;
+  padding:20px;
+  text-align:left;
+  vertical-align:middle;
+  font-weight:300;
+  font-size:18px;
+  text-shadow: -1px -1px 1px rgba(0, 0, 0, 0.1);
+  border-right: 1px solid #C1C3D1;
+}
+
+td:last-child {
+  border-right: 0px;
+}
+
+th.text-left {
+  text-align: left;
+}
+
+th.text-center {
+  text-align: center;
+}
+
+th.text-right {
+  text-align: right;
+}
+
+td.text-left {
+  text-align: left;
+}
+
+td.text-center {
+  text-align: center;
+}
+
+td.text-right {
+  text-align: right;
+}



reply via email to

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