From 3135b8954f4b6c68f5f7f523e5eb1ee163ce322a Mon Sep 17 00:00:00 2001
From: Frank Sauerburger <frank@sauerburger.com>
Date: Tue, 5 Jan 2021 18:58:58 +0100
Subject: [PATCH] Various frontend improvements

---
 uhepp-js/package-lock.json                    |  5 ++
 uhepp-js/package.json                         |  1 +
 uhepp-js/src/common.scss                      | 24 +++++++++-
 uhepp-js/src/index.js                         |  2 +
 uhepp_org/requirements.txt                    |  1 +
 uhepp_org/uhepp_org/settings.py               |  3 ++
 .../templates/registration/login.html         | 29 ++++++++----
 .../uhepp_vault/collection_detail.html        | 29 ++++++++----
 .../uhepp_vault/collection_form.html          | 25 ++++++++--
 .../uhepp_vault/collection_list.html          | 18 +++++--
 .../templates/uhepp_vault/plot_detail.html    |  7 ++-
 .../templates/uhepp_vault/plot_list.html      |  7 +++
 .../templates/uhepp_vault/profile_detail.html | 47 +++++++++++--------
 .../templates/uhepp_vault/profile_form.html   | 11 ++++-
 .../templates/uhepp_vault/profile_list.html   | 16 +++++--
 uhepp_org/uhepp_vault/views.py                | 27 ++++++++++-
 16 files changed, 193 insertions(+), 59 deletions(-)

diff --git a/uhepp-js/package-lock.json b/uhepp-js/package-lock.json
index 090b075..a542993 100644
--- a/uhepp-js/package-lock.json
+++ b/uhepp-js/package-lock.json
@@ -1173,6 +1173,11 @@
         "to-fast-properties": "^2.0.0"
       }
     },
+    "@fortawesome/fontawesome-free": {
+      "version": "5.15.1",
+      "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.1.tgz",
+      "integrity": "sha512-OEdH7SyC1suTdhBGW91/zBfR6qaIhThbcN8PUXtXilY4GYnSBbVqOntdHbC1vXwsDnX0Qix2m2+DSU1J51ybOQ=="
+    },
     "@popperjs/core": {
       "version": "2.6.0",
       "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.6.0.tgz",
diff --git a/uhepp-js/package.json b/uhepp-js/package.json
index b13cf47..21a10c7 100644
--- a/uhepp-js/package.json
+++ b/uhepp-js/package.json
@@ -9,6 +9,7 @@
     "build": "webpack --mode production"
   },
   "dependencies": {
+    "@fortawesome/fontawesome-free": "^5.15.1",
     "@vx/axis": "0.0.199",
     "@vx/grid": "0.0.199",
     "@vx/group": "0.0.199",
diff --git a/uhepp-js/src/common.scss b/uhepp-js/src/common.scss
index a5dd867..5313f30 100644
--- a/uhepp-js/src/common.scss
+++ b/uhepp-js/src/common.scss
@@ -21,9 +21,10 @@ a:hover {
   margin-bottom: 0;
 }
 
+
 .access-menu {
   .dropdown-menu {
-    width: 399px;
+    width: 350;
   }
   .highlight pre {
     overflow-x: auto;
@@ -33,6 +34,22 @@ a:hover {
 	}
 }
 
+@include media-breakpoint-up(md) { 
+  .access-menu {
+    .dropdown-menu {
+      width: 500px;
+    }
+  }
+}
+@include media-breakpoint-up(lg) { 
+  .access-menu {
+    .dropdown-menu {
+      width: auto;
+      min-width: 500px;
+    }
+  }
+}
+
 dd {
 	margin-left: 1rem;
 }
@@ -51,3 +68,8 @@ dd {
 		}
 	}
 }
+
+.controls-head {
+  display: flex;
+  justify-content: space-between;
+}
diff --git a/uhepp-js/src/index.js b/uhepp-js/src/index.js
index 110e05d..725bae5 100644
--- a/uhepp-js/src/index.js
+++ b/uhepp-js/src/index.js
@@ -10,6 +10,8 @@ import React from "react";
 import ReactDOM from "react-dom";
 import { HashRouter as Router, Route, Link } from "react-router-dom";
 
