From ebb420e0d782adb1de47c6e2d9e686ef6a913b18 Mon Sep 17 00:00:00 2001
From: Antoine Lambert <antoine.lambert@inria.fr>
Date: Fri, 12 Jan 2018 18:06:20 +0100
Subject: [PATCH] browse: UI improvements for landing page

This commit adds the following improvements:
  - landing page for browse in now the origin search interface
  - use a navbar instead of tabs in browse in order to get
    more vertical space for content display
  - remove the default browsing of torvalds/linux
  - some rework on the search interface

Closes T924
---
 swh/web/browse/urls.py                        |  15 +-
 swh/web/browse/views/content.py               |   3 +-
 swh/web/browse/views/directory.py             |   3 +-
 swh/web/browse/views/origin.py                |  12 +-
 swh/web/browse/views/person.py                |   3 +-
 swh/web/browse/views/revision.py              |   6 +-
 swh/web/templates/api.html                    |   2 +
 swh/web/templates/browse.html                 | 143 ++++++++++--------
 swh/web/templates/homepage.html               |   2 +-
 swh/web/templates/includes/browse-help.html   |   2 +-
 .../templates/includes/origins-search.html    |  44 ++++--
 swh/web/templates/layout.html                 |  23 +--
 swh/web/templates/origin.html                 |  18 ++-
 13 files changed, 161 insertions(+), 115 deletions(-)

diff --git a/swh/web/browse/urls.py b/swh/web/browse/urls.py
index ff02c3f6b..c65ffbb59 100644
--- a/swh/web/browse/urls.py
+++ b/swh/web/browse/urls.py
@@ -4,7 +4,7 @@
 # See top-level LICENSE file for more information
 
 from django.conf.urls import url
-from django.shortcuts import redirect
+from django.shortcuts import render
 
 import swh.web.browse.views.directory # noqa
 import swh.web.browse.views.content # noqa
@@ -13,7 +13,6 @@ import swh.web.browse.views.person # noqa
 import swh.web.browse.views.revision # noqa
 
 from swh.web.browse.browseurls import BrowseUrls
-from swh.web.common.utils import reverse
 
 
 def default_browse_view(request):
@@ -22,18 +21,12 @@ def default_browse_view(request):
 
     The url that point to it is /browse/.
 
