Repository: conbench/conbench (language: python)

Issue:
UI HTML: outest pattern confuses, why flask-bootstrap, bootstrap CSS is included twice
We seem to make use of the rather outdated https://github.com/mbr/flask-bootstrap.

It has a base template that gets automatically used:

https://github.com/mbr/flask-bootstrap/blob/master/flask_bootstrap/templates/bootstrap/base.html

We use this Flask extension here: https://github.com/conbench/conbench/blob/fbf5a6ce898532d44327e3ac961f5abb852843bc/conbench/extensions.py#L5

What is this extension good for?

> Flask-Bootstrap packages [Bootstrap](http://getbootstrap.com/) into an extension that mostly consists of a blueprint named 'bootstrap'. It can also create links to serve Bootstrap from a CDN and works with no boilerplate code in your application.

That's ambiguous. Value unclear right now. Results in complexity that is hard to see through.

When I look at the HTML served by conbench.ursa.dev then we can see that the bootstrap CSS is included twice, from two different CDNs:

```
    <!-- Bootstrap -->
    <link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<link rel="shortcut icon" href="/static/favicon.ico?q=1677772058">
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
```

I think the first one is included by Flask-Bootstrap, and the second one is manually included here:
https://github.com/conbench/conbench/blob/fbf5a6ce898532d44327e3ac961f5abb852843bc/conbench/templates/app.html#L10


UI: show footer in all views (+ misc changes)
Related: #836, #839


Discussion / hints:

Screenshot of footer part of ci-generated screenshot, there you can see the new horizontal ruler, the version info, and the api docs link:
![image](https://user-images.githubusercontent.com/265630/224416713-eb06376b-3b90-4be5-a5d6-ed74773afec3.png)


Fix patch:
diff --git a/conbench/templates/app.html b/conbench/templates/app.html
index 15f5f46bc..a12131655 100644
--- a/conbench/templates/app.html
+++ b/conbench/templates/app.html
@@ -1,17 +1,22 @@
-{% extends 'bootstrap/base.html' %}
-
-{% block title %}
-    {% if title %}{{ title }} - {{ application }}{% else %}{{ application }}{% endif %}
-{% endblock %}
-
+{% block doc -%}
+<!doctype html>
+<html lang="en">
+{%- block html %}
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
 {% block styles %}
-{{super()}}
 <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
 <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
 <link href="https://cdn.datatables.net/1.10.23/css/dataTables.bootstrap.min.css" rel="stylesheet" type="text/css">
 <link href="https://cdn.datatables.net/responsive/2.2.7/css/responsive.bootstrap.min.css" rel="stylesheet" type="text/css">
 <link href="{{ url_for('static', filename='app.css') }}" rel=stylesheet type=text/css />
 {% endblock %}
+<title>{% block title %}{% if title %}{{ application }} - {{ title }}{% else %}{{ application }}{% endif %}{% endblock %}</title>
+</head>
+<body>
+{% block body -%}
+
 
 {% block navbar %}
     <nav class="navbar navbar-default">
@@ -287,3 +292,9 @@ <h4 class="modal-title"><span class="glyphicon glyphicon-trash submenu"></span>&
 });
 </script>
 {% endblock %}
+
+{%- endblock body %}
+</body>
+{%- endblock html %}
+</html>
+{% endblock doc -%}


Test patch:
diff --git a/conbench/tests/app/_asserts.py b/conbench/tests/app/_asserts.py
index faf90cb20..7024816b3 100644
--- a/conbench/tests/app/_asserts.py
+++ b/conbench/tests/app/_asserts.py
@@ -66,12 +66,16 @@ def assert_registration_page(self, r):
 
     def assert_index_page(self, r):
         self.assert_200_ok(r)
-        assert b"Home - " in r.data, r.data
+        assert b"conbench-for-pytest" in r.data
+        assert b'<html lang="en">' in r.data
+        # assert b"Login" in r.data
 
     def assert_page(self, r, title):
         self.assert_200_ok(r)
-        title = "{} - ".format(title).encode()
-        assert title in r.data, r.data
+        # The HTML <title> tag starts with the conbench deployment name, in
+        # this case `conbench-for-pytest` and then contains a " - " seperator,
+        # followed by the more specific page name
+        assert b"conbench-for-pytest - " in r.data
 
     def create_benchmark(self, client):
         self.authenticate(client)
@@ -119,7 +123,7 @@ def test_public_data_off(self, client, monkeypatch):
         self.logout(client)
         response = client.get(self.url, follow_redirects=True)
         assert new_id.encode() not in response.data
-        assert b"Sign In - conbench-for-pytest" in response.data, response.data
+        assert b"Sign In" in response.data, response.data
 
 
 class GetEnforcer(Enforcer):
@@ -195,16 +199,16 @@ def test_public_data_off(self, client, monkeypatch):
         # be reworked.
         # assert new_id.encode() not in r2.data
 
-        assert b"Sign In - conbench-for-pytest" in r2.data, r2.data
+        assert b"conbench-for-pytest - Sign In" in r2.data, r2.data
 
     def test_unknown(self, client):
         self.authenticate(client)
         unknown_url = self.url.format("unknown")
         response = client.get(unknown_url, follow_redirects=True)
         if getattr(self, "redirect_on_unknown", True):
-            assert b"Home - conbench-for-pytest" in response.data, response.data
+            assert b"conbench-for-pytest - Home" in response.data, response.data
         else:
-            title = "{} - conbench-for-pytest".format(self.title).encode()
+            title = f"conbench-for-pytest - {self.title}".encode()
             assert title in response.data, response.data
 
 
diff --git a/conbench/tests/app/test_hardware.py b/conbench/tests/app/test_hardware.py
index efa7afa08..cd4c43499 100644
--- a/conbench/tests/app/test_hardware.py
+++ b/conbench/tests/app/test_hardware.py
@@ -27,7 +27,6 @@ def test_hardware_get_authenticated(self, client):
         self.authenticate(client)
         response = client.get(f"/hardware/{hardware_id}/")
         self.assert_page(response, "Hardware")
-        assert "Hardware - conbench-for-pytest".encode() in response.data
 
     def test_hardware_get_unauthenticated(self, client):
         self.create_benchmark(client)