+import '@fortawesome/fontawesome-free/js/fontawesome'
+import '@fortawesome/fontawesome-free/js/solid' 
 
 export const fe = {
   React: React, 
diff --git a/uhepp_org/requirements.txt b/uhepp_org/requirements.txt
index 3e8abd1..5e8da88 100644
--- a/uhepp_org/requirements.txt
+++ b/uhepp_org/requirements.txt
@@ -4,3 +4,4 @@ mozilla-django-oidc
 django-pygmentify
 django-inline-svg
 psycopg2
+django-crispy-forms
diff --git a/uhepp_org/uhepp_org/settings.py b/uhepp_org/uhepp_org/settings.py
index cbe3122..ca69151 100644
--- a/uhepp_org/uhepp_org/settings.py
+++ b/uhepp_org/uhepp_org/settings.py
@@ -108,8 +108,11 @@ INSTALLED_APPS = [
     'rest_framework.authtoken',
     'pygmentify',
     'svg',
+    'crispy_forms',
 ]
 
+CRISPY_TEMPLATE_PACK = 'bootstrap4'
+
 PYGMENTIFY = {
   'style': 'default',
   'cssclass': 'highlight border rounded bg-light px-2 m-2'
diff --git a/uhepp_org/uhepp_vault/templates/registration/login.html b/uhepp_org/uhepp_vault/templates/registration/login.html
index c206f86..db67857 100644
--- a/uhepp_org/uhepp_vault/templates/registration/login.html
+++ b/uhepp_org/uhepp_vault/templates/registration/login.html
@@ -1,17 +1,26 @@
 {% extends 'uhepp_vault/base.html' %}
+{% load crispy_forms_tags %}
 
 {% block content %}
 
 <h1>Login</h1>
 
-<h2>CERN Single Sign-On (preferred)</h2>
-<a href="{% url 'oidc_authentication_init' %}">Login via CERN SSO</a>
-
-<hr />
-
-<h2>uhepp.org account</h2>
-<form method="post">{% csrf_token %}
-{{ form }}
-<button type="submit">Log in</button>
-
+<div class="row">
+    <div class="col-md-6 p-4 card bg-light border-primary">
+        <h2 class="mt-2">
+        CERN Single Sign-On
+        <small class="text-muted">preferred</small>
+        </h2>
+        <p>Use your CERN account to sign in or create a new account.</p>
+        <p><a tabindex="0" class="btn btn-primary" href="{% url 'oidc_authentication_init' %}">Sign in with CERN SSO</a></p>
+    </div>
+    <div class="col-md-6 px-4">
+        <h2 class="mt-2">Uhepp hub account</h2>
+        <p>You can only use this option if you have received a special
+        account.</p>
+        <form method="post">{% csrf_token %}
+        {{ form|crispy }}
+        <button type="submit" class="btn btn-outline-primary">Sign in</button>
+    </div>
+</div>
 {% endblock %}
diff --git a/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_detail.html b/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_detail.html
index 12df392..4e6789c 100644
--- a/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_detail.html
+++ b/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_detail.html
@@ -10,17 +10,25 @@
   </ol>
 </nav>
 
-<h1>{{ collection.title }}</h1>
-{% if collection.owner.pk == user.pk %}
-<p>
-    <a href="{% url 'uhepp_vault:collection-update' collection.pk %}">
-    edit
+<h1 class="controls-head">
+  <span>
+    {{ collection.title }}
+    <i class="text-muted fas {% if collection.visibility >= 30 %} fa-globe-europe
+    {% elif collection.visibility >= 20 %} fa-shield-alt
+    {% elif collection.visibility >= 10 %} fa-lock
+    {% endif %}"></i>
+  </span>
+  {% if collection.owner.pk == user.pk %}
+  <span>
+    <a class="btn btn-outline-secondary" href="{% url 'uhepp_vault:collection-update' collection.pk %}">
+        <i class="fas fa-pen"></i>
     </a>
-    <a href="{% url 'uhepp_vault:collection-delete' collection.pk %}">
-    delete
+    <a class="btn btn-outline-danger" href="{% url 'uhepp_vault:collection-delete' collection.pk %}">
+        <i class="fas fa-trash"></i>
     </a>
-</p>
-{% endif %}
+  </span>
+  {% endif %}
+</h1>
 
 <div class="d-flex">
 <span>Collection ID: {{ collection.id }}</span>
@@ -61,6 +69,9 @@ hist.push({{ collection.pk }})
 		</button>
 		<div class="dropdown-menu dropdown-menu-right p-4 shadow">
           <form>
+			<p class="alert alert-info m-2">
+				Make sure you've set up an <a class="alert-link" href="{% url 'uhepp_vault:token-list' %}">API access token</a>.
+			</p>
 <h5>Pull collection</h5>
 {% pygmentify %}
 <pre class="bash">
diff --git a/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_form.html b/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_form.html
index dc83f97..0eda2f5 100644
--- a/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_form.html
+++ b/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_form.html
@@ -1,17 +1,34 @@
 {% extends 'uhepp_vault/base.html' %}
+{% load crispy_forms_tags %}
 
 {% block content %}
 
+<nav aria-label="breadcrumb">
+  <ol class="breadcrumb my-2">
+    <li class="breadcrumb-item"><a href="/">Home</a></li>
+    <li class="breadcrumb-item"><a href="{% url 'uhepp_vault:user-detail' user.username %}">{{ user.username }}</a></li>
+{% if view.edit %}
+    <li class="breadcrumb-item"><a href="{% url 'uhepp_vault:collection-detail' collection.pk %}">{{ collection.title }}</a></li>
+{% else %}
+    <li class="breadcrumb-item"><a class="active" href="{% url 'uhepp_vault:collection-create' %}">New collection</a></li>
+{% endif %}
+  </ol>
+</nav>
+
 {% if view.edit %}
 <h2>Edit collection</h2>
 {% else %}
 <h2>New collection</h2>
 {% endif %}
 
-<a href="{% url 'uhepp_vault:user-detail' request.user.username %}">Back to profile</a>
-
 <form method="post">{% csrf_token %}
-    {{ form.as_p }}
-    <input type="submit" value="Create">
+    {{ form|crispy }}
+    <button type="submit" class="btn btn-primary">
+{% if view.edit %}
+Save
+{% else %}
+Create
+{% endif %}
+    </button>
 </form>
 {% endblock %}
diff --git a/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_list.html b/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_list.html
index 068e808..77d2cce 100644
--- a/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_list.html
+++ b/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_list.html
@@ -1,6 +1,14 @@
 {% extends 'uhepp_vault/base.html' %}
 
 {% block content %}
+<nav aria-label="breadcrumb">
+  <ol class="breadcrumb my-2">
+    <li class="breadcrumb-item"><a href="/">Home</a></li>
+    <li class="breadcrumb-item">Explore</li>
+    <li class="breadcrumb-item active"><a class="active" href="{% url 'uhepp_vault:collection-list' %}">Collections</a></li>
+  </ol>
+</nav>
+
 <h1>Collections</h1>
 
 
@@ -11,11 +19,11 @@
         <div class="d-flex justify-content-between align-items-center">
             <span>
             {{ collection.title }}
-            <small class="text-muted">{% if collection.visibility >= 30 %}(public)
-            {% elif collection.visibility >= 20 %}(internal)
-            {% elif collection.visibility >= 10 %}(private)
-            {% endif %}
-            by <span class="text-body">{{ collection.owner.username}}</span>
+            <i class="text-muted fas {% if collection.visibility >= 30 %} fa-globe-europe
+            {% elif collection.visibility >= 20 %} fa-shield-alt
+            {% elif collection.visibility >= 10 %} fa-lock
+            {% endif %}"></i>
+            <small class="text-muted">by <span class="text-body">{{ collection.owner.username}}</span></small>
             </small>
 
             </span>
diff --git a/uhepp_org/uhepp_vault/templates/uhepp_vault/plot_detail.html b/uhepp_org/uhepp_vault/templates/uhepp_vault/plot_detail.html
index d5353f9..d24d9fe 100644
--- a/uhepp_org/uhepp_vault/templates/uhepp_vault/plot_detail.html
+++ b/uhepp_org/uhepp_vault/templates/uhepp_vault/plot_detail.html
@@ -11,8 +11,11 @@
   </ol>
 </nav>
 
-<h1>{{ plot }}</h1>
-
+<h1>{{ plot }}
+<i class="text-muted fas {% if plot.collection.visibility >= 30 %} fa-globe-europe
+{% elif plot.collection.visibility >= 20 %} fa-shield-alt
+{% elif plot.collection.visibility >= 10 %} fa-lock
+{% endif %}"></i></h1>
 
 <div class="d-flex">
 <span class="d-none d-md-inline">UUID: {{ plot.uuid }}</span>
diff --git a/uhepp_org/uhepp_vault/templates/uhepp_vault/plot_list.html b/uhepp_org/uhepp_vault/templates/uhepp_vault/plot_list.html
index cee6cea..d11a8fb 100644
--- a/uhepp_org/uhepp_vault/templates/uhepp_vault/plot_list.html
+++ b/uhepp_org/uhepp_vault/templates/uhepp_vault/plot_list.html
@@ -1,6 +1,13 @@
 {% extends 'uhepp_vault/base.html' %}
 
 {% block content %}
+<nav aria-label="breadcrumb">
+  <ol class="breadcrumb my-2">
+    <li class="breadcrumb-item"><a href="/">Home</a></li>
+    <li class="breadcrumb-item">Explore</li>
+    <li class="breadcrumb-item active"><a class="active" href="{% url 'uhepp_vault:plot-list' %}">Plots</a></li>
+  </ol>
+</nav>
 <h1>Plots</h1>
 {% if plot_list %}
 <ul>
diff --git a/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_detail.html b/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_detail.html
index 366866e..fda7419 100644
--- a/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_detail.html
+++ b/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_detail.html
@@ -7,25 +7,33 @@
     <li class="breadcrumb-item"><a class="active" href="{% url 'uhepp_vault:user-detail' user.username %}">{{ user.username }}</a></li>
   </ol>
 </nav>
-<h1>{{ user.first_name }} {{ user.last_name }}</h1>
-<p>Visibility:
-{% if user.profile.visibility >= 30 %} public
-{% elif user.profile.visibility >= 20 %} internal
-{% elif user.profile.visibility >= 10 %} private)
-{% endif %}</p>
-
-{% if user.username == request.user.username %}
-<p><a href="{% url 'uhepp_vault:account-detail' %}">Edit profile</a></p>
-{% endif %}
-
-<p>Home institute: {{ user.profile.home_institute }}</p>
-
-<h2>Collection</h2>
+<h1 class="controls-head" style="margin-bottom: -0.5rem">
+  <span>
+    {{ user.first_name }} {{ user.last_name }}
+    <i class="text-muted fas {% if user.profile.visibility >= 30 %} fa-user
+    {% elif user.profile.visibility >= 20 %} fa-user-shield
+    {% elif user.profile.visibility >= 10 %} fa-user-lock
+    {% endif %}"></i>
+  </span>
 {% if user.username == request.user.username %}
-<p><a href="{% url 'uhepp_vault:collection-create' %}">New collection</a></p>
+  <span>
+    <a class="btn btn-outline-secondary" href="{% url 'uhepp_vault:account-detail' %}">
+      <i class="fas fa-pen"></i>
+    </a>
+  </span>
 {% endif %}
+</h1>
 
+<p><small class="text-muted">{{ user.profile.home_institute }}</small></p>
 
+<h2 class="controls-head">
+    Collection
+    {% if user.username == request.user.username %}
+    <a class="btn btn-outline-primary" href="{% url 'uhepp_vault:collection-create' %}">
+        <i class="fas fa-plus"></i>
+    </a>
+    {% endif %}
+</h2>
 
 {% if user.collections %}
   <div class="list-group">
@@ -34,11 +42,10 @@
         <div class="d-flex justify-content-between align-items-center">
             <span>
             {{ collection.title }}
-            <small class="text-muted">{% if collection.visibility >= 30 %}(public)
-            {% elif collection.visibility >= 20 %}(internal)
-            {% elif collection.visibility >= 10 %}(private)
-            {% endif %}
-            </small>
+            <i class="text-muted fas {% if collection.visibility >= 30 %} fa-globe-europe
+            {% elif collection.visibility >= 20 %} fa-shield-alt
+            {% elif collection.visibility >= 10 %} fa-lock
+            {% endif %}"></i>
 
             </span>
 
diff --git a/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_form.html b/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_form.html
index 245f247..9fc3ab3 100644
--- a/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_form.html
+++ b/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_form.html
@@ -1,6 +1,13 @@
 {% extends 'uhepp_vault/base.html' %}
+{% load crispy_forms_tags %}
 
 {% block content %}
+<nav aria-label="breadcrumb">
+  <ol class="breadcrumb my-2">
+    <li class="breadcrumb-item"><a href="/">Home</a></li>
+    <li class="breadcrumb-item"><a class="active" href="{% url 'uhepp_vault:user-detail' user.username %}">{{ user.username }}</a></li>
+  </ol>
+</nav>
 <h1>Your account</h1>
 <p>You are logged in as {{ profile.user.username }}</p>
 
@@ -30,8 +37,8 @@
     <dt>Email<dt>
     <dd>{{ profile.user.email}}</dd>
 </dl>
-    {{ form }}
+    {{ form|crispy }}
 
-    <input type="submit" value="Update">
+    <button type="submit" class="btn btn-primary">Save</button
 </form>
 {% endblock %}
diff --git a/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_list.html b/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_list.html
index f3e8e20..8024631 100644
--- a/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_list.html
+++ b/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_list.html
@@ -1,6 +1,13 @@
 {% extends 'uhepp_vault/base.html' %}
 
 {% block content %}
+<nav aria-label="breadcrumb">
+  <ol class="breadcrumb my-2">
+    <li class="breadcrumb-item"><a href="/">Home</a></li>
+    <li class="breadcrumb-item">Explore</li>
+    <li class="breadcrumb-item active"><a class="active" href="{% url 'uhepp_vault:user-list' %}">Users</a></li>
+  </ol>
+</nav>
 <h1>Users</h1>
 {% if profile_list %}
 <ul>
@@ -8,11 +15,10 @@
     <li>
         <a href="{% url 'uhepp_vault:user-detail' profile.user.username %}">
         {{ profile.user.first_name }} {{ profile.user.last_name }}
-        </a>
-        {% if profile.visibility >= 30 %}(public)
-        {% elif profile.visibility >= 20 %}(internal)
-        {% elif profile.visibility >= 10 %}(private)
-        {% endif %}
+<i class="text-muted fas {% if profile.visibility >= 30 %} fa-user
+{% elif profile.visibility >= 20 %} fa-user-shield
+{% elif profile.visibility >= 10 %} fa-user-lock
+{% endif %}"></i></a>
     </li>
   {% endfor %}
 </ul>
diff --git a/uhepp_org/uhepp_vault/views.py b/uhepp_org/uhepp_vault/views.py
index aa396a9..b430005 100644
--- a/uhepp_org/uhepp_vault/views.py
+++ b/uhepp_org/uhepp_vault/views.py
@@ -3,9 +3,11 @@ from django.views import generic
 from django.db.models import Q
 from django.contrib.auth.mixins import LoginRequiredMixin
 from django.http import JsonResponse, HttpResponseRedirect, \
-                        HttpResponseForbidden
+                        HttpResponseForbidden, Http404
 from django.urls import reverse, reverse_lazy
 from django.shortcuts import get_object_or_404, redirect, render
+from django.conf import settings
+
 from django.contrib.auth.decorators import login_required
 from django.contrib.auth.models import User, Group
 from django.utils.translation import gettext_lazy as _
@@ -91,6 +93,14 @@ class UserDetailView(MaskedRelatedMixin, generic.DetailView):
             )
         return queryset
 
+    def get(self, request, *args, **kwargs):
+        try:
+            return super().get(request, *args, **kwargs)
+        except Http404 as original:
+            if not request.user.is_anonymous:
+                raise original
+            return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
+
 class CollectionListView(generic.ListView):
     model = Collection
 
@@ -117,6 +127,14 @@ class CollectionDetailView(generic.DetailView):
             )
         return queryset
 
+    def get(self, request, *args, **kwargs):
+        try:
+            return super().get(request, *args, **kwargs)
+        except Http404 as original:
+            if not request.user.is_anonymous:
+                raise original
+            return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
+
 class CollectionCreateView(LoginRequiredMixin, generic.CreateView):
     model = Collection
     template_name = 'uhepp_vault/collection_form.html'
@@ -190,6 +208,13 @@ class PlotDetail(generic.DetailView):
             )
         return queryset
 
+    def get(self, request, *args, **kwargs):
+        try:
+            return super().get(request, *args, **kwargs)
+        except Http404 as original:
+            if not request.user.is_anonymous:
+                raise original
+            return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
 
 
 def plot_download(request, uuid):
-- 
GitLab