guix-commits
[Top][All Lists]
Advanced

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

[no subject]


From: Tatiana
Date: Sat, 2 Jun 2018 08:26:59 -0400 (EDT)

branch: web-interface
commit 8e31e6f8af799b6d8a3c0ede9290d463ba436c61
Author: TSholokhova <address@hidden>
Date:   Wed May 23 16:37:23 2018 +0300

    Add basic HTML templates, main and specification builds pages.
    
    * src/cuirass/templates.scm: New file. Add main page template. Add builds 
tables (latest and queue). Add hyperref from the main page to the builds pages.
    * Makefile.am (dist_pkgmodule_DATA): Add it.
    * src/cuirass/http.scm (url-handler): Add handler for “status” endpoint. 
(%static-directory, file-mime-types): New variables. (url-handler): Add handler 
for “/status/<repo_name>”; add handler for static files.
    * src/static/style.css: New file.
---
 Makefile.am               |   3 +-
 src/cuirass/http.scm      |  75 +++++++++++++++++++++--
 src/cuirass/templates.scm |  93 ++++++++++++++++++++++++++++
 src/static/style.css      | 150 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 316 insertions(+), 5 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index d372b9e..75848ef 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -39,7 +39,8 @@ dist_pkgmodule_DATA =                         \
   src/cuirass/http.scm                         \
   src/cuirass/logging.scm                      \
   src/cuirass/ui.scm                           \
-  src/cuirass/utils.scm
+  src/cuirass/utils.scm             \
+  src/cuirass/templates.scm
 
 nodist_pkgmodule_DATA = \
   src/cuirass/config.scm
diff --git a/src/cuirass/http.scm b/src/cuirass/http.scm
index e911b9b..ec4f278 100644
--- a/src/cuirass/http.scm
+++ b/src/cuirass/http.scm
@@ -1,7 +1,9 @@
+
 ;;;; http.scm -- HTTP API
 ;;; 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.
 ;;;
@@ -22,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)
@@ -32,8 +36,29 @@
   #:use-module (web uri)
   #:use-module (fibers)
   #:use-module (fibers channels)
+  #:use-module (sxml simple)
+  #: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)
@@ -103,7 +128,7 @@ Hydra format."
              (string-split query #\&))
         '())))
 
-
+
 ;;;
 ;;; Web server.
 ;;;
@@ -112,6 +137,7 @@ Hydra format."
 ;;; https://github.com/NixOS/hydra/blob/master/doc/manual/api.xml
 ;;;
 
+
 (define (request-path-components request)
   (split-and-decode-uri-path (uri-path (request-uri request))))
 
@@ -135,6 +161,22 @@ Hydra format."
      #:body
      (object->json-string
       `((error . ,message)))))
+      
+  (define (respond-html body)
+    (respond '((content-type . (text/html)))
+             #:body (lambda (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
@@ -147,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)))
 
@@ -223,13 +270,33 @@ Hydra format."
                                       ,@params
                                       (order status+submission-time)))))
            (respond-json-with-error 500 "Parameter not defined!"))))
+    (("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
new file mode 100644
index 0000000..3f27939
--- /dev/null
+++ b/src/cuirass/templates.scm
@@ -0,0 +1,93 @@
+
+;;;; 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 (html-page
+            specifications-table
+            build-table))
+
+
+(define (html-page title body)
+  "Return html page with given title and body"
+  `(html
+    (head
+      (meta (@ (charset "utf-8")))
+      (link (@ (rel "stylesheet")
+               (type "text/css")
+               (href "/static/style.css")))
+      (title ,title))
+    (body ,body)))
+
+
+(define (specifications-table specs)
+  "Return body for main (Status) html-page"
+  `(table
+    (@ (class "table-fill"))
+    (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"))
+     (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..556d781
--- /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]