webapp.py: make it prettier
authorHelmut Grohne <helmut@subdivi.de>
Wed, 13 Mar 2019 20:26:05 +0000 (21:26 +0100)
committerHelmut Grohne <helmut@subdivi.de>
Wed, 13 Mar 2019 20:26:05 +0000 (21:26 +0100)
Thanks to Paul Wise, Guillem Jover and itd@oftc for their feedback.

webapp.py

index 84e83fb..e32a8af 100644 (file)
--- a/webapp.py
+++ b/webapp.py
@@ -21,68 +21,115 @@ db = flask_sqlalchemy.SQLAlchemy(app)
 src_template = """<!DOCTYPE html>
 <html>
  <head>
+  <title>{{ sourcepackage|e }} - Debian cross build</title>
+  <style>
+tr.dep.bad td:nth-child(1) {
+    background-color: #faa;
+}
+tr.dep.tempbad td:nth-child(1) {
+    background-color: #ffa;
+}
+tr.dep.good td:nth-child(1) {
+    background-color: #afa;
+}
+tr.build.bad td:nth-child(4) {
+    background-color: #faa;
+}
+tr.build.tempbad td:nth-child(4) {
+    background-color: #ffa;
+}
+tr.build.good td:nth-child(4) {
+    background-color: #afa;
+}
+th {
+    padding-left: 1em;
+    padding-right: 1em;
+}
+td {
+    padding-left: 1px;
+    padding-right: 1em;
+}
+td:last-child {
+    padding-right: 1px;
+}
+  </style>
  </head>
  <body>
-  <title>{{ sourcepackage|e }} - Debian cross build</title>
-  <h1>{{ sourcepackage|e }}</h1>
-  <h3>Cross satisfiability</h3>
-  <table>
-   <tr>
-    <th>state</th>
-    <th>architectures</th>
-   </tr>
-   {%- set okarchs = depresult.pop(None, None) -%}
-   {%- for reason, archs in depresult.items()|sort -%}
-    <tr>
-     <td>{{ reason|e }}</td>
-     <td>{{ archs|arch_format }}</td>
-    </tr>
-   {%- endfor -%}
-   {%- if okarchs -%}
-    <tr>
-     <td>ok</td>
-     <td>{{ okarchs|arch_format }}</td>
-    </tr>
-   {%- endif -%}
-  </table>
-  <h5>See also</h5>
-  <ul>
-   {%- if show_bootstrapdn -%}
-    <li>
-     <a href="https://bootstrap.debian.net/cross_all/{{ sourcepackage|e }}.html">bootstrap.debian.net</a>
-    </li>
-   {%- endif -%}
-   <li>
-    <a href="https://qa.debian.org/dose/debcheck/cross_unstable_main_amd64/">debcheck</a>
-   </li>
-  </ul>
-  {%- if builds -%}
-   <h3>Cross builds</h3>
+  <header>
+   <h1>
+    <a href="https://tracker.debian.org/pkg/{{ sourcepackage|e }}">
+     {{- sourcepackage|e -}}
+    </a>
+   </h1>
+  </header>
+  <section>
+   <h3>Cross build dependency satisfiability</h3>
    <table>
-    <tr>
-     <th>started</th>
-     <th>version</th>
-     <th>architecture</th>
-     <th>result</th>
-    </tr>
-    {%- for build in builds|sort(attribute='starttime', reverse=true) -%}
+    <thead>
      <tr>
-      <td>
-       <span title="{{ build.starttime|sqltimestamp }}">
-        {{- build.starttime|sqltimestamp|formatts -}}
-       </span>
-      </td>
-      <td>{{ build.version|e }}</td>
-      <td>{{ build.architecture|e }}</td>
-      <td>
-       <a href="{{ url_for("show_log", filename=build.filename[:-3]) }}">
-        {{- "ok" if build.success else "failed" -}}
-       </a>
-       <a href="{{ url_for("show_log", filename=build.filename) }}">xz</a>
-      </td>
+      <th>state</th>
+      <th>architectures</th>
      </tr>
-    {%- endfor -%}
+    </thead>
+    <tbody>
+     {%- set okarchs = depresult.pop(None, None) -%}
+     {%- for reason, archs in depresult.items()|sort -%}
+      <tr class="dep {{ "tempbad" if reason.startswith("skew") else "bad" }}">
+       <td>{{ reason|e }}</td>
+       <td>{{ archs|arch_format }}</td>
+      </tr>
+     {%- endfor -%}
+     {%- if okarchs -%}
+      <tr class="dep good">
+       <td>ok</td>
+       <td>{{ okarchs|arch_format }}</td>
+      </tr>
+     {%- endif -%}
+    </tbody>
    </table>
+   <h5>See also</h5>
+   <ul>
+    {%- if show_bootstrapdn -%}
+     <li>
+      <a href="https://bootstrap.debian.net/cross_all/{{ sourcepackage|e }}.html">bootstrap.debian.net</a>
+     </li>
+    {%- endif -%}
+    <li>
+     <a href="https://qa.debian.org/dose/debcheck/cross_unstable_main_amd64/">debcheck</a>
+    </li>
+   </ul>
+  </section>
+  {%- if builds -%}
+   <section>
+    <h3>Cross builds</h3>
+    <table>
+     <thead>
+      <tr>
+       <th>started</th>
+       <th>version</th>
+       <th>architecture</th>
+       <th>result log</th>
+      </tr>
+     </thead>
+     <tbody>
+      {%- for build in builds|sort(attribute='starttime', reverse=true) -%}
+       <tr class="build {{ "good" if build.success else "bad" }}">
+        <td>
+         {{- build.starttime|sqltimestamp|formatts -}}
+        </td>
+        <td>{{ build.version|e }}</td>
+        <td>{{ build.architecture|e }}</td>
+        <td>
+         <a href="{{ url_for("show_log", filename=build.filename[:-3]) }}">
+          {{- "ok" if build.success else "failed" -}}
+         </a>
+         <a href="{{ url_for("show_log", filename=build.filename) }}">xz</a>
+        </td>
+       </tr>
+      {%- endfor -%}
+     </tbody>
+    </table>
+   </section>
   {%- endif -%}
  </body>
 </html>
@@ -90,13 +137,14 @@ src_template = """<!DOCTYPE html>
 
 @app.template_filter("sqltimestamp")
 def sqltimestamp_filter(s):
+    strptime = datetime.datetime.strptime
     try:
-        return datetime.datetime.strptime(s, "%Y-%m-%d %H:%M:%S.%f")
+        return strptime(s, "%Y-%m-%d %H:%M:%S.%f").replace(microsecond=0)
     except ValueError:
-        return datetime.datetime.strptime(s, "%Y-%m-%d %H:%M:%S")
+        return strptime(s, "%Y-%m-%d %H:%M:%S")
 
-@app.template_filter("formatts")
-def formatts_filter(ts):
+
+def formatts(ts):
     assert isinstance(ts, datetime.datetime)
     dt = datetime.datetime.utcnow() - ts
     if dt < datetime.timedelta(seconds=1):
@@ -109,6 +157,12 @@ def formatts_filter(ts):
         return "%d h" % (dt.seconds // (60 * 60))
     return "%d d" % dt.days
 
+
+@app.template_filter("formatts")
+def formatts_filter(ts):
+    return jinja2.Markup('<time title="%s" datetime="%s">%s</time>' %
+                         (ts, ts, formatts(ts)))
+
 @app.template_filter('arch_format')
 @jinja2.contextfilter
 def arch_format_filter(context, some_archs):