-    Currently, it points to the origin view for the linux kernel
-    source tree github mirror.
-
-
     Args:
         request: input django http request
     """
-    linux_origin_url = 'https://github.com/torvalds/linux'
-    default_url = reverse('browse-origin',
-                          kwargs={'origin_type': 'git',
-                                  'origin_url': linux_origin_url})
-    return redirect(default_url)
+    return render(request, 'person.html',
+                  {'heading': 'Browse the Software Heritage archive',
+                   'empty_browse': True})
 
 
 urlpatterns = [
diff --git a/swh/web/browse/views/content.py b/swh/web/browse/views/content.py
index 9d5e92ea3..d1df4789c 100644
--- a/swh/web/browse/views/content.py
+++ b/swh/web/browse/views/content.py
@@ -138,7 +138,8 @@ def content_display(request, query_string):
     }
 
     return render(request, 'content.html',
-                  {'heading': 'Content information',
+                  {'empty_browse': False,
+                   'heading': 'Content information',
                    'top_panel_visible': True,
                    'top_panel_collapsible': True,
                    'top_panel_text_left': 'SWH object: Content',
diff --git a/swh/web/browse/views/directory.py b/swh/web/browse/views/directory.py
index c5c6581f8..a0c405ae0 100644
--- a/swh/web/browse/views/directory.py
+++ b/swh/web/browse/views/directory.py
@@ -89,7 +89,8 @@ def directory_browse(request, sha1_git, path=None):
                     'sum of regular file sizes': sum_file_sizes}
 
     return render(request, 'directory.html',
-                  {'heading': 'Directory information',
+                  {'empty_browse': False,
+                   'heading': 'Directory information',
                    'top_panel_visible': True,
                    'top_panel_collapsible': True,
                    'top_panel_text_left': 'SWH object: Directory',
diff --git a/swh/web/browse/views/origin.py b/swh/web/browse/views/origin.py
index 7b47b7f98..5d53a2f7c 100644
--- a/swh/web/browse/views/origin.py
+++ b/swh/web/browse/views/origin.py
@@ -255,7 +255,8 @@ def origin_directory_browse(request, origin_type, origin_url,
                     'browse revision url': browse_rev_url}
 
     return render(request, 'directory.html',
-                  {'heading': 'Directory information',
+                  {'empty_browse': False,
+                   'heading': 'Directory information',
                    'top_panel_visible': True,
                    'top_panel_collapsible': True,
                    'top_panel_text_left': 'SWH object: Directory',
@@ -426,7 +427,8 @@ def origin_content_display(request, origin_type, origin_url, path,
     }
 
     return render(request, 'content.html',
-                  {'heading': 'Content information',
+                  {'empty_browse': False,
+                   'heading': 'Content information',
                    'top_panel_visible': True,
                    'top_panel_collapsible': True,
                    'top_panel_text_left': 'SWH object: Content',
@@ -593,7 +595,8 @@ def origin_log_browse(request, origin_type, origin_url, timestamp=None):
     }
 
     return render(request, 'revision-log.html',
-                  {'heading': 'Revision history information',
+                  {'empty_browse': False,
+                   'heading': 'Revision history information',
                    'top_panel_visible': True,
                    'top_panel_collapsible': True,
                    'top_panel_text_left': 'SWH object: Revision history',
@@ -664,7 +667,8 @@ def origin_browse(request, origin_type=None, origin_url=None):
             {'date': visit_date.timestamp()})
 
     return render(request, 'origin.html',
-                  {'heading': 'Origin information',
+                  {'empty_browse': False,
+                   'heading': 'Origin information',
                    'top_panel_visible': True,
                    'top_panel_collapsible': True,
                    'top_panel_text_left': 'SWH object: Origin',
diff --git a/swh/web/browse/views/person.py b/swh/web/browse/views/person.py
index 4352152b1..fe40de613 100644
--- a/swh/web/browse/views/person.py
+++ b/swh/web/browse/views/person.py
@@ -32,7 +32,8 @@ def person_browse(request, person_id):
         return handle_view_exception(request, exc)
 
     return render(request, 'person.html',
-                  {'heading': 'Person information',
+                  {'empty_browse': False,
+                   'heading': 'Person information',
                    'top_panel_visible': True,
                    'top_panel_collapsible': False,
                    'top_panel_text_left': 'SWH object: Person',
diff --git a/swh/web/browse/views/revision.py b/swh/web/browse/views/revision.py
index ed440750d..42b343625 100644
--- a/swh/web/browse/views/revision.py
+++ b/swh/web/browse/views/revision.py
@@ -121,7 +121,8 @@ def revision_browse(request, sha1_git):
     revision_data['type'] = revision['type']
 
     return render(request, 'revision.html',
-                  {'heading': 'Revision information',
+                  {'empty_browse': False,
+                   'heading': 'Revision information',
                    'top_panel_visible': False,
                    'top_panel_collapsible': False,
                    'top_panel_text_left': 'SWH object: Revision',
@@ -189,7 +190,8 @@ def revision_log_browse(request, sha1_git):
         log['directory'] = _gen_directory_link(log['directory'], 'Tree')
 
     return render(request, 'revision-log.html',
-                  {'heading': 'Revision history information',
+                  {'empty_browse': False,
+                   'heading': 'Revision history information',
                    'top_panel_visible': False,
                    'top_panel_collapsible': False,
                    'top_panel_text_left': 'SWH object: Revision history',
diff --git a/swh/web/templates/api.html b/swh/web/templates/api.html
index e0fa64f0e..096047901 100644
--- a/swh/web/templates/api.html
+++ b/swh/web/templates/api.html
@@ -11,4 +11,6 @@
       {% include 'includes/apidoc-header.html' %}
     </div>
   </div>
+</div>
+
 {% endblock %}
diff --git a/swh/web/templates/browse.html b/swh/web/templates/browse.html
index 09dfb9bb8..ad192d0d5 100644
--- a/swh/web/templates/browse.html
+++ b/swh/web/templates/browse.html
@@ -3,84 +3,103 @@
 
 {% block title %}{{ heading }} &ndash; Software Heritage archive {% endblock %}
 
-{% block content %}
-
-<ul class="nav nav-tabs">
+{% block navbar-content %}
+<ul class="nav navbar-nav">
   <li class="active">
-    <a  href="#browse" data-toggle="tab" style="outline:none;">Browse</a>
-  </li>
-  <li>
     <a href="#search" data-toggle="tab" style="outline:none;">Search</a>
   </li>
   <li>
     <a  href="#help" data-toggle="tab" style="outline:none;">Help</a>
   </li>
+  <li>
+    <a  href="#browse" data-toggle="tab" style="outline:none;">Browse</a>
+  </li>
 </ul>
+{% endblock %}
+
+{% block content %}
 
 <div class="tab-content" style="margin-top: 5px;">
 
-  <div class="tab-pane active" id="browse">
+  <div class="tab-pane active" id="search">
+    {% include "includes/origins-search.html" %}
+  </div>
+
+  <div class="tab-pane" id="help">
+    {% include "includes/browse-help.html" %}
+  </div>
+
+  <div class="tab-pane" id="browse">
 
-    <div class="panel-group" id="accordion">
-      {% if top_panel_visible %}
+    {% if empty_browse %}
       <div class="panel panel-default" style="overflow-x: auto;">
-          <div class="panel-heading">
+        <div class="panel-heading">
+          <h2>Browse the Software Heritage archive</h2>
+        </div>
+        <div class ="panel-body">
+          <p>
+            No Software Heritage object currently browsed.
+            <br/>
+            To browse the content of the archive, you can either use
+            the <a href="{% url 'browse-homepage' %}#search">Search</a> interface or refer to the URI scheme described
+            in the <a href="{% url 'browse-homepage' %}#help">Help</a> page.
+          </p>
+        </div>
+      </div>
+    {% else %}
+      <div class="panel-group" id="accordion">
+        {% if top_panel_visible %}
+        <div class="panel panel-default" style="overflow-x: auto;">
+            <div class="panel-heading">
+              {% if top_panel_collapsible %}
+              <a data-toggle="collapse" data-parent="#accordion" href="#swh-browse-top-collapse" style="outline:none;">
+              {% endif %}
+                <div class="pull-left">
+                  <h2>{{ top_panel_text_left }}</h2>
+                </div>
+                <div class="pull-right">
+                  <h2>{{ top_panel_text_right }}</h2>
+                </div>
+                <div class="clearfix"></div>
+              {% if top_panel_collapsible %}
+              </a>
+              {% endif %}
+
+            </div>
             {% if top_panel_collapsible %}
-            <a data-toggle="collapse" data-parent="#accordion" href="#swh-browse-top-collapse" style="outline:none;">
+            <div id="swh-browse-top-collapse" class="panel-collapse collapse">
             {% endif %}
-              <div class="pull-left">
-                <h2>{{ top_panel_text_left }}</h2>
-              </div>
-              <div class="pull-right">
-                <h2>{{ top_panel_text_right }}</h2>
-              </div>
-              <div class="clearfix"></div>
+              <table class="table">
+                <tbody>
+                  {% for key, val in swh_object_metadata.items|dictsort:"0.lower" %}
+                    <tr>
+                      <th class="swh-metadata-table-row">{{ key }}</th>
+                      <td class="swh-metadata-table-row">
+                        <pre>{{ val | safe | urlize_links_and_mails | safe }}</pre>
+                      </td>
+                    </tr>
+                  {% endfor %}
+                </tbody>
+              </table>
             {% if top_panel_collapsible %}
-            </a>
+            </div>
             {% endif %}
+        </div>
+        {% endif %}
+        {% if main_panel_visible %}
+        <div class="panel panel-default" style="overflow-x: auto;">
+          {% block swh-browse-main-panel-content %}{% endblock %}
+        </div>
+        {% endif %}
+
+        {% block swh-browse-panels-group-end %}{% endblock %}
 
-          </div>
-          {% if top_panel_collapsible %}
-          <div id="swh-browse-top-collapse" class="panel-collapse collapse">
-          {% endif %}
-            <table class="table">
-              <tbody>
-                {% for key, val in swh_object_metadata.items|dictsort:"0.lower" %}
-                  <tr>
-                    <th class="swh-metadata-table-row">{{ key }}</th>
-                    <td class="swh-metadata-table-row">
-                      <pre>{{ val | safe | urlize_links_and_mails | safe }}</pre>
-                    </td>
-                  </tr>
-                {% endfor %}
-              </tbody>
-            </table>
-          {% if top_panel_collapsible %}
-          </div>
-          {% endif %}
-      </div>
-      {% endif %}
-      {% if main_panel_visible %}
-      <div class="panel panel-default" style="overflow-x: auto;">
-        {% block swh-browse-main-panel-content %}{% endblock %}
       </div>
-      {% endif %}
 
-      {% block swh-browse-panels-group-end %}{% endblock %}
+      {% block swh-browse-after-panels %}{% endblock %}
 
     </div>
-
-    {% block swh-browse-after-panels %}{% endblock %}
-
-  </div>
-
-  <div class="tab-pane" id="search">
-    {% include "includes/origins-search.html" %}
-  </div>
-
-  <div class="tab-pane" id="help">
-    {% include "includes/browse-help.html" %}
-  </div>
+  {% endif %}
 
 </div>
 
@@ -95,22 +114,22 @@
   // Javascript to enable link to tab
   function show_requested_tab() {
     var hash = window.location.hash;
-    if (browse_tabs_hash.indexOf(hash) == -1) {
+    if (hash && browse_tabs_hash.indexOf(hash) == -1) {
       return;
     }
     if (hash) {
-      $('.nav-tabs a[href="' + hash + '"]').tab('show');
+      $('.navbar-nav a[href="' + hash + '"]').tab('show');
     } else {
-      $('.nav-tabs a[href="#browse"]').tab('show');
+      $('.navbar-nav a[href="#browse"]').tab('show');
     }
-    window.scrollTo(0, 0);
+      window.scrollTo(0, 0);
   }
 
   // show requested tab when loading the page
   $(document).ready(function() {
 
     // Change hash for page reload
-    $('.nav-tabs a').on('shown.bs.tab', function (e) {
+    $('.navbar-nav a').on('shown.bs.tab', function (e) {
       if (e.target.hash != '#browse') {
         window.location.hash = e.target.hash;
       } else {
diff --git a/swh/web/templates/homepage.html b/swh/web/templates/homepage.html
index 84e94ba8a..b8d13a586 100644
--- a/swh/web/templates/homepage.html
+++ b/swh/web/templates/homepage.html
@@ -82,7 +82,7 @@ archive. It currently includes:
     </a>
   </div>
   <div class="col-md-3 swh-web-app-link" align="center">
-    <a href="{% url 'browse-homepage' %}#help">
+    <a href="{% url 'browse-homepage' %}#search">
       <img alt="Browse the Software Heritage archive" src="{% static 'img/swh-browse.png' %}"/>
       <h3>Browse</h3>
       <p>Explore the archive using a dedicated web interface.</p>
diff --git a/swh/web/templates/includes/browse-help.html b/swh/web/templates/includes/browse-help.html
index b75f7c012..f1b5c04e7 100644
--- a/swh/web/templates/includes/browse-help.html
+++ b/swh/web/templates/includes/browse-help.html
@@ -1,7 +1,7 @@
 
 <div class="panel panel-default" style="overflow-x: auto;">
   <div class="panel-heading">
-    <h2>Browse the Software Heritage archive</h2>
+    <h2>How to browse the Software Heritage archive ?</h2>
   </div>
   <div class ="panel-body">
 
diff --git a/swh/web/templates/includes/origins-search.html b/swh/web/templates/includes/origins-search.html
index 50f9903bf..11dfba307 100644
--- a/swh/web/templates/includes/origins-search.html
+++ b/swh/web/templates/includes/origins-search.html
@@ -19,22 +19,28 @@
       <p>Searching origins ...</p>
     </div>
 
-    <div class="table-responsive">
-      <table class="table" id="origin-search-results">
-        <thead>
-          <tr>
-            <th>Origin type</th>
-            <th>Origin browse url</th>
-          </tr>
-        </thead>
-        <tbody></tbody>
-      </table>
-    </div>
+    <div id="swh-origin-search-results" style="display: none;">
+      <div class="table-responsive">
+        <table class="table" id="origin-search-results">
+          <thead>
+            <tr>
+              <th>Origin type</th>
+              <th>Origin browse url</th>
+            </tr>
+          </thead>
+          <tbody></tbody>
+        </table>
+      </div>
 
-    <ul class="pager">
-      <li class="disabled" id="origins-prev-results-button" style="cursor:pointer"><a>Previous</a></li>
-      <li class="disabled" id="origins-next-results-button" style="cursor:pointer"><a>Next</a></li>
-    </ul>
+      <ul class="pager">
+        <li class="disabled" id="origins-prev-results-button" style="cursor:pointer"><a>Previous</a></li>
+        <li class="disabled" id="origins-next-results-button" style="cursor:pointer"><a>Next</a></li>
+      </ul>
+    </div>
+    <p id="swh-no-origins-found" style="display: none;">
+      <br/>
+      No origins matching the search criteria were found
+    </p>
   </div>
 </div>
 <script>
@@ -51,6 +57,8 @@
   function populateOriginSearchResultsTable(data, offset) {
     var local_offset = offset % limit;
     if (data.length > 0) {
+      $("#swh-origin-search-results").show();
+      $("#swh-no-origins-found").hide();
       $("#origin-search-results tbody tr").remove();
       var table = $("#origin-search-results tbody");
       for (var i = local_offset ; i < local_offset + per_page && i < data.length ; ++i) {
@@ -62,6 +70,9 @@
         tableRow += '</tr>';
         table.append(tableRow);
       }
+    } else {
+      $("#swh-origin-search-results").hide();
+      $("#swh-no-origins-found").show();
     }
     if (data.length - local_offset < per_page ||
         (data.length < limit && (local_offset + per_page) == data.length)) {
@@ -75,6 +86,9 @@
       $('#origins-prev-results-button').addClass('disabled');
     }
     in_search = false;
+    setTimeout(function() {
+      window.scrollTo(0, 0);
+    });
   }
 
   $(document).ready(function() {
diff --git a/swh/web/templates/layout.html b/swh/web/templates/layout.html
index 9309ea0e2..46db1317b 100644
--- a/swh/web/templates/layout.html
+++ b/swh/web/templates/layout.html
@@ -29,15 +29,20 @@
     <link rel="icon" href="{% static 'img/icons/swh-logo-archive-192x192.png' %}" sizes="192x192" />
     <link rel="apple-touch-icon-precomposed" href="{% static 'img/icons/swh-logo-archive-180x180.png' %}" />
     <meta name="msapplication-TileImage" content="{% static 'img/icons/swh-logo-archive-270x270.png' %}" />
-    <script>document.domain = "softwareheritage.org";</script>
+    <script>document.domain = "archive.softwareheritage.org";</script>
 
   </head>
-  <body
+  <body>
     <a id="top"></a>
     <nav class="navbar navbar-default navbar-static-top" id="swh-navbar-collapse">
       <div class="navbar-header">
+        <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#swh-collapse-navbar" aria-expanded="false">
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+          <span class="icon-bar"></span>
+        </button>
         <div class="logo">
-          <a class="navbar-brand" href="{% url 'swh-web-homepage' %}"> <!-- logo -->
+          <a class="navbar-brand" href="{% url 'swh-web-homepage' %}">
             <img alt="SWH Archive" src="{% static 'img/swh-logo-archive.png' %}" class="swh-logo" />
           </a>
           <a class="navbar-brand sitename" href="{% url 'swh-web-homepage' %}">
@@ -45,15 +50,15 @@
           </a>
         </div>
       </div>
+      <div class="collapse navbar-collapse" id="swh-collapse-navbar">
+        {% block navbar-content %}{% endblock %}
+      </div>
     </nav>
 
-    <div class="container">
-      <div class="container">
-      </div>
-      <div class="container content">
-        {% block content %}{% endblock %}
-      </div>
+    <div class="container content">
+      {% block content %}{% endblock %}
     </div>
+
     <div id="footer" class="panel-footer">
       <a href="https://www.softwareheritage.org">Software Heritage</a> &mdash;
       Copyright (C) 2015&ndash;{% now "Y" %}, The Software Heritage developers.
diff --git a/swh/web/templates/origin.html b/swh/web/templates/origin.html
index 2b510978a..29d32046e 100644
--- a/swh/web/templates/origin.html
+++ b/swh/web/templates/origin.html
@@ -9,8 +9,8 @@
   <h3>Calendar</h3>
   <div class="timeline" style="margin-bottom: 20px">
     <div id="swh-calendar-window" style="height: 200px">
-      <div id="cal-zoom-window" style="height: 60%"></div>
-      <div id="cal-static-window" style="height: 40%"></div>
+      <div id="cal-zoom-window" style="width: 100%; height: 60%"></div>
+      <div id="cal-static-window" style="width: 100%; height: 40%"></div>
     </div>
     <button class="btn btn-sm btn-swh pull-right" id="cal-clear">Reset zoom</button>
   </div>
@@ -46,11 +46,15 @@
 <script language="javascript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/flot.tooltip/0.9.0/jquery.flot.tooltip.min.js"></script>
 <script language="javascript" type="text/javascript" src="{% static 'js/calendar.js' %}"></script>
 <script>
-$(function(){
-  var cal = new Calendar('{{ browse_url_base }}', {{ origin_visits_data | safe }},
-                         {{ swh_object_metadata.id }}, $('#cal-zoom-window'),
-                         $('#cal-static-window'),  $('#cal-clear'));
-});
+  var cal = null;
+  $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
+    var target = $(e.target).attr("href");
+    if (!cal && target == '#browse') {
+      cal = new Calendar('{{ browse_url_base }}', {{ origin_visits_data | safe }},
+                          {{ swh_object_metadata.id }}, $('#cal-zoom-window'),
+                          $('#cal-static-window'),  $('#cal-clear'));
+    }
+  });
 </script>
 
 {% endblock %}
-- 
GitLab