diff --git a/cypress/integration/origin-browse.spec.js b/cypress/integration/origin-browse.spec.js
new file mode 100644
index 00000000..30f4b02a
--- /dev/null
+++ b/cypress/integration/origin-browse.spec.js
@@ -0,0 +1,87 @@
+/**
+ * Copyright (C) 2020  The Software Heritage developers
+ * See the AUTHORS file at the top-level directory of this distribution
+ * License: GNU Affero General Public License version 3, or any later version
+ * See top-level LICENSE file for more information
+ */
+
+describe('Test origin browse', function() {
+  beforeEach(function() {
+    const url = `${this.Urls.browse_origin()}?origin_url=${this.origin[1].url}`;
+    cy.visit(url);
+  });
+
+  it('should have code tab active by default', function() {
+    cy.get('#swh-browse-code-nav-link')
+      .should('have.class', 'active');
+  });
+
+  it('should load branches view when clicking on the Branches tab', function() {
+    cy.get('#swh-browse-snapshot-branches-nav-link')
+      .click();
+
+    cy.location('pathname')
+      .should('eq', this.Urls.browse_origin_branches());
+
+    cy.location('search')
+      .should('eq', `?origin_url=${this.origin[1].url}`);
+
+    cy.get('#swh-browse-snapshot-branches-nav-link')
+      .should('have.class', 'active');
+  });
+
+  it('should load releases view when clicking on the Releases tab', function() {
+    cy.get('#swh-browse-snapshot-releases-nav-link')
+      .click();
+
+    cy.location('pathname')
+      .should('eq', this.Urls.browse_origin_releases());
+
+    cy.location('search')
+      .should('eq', `?origin_url=${this.origin[1].url}`);
+
+    cy.get('#swh-browse-snapshot-releases-nav-link')
+      .should('have.class', 'active');
+  });
+
+  it('should load visits view when clicking on the Visits tab', function() {
+    cy.get('#swh-browse-origin-visits-nav-link')
+      .click();
+
+    cy.location('pathname')
+      .should('eq', this.Urls.browse_origin_visits());
+
+    cy.location('search')
+      .should('eq', `?origin_url=${this.origin[1].url}`);
+
+    cy.get('#swh-browse-origin-visits-nav-link')
+      .should('have.class', 'active');
+  });
+
+  it('should load code view when clicking on the Code tab', function() {
+    cy.get('#swh-browse-origin-visits-nav-link')
+      .click();
+
+    cy.get('#swh-browse-code-nav-link')
+      .click();
+
+    cy.location('pathname')
+      .should('eq', this.Urls.browse_origin_directory());
+
+    cy.location('search')
+      .should('eq', `?origin_url=${this.origin[1].url}`);
+
+    cy.get('#swh-browse-code-nav-link')
+      .should('have.class', 'active');
+
+  });
+
+  it('should have Releases tab link disabled when there is no releases', function() {
+    const url = `${this.Urls.browse_origin()}?origin_url=${this.origin[0].url}`;
+    cy.visit(url);
+
+    cy.get('#swh-browse-snapshot-releases-nav-link')
+      .should('have.class', 'disabled');
+  });
+
+});
diff --git a/swh/web/assets/src/bundles/browse/browse-utils.js b/swh/web/assets/src/bundles/browse/browse-utils.js
index 0dd6f8fa..a7bb7ca9 100644
--- a/swh/web/assets/src/bundles/browse/browse-utils.js
+++ b/swh/web/assets/src/bundles/browse/browse-utils.js
@@ -1,72 +1,86 @@
 /**
- * Copyright (C) 2018-2019  The Software Heritage developers
+ * Copyright (C) 2018-2020  The Software Heritage developers
  * See the AUTHORS file at the top-level directory of this distribution
  * License: GNU Affero General Public License version 3, or any later version
  * See top-level LICENSE file for more information
  */
 
 import {BREAKPOINT_SM} from 'utils/constants';
 
 $(document).ready(() => {
 
   $('.dropdown-submenu a.dropdown-item').on('click', e => {
     $(e.target).next('div').toggle();
     if ($(e.target).next('div').css('display') !== 'none') {
       $(e.target).focus();
     } else {
       $(e.target).blur();
     }
     e.stopPropagation();
     e.preventDefault();
   });
 
   $('.swh-popover-toggler').popover({
     boundary: 'viewport',
     container: 'body',
     html: true,
     placement: function() {
       const width = $(window).width();
       if (width < BREAKPOINT_SM) {
         return 'top';
       } else {
         return 'right';
       }
     },
     template: `<div class="popover" role="tooltip">
                  <div class="arrow"></div>
                  <h3 class="popover-header"></h3>
                  <div class="popover-body swh-popover"></div>
                </div>`,
     content: function() {
       var content = $(this).attr('data-popover-content');
       return $(content).children('.popover-body').remove().html();
     },
     title: function() {
       var title = $(this).attr('data-popover-content');
       return $(title).children('.popover-heading').html();
     },
     offset: '50vh',
     sanitize: false
   });
 
   $('.swh-vault-menu a.dropdown-item').on('click', e => {
     $('.swh-popover-toggler').popover('hide');
   });
 
   $('.swh-popover-toggler').on('show.bs.popover', (e) => {
     $(`.swh-popover-toggler:not(#${e.currentTarget.id})`).popover('hide');
     $('.swh-vault-menu .dropdown-menu').hide();
   });
 
   $('.swh-actions-dropdown').on('hide.bs.dropdown', () => {
     $('.swh-vault-menu .dropdown-menu').hide();
     $('.swh-popover-toggler').popover('hide');
   });
 
   $('body').on('click', e => {
     if ($(e.target).parents('.swh-popover').length) {
       e.stopPropagation();
     }
   });
 
 });
+
+export function initBrowseNavbar() {
+  if (window.location.pathname === Urls.browse_origin_visits()) {
+    $('#swh-browse-origin-visits-nav-link').addClass('active');
+  } else if (window.location.pathname === Urls.browse_origin_branches() ||
+    window.location.pathname === Urls.browse_snapshot_branches()) {
+    $('#swh-browse-snapshot-branches-nav-link').addClass('active');
+  } else if (window.location.pathname === Urls.browse_origin_releases() ||
+             window.location.pathname === Urls.browse_snapshot_releases()) {
+    $('#swh-browse-snapshot-releases-nav-link').addClass('active');
+  } else {
+    $('#swh-browse-code-nav-link').addClass('active');
+  }
+}
diff --git a/swh/web/assets/src/bundles/webapp/webapp.css b/swh/web/assets/src/bundles/webapp/webapp.css
index 91073170..6b252251 100644
--- a/swh/web/assets/src/bundles/webapp/webapp.css
+++ b/swh/web/assets/src/bundles/webapp/webapp.css
@@ -1,679 +1,675 @@
 /**
- * Copyright (C) 2018-2019  The Software Heritage developers
+ * Copyright (C) 2018-2020  The Software Heritage developers
  * See the AUTHORS file at the top-level directory of this distribution
  * License: GNU Affero General Public License version 3, or any later version
  * See top-level LICENSE file for more information
  */
 
 html {
     height: 100%;
     overflow-x: hidden;
     scroll-behavior: auto !important;
 }
 
 body {
     min-height: 100%;
     margin: 0;
     position: relative;
     padding-bottom: 120px;
 }
 
 a:active,
 a.active {
     outline: none;
 }
 
 code {
     background-color: #f9f2f4;
 }
 
 pre code {
     background-color: transparent;
 }
 
 footer {
     background-color: #262626;
     color: #fff;
     font-size: 0.8rem;
     position: absolute;
     bottom: 0;
     width: 100%;
     padding-top: 20px;
     padding-bottom: 20px;
 }
 
 footer a,
 footer a:visited,
 footer a:hover {
     color: #fecd1b;
 }
 
 footer a:hover {
     text-decoration: underline;
 }
 
 .link-color {
     color: #fecd1b;
 }
 
 pre {
     background-color: #f5f5f5;
     border: 1px solid #ccc;
     border-radius: 4px;
     padding: 9.5px;
     font-size: 0.8rem;
 }
 
 .btn.active {
     background-color: #e7e7e7;
 }
 
 .card {
     margin-bottom: 5px !important;
     overflow-x: auto;
 }
 
 .navbar-brand {
     padding: 5px;
     margin-right: 0;
 }
 
 .table {
     margin-bottom: 0;
 }
 
 .swh-table thead {
     background-color: #f2f4f5;
     border-top: 1px solid rgba(0, 0, 0, 0.2);
     font-weight: normal;
 }
 
 .swh-table-striped th {
     border-top: none;
 }
 
 .swh-table-striped tbody tr:nth-child(even) {
     background-color: #f2f4f5;
 }
 
 .swh-table-striped tbody tr:nth-child(odd) {
     background-color: #fff;
 }
 
 .swh-web-app-link a {
     text-decoration: none;
     border: none;
 }
 
 .swh-web-app-link:hover {
     background-color: #efeff2;
 }
 
 .table > thead > tr > th {
     border-top: none;
     border-bottom: 1px solid #e20026;
 }
 
 .table > tbody > tr > td {
     border-style: none;
 }
 
 .sitename .first-word,
 .sitename .second-word {
     color: rgba(0, 0, 0, 0.75);
     font-weight: normal;
     font-size: 1.2rem;
 }
 
 .sitename .first-word {
     font-family: 'Alegreya Sans', sans-serif;
 }
 
 .sitename .second-word {
     font-family: 'Alegreya', serif;
 }
 
 .swh-counter {
     font-size: 150%;
 }
 
 @media (max-width: 600px) {
     .swh-counter-container {
         margin-top: 1rem;
     }
 }
 
 .swh-http-error {
     margin: 0 auto;
     text-align: center;
 }
 
 .swh-http-error-head {
     color: #2d353c;
     font-size: 30px;
 }
 
 .swh-http-error-code {
     bottom: 60%;
     color: #2d353c;
     font-size: 96px;
     line-height: 80px;
     margin-bottom: 10px !important;
 }
 
 .swh-http-error-desc {
     font-size: 12px;
     color: #647788;
     text-align: center;
 }
 
 .swh-http-error-desc pre {
     display: inline-block;
     text-align: left;
     max-width: 800px;
     white-space: pre-wrap;
 }
 
 .swh-list-unstyled {
     list-style: none;
 }
 
 .popover {
     max-width: 97%;
     z-index: 40000;
 }
 
 .modal {
     text-align: center;
     padding: 0 !important;
     z-index: 50000;
 }
 
 .modal::before {
     content: '';
     display: inline-block;
     height: 100%;
     vertical-align: middle;
     margin-right: -4px;
 }
 
 .modal-dialog {
     display: inline-block;
     text-align: left;
     vertical-align: middle;
 }
 
 .dropdown-submenu {
     position: relative;
 }
 
 .dropdown-submenu .dropdown-menu {
     top: 0;
     left: -100%;
     margin-top: -5px;
     margin-left: -2px;
 }
 
 .dropdown-item:hover,
 .dropdown-item:focus {
     background-color: rgba(0, 0, 0, 0.1);
 }
 
 a.dropdown-left::before {
     content: "\f035e";
     font-family: 'Material Design Icons';
     display: block;
     width: 20px;
     height: 20px;
     float: left;
     margin-left: 0;
 }
 
 #swh-navbar {
     border-top-style: none;
     border-left-style: none;
     border-right-style: none;
     border-bottom-style: solid;
     border-bottom-width: 5px;
     border-image: linear-gradient(to right, rgb(226, 0, 38) 0%, rgb(254, 205, 27) 100%) 1 1 1 1;
     width: 100%;
     padding: 5px;
     margin-bottom: 10px;
     margin-top: 30px;
     justify-content: normal;
     flex-wrap: nowrap;
     height: 72px;
     overflow: hidden;
 }
 
 #back-to-top {
     display: none;
     position: fixed;
     bottom: 30px;
     right: 30px;
     z-index: 10;
 }
 
 #back-to-top a img {
     display: block;
     width: 32px;
     height: 32px;
     background-size: 32px 32px;
     text-indent: -999px;
     overflow: hidden;
 }
 
 .swh-top-bar {
     direction: ltr;
     height: 30px;
     position: fixed;
     top: 0;
     left: 0;
     width: 100%;
     z-index: 99999;
     background-color: #262626;
     color: #fff;
     text-align: center;
     font-size: 14px;
 }
 
 .swh-top-bar ul {
     margin-top: 4px;
     padding-left: 0;
     white-space: nowrap;
 }
 
 .swh-top-bar li {
     display: inline-block;
     margin-left: 10px;
     margin-right: 10px;
 }
 
 .swh-top-bar a,
 .swh-top-bar a:visited {
     color: white;
 }
 
 .swh-top-bar a.swh-current-site,
 .swh-top-bar a.swh-current-site:visited {
     color: #fecd1b;
 }
 
 .swh-position-left {
     position: absolute;
     left: 0;
 }
 
 .swh-position-right {
     position: absolute;
     right: 0;
 }
 
 .swh-background-gray {
     background: #efeff2;
 }
 
 .swh-donate-link {
     border: 1px solid #fecd1b;
     background-color: #e20026;
     color: white !important;
     padding: 3px;
     border-radius: 3px;
 }
 
 .swh-navbar-content h4 {
     padding-top: 7px;
 }
 
 .swh-navbar-content .bread-crumbs {
     display: block;
     margin-left: -40px;
 }
 
 .swh-navbar-content .bread-crumbs li.bc-no-root {
     padding-top: 7px;
 }
 
 .main-sidebar {
     margin-top: 30px;
 }
 
 .content-wrapper {
     background: none;
 }
 
 .brand-image {
     max-height: 40px;
 }
 
 .brand-link {
     padding-top: 18.5px;
     padding-bottom: 18px;
     padding-left: 4px;
     border-bottom: 5px solid #e20026 !important;
 }
 
 .navbar-header a,
 ul.dropdown-menu a,
 ul.navbar-nav a,
 ul.nav-sidebar a {
     border-bottom-style: none;
     color: #323232;
 }
 
 .swh-sidebar .nav-link.active {
     color: #323232 !important;
     background-color: #e7e7e7 !important;
 }
 
 .nav-tabs .nav-link.active {
     border-top: 3px solid #e20026;
 }
 
 .swh-image-error {
     width: 80px;
     height: auto;
 }
 
 @media (max-width: 600px) {
     .card {
         min-width: 80%;
     }
 
     .swh-image-error {
         width: 40px;
         height: auto;
     }
 
-    .swh-navbar-content h4 {
-        font-size: 1rem;
-    }
-
     .swh-donate-link {
         display: none;
     }
 }
 
 .form-check-label {
     padding-top: 4px;
 }
 
 .swh-id {
     white-space: pre-wrap;
 }
 
 .swh-id .swh-id-option {
     display: inline-block;
     margin-right: 5px;
     line-height: 1rem;
 }
 
 .nav-pills .nav-link:not(.active):hover {
     color: rgba(0, 0, 0, 0.55);
 }
 
 .swh-heading-color {
     color: #e20026 !important;
 }
 
 .sidebar-mini.sidebar-collapse .main-sidebar:hover {
     width: 4.6rem;
 }
 
 .sidebar-mini.sidebar-collapse .main-sidebar:hover .user-panel > .info,
 .sidebar-mini.sidebar-collapse .main-sidebar:hover .nav-sidebar .nav-link p,
 .sidebar-mini.sidebar-collapse .main-sidebar:hover .brand-text {
     visibility: hidden !important;
 }
 
 .sidebar .nav-link p,
 .main-sidebar .brand-text,
 .sidebar .user-panel .info {
     transition: none;
 }
 
 .sidebar-mini.sidebar-mini.sidebar-collapse .sidebar {
     padding-right: 0;
 }
 
 .swh-words-logo {
     position: absolute;
     top: 0;
     left: 0;
     width: 73px;
     height: 73px;
     text-align: center;
     font-size: 10pt;
     color: rgba(0, 0, 0, 0.75);
 }
 
 .swh-words-logo:hover {
     text-decoration: none;
 }
 
 .swh-words-logo-swh {
     line-height: 1;
     padding-top: 13px;
     visibility: hidden;
 }
 
 hr.swh-faded-line {
     border: 0;
     height: 1px;
     background-image: linear-gradient(to left, #f0f0f0, #8c8b8b, #f0f0f0);
 }
 
 /* Ensure that section title with link is colored like standard section title */
 .swh-readme h1 a,
 .swh-readme h2 a,
 .swh-readme h3 a,
 .swh-readme h4 a,
 .swh-readme h5 a,
 .swh-readme h6 a {
     color: #e20026;
 }
 
 /* Make list compact in reStructuredText rendering */
 .swh-rst li p {
     margin-bottom: 0;
 }
 
 .swh-readme-txt pre {
     background: none;
     border: none;
 }
 
 .swh-coverage-col {
     padding-left: 10px;
     padding-right: 10px;
 }
 
 .swh-coverage {
     height: calc(65px + 1em);
     padding-top: 0.3rem;
     border: none;
 }
 
 .swh-coverage a {
     text-decoration: none;
 }
 
 .swh-coverage-logo {
     display: block;
     width: 100%;
     height: 50px;
     margin-left: auto;
     margin-right: auto;
     object-fit: contain;
 
     /* polyfill for old browsers, see https://github.com/bfred-it/object-fit-images */
     font-family: 'object-fit: contain;';
 }
 
 .swh-coverage-list {
     width: 100%;
     height: 320px;
     border: none;
 }
 
 tr.swh-tr-hover-highlight:hover td {
     background: #ededed;
 }
 
 tr.swh-api-doc-route a {
     text-decoration: none;
 }
 
 .swh-apidoc .col {
     margin: 10px;
 }
 
 .swh-apidoc .swh-rst blockquote {
     border: 0;
     margin: 0;
     padding: 0;
 }
 
 a.toggle-col {
     text-decoration: none;
 }
 
 a.toggle-col.col-hidden {
     text-decoration: line-through;
 }
 
 .admonition.warning {
     background: #fcf8e3;
     border: 1px solid #faebcc;
     padding: 15px;
     border-radius: 4px;
 }
 
 .admonition.warning p {
     margin-bottom: 0;
 }
 
 .admonition.warning .first {
     font-size: 1.5rem;
 }
 
 .swh-popover {
     max-height: 50vh;
     overflow-y: auto;
     overflow-x: auto;
     padding: 0;
     padding-right: 1.4em;
 }
 
 @media screen and (min-width: 768px) {
     .swh-popover {
         max-width: 50vw;
     }
 }
 
 .swh-metadata-table-row {
     border-top: 1px solid #ddd !important;
 }
 
 .swh-metadata-table-key {
     min-width: 200px;
     max-width: 200px;
     width: 200px;
 }
 
 .swh-metadata-table-value pre {
     white-space: pre-wrap;
 }
 
 .d3-wrapper {
     position: relative;
     height: 0;
     width: 100%;
     padding: 0;
 
     /* padding-bottom will be overwritten by JavaScript later */
     padding-bottom: 100%;
 }
 
 .d3-wrapper > svg {
     position: absolute;
     height: 100%;
     width: 100%;
     left: 0;
     top: 0;
 }
 
 div.d3-tooltip {
     position: absolute;
     text-align: center;
     width: auto;
     height: auto;
     padding: 2px;
     font: 12px sans-serif;
     background: white;
     border: 1px solid black;
     border-radius: 4px;
     pointer-events: none;
 }
 
 .page-link {
     cursor: pointer;
 }
 
 .wrapper {
     overflow: hidden;
 }
 
 .swh-badge {
     padding-bottom: 1rem;
     cursor: pointer;
 }
 
 .swh-badge-html,
 .swh-badge-md,
 .swh-badge-rst {
     white-space: pre-wrap;
 }
 
 /* Material Design icons alignment tweaks */
 
 .mdi {
     display: inline-block;
 }
 
 .mdi-camera {
     transform: translateY(1px);
 }
 
 .mdi-source-commit {
     transform: translateY(2px);
 }
 
 /* To set icons at a fixed width. Great to use when different
    icon widths throw off alignment. Courtesy of Font Awesome. */
 .mdi-fw {
     text-align: center;
     width: 1.25em;
 }
 
 .main-header .nav-link {
     height: inherit;
 }
 
 .nav-sidebar .nav-header:not(:first-of-type) {
     padding-top: 1rem;
 }
 
 .nav-sidebar .nav-link {
     padding-top: 0;
     padding-bottom: 0;
 }
 
 .nav-sidebar > .nav-item .nav-icon {
     vertical-align: sub;
 }
 
 .swh-search-icon {
     line-height: 1rem;
     vertical-align: middle;
 }
diff --git a/swh/web/common/utils.py b/swh/web/common/utils.py
index d28a2a74..9ff3fb7e 100644
--- a/swh/web/common/utils.py
+++ b/swh/web/common/utils.py
@@ -1,364 +1,365 @@
 # Copyright (C) 2017-2020  The Software Heritage developers
 # See the AUTHORS file at the top-level directory of this distribution
 # License: GNU Affero General Public License version 3, or any later version
 # See top-level LICENSE file for more information
 
 import re
 
 from datetime import datetime, timezone
 from dateutil import parser as date_parser
 from dateutil import tz
 
 from typing import Optional, Dict, Any
 
 import docutils.parsers.rst
 import docutils.utils
 
 from bs4 import BeautifulSoup
 
 from docutils.core import publish_parts
 from docutils.writers.html5_polyglot import Writer, HTMLTranslator
 
 from django.urls import reverse as django_reverse
 from django.http import QueryDict, HttpRequest
 
 from prometheus_client.registry import CollectorRegistry
 
 from rest_framework.authentication import SessionAuthentication
 
 from swh.web.common.exc import BadInputExc
 from swh.web.common.typing import QueryParameters
 from swh.web.config import get_config
 
 
 SWH_WEB_METRICS_REGISTRY = CollectorRegistry(auto_describe=True)
 
 swh_object_icons = {
     "branch": "mdi mdi-source-branch",
     "branches": "mdi mdi-source-branch",
     "content": "mdi mdi-file-document",
     "directory": "mdi mdi-folder",
+    "origin": "mdi mdi-source-repository",
     "person": "mdi mdi-account",
     "revisions history": "mdi mdi-history",
     "release": "mdi mdi-tag",
     "releases": "mdi mdi-tag",
     "revision": "mdi mdi-rotate-90 mdi-source-commit",
     "snapshot": "mdi mdi-camera",
     "visits": "mdi mdi-calendar-month",
 }
 
 
 def reverse(
     viewname: str,
     url_args: Optional[Dict[str, Any]] = None,
     query_params: Optional[QueryParameters] = None,
     current_app: Optional[str] = None,
     urlconf: Optional[str] = None,
     request: Optional[HttpRequest] = None,
 ) -> str:
     """An override of django reverse function supporting query parameters.
 
     Args:
         viewname: the name of the django view from which to compute a url
         url_args: dictionary of url arguments indexed by their names
         query_params: dictionary of query parameters to append to the
             reversed url
         current_app: the name of the django app tighten to the view
         urlconf: url configuration module
         request: build an absolute URI if provided
 
     Returns:
         str: the url of the requested view with processed arguments and
         query parameters
     """
 
     if url_args:
         url_args = {k: v for k, v in url_args.items() if v is not None}
 
     url = django_reverse(
         viewname, urlconf=urlconf, kwargs=url_args, current_app=current_app
     )
 
     if query_params:
         query_params = {k: v for k, v in query_params.items() if v}
 
     if query_params and len(query_params) > 0:
         query_dict = QueryDict("", mutable=True)
         for k in sorted(query_params.keys()):
             query_dict[k] = query_params[k]
         url += "?" + query_dict.urlencode(safe="/;:")
 
     if request is not None:
         url = request.build_absolute_uri(url)
 
     return url
 
 
 def datetime_to_utc(date):
     """Returns datetime in UTC without timezone info
 
     Args:
         date (datetime.datetime): input datetime with timezone info
 
     Returns:
         datetime.datetime: datetime in UTC without timezone info
     """
     if date.tzinfo:
         return date.astimezone(tz.gettz("UTC")).replace(tzinfo=timezone.utc)
     else:
         return date
 
 
 def parse_timestamp(timestamp):
     """Given a time or timestamp (as string), parse the result as UTC datetime.
 
     Returns:
         datetime.datetime: a timezone-aware datetime representing the
             parsed value or None if the parsing fails.
 
     Samples:
         - 2016-01-12
         - 2016-01-12T09:19:12+0100
         - Today is January 1, 2047 at 8:21:00AM
         - 1452591542
 
     """
     if not timestamp:
         return None
 
     try:
         date = date_parser.parse(timestamp, ignoretz=False, fuzzy=True)
         return datetime_to_utc(date)
     except Exception:
         try:
             return datetime.utcfromtimestamp(float(timestamp)).replace(
                 tzinfo=timezone.utc
             )
         except (ValueError, OverflowError) as e:
             raise BadInputExc(e)
 
 
 def shorten_path(path):
     """Shorten the given path: for each hash present, only return the first
     8 characters followed by an ellipsis"""
 
     sha256_re = r"([0-9a-f]{8})[0-9a-z]{56}"
     sha1_re = r"([0-9a-f]{8})[0-9a-f]{32}"
 
     ret = re.sub(sha256_re, r"\1...", path)
     return re.sub(sha1_re, r"\1...", ret)
 
 
 def format_utc_iso_date(iso_date, fmt="%d %B %Y, %H:%M UTC"):
     """Turns a string representation of an ISO 8601 date string
     to UTC and format it into a more human readable one.
 
     For instance, from the following input
     string: '2017-05-04T13:27:13+02:00' the following one
     is returned: '04 May 2017, 11:27 UTC'.
     Custom format string may also be provided
     as parameter
 
     Args:
         iso_date (str): a string representation of an ISO 8601 date
         fmt (str): optional date formatting string
 
     Returns:
         str: a formatted string representation of the input iso date
     """
     if not iso_date:
         return iso_date
     date = parse_timestamp(iso_date)
     return date.strftime(fmt)
 
 
 def gen_path_info(path):
     """Function to generate path data navigation for use
     with a breadcrumb in the swh web ui.
 
     For instance, from a path /folder1/folder2/folder3,
     it returns the following list::
 
         [{'name': 'folder1', 'path': 'folder1'},
          {'name': 'folder2', 'path': 'folder1/folder2'},
          {'name': 'folder3', 'path': 'folder1/folder2/folder3'}]
 
     Args:
         path: a filesystem path
 
     Returns:
         list: a list of path data for navigation as illustrated above.
 
     """
     path_info = []
     if path:
         sub_paths = path.strip("/").split("/")
         path_from_root = ""
         for p in sub_paths:
             path_from_root += "/" + p
             path_info.append({"name": p, "path": path_from_root.strip("/")})
     return path_info
 
 
 def parse_rst(text, report_level=2):
     """
     Parse a reStructuredText string with docutils.
 
     Args:
         text (str): string with reStructuredText markups in it
         report_level (int): level of docutils report messages to print
             (1 info 2 warning 3 error 4 severe 5 none)
 
     Returns:
         docutils.nodes.document: a parsed docutils document
     """
     parser = docutils.parsers.rst.Parser()
     components = (docutils.parsers.rst.Parser,)
     settings = docutils.frontend.OptionParser(
         components=components
     ).get_default_values()
     settings.report_level = report_level
     document = docutils.utils.new_document("rst-doc", settings=settings)
     parser.parse(text, document)
     return document
 
 
 def get_client_ip(request):
     """
     Return the client IP address from an incoming HTTP request.
 
     Args:
         request (django.http.HttpRequest): the incoming HTTP request
 
     Returns:
         str: The client IP address
     """
     x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
     if x_forwarded_for:
         ip = x_forwarded_for.split(",")[0]
     else:
         ip = request.META.get("REMOTE_ADDR")
     return ip
 
 
 browsers_supported_image_mimes = set(
     [
         "image/gif",
         "image/png",
         "image/jpeg",
         "image/bmp",
         "image/webp",
         "image/svg",
         "image/svg+xml",
     ]
 )
 
 
 def context_processor(request):
     """
     Django context processor used to inject variables
     in all swh-web templates.
     """
     config = get_config()
     if (
         hasattr(request, "user")
         and request.user.is_authenticated
         and not hasattr(request.user, "backend")
     ):
         # To avoid django.template.base.VariableDoesNotExist errors
         # when rendering templates when standard Django user is logged in.
         request.user.backend = "django.contrib.auth.backends.ModelBackend"
     return {
         "swh_object_icons": swh_object_icons,
         "available_languages": None,
         "swh_client_config": config["client_config"],
         "oidc_enabled": bool(config["keycloak"]["server_url"]),
         "browsers_supported_image_mimes": browsers_supported_image_mimes,
     }
 
 
 class EnforceCSRFAuthentication(SessionAuthentication):
     """
     Helper class to enforce CSRF validation on a DRF view
     when a user is not authenticated.
     """
 
     def authenticate(self, request):
         user = getattr(request._request, "user", None)
         self.enforce_csrf(request)
         return (user, None)
 
 
 def resolve_branch_alias(
     snapshot: Dict[str, Any], branch: Optional[Dict[str, Any]]
 ) -> Optional[Dict[str, Any]]:
     """
     Resolve branch alias in snapshot content.
 
     Args:
         snapshot: a full snapshot content
         branch: a branch alias contained in the snapshot
     Returns:
         The real snapshot branch that got aliased.
     """
     while branch and branch["target_type"] == "alias":
         if branch["target"] in snapshot["branches"]:
             branch = snapshot["branches"][branch["target"]]
         else:
             from swh.web.common import service
 
             snp = service.lookup_snapshot(
                 snapshot["id"], branches_from=branch["target"], branches_count=1
             )
             if snp and branch["target"] in snp["branches"]:
                 branch = snp["branches"][branch["target"]]
             else:
                 branch = None
     return branch
 
 
 class _NoHeaderHTMLTranslator(HTMLTranslator):
     """
     Docutils translator subclass to customize the generation of HTML
     from reST-formatted docstrings
     """
 
     def __init__(self, document):
         super().__init__(document)
         self.body_prefix = []
         self.body_suffix = []
 
 
 _HTML_WRITER = Writer()
 _HTML_WRITER.translator_class = _NoHeaderHTMLTranslator
 
 
 def rst_to_html(rst: str) -> str:
     """
     Convert reStructuredText document into HTML.
 
     Args:
         rst: A string containing a reStructuredText document
 
     Returns:
         Body content of the produced HTML conversion.
 
     """
     settings = {
         "initial_header_level": 2,
     }
     pp = publish_parts(rst, writer=_HTML_WRITER, settings_overrides=settings)
     return f'<div class="swh-rst">{pp["html_body"]}</div>'
 
 
 def prettify_html(html: str) -> str:
     """
     Prettify an HTML document.
 
     Args:
         html: Input HTML document
 
     Returns:
         The prettified HTML document
     """
     return BeautifulSoup(html, "lxml").prettify()
diff --git a/swh/web/templates/browse/browse.html b/swh/web/templates/browse/browse.html
index 184a4846..1e98e7cc 100644
--- a/swh/web/templates/browse/browse.html
+++ b/swh/web/templates/browse/browse.html
@@ -1,65 +1,38 @@
 {% extends "./layout.html" %}
 
 {% comment %}
 Copyright (C) 2017-2020  The Software Heritage developers
 See the AUTHORS file at the top-level directory of this distribution
 License: GNU Affero General Public License version 3, or any later version
 See top-level LICENSE file for more information
 {% endcomment %}
 
 {% load swh_templatetags %}
 
 {% block title %}{{ heading }} &ndash; Software Heritage archive{% endblock %}
 
 {% block navbar-content %}
 
-{% if snapshot_context %}
-  <h4>
-    <i class="{{ swh_object_icons|key_value:swh_object_name.lower }} mdi-fw" aria-hidden="true"></i>
-
-    {% if snapshot_context.origin_info %}
-      Browse archived {{ swh_object_name.lower }} for origin
-      <a href="{% url 'browse-origin' %}?origin_url={{ snapshot_context.origin_info.url }}">
-        {{ snapshot_context.origin_info.url }}
-      </a>
-      {% if snapshot_context.origin_info.url|slice:"0:4" == "http" %}
-        <a href="{{ snapshot_context.origin_info.url }}" title="Go to origin">
-          <i class="mdi mdi-open-in-new" aria-hidden="true"></i>
-        </a>
-      {% endif %}
-    {% else %}
-      Browse archived {{ swh_object_name.lower }} for snapshot
-      <a href="{% url 'browse-swh-id' snapshot_context.snapshot_swhid %}">
-        {{ snapshot_context.snapshot_swhid }}
-      </a>
-    {% endif %}
-  </h4>
-{% else %}
-  <h4>
-    <i class="{{ swh_object_icons|key_value:swh_object_name.lower }} mdi-fw" aria-hidden="true"></i>
-    Browse archived {{ swh_object_name.lower }}
-    <a href="{% url 'browse-swh-id' swh_object_id %}">
-      {{ swh_object_id }}
-    </a>
-  </h4>
-{% endif %}
+<h4>
+  Browse the archive
+</h4>
 
 {% endblock %}
 
 {% block browse-content %}
 
 {% block swh-browse-before-content %}
 {% if snapshot_context %}
   {% include "includes/snapshot-context.html" %}
 {% endif %}
 {% endblock %}
 
 {% block swh-browse-content %}{% endblock %}
 
 {% block swh-browse-after-content %}{% endblock %}
 
 <script>
   swh.webapp.initPage('browse');
 </script>
 
 {% endblock %}
diff --git a/swh/web/templates/browse/origin-visits.html b/swh/web/templates/browse/origin-visits.html
index 324c76f6..7ac93ebc 100644
--- a/swh/web/templates/browse/origin-visits.html
+++ b/swh/web/templates/browse/origin-visits.html
@@ -1,82 +1,85 @@
 {% extends "./browse.html" %}
 
 {% comment %}
-Copyright (C) 2017-2018  The Software Heritage developers
+Copyright (C) 2017-2020  The Software Heritage developers
 See the AUTHORS file at the top-level directory of this distribution
 License: GNU Affero General Public License version 3, or any later version
 See top-level LICENSE file for more information
 {% endcomment %}
 
 {% load static %}
 {% load swh_templatetags %}
 {% load render_bundle from webpack_loader %}
 
 {% block header %}
 {{ block.super }}
 {% render_bundle 'origin' %}
 {% endblock %}
 
 {% block swh-browse-content %}
 
-<h4>Overview</h4>
-
-<ul>
-  <li class="d-inline-block">
-    <b>Total number of visits: </b>{{ origin_visits|length }}
-    <i class="mdi mdi-fw" aria-hidden="true"></i>
-  </li>
-  <li class="d-inline-block">
-    <b>Last full visit: </b><span style="margin-left: 20px;" id="swh-last-full-visit"></span>
-    <i class="mdi mdi-fw" aria-hidden="true"></i>
-  </li>
-  <li class="d-inline-block">
-    <b>First full visit: </b><span style="margin-left: 20px;" id="swh-first-full-visit"></span>
-    <i class="mdi mdi-fw" aria-hidden="true"></i>
-  </li>
-  <li class="d-inline-block">
-    <b>Last visit: </b><span style="margin-left: 20px;" id="swh-last-visit"></span>
-    <i class="mdi mdi-fw" aria-hidden="true"></i>
-  </li>
-</ul>
-
-<h4>History</h4>
-
-<form class="text-center">
-  <div class="custom-control custom-radio custom-control-inline">
-    <input class="custom-control-input" type="radio" id="swh-different-snapshot-visits" name="swh-visits" value="option1" checked>
-    <label class="custom-control-label font-weight-normal" for="swh-different-snapshot-visits" onclick="swh.origin.showFullVisitsDifferentSnapshots(event)">
-      Show full visits with different snapshots
-    </label>
-  </div>
-  <div class="custom-control custom-radio custom-control-inline">
-    <input class="custom-control-input" type="radio" id="swh-full-visits" name="swh-visits" value="option2">
-    <label class="custom-control-label font-weight-normal" for="swh-full-visits" onclick="swh.origin.showFullVisits(event)">
-      Show all full visits
-    </label>
-  </div>
-  <div class="custom-control custom-radio custom-control-inline">
-    <input class="custom-control-input" type="radio" id="swh-all-visits" name="swh-visits" value="option3">
-    <label class="custom-control-label font-weight-normal" for="swh-all-visits" onclick="swh.origin.showAllVisits(event)">
-      Show all visits
-    </label>
-  </div>
-</form>
-
-<h5>Calendar</h5>
-
-<div id="swh-visits-calendar"></div>
-
-<h5>List</h5>
-
-<div id="swh-visits-list"></div>
-
-<h5>Timeline</h5>
-
-<div id="swh-visits-timeline" class="d3-wrapper"></div>
+<div class="p-3">
+
+  <h4>Overview</h4>
+
+  <ul>
+    <li class="d-inline-block">
+      <b>Total number of visits: </b>{{ origin_visits|length }}
+      <i class="mdi mdi-fw" aria-hidden="true"></i>
+    </li>
+    <li class="d-inline-block">
+      <b>Last full visit: </b><span style="margin-left: 20px;" id="swh-last-full-visit"></span>
+      <i class="mdi mdi-fw" aria-hidden="true"></i>
+    </li>
+    <li class="d-inline-block">
+      <b>First full visit: </b><span style="margin-left: 20px;" id="swh-first-full-visit"></span>
+      <i class="mdi mdi-fw" aria-hidden="true"></i>
+    </li>
+    <li class="d-inline-block">
+      <b>Last visit: </b><span style="margin-left: 20px;" id="swh-last-visit"></span>
+      <i class="mdi mdi-fw" aria-hidden="true"></i>
+    </li>
+  </ul>
+
+  <h4>History</h4>
+
+  <form class="text-center">
+    <div class="custom-control custom-radio custom-control-inline">
+      <input class="custom-control-input" type="radio" id="swh-different-snapshot-visits" name="swh-visits" value="option1" checked>
+      <label class="custom-control-label font-weight-normal" for="swh-different-snapshot-visits" onclick="swh.origin.showFullVisitsDifferentSnapshots(event)">
+        Show full visits with different snapshots
+      </label>
+    </div>
+    <div class="custom-control custom-radio custom-control-inline">
+      <input class="custom-control-input" type="radio" id="swh-full-visits" name="swh-visits" value="option2">
+      <label class="custom-control-label font-weight-normal" for="swh-full-visits" onclick="swh.origin.showFullVisits(event)">
+        Show all full visits
+      </label>
+    </div>
+    <div class="custom-control custom-radio custom-control-inline">
+      <input class="custom-control-input" type="radio" id="swh-all-visits" name="swh-visits" value="option3">
+      <label class="custom-control-label font-weight-normal" for="swh-all-visits" onclick="swh.origin.showAllVisits(event)">
+        Show all visits
+      </label>
+    </div>
+  </form>
+
+  <h5>Calendar</h5>
+
+  <div id="swh-visits-calendar"></div>
+
+  <h5>List</h5>
+
+  <div id="swh-visits-list"></div>
+
+  <h5>Timeline</h5>
+
+  <div id="swh-visits-timeline" class="d3-wrapper"></div>
+</div>
 
 <script>
   // all origin visits
   var visits = {{ origin_visits|jsonify }};
   swh.origin.initVisitsReporting(visits);
 </script>
 {% endblock %}
diff --git a/swh/web/templates/includes/snapshot-context.html b/swh/web/templates/includes/snapshot-context.html
index 7f736393..741fea20 100644
--- a/swh/web/templates/includes/snapshot-context.html
+++ b/swh/web/templates/includes/snapshot-context.html
@@ -1,31 +1,86 @@
 {% comment %}
-Copyright (C) 2017-2018  The Software Heritage developers
+Copyright (C) 2017-2020  The Software Heritage developers
 See the AUTHORS file at the top-level directory of this distribution
 License: GNU Affero General Public License version 3, or any later version
 See top-level LICENSE file for more information
 {% endcomment %}
 
 {% load swh_templatetags %}
 
-<hr class="mt-1 mb-1">
-<div class="swh-origin-visit-details">
-  <ul>
-    {% if snapshot_context.origin_info %}
-      <li><i class="{{ swh_object_icons.visits }} mdi-fw"></i><a href="{{ snapshot_context.origin_visits_url }}">Visits</a></li>
-    {% endif %}
-    {% if snapshot_context.visit_info %}
-      <li><i class="{{ swh_object_icons.snapshot }} mdi-fw" aria-hidden="true"></i> Snapshot date: <a href="{{ snapshot_context.visit_info.url }}">{{ snapshot_context.visit_info.formatted_date }}</a></li>
-    {% endif %}
-    {% if not snapshot_context.snapshot_sizes.revision %}
-      <li><i class="{{ swh_object_icons.branches }} mdi-fw" aria-hidden="true"></i> Branches (0)</li>
-    {% else %}
-      <li><i class="{{ swh_object_icons.branches }} mdi-fw" aria-hidden="true"></i> <a href="{{ snapshot_context.branches_url }}">Branches ({{ snapshot_context.snapshot_sizes.revision}})</a></li>
-    {% endif %}
-    {% if not snapshot_context.snapshot_sizes.release %}
-      <li><i class="{{ swh_object_icons.releases }} mdi-fw" aria-hidden="true"></i> Releases (0)</li>
-    {% else %}
-      <li><i class="{{ swh_object_icons.releases }} mdi-fw" aria-hidden="true"></i> <a href="{{ snapshot_context.releases_url }}">Releases ({{ snapshot_context.snapshot_sizes.release }})</a></li>
-    {% endif %}
-  </ul>
-</div>
-<hr class="mt-1 mb-1">
\ No newline at end of file
+<h5>
+{% if snapshot_context.origin_info %}
+  <i class="{{ swh_object_icons.origin }} mdi-fw" aria-hidden="true" title="Origin"></i>
+    <a class="swh-heading-color" href="{% url 'browse-origin' %}?origin_url={{ snapshot_context.origin_info.url }}">
+    {{ snapshot_context.origin_info.url }}
+  </a>
+  {% if snapshot_context.origin_info.url|slice:"0:4" == "http" %}
+    <a href="{{ snapshot_context.origin_info.url }}" title="Go to origin">
+      <i class="mdi mdi-open-in-new" aria-hidden="true"></i>
+    </a>
+  {% endif %}
+{% else %}
+  <i class="{{ swh_object_icons.snapshot }} mdi-fw" aria-hidden="true" title="Snapshot"></i>
+  <a class="swh-heading-color" href="{% url 'browse-swh-id' snapshot_context.snapshot_swhid %}">
+    {{ snapshot_context.snapshot_swhid }}
+  </a>
+{% endif %}
+</h5>
+{% if snapshot_context.visit_info %}
+  <div class="mb-1 pl-1">
+    <i class="{{ swh_object_icons.snapshot }} mdi-fw" aria-hidden="true" title="Snapshot date"></i>
+    <a href="{{ snapshot_context.visit_info.url }}">
+      {{ snapshot_context.visit_info.formatted_date }}
+    </a>
+  </div>
+{% endif %}
+
+<ul class="nav nav-tabs" id="swh-snapshot-context-nav" style="padding-left: 5px;">
+  <li class="nav-item">
+    <a class="nav-link" id="swh-browse-code-nav-link" href="{{ snapshot_context.visit_info.url }}">
+      <i class="mdi mdi-code-tags mdi-fw" aria-hidden="true"></i>
+      Code
+    </a>
+  </li>
+  {% if not snapshot_context.snapshot_sizes.revision %}
+    <li class="nav-item">
+      <a class="nav-link disabled" id="swh-browse-snapshot-branches-nav-link" href="#">
+        <i class="{{ swh_object_icons.branches }} mdi-fw" aria-hidden="true"></i>
+        Branches (0)
+      </a>
+    </li>
+  {% else %}
+    <li class="nav-item">
+      <a class="nav-link" id="swh-browse-snapshot-branches-nav-link" href="{{ snapshot_context.branches_url }}">
+        <i class="{{ swh_object_icons.branches }} mdi-fw" aria-hidden="true"></i>
+        Branches ({{ snapshot_context.snapshot_sizes.revision}})
+      </a>
+    </li>
+  {% endif %}
+  {% if not snapshot_context.snapshot_sizes.release %}
+    <li class="nav-item">
+      <a class="nav-link disabled" id="swh-browse-snapshot-releases-nav-link" href="#">
+        <i class="{{ swh_object_icons.releases }} mdi-fw" aria-hidden="true"></i>
+        Releases (0)
+      </a>
+    </li>
+  {% else %}
+    <li class="nav-item">
+      <a class="nav-link" id="swh-browse-snapshot-releases-nav-link" href="{{ snapshot_context.releases_url }}">
+        <i class="{{ swh_object_icons.releases }} mdi-fw" aria-hidden="true"></i>
+        Releases ({{ snapshot_context.snapshot_sizes.release }})
+      </a>
+    </li>
+  {% endif %}
+  {% if snapshot_context.origin_info %}
+    <li class="nav-item">
+      <a class="nav-link" id="swh-browse-origin-visits-nav-link" href="{{ snapshot_context.origin_visits_url }}">
+        <i class="{{ swh_object_icons.visits }} mdi-fw"></i>
+        Visits
+      </a>
+    </li>
+  {% endif %}
+</ul>
+
+<script>
+  swh.browse.initBrowseNavbar();
+</script>
\ No newline at end of file
diff --git a/swh/web/templates/includes/top-navigation.html b/swh/web/templates/includes/top-navigation.html
index 2e66468e..d961e927 100644
--- a/swh/web/templates/includes/top-navigation.html
+++ b/swh/web/templates/includes/top-navigation.html
@@ -1,141 +1,141 @@
 {% comment %}
-Copyright (C) 2017-2019  The Software Heritage developers
+Copyright (C) 2017-2020  The Software Heritage developers
 See the AUTHORS file at the top-level directory of this distribution
 License: GNU Affero General Public License version 3, or any later version
 See top-level LICENSE file for more information
 {% endcomment %}
 
 {% load swh_templatetags %}
 
-<div class="swh-browse-top-navigation d-flex align-items-start justify-content-between flex-wrap">
+<div class="swh-browse-top-navigation d-flex align-items-start justify-content-between flex-wrap mt-1">
   {% if snapshot_context %}
     {% if snapshot_context.branch or snapshot_context.release %}
       <div class="dropdown" id="swh-branches-releases-dd">
         <button class="btn btn-block btn-default btn-sm dropdown-toggle" type="button" data-toggle="dropdown">
           {% if snapshot_context.branch %}
             <i class="{{ swh_object_icons.branch }} mdi-fw" aria-hidden="true"></i>
             Branch: <strong>{{ snapshot_context.branch }}</strong>
           {% else %}
             <i class="{{ swh_object_icons.release }} mdi-fw" aria-hidden="true"></i>
             Release: <strong>{{ snapshot_context.release }}</strong>
           {% endif %}
           <span class="caret"></span>
         </button>
         <ul class="scrollable-menu dropdown-menu swh-branches-releases">
           <ul class="nav nav-tabs">
             <li class="nav-item"><a class="nav-link active swh-branches-switch" data-toggle="tab">Branches</a></li>
             <li class="nav-item"><a class="nav-link swh-releases-switch" data-toggle="tab">Releases</a></li>
           </ul>
           <div class="tab-content">
             <div class="tab-pane active" id="swh-tab-branches">
               {% for b in snapshot_context.branches %}
                 <li class="swh-branch">
                   <a href="{{ b.url | safe }}">
                     <i class="{{ swh_object_icons.branch }} mdi-fw" aria-hidden="true"></i>
                     {% if b.name == snapshot_context.branch %}
                       <i class="mdi mdi-check-bold mdi-fw" aria-hidden="true"></i>
                     {% else %}
                       <i class="mdi mdi-fw" aria-hidden="true"></i>
                     {% endif %}
                     {{ b.name }}
                   </a>
                 </li>
               {% endfor %}
               {% if snapshot_context.branches|length < snapshot_context.snapshot_sizes.revision %}
                 <li>
                   <i class="mdi mdi-alert mdi-fw" aria-hidden="true"></i>
                   Branches list truncated to {{ snapshot_context.branches|length }} entries,
                   {{ snapshot_context.branches|length|mul:-1|add:snapshot_context.snapshot_sizes.revision }}
                   were omitted.
                 </li>
               {% endif %}
             </div>
             <div class="tab-pane" id="swh-tab-releases">
               {% if snapshot_context.releases %}
                 {% for r in snapshot_context.releases %}
                   {% if r.target_type == 'revision' %}
                     <li class="swh-release">
                       <a href="{{ r.url | safe }}">
                         <i class="{{ swh_object_icons.release }} mdi-fw" aria-hidden="true"></i>
                         {% if r.name == snapshot_context.release %}
                           <i class="mdi mdi-check-bold mdi-fw" aria-hidden="true"></i>
                         {% else %}
                           <i class="mdi mdi-fw" aria-hidden="true"></i>
                         {% endif %}
                         {{ r.name }}
                       </a>
                     </li>
                   {% endif %}
                 {% endfor %}
                 {% if snapshot_context.releases|length < snapshot_context.snapshot_sizes.release %}
                 <li>
                   <i class="mdi mdi-alert mdi-fw" aria-hidden="true"></i>
                   Releases list truncated to {{ snapshot_context.releases|length }} entries,
                   {{ snapshot_context.releases|length|mul:-1|add:snapshot_context.snapshot_sizes.release }}
                   were omitted.
                 </li>
               {% endif %}
               {% else %}
                 <span>No releases to show</span>
               {% endif %}
             </div>
           </div>
         </ul>
       </div>
     {% endif %}
   {% endif %}
 
   <div class="flex-grow-1">
     {% include "includes/breadcrumbs.html" %}
   </div>
 
   <div class="btn-group swh-actions-dropdown ml-auto">
     {% if top_right_link %}
       <a href="{{ top_right_link.url | safe }}" class="btn btn-default btn-sm swh-tr-link" role="button">
         {% if top_right_link.icon %}
           <i class="{{ top_right_link.icon }} mdi-fw" aria-hidden="true"></i>
         {% endif %}
         {{ top_right_link.text }}
       </a>
     {% endif %}
     {% if available_languages %}
       <select data-placeholder="Select Language" class="language-select chosen-select">
         <option value=""></option>
         {% for lang in available_languages %}
           <option value="{{ lang }}">{{ lang }}</option>
         {% endfor %}
       </select>
     {% endif %}
     {% if show_actions_menu %}
       <button class="btn btn-default btn-sm dropdown-toggle" type="button" data-toggle="dropdown">
         <i class="mdi mdi-menu mdi-fw" aria-hidden="true"></i>Actions
         <span class="caret"></span>
       </button>
       <ul class="dropdown-menu dropdown-menu-right swh-browse-actions-menu">
         {% if not snapshot_context or not snapshot_context.is_empty %}
           {% include "includes/vault-create-tasks.html" %}
         {% endif %}
         {% include "includes/show-metadata.html" %}
         {% include "includes/take-new-snapshot.html" %}
       </ul>
     {% endif %}
   </div>
 </div>
 
 {% include "includes/show-swh-ids.html" %}
 
 <script>
   var snapshotContext = false;
   var branch = false;
   {% if snapshot_context %}
     snapshotContext = true;
     branch = "{{ snapshot_context.branch|escape }}";
   {% endif %}
   {% if available_languages %}
     $(".chosen-select").val("{{ language }}");
     $(".chosen-select").chosen().change(function(event, params) {
       updateLanguage(params.selected);
     });
   {% endif %}
   swh.browse.initSnapshotNavigation(snapshotContext, branch !== "None");
 </script>
diff --git a/swh/web/tests/browse/views/test_content.py b/swh/web/tests/browse/views/test_content.py
index d5545215..a4c9fe1b 100644
--- a/swh/web/tests/browse/views/test_content.py
+++ b/swh/web/tests/browse/views/test_content.py
@@ -1,635 +1,607 @@
 # Copyright (C) 2017-2020  The Software Heritage developers
 # See the AUTHORS file at the top-level directory of this distribution
 # License: GNU Affero General Public License version 3, or any later version
 # See top-level LICENSE file for more information
 
 import random
-import textwrap
 
 from django.utils.html import escape
 
 from hypothesis import given
 
 from swh.model.identifiers import CONTENT, DIRECTORY, RELEASE, REVISION, SNAPSHOT
 from swh.web.browse.snapshot_context import process_snapshot_branches
 from swh.web.browse.utils import (
     get_mimetype_and_encoding_for_content,
     prepare_content_for_display,
     _re_encode_content,
 )
 from swh.web.common.exc import NotFoundExc
 from swh.web.common.identifiers import get_swh_persistent_id
 from swh.web.common.utils import gen_path_info, reverse
 from swh.web.tests.django_asserts import (
     assert_contains,
     assert_not_contains,
     assert_template_used,
 )
 from swh.web.tests.strategies import (
     content,
     content_text_non_utf8,
     content_text_no_highlight,
     content_image_type,
     content_unsupported_image_type_rendering,
     content_text,
     invalid_sha1,
     unknown_content,
     content_utf8_detected_as_binary,
     origin_with_multiple_visits,
 )
 
 
 @given(content_text())
 def test_content_view_text(client, archive_data, content):
     sha1_git = content["sha1_git"]
 
     url = reverse(
         "browse-content",
         url_args={"query_string": content["sha1"]},
         query_params={"path": content["path"]},
     )
 
     url_raw = reverse("browse-content-raw", url_args={"query_string": content["sha1"]})
 
     resp = client.get(url)
 
     content_display = _process_content_for_display(archive_data, content)
     mimetype = content_display["mimetype"]
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/content.html")
 
     if mimetype.startswith("text/"):
         assert_contains(resp, '<code class="%s">' % content_display["language"])
         assert_contains(resp, escape(content_display["content_data"]))
     assert_contains(resp, url_raw)
 
     swh_cnt_id = get_swh_persistent_id(CONTENT, sha1_git)
     swh_cnt_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_cnt_id})
     assert_contains(resp, swh_cnt_id)
     assert_contains(resp, swh_cnt_id_url)
-    assert_contains(
-        resp,
-        textwrap.indent(
-            (
-                f"Browse archived content\n"
-                f'<a href="{swh_cnt_id_url}">\n'
-                f"  {swh_cnt_id}\n"
-                f"</a>"
-            ),
-            " " * 4,
-        ),
-    )
 
 
 @given(content_text_no_highlight())
 def test_content_view_text_no_highlight(client, archive_data, content):
     sha1_git = content["sha1_git"]
 
     url = reverse("browse-content", url_args={"query_string": content["sha1"]})
 
     url_raw = reverse("browse-content-raw", url_args={"query_string": content["sha1"]})
 
     resp = client.get(url)
 
     content_display = _process_content_for_display(archive_data, content)
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/content.html")
 
     assert_contains(resp, '<code class="nohighlight">')
     assert_contains(resp, escape(content_display["content_data"]))
     assert_contains(resp, url_raw)
 
     swh_cnt_id = get_swh_persistent_id(CONTENT, sha1_git)
     swh_cnt_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_cnt_id})
 
     assert_contains(resp, swh_cnt_id)
     assert_contains(resp, swh_cnt_id_url)
 
 
 @given(content_text_non_utf8())
 def test_content_view_no_utf8_text(client, archive_data, content):
     sha1_git = content["sha1_git"]
 
     url = reverse("browse-content", url_args={"query_string": content["sha1"]})
 
     resp = client.get(url)
 
     content_display = _process_content_for_display(archive_data, content)
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/content.html")
     swh_cnt_id = get_swh_persistent_id(CONTENT, sha1_git)
     swh_cnt_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_cnt_id})
     assert_contains(resp, swh_cnt_id_url)
     assert_contains(resp, escape(content_display["content_data"]))
 
 
 @given(content_image_type())
 def test_content_view_image(client, archive_data, content):
     url = reverse("browse-content", url_args={"query_string": content["sha1"]})
 
     url_raw = reverse("browse-content-raw", url_args={"query_string": content["sha1"]})
 
     resp = client.get(url)
 
     content_display = _process_content_for_display(archive_data, content)
     mimetype = content_display["mimetype"]
     content_data = content_display["content_data"]
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/content.html")
     assert_contains(resp, '<img src="data:%s;base64,%s"/>' % (mimetype, content_data))
     assert_contains(resp, url_raw)
 
 
 @given(content_unsupported_image_type_rendering())
 def test_content_view_image_no_rendering(client, archive_data, content):
     url = reverse("browse-content", url_args={"query_string": content["sha1"]})
 
     resp = client.get(url)
 
     mimetype = content["mimetype"]
     encoding = content["encoding"]
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/content.html")
     assert_contains(
         resp,
         (
             f"Content with mime type {mimetype} and encoding {encoding} "
             "cannot be displayed."
         ),
     )
 
 
 @given(content_text())
 def test_content_view_text_with_path(client, archive_data, content):
     path = content["path"]
 
     url = reverse(
         "browse-content",
         url_args={"query_string": content["sha1"]},
         query_params={"path": path},
     )
 
     resp = client.get(url)
     assert resp.status_code == 200
     assert_template_used(resp, "browse/content.html")
 
     assert_contains(resp, '<nav class="bread-crumbs')
 
     content_display = _process_content_for_display(archive_data, content)
     mimetype = content_display["mimetype"]
 
     if mimetype.startswith("text/"):
         hljs_language = content["hljs_language"]
         assert_contains(resp, '<code class="%s">' % hljs_language)
         assert_contains(resp, escape(content_display["content_data"]))
 
     split_path = path.split("/")
 
     root_dir_sha1 = split_path[0]
     filename = split_path[-1]
     path = path.replace(root_dir_sha1 + "/", "").replace(filename, "")
 
     swhid_context = {
         "anchor": get_swh_persistent_id(DIRECTORY, root_dir_sha1),
         "path": f"/{path}{filename}",
     }
 
     swh_cnt_id = get_swh_persistent_id(
         CONTENT, content["sha1_git"], metadata=swhid_context
     )
     swh_cnt_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_cnt_id})
     assert_contains(resp, swh_cnt_id)
     assert_contains(resp, swh_cnt_id_url)
 
     path_info = gen_path_info(path)
 
     root_dir_url = reverse("browse-directory", url_args={"sha1_git": root_dir_sha1})
 
     assert_contains(resp, '<li class="swh-path">', count=len(path_info) + 1)
 
     assert_contains(
         resp, '<a href="' + root_dir_url + '">' + root_dir_sha1[:7] + "</a>"
     )
 
     for p in path_info:
         dir_url = reverse(
             "browse-directory",
             url_args={"sha1_git": root_dir_sha1},
             query_params={"path": p["path"]},
         )
         assert_contains(resp, '<a href="' + dir_url + '">' + p["name"] + "</a>")
 
     assert_contains(resp, "<li>" + filename + "</li>")
 
     url_raw = reverse(
         "browse-content-raw",
         url_args={"query_string": content["sha1"]},
         query_params={"filename": filename},
     )
     assert_contains(resp, url_raw)
 
     url = reverse(
         "browse-content",
         url_args={"query_string": content["sha1"]},
         query_params={"path": filename},
     )
 
     resp = client.get(url)
     assert resp.status_code == 200
     assert_template_used(resp, "browse/content.html")
 
     assert_not_contains(resp, '<nav class="bread-crumbs')
 
     invalid_path = "%s/foo/bar/baz" % root_dir_sha1
     url = reverse(
         "browse-content",
         url_args={"query_string": content["sha1"]},
         query_params={"path": invalid_path},
     )
     resp = client.get(url)
     assert resp.status_code == 404
 
 
 @given(content_text())
 def test_content_raw_text(client, archive_data, content):
     url = reverse("browse-content-raw", url_args={"query_string": content["sha1"]})
 
     resp = client.get(url)
 
     content_data = archive_data.content_get(content["sha1"])["data"]
 
     assert resp.status_code == 200
     assert resp["Content-Type"] == "text/plain"
     assert resp["Content-disposition"] == ("filename=%s_%s" % ("sha1", content["sha1"]))
     assert resp.content == content_data
 
     filename = content["path"].split("/")[-1]
 
     url = reverse(
         "browse-content-raw",
         url_args={"query_string": content["sha1"]},
         query_params={"filename": filename},
     )
 
     resp = client.get(url)
 
     assert resp.status_code == 200
     assert resp["Content-Type"] == "text/plain"
     assert resp["Content-disposition"] == "filename=%s" % filename
     assert resp.content == content_data
 
 
 @given(content_text_non_utf8())
 def test_content_raw_no_utf8_text(client, content):
     url = reverse("browse-content-raw", url_args={"query_string": content["sha1"]})
 
     resp = client.get(url)
     assert resp.status_code == 200
     _, encoding = get_mimetype_and_encoding_for_content(resp.content)
     assert encoding == content["encoding"]
 
 
 @given(content_image_type())
 def test_content_raw_bin(client, archive_data, content):
     url = reverse("browse-content-raw", url_args={"query_string": content["sha1"]})
 
     resp = client.get(url)
 
     filename = content["path"].split("/")[-1]
     content_data = archive_data.content_get(content["sha1"])["data"]
 
     assert resp.status_code == 200
     assert resp["Content-Type"] == "application/octet-stream"
     assert resp["Content-disposition"] == "attachment; filename=%s_%s" % (
         "sha1",
         content["sha1"],
     )
     assert resp.content == content_data
 
     url = reverse(
         "browse-content-raw",
         url_args={"query_string": content["sha1"]},
         query_params={"filename": filename},
     )
 
     resp = client.get(url)
 
     assert resp.status_code == 200
     assert resp["Content-Type"] == "application/octet-stream"
     assert resp["Content-disposition"] == "attachment; filename=%s" % filename
     assert resp.content == content_data
 
 
 @given(invalid_sha1(), unknown_content())
 def test_content_request_errors(client, invalid_sha1, unknown_content):
     url = reverse("browse-content", url_args={"query_string": invalid_sha1})
     resp = client.get(url)
     assert resp.status_code == 400
     assert_template_used(resp, "error.html")
 
     url = reverse("browse-content", url_args={"query_string": unknown_content["sha1"]})
     resp = client.get(url)
     assert resp.status_code == 404
     assert_template_used(resp, "error.html")
 
 
 @given(content())
 def test_content_bytes_missing(client, archive_data, mocker, content):
     mock_service = mocker.patch("swh.web.browse.utils.service")
     content_data = archive_data.content_get_metadata(content["sha1"])
     content_data["data"] = None
 
     mock_service.lookup_content.return_value = content_data
     mock_service.lookup_content_filetype.side_effect = Exception()
     mock_service.lookup_content_raw.side_effect = NotFoundExc(
         "Content bytes not available!"
     )
 
     url = reverse("browse-content", url_args={"query_string": content["sha1"]})
 
     resp = client.get(url)
 
     assert resp.status_code == 404
     assert_template_used(resp, "browse/content.html")
 
 
 def test_content_too_large(client, mocker):
     mock_request_content = mocker.patch("swh.web.browse.views.content.request_content")
     stub_content_too_large_data = {
         "checksums": {
             "sha1": "8624bcdae55baeef00cd11d5dfcfa60f68710a02",
             "sha1_git": "94a9ed024d3859793618152ea559a168bbcbb5e2",
             "sha256": (
                 "8ceb4b9ee5adedde47b31e975c1d90c73ad27b6b16" "5a1dcd80c7c545eb65b903"
             ),
             "blake2s256": (
                 "38702b7168c7785bfe748b51b45d9856070ba90" "f9dc6d90f2ea75d4356411ffe"
             ),
         },
         "length": 30000000,
         "raw_data": None,
         "mimetype": "text/plain",
         "encoding": "us-ascii",
         "language": "not detected",
         "licenses": "GPL",
         "error_code": 200,
         "error_message": "",
         "error_description": "",
     }
 
     content_sha1 = stub_content_too_large_data["checksums"]["sha1"]
 
     mock_request_content.return_value = stub_content_too_large_data
 
     url = reverse("browse-content", url_args={"query_string": content_sha1})
 
     url_raw = reverse("browse-content-raw", url_args={"query_string": content_sha1})
 
     resp = client.get(url)
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/content.html")
 
     assert_contains(resp, "Content is too large to be displayed")
     assert_contains(resp, url_raw)
 
 
 @given(content())
 def test_content_uppercase(client, content):
     url = reverse(
         "browse-content-uppercase-checksum",
         url_args={"query_string": content["sha1"].upper()},
     )
     resp = client.get(url)
     assert resp.status_code == 302
 
     redirect_url = reverse("browse-content", url_args={"query_string": content["sha1"]})
 
     assert resp["location"] == redirect_url
 
 
 @given(content_utf8_detected_as_binary())
 def test_content_utf8_detected_as_binary_display(client, archive_data, content):
     url = reverse("browse-content", url_args={"query_string": content["sha1"]})
     resp = client.get(url)
 
     content_display = _process_content_for_display(archive_data, content)
 
     assert_contains(resp, escape(content_display["content_data"]))
 
 
 @given(origin_with_multiple_visits())
 def test_content_origin_snapshot_branch_browse(client, archive_data, origin):
     visits = archive_data.origin_visit_get(origin["url"])
     visit = random.choice(visits)
     snapshot = archive_data.snapshot_get(visit["snapshot"])
     branches, releases = process_snapshot_branches(snapshot)
     branch_info = random.choice(branches)
 
     directory = archive_data.revision_get(branch_info["revision"])["directory"]
     directory_content = archive_data.directory_ls(directory)
     directory_file = random.choice(
         [e for e in directory_content if e["type"] == "file"]
     )
 
     url = reverse(
         "browse-content",
         url_args={"query_string": directory_file["checksums"]["sha1"]},
         query_params={
             "origin_url": origin["url"],
             "snapshot": snapshot["id"],
             "branch": branch_info["name"],
             "path": directory_file["name"],
         },
     )
 
     resp = client.get(url)
     assert resp.status_code == 200
     assert_template_used(resp, "browse/content.html")
     _check_origin_snapshot_related_html(resp, origin, snapshot, branches, releases)
     assert_contains(resp, directory_file["name"])
     assert_contains(resp, f"Branch: <strong>{branch_info['name']}</strong>")
 
     cnt_swhid = get_swh_persistent_id(
         CONTENT,
         directory_file["checksums"]["sha1_git"],
         metadata={
             "origin": origin["url"],
             "visit": get_swh_persistent_id(SNAPSHOT, snapshot),
             "anchor": get_swh_persistent_id(REVISION, branch_info["revision"]),
             "path": f"/{directory_file['name']}",
         },
     )
     assert_contains(resp, cnt_swhid)
 
     dir_swhid = get_swh_persistent_id(
         DIRECTORY,
         directory,
         metadata={
             "origin": origin["url"],
             "visit": get_swh_persistent_id(SNAPSHOT, snapshot),
             "anchor": get_swh_persistent_id(REVISION, branch_info["revision"]),
             "path": "/",
         },
     )
     assert_contains(resp, dir_swhid)
 
     rev_swhid = get_swh_persistent_id(
         REVISION,
         branch_info["revision"],
         metadata={
             "origin": origin["url"],
             "visit": get_swh_persistent_id(SNAPSHOT, snapshot),
         },
     )
     assert_contains(resp, rev_swhid)
 
     snp_swhid = get_swh_persistent_id(
         SNAPSHOT, snapshot, metadata={"origin": origin["url"],},
     )
     assert_contains(resp, snp_swhid)
 
 
 @given(origin_with_multiple_visits())
 def test_content_origin_snapshot_release_browse(client, archive_data, origin):
     visits = archive_data.origin_visit_get(origin["url"])
     visit = random.choice(visits)
     snapshot = archive_data.snapshot_get(visit["snapshot"])
     branches, releases = process_snapshot_branches(snapshot)
     release_info = random.choice(releases)
 
     directory_content = archive_data.directory_ls(release_info["directory"])
     directory_file = random.choice(
         [e for e in directory_content if e["type"] == "file"]
     )
 
     url = reverse(
         "browse-content",
         url_args={"query_string": directory_file["checksums"]["sha1"]},
         query_params={
             "origin_url": origin["url"],
             "snapshot": snapshot["id"],
             "release": release_info["name"],
             "path": directory_file["name"],
         },
     )
 
     resp = client.get(url)
     assert resp.status_code == 200
     assert_template_used(resp, "browse/content.html")
     _check_origin_snapshot_related_html(resp, origin, snapshot, branches, releases)
     assert_contains(resp, directory_file["name"])
     assert_contains(resp, f"Release: <strong>{release_info['name']}</strong>")
 
     cnt_swhid = get_swh_persistent_id(
         CONTENT,
         directory_file["checksums"]["sha1_git"],
         metadata={
             "origin": origin["url"],
             "visit": get_swh_persistent_id(SNAPSHOT, snapshot),
             "anchor": get_swh_persistent_id(RELEASE, release_info["id"]),
             "path": f"/{directory_file['name']}",
         },
     )
     assert_contains(resp, cnt_swhid)
 
     dir_swhid = get_swh_persistent_id(
         DIRECTORY,
         release_info["directory"],
         metadata={
             "origin": origin["url"],
             "visit": get_swh_persistent_id(SNAPSHOT, snapshot),
             "anchor": get_swh_persistent_id(RELEASE, release_info["id"]),
             "path": "/",
         },
     )
     assert_contains(resp, dir_swhid)
 
     rev_swhid = get_swh_persistent_id(
         REVISION,
         release_info["target"],
         metadata={
             "origin": origin["url"],
             "visit": get_swh_persistent_id(SNAPSHOT, snapshot),
         },
     )
     assert_contains(resp, rev_swhid)
 
     rel_swhid = get_swh_persistent_id(
         RELEASE,
         release_info["id"],
         metadata={
             "origin": origin["url"],
             "visit": get_swh_persistent_id(SNAPSHOT, snapshot),
         },
     )
     assert_contains(resp, rel_swhid)
 
     snp_swhid = get_swh_persistent_id(
         SNAPSHOT, snapshot, metadata={"origin": origin["url"],},
     )
     assert_contains(resp, snp_swhid)
 
 
 def _check_origin_snapshot_related_html(resp, origin, snapshot, branches, releases):
     browse_origin_url = reverse(
         "browse-origin", query_params={"origin_url": origin["url"]}
     )
-    assert_contains(
-        resp,
-        textwrap.indent(
-            (
-                "Browse archived content for origin\n"
-                f'<a href="{browse_origin_url}">\n'
-                f"  {origin['url']}\n"
-                f"</a>"
-            ),
-            " " * 6,
-        ),
-    )
+    assert_contains(resp, f'href="{browse_origin_url}"')
 
     origin_branches_url = reverse(
         "browse-origin-branches",
         query_params={"origin_url": origin["url"], "snapshot": snapshot["id"]},
     )
 
-    assert_contains(
-        resp,
-        '<a href="%s">Branches (%s)</a>' % (escape(origin_branches_url), len(branches)),
-    )
+    assert_contains(resp, f'href="{escape(origin_branches_url)}"')
+    assert_contains(resp, f"Branches ({len(branches)})")
 
     origin_releases_url = reverse(
         "browse-origin-releases",
         query_params={"origin_url": origin["url"], "snapshot": snapshot["id"]},
     )
 
-    assert_contains(
-        resp,
-        '<a href="%s">Releases (%s)</a>' % (escape(origin_releases_url), len(releases)),
-    )
+    assert_contains(resp, f'href="{escape(origin_releases_url)}"')
+    assert_contains(resp, f"Releases ({len(releases)})")
 
     assert_contains(resp, '<li class="swh-branch">', count=len(branches))
     assert_contains(resp, '<li class="swh-release">', count=len(releases))
 
 
 def _process_content_for_display(archive_data, content):
     content_data = archive_data.content_get(content["sha1"])
 
     mime_type, encoding = get_mimetype_and_encoding_for_content(content_data["data"])
 
     mime_type, encoding, content_data = _re_encode_content(
         mime_type, encoding, content_data["data"]
     )
 
     content_display = prepare_content_for_display(
         content_data, mime_type, content["path"]
     )
 
     assert type(content_display["content_data"]) == str
 
     return content_display
diff --git a/swh/web/tests/browse/views/test_directory.py b/swh/web/tests/browse/views/test_directory.py
index 1a023417..65a4c4fd 100644
--- a/swh/web/tests/browse/views/test_directory.py
+++ b/swh/web/tests/browse/views/test_directory.py
@@ -1,358 +1,330 @@
 # Copyright (C) 2017-2020  The Software Heritage developers
 # See the AUTHORS file at the top-level directory of this distribution
 # License: GNU Affero General Public License version 3, or any later version
 # See top-level LICENSE file for more information
 
 import random
-import textwrap
 
 from django.utils.html import escape
 from hypothesis import given
 
 from swh.model.identifiers import DIRECTORY, RELEASE, REVISION, SNAPSHOT
 from swh.web.browse.snapshot_context import process_snapshot_branches
 from swh.web.common.identifiers import get_swh_persistent_id
 from swh.web.common.utils import gen_path_info, reverse
 from swh.web.tests.django_asserts import assert_contains, assert_template_used
 from swh.web.tests.strategies import (
     directory,
     directory_with_subdirs,
     invalid_sha1,
     unknown_directory,
     origin_with_multiple_visits,
 )
 
 
 @given(directory())
 def test_root_directory_view(client, archive_data, directory):
     _directory_view_checks(client, directory, archive_data.directory_ls(directory))
 
 
 @given(directory_with_subdirs())
 def test_sub_directory_view(client, archive_data, directory):
     dir_content = archive_data.directory_ls(directory)
     subdir = random.choice([e for e in dir_content if e["type"] == "dir"])
     subdir_content = archive_data.directory_ls(subdir["target"])
     _directory_view_checks(client, directory, subdir_content, subdir["name"])
 
 
 @given(invalid_sha1(), unknown_directory())
 def test_directory_request_errors(client, invalid_sha1, unknown_directory):
     dir_url = reverse("browse-directory", url_args={"sha1_git": invalid_sha1})
 
     resp = client.get(dir_url)
     assert resp.status_code == 400
     assert_template_used(resp, "error.html")
 
     dir_url = reverse("browse-directory", url_args={"sha1_git": unknown_directory})
 
     resp = client.get(dir_url)
     assert resp.status_code == 404
     assert_template_used(resp, "error.html")
 
 
 @given(directory())
 def test_directory_uppercase(client, directory):
     url = reverse(
         "browse-directory-uppercase-checksum", url_args={"sha1_git": directory.upper()}
     )
 
     resp = client.get(url)
     assert resp.status_code == 302
 
     redirect_url = reverse("browse-directory", url_args={"sha1_git": directory})
 
     assert resp["location"] == redirect_url
 
 
 @given(directory())
 def test_permalink_box_context(client, tests_data, directory):
     origin_url = random.choice(tests_data["origins"])["url"]
     url = reverse(
         "browse-directory",
         url_args={"sha1_git": directory},
         query_params={"origin_url": origin_url},
     )
 
     resp = client.get(url)
 
     assert resp.status_code == 200
     assert_contains(resp, 'id="swh-id-context-option-directory"')
 
 
 @given(origin_with_multiple_visits())
 def test_directory_origin_snapshot_branch_browse(client, archive_data, origin):
     visits = archive_data.origin_visit_get(origin["url"])
     visit = random.choice(visits)
     snapshot = archive_data.snapshot_get(visit["snapshot"])
     branches, releases = process_snapshot_branches(snapshot)
     branch_info = random.choice(branches)
 
     directory = archive_data.revision_get(branch_info["revision"])["directory"]
     directory_content = archive_data.directory_ls(directory)
     directory_subdir = random.choice(
         [e for e in directory_content if e["type"] == "dir"]
     )
 
     url = reverse(
         "browse-directory",
         url_args={"sha1_git": directory},
         query_params={
             "origin_url": origin["url"],
             "snapshot": snapshot["id"],
             "branch": branch_info["name"],
             "path": directory_subdir["name"],
         },
     )
 
     resp = client.get(url)
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/directory.html")
     _check_origin_snapshot_related_html(resp, origin, snapshot, branches, releases)
     assert_contains(resp, directory_subdir["name"])
     assert_contains(resp, f"Branch: <strong>{branch_info['name']}</strong>")
 
     dir_swhid = get_swh_persistent_id(
         DIRECTORY,
         directory_subdir["target"],
         metadata={
             "origin": origin["url"],
             "visit": get_swh_persistent_id(SNAPSHOT, snapshot),
             "anchor": get_swh_persistent_id(REVISION, branch_info["revision"]),
             "path": "/",
         },
     )
     assert_contains(resp, dir_swhid)
 
     rev_swhid = get_swh_persistent_id(
         REVISION,
         branch_info["revision"],
         metadata={
             "origin": origin["url"],
             "visit": get_swh_persistent_id(SNAPSHOT, snapshot),
         },
     )
     assert_contains(resp, rev_swhid)
 
     snp_swhid = get_swh_persistent_id(
         SNAPSHOT, snapshot, metadata={"origin": origin["url"],},
     )
     assert_contains(resp, snp_swhid)
 
 
 @given(origin_with_multiple_visits())
 def test_content_origin_snapshot_release_browse(client, archive_data, origin):
     visits = archive_data.origin_visit_get(origin["url"])
     visit = random.choice(visits)
     snapshot = archive_data.snapshot_get(visit["snapshot"])
     branches, releases = process_snapshot_branches(snapshot)
     release_info = random.choice(releases)
 
     directory = release_info["directory"]
     directory_content = archive_data.directory_ls(directory)
     directory_subdir = random.choice(
         [e for e in directory_content if e["type"] == "dir"]
     )
 
     url = reverse(
         "browse-directory",
         url_args={"sha1_git": directory},
         query_params={
             "origin_url": origin["url"],
             "snapshot": snapshot["id"],
             "release": release_info["name"],
             "path": directory_subdir["name"],
         },
     )
 
     resp = client.get(url)
     assert resp.status_code == 200
     assert_template_used(resp, "browse/directory.html")
     _check_origin_snapshot_related_html(resp, origin, snapshot, branches, releases)
     assert_contains(resp, directory_subdir["name"])
     assert_contains(resp, f"Release: <strong>{release_info['name']}</strong>")
 
     dir_swhid = get_swh_persistent_id(
         DIRECTORY,
         directory_subdir["target"],
         metadata={
             "origin": origin["url"],
             "visit": get_swh_persistent_id(SNAPSHOT, snapshot),
             "anchor": get_swh_persistent_id(RELEASE, release_info["id"]),
             "path": "/",
         },
     )
     assert_contains(resp, dir_swhid)
 
     rev_swhid = get_swh_persistent_id(
         REVISION,
         release_info["target"],
         metadata={
             "origin": origin["url"],
             "visit": get_swh_persistent_id(SNAPSHOT, snapshot),
         },
     )
     assert_contains(resp, rev_swhid)
 
     rel_swhid = get_swh_persistent_id(
         RELEASE,
         release_info["id"],
         metadata={
             "origin": origin["url"],
             "visit": get_swh_persistent_id(SNAPSHOT, snapshot),
         },
     )
     assert_contains(resp, rel_swhid)
 
     snp_swhid = get_swh_persistent_id(
         SNAPSHOT, snapshot, metadata={"origin": origin["url"],},
     )
     assert_contains(resp, snp_swhid)
 
 
 def _check_origin_snapshot_related_html(resp, origin, snapshot, branches, releases):
     browse_origin_url = reverse(
         "browse-origin", query_params={"origin_url": origin["url"]}
     )
-    assert_contains(
-        resp,
-        textwrap.indent(
-            (
-                "Browse archived directory for origin\n"
-                f'<a href="{browse_origin_url}">\n'
-                f"  {origin['url']}\n"
-                f"</a>"
-            ),
-            " " * 6,
-        ),
-    )
+
+    assert_contains(resp, f'href="{browse_origin_url}"')
 
     origin_branches_url = reverse(
         "browse-origin-branches",
         query_params={"origin_url": origin["url"], "snapshot": snapshot["id"]},
     )
 
-    assert_contains(
-        resp,
-        '<a href="%s">Branches (%s)</a>' % (escape(origin_branches_url), len(branches)),
-    )
+    assert_contains(resp, f'href="{escape(origin_branches_url)}"')
+    assert_contains(resp, f"Branches ({len(branches)})")
 
     origin_releases_url = reverse(
         "browse-origin-releases",
         query_params={"origin_url": origin["url"], "snapshot": snapshot["id"]},
     )
 
-    assert_contains(
-        resp,
-        '<a href="%s">Releases (%s)</a>' % (escape(origin_releases_url), len(releases)),
-    )
+    assert_contains(resp, f'href="{escape(origin_releases_url)}"')
+    assert_contains(resp, f"Releases ({len(releases)})")
 
     assert_contains(resp, '<li class="swh-branch">', count=len(branches))
     assert_contains(resp, '<li class="swh-release">', count=len(releases))
 
 
 def _directory_view_checks(
     client,
     root_directory_sha1,
     directory_entries,
     path=None,
     origin_url=None,
     snapshot_id=None,
 ):
     dirs = [e for e in directory_entries if e["type"] in ("dir", "rev")]
     files = [e for e in directory_entries if e["type"] == "file"]
 
     url_args = {"sha1_git": root_directory_sha1}
     query_params = {"path": path, "origin_url": origin_url, "snapshot": snapshot_id}
 
     url = reverse("browse-directory", url_args=url_args, query_params=query_params)
 
     root_dir_url = reverse(
         "browse-directory", url_args={"sha1_git": root_directory_sha1}
     )
 
     resp = client.get(url)
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/directory.html")
     assert_contains(
         resp, '<a href="' + root_dir_url + '">' + root_directory_sha1[:7] + "</a>"
     )
     assert_contains(resp, '<td class="swh-directory">', count=len(dirs))
     assert_contains(resp, '<td class="swh-content">', count=len(files))
 
     for d in dirs:
         if d["type"] == "rev":
             dir_url = reverse("browse-revision", url_args={"sha1_git": d["target"]})
         else:
             dir_path = d["name"]
             if path:
                 dir_path = "%s/%s" % (path, d["name"])
             dir_url = reverse(
                 "browse-directory",
                 url_args={"sha1_git": root_directory_sha1},
                 query_params={"path": dir_path},
             )
         assert_contains(resp, dir_url)
 
     for f in files:
         file_path = "%s/%s" % (root_directory_sha1, f["name"])
         if path:
             file_path = "%s/%s/%s" % (root_directory_sha1, path, f["name"])
         query_string = "sha1_git:" + f["target"]
         file_url = reverse(
             "browse-content",
             url_args={"query_string": query_string},
             query_params={"path": file_path},
         )
         assert_contains(resp, file_url)
 
     path_info = gen_path_info(path)
 
     assert_contains(resp, '<li class="swh-path">', count=len(path_info) + 1)
     assert_contains(
         resp, '<a href="%s">%s</a>' % (root_dir_url, root_directory_sha1[:7])
     )
 
     for p in path_info:
         dir_url = reverse(
             "browse-directory",
             url_args={"sha1_git": root_directory_sha1},
             query_params={"path": p["path"]},
         )
         assert_contains(resp, '<a href="%s">%s</a>' % (dir_url, p["name"]))
 
     assert_contains(resp, "vault-cook-directory")
 
     swh_dir_id = get_swh_persistent_id(DIRECTORY, directory_entries[0]["dir_id"])
     swh_dir_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_dir_id})
 
-    assert_contains(
-        resp,
-        textwrap.indent(
-            (
-                f"Browse archived directory\n"
-                f'<a href="{swh_dir_id_url}">\n'
-                f"  {swh_dir_id}\n"
-                f"</a>"
-            ),
-            " " * 4,
-        ),
-    )
-
     swhid_context = {}
     if root_directory_sha1 != directory_entries[0]["dir_id"]:
         swhid_context["anchor"] = get_swh_persistent_id(DIRECTORY, root_directory_sha1)
 
     swhid_context["path"] = f"/{path}/" if path else "/"
 
     if root_directory_sha1 != directory_entries[0]["dir_id"]:
         swhid_context["anchor"] = get_swh_persistent_id(DIRECTORY, root_directory_sha1)
 
     swh_dir_id = get_swh_persistent_id(
         DIRECTORY, directory_entries[0]["dir_id"], metadata=swhid_context
     )
     swh_dir_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_dir_id})
     assert_contains(resp, swh_dir_id)
     assert_contains(resp, swh_dir_id_url)
diff --git a/swh/web/tests/browse/views/test_origin.py b/swh/web/tests/browse/views/test_origin.py
index ce8e65c2..fa160eb4 100644
--- a/swh/web/tests/browse/views/test_origin.py
+++ b/swh/web/tests/browse/views/test_origin.py
@@ -1,1351 +1,1314 @@
 # Copyright (C) 2017-2020  The Software Heritage developers
 # See the AUTHORS file at the top-level directory of this distribution
 # License: GNU Affero General Public License version 3, or any later version
 # See top-level LICENSE file for more information
 
 import random
 import re
 import string
-import textwrap
 
 from django.utils.html import escape
 
 from hypothesis import given
 
 from swh.storage.utils import now
 
 from swh.model.hashutil import hash_to_bytes
 from swh.model.identifiers import CONTENT, DIRECTORY, RELEASE, REVISION, SNAPSHOT
 from swh.model.model import (
     Snapshot,
     SnapshotBranch,
     TargetType,
     OriginVisit,
     OriginVisitStatus,
 )
 from swh.web.browse.snapshot_context import process_snapshot_branches
 from swh.web.common.exc import NotFoundExc
 from swh.web.common.identifiers import get_swh_persistent_id
 from swh.web.common.utils import (
     reverse,
     gen_path_info,
     format_utc_iso_date,
     parse_timestamp,
 )
 from swh.web.tests.data import get_content, random_sha1
 from swh.web.tests.django_asserts import assert_contains, assert_template_used
 from swh.web.tests.strategies import (
     origin,
     origin_with_multiple_visits,
     new_origin,
     new_snapshot,
     visit_dates,
     revisions,
     origin_with_releases,
     release as existing_release,
     unknown_revision,
 )
 
 
 @given(origin_with_multiple_visits())
 def test_origin_visits_browse(client, archive_data, origin):
     url = reverse("browse-origin-visits", query_params={"origin_url": origin["url"]})
     resp = client.get(url)
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/origin-visits.html")
 
     url = reverse("browse-origin-visits", query_params={"origin_url": origin["url"]})
     resp = client.get(url)
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/origin-visits.html")
 
     visits = archive_data.origin_visit_get(origin["url"])
 
     for v in visits:
         vdate = format_utc_iso_date(v["date"], "%Y-%m-%dT%H:%M:%SZ")
         browse_dir_url = reverse(
             "browse-origin-directory",
             query_params={"origin_url": origin["url"], "timestamp": vdate},
         )
         assert_contains(resp, browse_dir_url)
 
-    _check_origin_view_title(resp, origin["url"], "visits")
+    _check_origin_link(resp, origin["url"])
 
 
 @given(origin_with_multiple_visits())
 def test_origin_content_view(client, archive_data, origin):
     origin_visits = archive_data.origin_visit_get(origin["url"])
 
     def _get_archive_data(visit_idx):
         snapshot = archive_data.snapshot_get(origin_visits[visit_idx]["snapshot"])
         head_rev_id = archive_data.snapshot_get_head(snapshot)
         head_rev = archive_data.revision_get(head_rev_id)
         dir_content = archive_data.directory_ls(head_rev["directory"])
         dir_files = [e for e in dir_content if e["type"] == "file"]
         dir_file = random.choice(dir_files)
         branches, releases = process_snapshot_branches(snapshot)
         return {
             "branches": branches,
             "releases": releases,
             "root_dir_sha1": head_rev["directory"],
             "content": get_content(dir_file["checksums"]["sha1"]),
             "visit": origin_visits[visit_idx],
         }
 
     tdata = _get_archive_data(-1)
 
     _origin_content_view_test_helper(
         client,
         archive_data,
         origin,
         origin_visits[-1],
         tdata["branches"],
         tdata["releases"],
         tdata["root_dir_sha1"],
         tdata["content"],
     )
 
     _origin_content_view_test_helper(
         client,
         archive_data,
         origin,
         origin_visits[-1],
         tdata["branches"],
         tdata["releases"],
         tdata["root_dir_sha1"],
         tdata["content"],
         timestamp=tdata["visit"]["date"],
     )
 
     visit_unix_ts = parse_timestamp(tdata["visit"]["date"]).timestamp()
     visit_unix_ts = int(visit_unix_ts)
 
     _origin_content_view_test_helper(
         client,
         archive_data,
         origin,
         origin_visits[-1],
         tdata["branches"],
         tdata["releases"],
         tdata["root_dir_sha1"],
         tdata["content"],
         timestamp=visit_unix_ts,
     )
 
     _origin_content_view_test_helper(
         client,
         archive_data,
         origin,
         origin_visits[-1],
         tdata["branches"],
         tdata["releases"],
         tdata["root_dir_sha1"],
         tdata["content"],
         snapshot_id=tdata["visit"]["snapshot"],
     )
 
     tdata = _get_archive_data(0)
 
     _origin_content_view_test_helper(
         client,
         archive_data,
         origin,
         origin_visits[0],
         tdata["branches"],
         tdata["releases"],
         tdata["root_dir_sha1"],
         tdata["content"],
         visit_id=tdata["visit"]["visit"],
     )
 
     _origin_content_view_test_helper(
         client,
         archive_data,
         origin,
         origin_visits[0],
         tdata["branches"],
         tdata["releases"],
         tdata["root_dir_sha1"],
         tdata["content"],
         snapshot_id=tdata["visit"]["snapshot"],
     )
 
 
 @given(origin())
 def test_origin_root_directory_view(client, archive_data, origin):
     origin_visits = archive_data.origin_visit_get(origin["url"])
 
     visit = origin_visits[-1]
     snapshot = archive_data.snapshot_get(visit["snapshot"])
     head_rev_id = archive_data.snapshot_get_head(snapshot)
     head_rev = archive_data.revision_get(head_rev_id)
     root_dir_sha1 = head_rev["directory"]
     dir_content = archive_data.directory_ls(root_dir_sha1)
     branches, releases = process_snapshot_branches(snapshot)
     visit_unix_ts = parse_timestamp(visit["date"]).timestamp()
     visit_unix_ts = int(visit_unix_ts)
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         dir_content,
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         dir_content,
         visit_id=visit["visit"],
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         dir_content,
         timestamp=visit_unix_ts,
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         dir_content,
         timestamp=visit["date"],
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         dir_content,
         snapshot_id=visit["snapshot"],
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         dir_content,
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         dir_content,
         visit_id=visit["visit"],
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         dir_content,
         timestamp=visit_unix_ts,
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         dir_content,
         timestamp=visit["date"],
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         dir_content,
         snapshot_id=visit["snapshot"],
     )
 
 
 @given(origin())
 def test_origin_sub_directory_view(client, archive_data, origin):
     origin_visits = archive_data.origin_visit_get(origin["url"])
 
     visit = origin_visits[-1]
     snapshot = archive_data.snapshot_get(visit["snapshot"])
     head_rev_id = archive_data.snapshot_get_head(snapshot)
     head_rev = archive_data.revision_get(head_rev_id)
     root_dir_sha1 = head_rev["directory"]
     subdirs = [
         e for e in archive_data.directory_ls(root_dir_sha1) if e["type"] == "dir"
     ]
     branches, releases = process_snapshot_branches(snapshot)
     visit_unix_ts = parse_timestamp(visit["date"]).timestamp()
     visit_unix_ts = int(visit_unix_ts)
 
     if len(subdirs) == 0:
         return
 
     subdir = random.choice(subdirs)
     subdir_content = archive_data.directory_ls(subdir["target"])
     subdir_path = subdir["name"]
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         subdir_content,
         path=subdir_path,
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         subdir_content,
         path=subdir_path,
         visit_id=visit["visit"],
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         subdir_content,
         path=subdir_path,
         timestamp=visit_unix_ts,
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         subdir_content,
         path=subdir_path,
         timestamp=visit["date"],
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         subdir_content,
         path=subdir_path,
         snapshot_id=visit["snapshot"],
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         subdir_content,
         path=subdir_path,
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         subdir_content,
         path=subdir_path,
         visit_id=visit["visit"],
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         subdir_content,
         path=subdir_path,
         timestamp=visit_unix_ts,
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         subdir_content,
         path=subdir_path,
         timestamp=visit["date"],
     )
 
     _origin_directory_view_test_helper(
         client,
         archive_data,
         origin,
         visit,
         branches,
         releases,
         root_dir_sha1,
         subdir_content,
         path=subdir_path,
         snapshot_id=visit["snapshot"],
     )
 
 
 @given(origin())
 def test_origin_branches(client, archive_data, origin):
     origin_visits = archive_data.origin_visit_get(origin["url"])
 
     visit = origin_visits[-1]
     snapshot = archive_data.snapshot_get(visit["snapshot"])
     snapshot_content = process_snapshot_branches(snapshot)
 
     _origin_branches_test_helper(client, origin, snapshot_content)
 
     _origin_branches_test_helper(
         client, origin, snapshot_content, snapshot_id=visit["snapshot"]
     )
 
 
 @given(origin())
 def test_origin_releases(client, archive_data, origin):
     origin_visits = archive_data.origin_visit_get(origin["url"])
 
     visit = origin_visits[-1]
     snapshot = archive_data.snapshot_get(visit["snapshot"])
     snapshot_content = process_snapshot_branches(snapshot)
 
     _origin_releases_test_helper(client, origin, snapshot_content)
 
     _origin_releases_test_helper(
         client, origin, snapshot_content, snapshot_id=visit["snapshot"]
     )
 
 
 @given(
     new_origin(),
     new_snapshot(min_size=4, max_size=4),
     visit_dates(),
     revisions(min_size=3, max_size=3),
 )
 def test_origin_snapshot_null_branch(
     client, archive_data, new_origin, new_snapshot, visit_dates, revisions
 ):
     snp_dict = new_snapshot.to_dict()
     new_origin = archive_data.origin_add([new_origin])[0]
     for i, branch in enumerate(snp_dict["branches"].keys()):
         if i == 0:
             snp_dict["branches"][branch] = None
         else:
             snp_dict["branches"][branch] = {
                 "target_type": "revision",
                 "target": hash_to_bytes(revisions[i - 1]),
             }
 
     archive_data.snapshot_add([Snapshot.from_dict(snp_dict)])
     visit = archive_data.origin_visit_add(
         [
             OriginVisit(
                 origin=new_origin["url"],
                 date=visit_dates[0],
                 type="git",
                 status="ongoing",
                 snapshot=None,
             )
         ]
     )[0]
     visit_status = OriginVisitStatus(
         origin=new_origin["url"],
         visit=visit.visit,
         date=now(),
         status="partial",
         snapshot=snp_dict["id"],
     )
     archive_data.origin_visit_status_add([visit_status])
 
     url = reverse(
         "browse-origin-directory", query_params={"origin_url": new_origin["url"]}
     )
     rv = client.get(url)
     assert rv.status_code == 200
 
 
 @given(
     new_origin(),
     new_snapshot(min_size=4, max_size=4),
     visit_dates(),
     revisions(min_size=4, max_size=4),
 )
 def test_origin_snapshot_invalid_branch(
     client, archive_data, new_origin, new_snapshot, visit_dates, revisions
 ):
     snp_dict = new_snapshot.to_dict()
     new_origin = archive_data.origin_add([new_origin])[0]
     for i, branch in enumerate(snp_dict["branches"].keys()):
         snp_dict["branches"][branch] = {
             "target_type": "revision",
             "target": hash_to_bytes(revisions[i]),
         }
 
     archive_data.snapshot_add([Snapshot.from_dict(snp_dict)])
     visit = archive_data.origin_visit_add(
         [
             OriginVisit(
                 origin=new_origin["url"],
                 date=visit_dates[0],
                 type="git",
                 status="ongoing",
                 snapshot=None,
             )
         ]
     )[0]
     visit_status = OriginVisitStatus(
         origin=new_origin["url"],
         visit=visit.visit,
         date=now(),
         status="full",
         snapshot=snp_dict["id"],
     )
     archive_data.origin_visit_status_add([visit_status])
 
     url = reverse(
         "browse-origin-directory",
         query_params={"origin_url": new_origin["url"], "branch": "invalid_branch"},
     )
     rv = client.get(url)
     assert rv.status_code == 404
 
 
 @given(new_origin())
 def test_browse_visits_origin_not_found(client, new_origin):
     url = reverse("browse-origin-visits", query_params={"origin_url": new_origin.url})
     resp = client.get(url)
     assert resp.status_code == 404
     assert_template_used(resp, "error.html")
     assert_contains(
         resp, f"Origin with url {new_origin.url} not found", status_code=404
     )
 
 
 @given(origin())
 def test_browse_origin_directory_no_visit(client, mocker, origin):
     mock_get_origin_visits = mocker.patch(
         "swh.web.common.origin_visits.get_origin_visits"
     )
     mock_get_origin_visits.return_value = []
     url = reverse("browse-origin-directory", query_params={"origin_url": origin["url"]})
     resp = client.get(url)
     assert resp.status_code == 404
     assert_template_used(resp, "error.html")
     assert_contains(resp, "No visit", status_code=404)
     assert mock_get_origin_visits.called
 
 
 @given(origin())
 def test_browse_origin_directory_unknown_visit(client, mocker, origin):
     mock_get_origin_visits = mocker.patch(
         "swh.web.common.origin_visits.get_origin_visits"
     )
     mock_get_origin_visits.return_value = [{"visit": 1}]
 
     url = reverse(
         "browse-origin-directory",
         query_params={"origin_url": origin["url"], "visit_id": 2},
     )
     resp = client.get(url)
     assert resp.status_code == 404
     assert_template_used(resp, "error.html")
     assert re.search("Visit.*not found", resp.content.decode("utf-8"))
     assert mock_get_origin_visits.called
 
 
 @given(origin())
 def test_browse_origin_directory_not_found(client, origin):
     url = reverse(
         "browse-origin-directory",
         query_params={"origin_url": origin["url"], "path": "/invalid/dir/path/"},
     )
     resp = client.get(url)
     assert resp.status_code == 404
     assert_template_used(resp, "error.html")
     assert re.search("Directory.*not found", resp.content.decode("utf-8"))
 
 
 @given(origin())
 def test_browse_origin_content_no_visit(client, mocker, origin):
     mock_get_origin_visits = mocker.patch(
         "swh.web.common.origin_visits.get_origin_visits"
     )
     mock_get_origin_visits.return_value = []
     url = reverse(
         "browse-origin-content",
         query_params={"origin_url": origin["url"], "path": "foo"},
     )
     resp = client.get(url)
     assert resp.status_code == 404
     assert_template_used(resp, "error.html")
     assert_contains(resp, "No visit", status_code=404)
     assert mock_get_origin_visits.called
 
 
 @given(origin())
 def test_browse_origin_content_unknown_visit(client, mocker, origin):
     mock_get_origin_visits = mocker.patch(
         "swh.web.common.origin_visits.get_origin_visits"
     )
     mock_get_origin_visits.return_value = [{"visit": 1}]
 
     url = reverse(
         "browse-origin-content",
         query_params={"origin_url": origin["url"], "path": "foo", "visit_id": 2},
     )
     resp = client.get(url)
     assert resp.status_code == 404
     assert_template_used(resp, "error.html")
     assert re.search("Visit.*not found", resp.content.decode("utf-8"))
     assert mock_get_origin_visits.called
 
 
 @given(origin())
 def test_browse_origin_content_directory_empty_snapshot(client, mocker, origin):
     mock_snapshot_service = mocker.patch("swh.web.browse.snapshot_context.service")
     mock_get_origin_visit_snapshot = mocker.patch(
         "swh.web.browse.snapshot_context.get_origin_visit_snapshot"
     )
     mock_get_origin_visit_snapshot.return_value = ([], [])
     mock_snapshot_service.lookup_origin.return_value = origin
     mock_snapshot_service.lookup_snapshot_sizes.return_value = {
         "revision": 0,
         "release": 0,
     }
 
     for browse_context in ("content", "directory"):
 
         url = reverse(
             f"browse-origin-{browse_context}",
             query_params={"origin_url": origin["url"], "path": "baz"},
         )
         resp = client.get(url)
         assert resp.status_code == 200
         assert_template_used(resp, f"browse/{browse_context}.html")
         assert re.search("snapshot.*is empty", resp.content.decode("utf-8"))
         assert mock_get_origin_visit_snapshot.called
         assert mock_snapshot_service.lookup_origin.called
         assert mock_snapshot_service.lookup_snapshot_sizes.called
 
 
 @given(origin())
 def test_browse_origin_content_not_found(client, origin):
     url = reverse(
         "browse-origin-content",
         query_params={"origin_url": origin["url"], "path": "/invalid/file/path"},
     )
     resp = client.get(url)
     assert resp.status_code == 404
     assert_template_used(resp, "error.html")
     assert re.search("Directory entry.*not found", resp.content.decode("utf-8"))
 
 
 @given(origin())
 def test_browse_directory_snapshot_not_found(client, mocker, origin):
     mock_get_snapshot_context = mocker.patch(
         "swh.web.browse.snapshot_context.get_snapshot_context"
     )
     mock_get_snapshot_context.side_effect = NotFoundExc("Snapshot not found")
     url = reverse("browse-origin-directory", query_params={"origin_url": origin["url"]})
     resp = client.get(url)
     assert resp.status_code == 404
     assert_template_used(resp, "error.html")
     assert_contains(resp, "Snapshot not found", status_code=404)
     assert mock_get_snapshot_context.called
 
 
 @given(origin())
 def test_origin_empty_snapshot(client, mocker, origin):
     mock_service = mocker.patch("swh.web.browse.snapshot_context.service")
     mock_get_origin_visit_snapshot = mocker.patch(
         "swh.web.browse.snapshot_context.get_origin_visit_snapshot"
     )
     mock_get_origin_visit_snapshot.return_value = ([], [])
     mock_service.lookup_snapshot_sizes.return_value = {
         "revision": 0,
         "release": 0,
     }
     mock_service.lookup_origin.return_value = origin
     url = reverse("browse-origin-directory", query_params={"origin_url": origin["url"]})
     resp = client.get(url)
     assert resp.status_code == 200
     assert_template_used(resp, "browse/directory.html")
     resp_content = resp.content.decode("utf-8")
     assert re.search("snapshot.*is empty", resp_content)
     assert not re.search("swh-tr-link", resp_content)
     assert mock_get_origin_visit_snapshot.called
     assert mock_service.lookup_snapshot_sizes.called
 
 
 @given(origin_with_releases())
 def test_origin_release_browse(client, archive_data, origin):
     snapshot = archive_data.snapshot_get_latest(origin["url"])
     release = [
         b for b in snapshot["branches"].values() if b["target_type"] == "release"
     ][-1]
     release_data = archive_data.release_get(release["target"])
     revision_data = archive_data.revision_get(release_data["target"])
     url = reverse(
         "browse-origin-directory",
         query_params={"origin_url": origin["url"], "release": release_data["name"]},
     )
 
     resp = client.get(url)
     assert resp.status_code == 200
     assert_contains(resp, release_data["name"])
     assert_contains(resp, release["target"])
 
     swhid_context = {
         "origin": origin["url"],
         "visit": get_swh_persistent_id(SNAPSHOT, snapshot["id"]),
         "anchor": get_swh_persistent_id(RELEASE, release_data["id"]),
         "path": "/",
     }
 
     swh_dir_id = get_swh_persistent_id(
         DIRECTORY, revision_data["directory"], metadata=swhid_context
     )
     swh_dir_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_dir_id})
     assert_contains(resp, swh_dir_id)
     assert_contains(resp, swh_dir_id_url)
 
 
 @given(origin_with_releases())
 def test_origin_release_browse_not_found(client, origin):
 
     invalid_release_name = "swh-foo-bar"
     url = reverse(
         "browse-origin-directory",
         query_params={"origin_url": origin["url"], "release": invalid_release_name},
     )
 
     resp = client.get(url)
     assert resp.status_code == 404
     assert re.search(
         f"Release {invalid_release_name}.*not found", resp.content.decode("utf-8")
     )
 
 
 @given(new_origin(), unknown_revision())
 def test_origin_browse_directory_branch_with_non_resolvable_revision(
     client, archive_data, new_origin, unknown_revision
 ):
     branch_name = "master"
     snapshot = Snapshot(
         branches={
             branch_name.encode(): SnapshotBranch(
                 target=hash_to_bytes(unknown_revision), target_type=TargetType.REVISION,
             )
         }
     )
     new_origin = archive_data.origin_add([new_origin])[0]
     archive_data.snapshot_add([snapshot])
     visit = archive_data.origin_visit_add(
         [
             OriginVisit(
                 origin=new_origin["url"],
                 date=now(),
                 type="git",
                 status="ongoing",
                 snapshot=None,
             )
         ]
     )[0]
     visit_status = OriginVisitStatus(
         origin=new_origin["url"],
         visit=visit.visit,
         date=now(),
         status="partial",
         snapshot=snapshot.id,
     )
     archive_data.origin_visit_status_add([visit_status])
 
     url = reverse(
         "browse-origin-directory",
         query_params={"origin_url": new_origin["url"], "branch": branch_name},
     )
 
     resp = client.get(url)
 
     assert resp.status_code == 200
     assert_contains(
         resp, f"Revision {unknown_revision } could not be found in the archive."
     )
 
 
 @given(origin())
 def test_origin_content_no_path(client, origin):
     url = reverse("browse-origin-content", query_params={"origin_url": origin["url"]})
 
     resp = client.get(url)
 
     assert resp.status_code == 400
     assert_contains(
         resp, "The path of a content must be given as query parameter.", status_code=400
     )
 
 
 def test_origin_views_no_url_query_parameter(client):
     for browse_context in (
         "content",
         "directory",
         "log",
         "branches",
         "releases",
         "visits",
     ):
         url = reverse(f"browse-origin-{browse_context}")
         resp = client.get(url)
         assert resp.status_code == 400
         assert_contains(
             resp, "An origin URL must be provided as query parameter.", status_code=400
         )
 
 
 def _origin_content_view_test_helper(
     client,
     archive_data,
     origin_info,
     origin_visit,
     origin_branches,
     origin_releases,
     root_dir_sha1,
     content,
     visit_id=None,
     timestamp=None,
     snapshot_id=None,
 ):
     content_path = "/".join(content["path"].split("/")[1:])
 
     if not visit_id and not snapshot_id:
         visit_id = origin_visit["visit"]
 
     query_params = {"origin_url": origin_info["url"], "path": content_path}
 
     if timestamp:
         query_params["timestamp"] = timestamp
 
     if visit_id:
         query_params["visit_id"] = visit_id
     elif snapshot_id:
         query_params["snapshot"] = snapshot_id
 
     url = reverse("browse-origin-content", query_params=query_params)
 
     resp = client.get(url)
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/content.html")
 
     assert type(content["data"]) == str
 
     assert_contains(resp, '<code class="%s">' % content["hljs_language"])
     assert_contains(resp, escape(content["data"]))
 
     split_path = content_path.split("/")
 
     filename = split_path[-1]
     path = content_path.replace(filename, "")[:-1]
 
     path_info = gen_path_info(path)
 
     del query_params["path"]
 
     if timestamp:
         query_params["timestamp"] = format_utc_iso_date(
             parse_timestamp(timestamp).isoformat(), "%Y-%m-%dT%H:%M:%SZ"
         )
 
     root_dir_url = reverse("browse-origin-directory", query_params=query_params)
 
     assert_contains(resp, '<li class="swh-path">', count=len(path_info) + 1)
 
     assert_contains(resp, '<a href="%s">%s</a>' % (root_dir_url, root_dir_sha1[:7]))
 
     for p in path_info:
         query_params["path"] = p["path"]
         dir_url = reverse("browse-origin-directory", query_params=query_params)
         assert_contains(resp, '<a href="%s">%s</a>' % (dir_url, p["name"]))
 
     assert_contains(resp, "<li>%s</li>" % filename)
 
     query_string = "sha1_git:" + content["sha1_git"]
 
     url_raw = reverse(
         "browse-content-raw",
         url_args={"query_string": query_string},
         query_params={"filename": filename},
     )
     assert_contains(resp, url_raw)
 
     if "path" in query_params:
         del query_params["path"]
 
     origin_branches_url = reverse("browse-origin-branches", query_params=query_params)
 
-    assert_contains(
-        resp,
-        '<a href="%s">Branches (%s)</a>'
-        % (escape(origin_branches_url), len(origin_branches)),
-    )
+    assert_contains(resp, f'href="{escape(origin_branches_url)}"')
+    assert_contains(resp, f"Branches ({len(origin_branches)})")
 
     origin_releases_url = reverse("browse-origin-releases", query_params=query_params)
 
-    assert_contains(
-        resp,
-        '<a href="%s">Releases (%s)</a>'
-        % (escape(origin_releases_url), len(origin_releases)),
-    )
+    assert_contains(resp, f'href="{escape(origin_releases_url)}">')
+    assert_contains(resp, f"Releases ({len(origin_releases)})")
 
     assert_contains(resp, '<li class="swh-branch">', count=len(origin_branches))
 
     query_params["path"] = content_path
 
     for branch in origin_branches:
         root_dir_branch_url = reverse(
             "browse-origin-content",
             query_params={"branch": branch["name"], **query_params},
         )
 
         assert_contains(resp, '<a href="%s">' % root_dir_branch_url)
 
     assert_contains(resp, '<li class="swh-release">', count=len(origin_releases))
 
     query_params["branch"] = None
     for release in origin_releases:
         root_dir_release_url = reverse(
             "browse-origin-content",
             query_params={"release": release["name"], **query_params},
         )
 
         assert_contains(resp, '<a href="%s">' % root_dir_release_url)
 
     url = reverse("browse-origin-content", query_params=query_params)
 
     resp = client.get(url)
     assert resp.status_code == 200
     assert_template_used(resp, "browse/content.html")
 
     snapshot = archive_data.snapshot_get(origin_visit["snapshot"])
     head_rev_id = archive_data.snapshot_get_head(snapshot)
 
     swhid_context = {
         "origin": origin_info["url"],
         "visit": get_swh_persistent_id(SNAPSHOT, snapshot["id"]),
         "anchor": get_swh_persistent_id(REVISION, head_rev_id),
         "path": f"/{content_path}",
     }
 
     swh_cnt_id = get_swh_persistent_id(
         CONTENT, content["sha1_git"], metadata=swhid_context
     )
     swh_cnt_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_cnt_id})
     assert_contains(resp, swh_cnt_id)
     assert_contains(resp, swh_cnt_id_url)
 
     assert_contains(resp, "swh-take-new-snapshot")
 
-    _check_origin_view_title(resp, origin_info["url"], "content")
+    _check_origin_link(resp, origin_info["url"])
 
 
 def _origin_directory_view_test_helper(
     client,
     archive_data,
     origin_info,
     origin_visit,
     origin_branches,
     origin_releases,
     root_directory_sha1,
     directory_entries,
     visit_id=None,
     timestamp=None,
     snapshot_id=None,
     path=None,
 ):
     dirs = [e for e in directory_entries if e["type"] in ("dir", "rev")]
     files = [e for e in directory_entries if e["type"] == "file"]
 
     if not visit_id and not snapshot_id:
         visit_id = origin_visit["visit"]
 
     query_params = {"origin_url": origin_info["url"]}
 
     if timestamp:
         query_params["timestamp"] = timestamp
     elif visit_id:
         query_params["visit_id"] = visit_id
     else:
         query_params["snapshot"] = snapshot_id
 
     if path:
         query_params["path"] = path
 
     url = reverse("browse-origin-directory", query_params=query_params)
 
     resp = client.get(url)
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/directory.html")
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/directory.html")
 
     assert_contains(resp, '<td class="swh-directory">', count=len(dirs))
     assert_contains(resp, '<td class="swh-content">', count=len(files))
 
     if timestamp:
         query_params["timestamp"] = format_utc_iso_date(
             parse_timestamp(timestamp).isoformat(), "%Y-%m-%dT%H:%M:%SZ"
         )
 
     for d in dirs:
         if d["type"] == "rev":
             dir_url = reverse("browse-revision", url_args={"sha1_git": d["target"]})
         else:
             dir_path = d["name"]
             if path:
                 dir_path = "%s/%s" % (path, d["name"])
             query_params["path"] = dir_path
             dir_url = reverse("browse-origin-directory", query_params=query_params,)
         assert_contains(resp, dir_url)
 
     for f in files:
         file_path = f["name"]
         if path:
             file_path = "%s/%s" % (path, f["name"])
         query_params["path"] = file_path
         file_url = reverse("browse-origin-content", query_params=query_params)
         assert_contains(resp, file_url)
 
     if "path" in query_params:
         del query_params["path"]
 
     root_dir_branch_url = reverse("browse-origin-directory", query_params=query_params)
 
     nb_bc_paths = 1
     if path:
         nb_bc_paths = len(path.split("/")) + 1
 
     assert_contains(resp, '<li class="swh-path">', count=nb_bc_paths)
     assert_contains(
         resp, '<a href="%s">%s</a>' % (root_dir_branch_url, root_directory_sha1[:7])
     )
 
     origin_branches_url = reverse("browse-origin-branches", query_params=query_params)
 
-    assert_contains(
-        resp,
-        '<a href="%s">Branches (%s)</a>'
-        % (escape(origin_branches_url), len(origin_branches)),
-    )
+    assert_contains(resp, f'href="{escape(origin_branches_url)}"')
+    assert_contains(resp, f"Branches ({len(origin_branches)})")
 
     origin_releases_url = reverse("browse-origin-releases", query_params=query_params)
 
     nb_releases = len(origin_releases)
     if nb_releases > 0:
-        assert_contains(
-            resp,
-            '<a href="%s">Releases (%s)</a>'
-            % (escape(origin_releases_url), nb_releases),
-        )
+        assert_contains(resp, f'href="{escape(origin_releases_url)}"')
+        assert_contains(resp, f"Releases ({nb_releases})")
 
     if path:
         query_params["path"] = path
 
     assert_contains(resp, '<li class="swh-branch">', count=len(origin_branches))
 
     for branch in origin_branches:
         query_params["branch"] = branch["name"]
         root_dir_branch_url = reverse(
             "browse-origin-directory", query_params=query_params
         )
 
         assert_contains(resp, '<a href="%s">' % root_dir_branch_url)
 
     assert_contains(resp, '<li class="swh-release">', count=len(origin_releases))
 
     query_params["branch"] = None
     for release in origin_releases:
         query_params["release"] = release["name"]
         root_dir_release_url = reverse(
             "browse-origin-directory", query_params=query_params
         )
 
-        assert_contains(resp, '<a href="%s">' % root_dir_release_url)
+        assert_contains(resp, 'href="%s"' % root_dir_release_url)
 
     assert_contains(resp, "vault-cook-directory")
     assert_contains(resp, "vault-cook-revision")
 
     snapshot = archive_data.snapshot_get(origin_visit["snapshot"])
     head_rev_id = archive_data.snapshot_get_head(snapshot)
 
     swhid_context = {
         "origin": origin_info["url"],
         "visit": get_swh_persistent_id(SNAPSHOT, snapshot["id"]),
         "anchor": get_swh_persistent_id(REVISION, head_rev_id),
         "path": f"/{path}" if path else "/",
     }
 
     swh_dir_id = get_swh_persistent_id(
         DIRECTORY, directory_entries[0]["dir_id"], metadata=swhid_context
     )
     swh_dir_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_dir_id})
     assert_contains(resp, swh_dir_id)
     assert_contains(resp, swh_dir_id_url)
 
     assert_contains(resp, "swh-take-new-snapshot")
 
-    _check_origin_view_title(resp, origin_info["url"], "directory")
+    _check_origin_link(resp, origin_info["url"])
 
 
 def _origin_branches_test_helper(
     client, origin_info, origin_snapshot, snapshot_id=None
 ):
     query_params = {"origin_url": origin_info["url"], "snapshot": snapshot_id}
 
     url = reverse("browse-origin-branches", query_params=query_params)
 
     resp = client.get(url)
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/branches.html")
 
     origin_branches = origin_snapshot[0]
     origin_releases = origin_snapshot[1]
 
     origin_branches_url = reverse("browse-origin-branches", query_params=query_params)
 
-    assert_contains(
-        resp,
-        '<a href="%s">Branches (%s)</a>'
-        % (escape(origin_branches_url), len(origin_branches)),
-    )
+    assert_contains(resp, f'href="{escape(origin_branches_url)}"')
+    assert_contains(resp, f"Branches ({len(origin_branches)})")
 
     origin_releases_url = reverse("browse-origin-releases", query_params=query_params)
 
     nb_releases = len(origin_releases)
     if nb_releases > 0:
-        assert_contains(
-            resp,
-            '<a href="%s">Releases (%s)</a>'
-            % (escape(origin_releases_url), nb_releases),
-        )
+        assert_contains(resp, f'href="{escape(origin_releases_url)}">')
+        assert_contains(resp, f"Releases ({nb_releases})")
 
     assert_contains(resp, '<tr class="swh-branch-entry', count=len(origin_branches))
 
     for branch in origin_branches:
         browse_branch_url = reverse(
             "browse-origin-directory",
             query_params={"branch": branch["name"], **query_params},
         )
         assert_contains(resp, '<a href="%s">' % escape(browse_branch_url))
 
         browse_revision_url = reverse(
             "browse-revision",
             url_args={"sha1_git": branch["revision"]},
             query_params=query_params,
         )
         assert_contains(resp, '<a href="%s">' % escape(browse_revision_url))
 
-    _check_origin_view_title(resp, origin_info["url"], "branches")
+    _check_origin_link(resp, origin_info["url"])
 
 
 def _origin_releases_test_helper(
     client, origin_info, origin_snapshot, snapshot_id=None
 ):
     query_params = {"origin_url": origin_info["url"], "snapshot": snapshot_id}
 
     url = reverse("browse-origin-releases", query_params=query_params)
 
     resp = client.get(url)
     assert resp.status_code == 200
     assert_template_used(resp, "browse/releases.html")
 
     origin_branches = origin_snapshot[0]
     origin_releases = origin_snapshot[1]
 
     origin_branches_url = reverse("browse-origin-branches", query_params=query_params)
 
-    assert_contains(
-        resp,
-        '<a href="%s">Branches (%s)</a>'
-        % (escape(origin_branches_url), len(origin_branches)),
-    )
+    assert_contains(resp, f'href="{escape(origin_branches_url)}"')
+    assert_contains(resp, f"Branches ({len(origin_branches)})")
 
     origin_releases_url = reverse("browse-origin-releases", query_params=query_params)
 
     nb_releases = len(origin_releases)
     if nb_releases > 0:
-        assert_contains(
-            resp,
-            '<a href="%s">Releases (%s)</a>'
-            % (escape(origin_releases_url), nb_releases),
-        )
+        assert_contains(resp, f'href="{escape(origin_releases_url)}"')
+        assert_contains(resp, f"Releases ({nb_releases})")
 
     assert_contains(resp, '<tr class="swh-release-entry', count=nb_releases)
 
     for release in origin_releases:
         browse_release_url = reverse(
             "browse-release",
             url_args={"sha1_git": release["id"]},
             query_params=query_params,
         )
         browse_revision_url = reverse(
             "browse-revision",
             url_args={"sha1_git": release["target"]},
             query_params=query_params,
         )
 
         assert_contains(resp, '<a href="%s">' % escape(browse_release_url))
         assert_contains(resp, '<a href="%s">' % escape(browse_revision_url))
 
-    _check_origin_view_title(resp, origin_info["url"], "releases")
+    _check_origin_link(resp, origin_info["url"])
 
 
 @given(
     new_origin(), visit_dates(), revisions(min_size=10, max_size=10), existing_release()
 )
 def test_origin_branches_pagination_with_alias(
     client, archive_data, mocker, new_origin, visit_dates, revisions, existing_release
 ):
     """
     When a snapshot contains a branch or a release alias, pagination links
     in the branches / releases view should be displayed.
     """
     mocker.patch("swh.web.browse.snapshot_context.PER_PAGE", len(revisions) / 2)
     snp_dict = {"branches": {}, "id": hash_to_bytes(random_sha1())}
     for i in range(len(revisions)):
         branch = "".join(random.choices(string.ascii_lowercase, k=8))
         snp_dict["branches"][branch.encode()] = {
             "target_type": "revision",
             "target": hash_to_bytes(revisions[i]),
         }
     release = "".join(random.choices(string.ascii_lowercase, k=8))
     snp_dict["branches"][b"RELEASE_ALIAS"] = {
         "target_type": "alias",
         "target": release.encode(),
     }
     snp_dict["branches"][release.encode()] = {
         "target_type": "release",
         "target": hash_to_bytes(existing_release),
     }
     new_origin = archive_data.origin_add([new_origin])[0]
     archive_data.snapshot_add([Snapshot.from_dict(snp_dict)])
     visit = archive_data.origin_visit_add(
         [
             OriginVisit(
                 origin=new_origin["url"],
                 date=visit_dates[0],
                 type="git",
                 status="ongoing",
                 snapshot=None,
             )
         ]
     )[0]
     visit_status = OriginVisitStatus(
         origin=new_origin["url"],
         visit=visit.visit,
         date=now(),
         status="full",
         snapshot=snp_dict["id"],
     )
     archive_data.origin_visit_status_add([visit_status])
 
     url = reverse(
         "browse-origin-branches", query_params={"origin_url": new_origin["url"]}
     )
     resp = client.get(url)
     assert resp.status_code == 200
     assert_template_used(resp, "browse/branches.html")
     assert_contains(resp, '<ul class="pagination')
 
 
-def _check_origin_view_title(resp, origin_url, object_type):
+def _check_origin_link(resp, origin_url):
     browse_origin_url = reverse(
         "browse-origin", query_params={"origin_url": origin_url}
     )
-
-    assert_contains(
-        resp,
-        textwrap.indent(
-            (
-                f"Browse archived {object_type} for origin\n"
-                f'<a href="{browse_origin_url}">\n'
-                f"  {origin_url}\n"
-                f"</a>"
-            ),
-            " " * 6,
-        ),
-    )
+    assert_contains(resp, f'href="{browse_origin_url}"')
diff --git a/swh/web/tests/browse/views/test_release.py b/swh/web/tests/browse/views/test_release.py
index a2e65241..077619d7 100644
--- a/swh/web/tests/browse/views/test_release.py
+++ b/swh/web/tests/browse/views/test_release.py
@@ -1,169 +1,144 @@
 # Copyright (C) 2018-2020  The Software Heritage developers
 # See the AUTHORS file at the top-level directory of this distribution
 # License: GNU Affero General Public License version 3, or any later version
 # See top-level LICENSE file for more information
 
 import random
-import textwrap
 
 from django.utils.html import escape
 from hypothesis import given
 
 from swh.web.common.identifiers import get_swh_persistent_id
 from swh.web.common.utils import reverse, format_utc_iso_date
 from swh.web.tests.django_asserts import assert_contains, assert_template_used
 from swh.web.tests.strategies import release, origin_with_releases, unknown_release
 
 
 @given(release())
 def test_release_browse(client, archive_data, release):
     _release_browse_checks(client, release, archive_data)
 
 
 @given(origin_with_releases())
 def test_release_browse_with_origin_snapshot(client, archive_data, origin):
     snapshot = archive_data.snapshot_get_latest(origin["url"])
     release = random.choice(
         [
             b["target"]
             for b in snapshot["branches"].values()
             if b["target_type"] == "release"
         ]
     )
 
     _release_browse_checks(client, release, archive_data, origin_url=origin["url"])
     _release_browse_checks(client, release, archive_data, snapshot_id=snapshot["id"])
     _release_browse_checks(
         client,
         release,
         archive_data,
         origin_url=origin["url"],
         snapshot_id=snapshot["id"],
     )
 
 
 @given(unknown_release())
 def test_release_browse_not_found(client, archive_data, unknown_release):
     url = reverse("browse-release", url_args={"sha1_git": unknown_release})
     resp = client.get(url)
     assert resp.status_code == 404
     assert_template_used(resp, "error.html")
     err_msg = "Release with sha1_git %s not found" % unknown_release
     assert_contains(resp, err_msg, status_code=404)
 
 
 @given(release())
 def test_release_uppercase(client, release):
     url = reverse(
         "browse-release-uppercase-checksum", url_args={"sha1_git": release.upper()}
     )
 
     resp = client.get(url)
     assert resp.status_code == 302
 
     redirect_url = reverse("browse-release", url_args={"sha1_git": release})
 
     assert resp["location"] == redirect_url
 
 
 def _release_browse_checks(
     client, release, archive_data, origin_url=None, snapshot_id=None
 ):
     query_params = {"origin_url": origin_url, "snapshot": snapshot_id}
 
     url = reverse(
         "browse-release", url_args={"sha1_git": release}, query_params=query_params
     )
 
     release_data = archive_data.release_get(release)
 
     resp = client.get(url)
 
     release_id = release_data["id"]
     release_name = release_data["name"]
     author_name = release_data["author"]["name"]
 
     release_date = release_data["date"]
     message = release_data["message"]
     target_type = release_data["target_type"]
     target = release_data["target"]
 
     target_url = reverse(
         "browse-revision", url_args={"sha1_git": target}, query_params=query_params
     )
     message_lines = message.split("\n")
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/release.html")
     assert_contains(resp, author_name)
     assert_contains(resp, format_utc_iso_date(release_date))
     assert_contains(
         resp,
         "<h6>%s</h6>%s" % (message_lines[0] or "None", "\n".join(message_lines[1:])),
     )
     assert_contains(resp, release_id)
     assert_contains(resp, release_name)
     assert_contains(resp, target_type)
     assert_contains(resp, '<a href="%s">%s</a>' % (escape(target_url), target))
 
     swh_rel_id = get_swh_persistent_id("release", release_id)
     swh_rel_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_rel_id})
     assert_contains(resp, swh_rel_id)
     assert_contains(resp, swh_rel_id_url)
 
     if origin_url:
         browse_origin_url = reverse(
             "browse-origin", query_params={"origin_url": origin_url}
         )
-        title = (
-            f"Browse archived release for origin\n"
-            f'<a href="{browse_origin_url}">\n'
-            f"  {origin_url}\n"
-            f"</a>"
-        )
-        indent = " " * 6
+        assert_contains(resp, f'href="{browse_origin_url}"')
     elif snapshot_id:
         swh_snp_id = get_swh_persistent_id("snapshot", snapshot_id)
         swh_snp_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_snp_id})
-        title = (
-            f"Browse archived release for snapshot\n"
-            f'<a href="{swh_snp_id_url}">\n'
-            f"  {swh_snp_id}\n"
-            f"</a>"
-        )
-        indent = " " * 6
-    else:
-        title = (
-            f"Browse archived release\n"
-            f'<a href="{swh_rel_id_url}">\n'
-            f"  {swh_rel_id}\n"
-            f"</a>"
-        )
-        indent = " " * 4
-
-    assert_contains(
-        resp, textwrap.indent(title, indent),
-    )
+        assert_contains(resp, f'href="{swh_snp_id_url}"')
 
     if release_data["target_type"] == "revision":
         if origin_url:
             directory_url = reverse(
                 "browse-origin-directory",
                 query_params={
                     "origin_url": origin_url,
                     "release": release_data["name"],
                     "snapshot": snapshot_id,
                 },
             )
         elif snapshot_id:
             directory_url = reverse(
                 "browse-snapshot-directory",
                 url_args={"snapshot_id": snapshot_id},
                 query_params={"release": release_data["name"],},
             )
         else:
             rev = archive_data.revision_get(release_data["target"])
             directory_url = reverse(
                 "browse-directory", url_args={"sha1_git": rev["directory"]}
             )
         assert_contains(resp, escape(directory_url))
diff --git a/swh/web/tests/browse/views/test_revision.py b/swh/web/tests/browse/views/test_revision.py
index a5b97602..baf7e116 100644
--- a/swh/web/tests/browse/views/test_revision.py
+++ b/swh/web/tests/browse/views/test_revision.py
@@ -1,335 +1,294 @@
 # Copyright (C) 2017-2020  The Software Heritage developers
 # See the AUTHORS file at the top-level directory of this distribution
 # License: GNU Affero General Public License version 3, or any later version
 # See top-level LICENSE file for more information
 
 import random
-import textwrap
 
 from django.utils.html import escape
 from hypothesis import given
 
 from swh.model.identifiers import DIRECTORY, REVISION, SNAPSHOT
 from swh.web.common.identifiers import get_swh_persistent_id
 from swh.web.common.utils import reverse, format_utc_iso_date, parse_timestamp
 from swh.web.tests.django_asserts import assert_contains, assert_template_used
 from swh.web.tests.strategies import origin, revision, unknown_revision, new_origin
 
 
 @given(revision())
 def test_revision_browse(client, archive_data, revision):
     _revision_browse_checks(client, archive_data, revision)
 
 
 @given(origin())
 def test_revision_origin_snapshot_browse(client, archive_data, origin):
     snapshot = archive_data.snapshot_get_latest(origin["url"])
     revision = archive_data.snapshot_get_head(snapshot)
 
     _revision_browse_checks(client, archive_data, revision, origin_url=origin["url"])
     _revision_browse_checks(client, archive_data, revision, snapshot=snapshot)
     _revision_browse_checks(
         client, archive_data, revision, origin_url=origin["url"], snapshot=snapshot,
     )
 
     revision = random.choice(archive_data.revision_log(revision))["id"]
     _revision_browse_checks(client, archive_data, revision, origin_url=origin["url"])
 
 
 @given(revision())
 def test_revision_log_browse(client, archive_data, revision):
     per_page = 10
 
     revision_log = archive_data.revision_log(revision)
 
     revision_log_sorted = sorted(
         revision_log,
         key=lambda rev: -parse_timestamp(rev["committer_date"]).timestamp(),
     )
 
     url = reverse(
         "browse-revision-log",
         url_args={"sha1_git": revision},
         query_params={"per_page": per_page},
     )
 
     resp = client.get(url)
 
     next_page_url = reverse(
         "browse-revision-log",
         url_args={"sha1_git": revision},
         query_params={"offset": per_page, "per_page": per_page},
     )
 
     nb_log_entries = per_page
     if len(revision_log_sorted) < per_page:
         nb_log_entries = len(revision_log_sorted)
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/revision-log.html")
     assert_contains(resp, '<tr class="swh-revision-log-entry', count=nb_log_entries)
     assert_contains(resp, '<a class="page-link">Newer</a>')
 
     if len(revision_log_sorted) > per_page:
         assert_contains(
             resp, '<a class="page-link" href="%s">Older</a>' % escape(next_page_url),
         )
 
     for log in revision_log_sorted[:per_page]:
         revision_url = reverse("browse-revision", url_args={"sha1_git": log["id"]})
         assert_contains(resp, log["id"][:7])
         assert_contains(resp, log["author"]["name"])
         assert_contains(resp, format_utc_iso_date(log["date"]))
         assert_contains(resp, escape(log["message"]))
         assert_contains(resp, format_utc_iso_date(log["committer_date"]))
         assert_contains(resp, revision_url)
 
     if len(revision_log_sorted) <= per_page:
         return
 
     resp = client.get(next_page_url)
 
     prev_page_url = reverse(
         "browse-revision-log",
         url_args={"sha1_git": revision},
         query_params={"per_page": per_page},
     )
     next_page_url = reverse(
         "browse-revision-log",
         url_args={"sha1_git": revision},
         query_params={"offset": 2 * per_page, "per_page": per_page},
     )
 
     nb_log_entries = len(revision_log_sorted) - per_page
     if nb_log_entries > per_page:
         nb_log_entries = per_page
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/revision-log.html")
     assert_contains(resp, '<tr class="swh-revision-log-entry', count=nb_log_entries)
 
     assert_contains(
         resp, '<a class="page-link" href="%s">Newer</a>' % escape(prev_page_url)
     )
 
     if len(revision_log_sorted) > 2 * per_page:
         assert_contains(
             resp, '<a class="page-link" href="%s">Older</a>' % escape(next_page_url),
         )
 
     if len(revision_log_sorted) <= 2 * per_page:
         return
 
     resp = client.get(next_page_url)
 
     prev_page_url = reverse(
         "browse-revision-log",
         url_args={"sha1_git": revision},
         query_params={"offset": per_page, "per_page": per_page},
     )
     next_page_url = reverse(
         "browse-revision-log",
         url_args={"sha1_git": revision},
         query_params={"offset": 3 * per_page, "per_page": per_page},
     )
 
     nb_log_entries = len(revision_log_sorted) - 2 * per_page
     if nb_log_entries > per_page:
         nb_log_entries = per_page
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/revision-log.html")
     assert_contains(resp, '<tr class="swh-revision-log-entry', count=nb_log_entries)
     assert_contains(
         resp, '<a class="page-link" href="%s">Newer</a>' % escape(prev_page_url)
     )
 
     if len(revision_log_sorted) > 3 * per_page:
         assert_contains(
             resp, '<a class="page-link" href="%s">Older</a>' % escape(next_page_url),
         )
 
-    swh_rev_id = get_swh_persistent_id(REVISION, revision)
-    swh_rev_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_rev_id})
-
-    assert_contains(
-        resp,
-        textwrap.indent(
-            (
-                f"Browse archived revisions history\n"
-                f'<a href="{swh_rev_id_url}">\n'
-                f"  {swh_rev_id}\n"
-                f"</a>"
-            ),
-            " " * 4,
-        ),
-    )
-
 
 @given(revision(), unknown_revision(), new_origin())
 def test_revision_request_errors(client, revision, unknown_revision, new_origin):
     url = reverse("browse-revision", url_args={"sha1_git": unknown_revision})
     resp = client.get(url)
     assert resp.status_code == 404
     assert_template_used(resp, "error.html")
     assert_contains(
         resp, "Revision with sha1_git %s not found" % unknown_revision, status_code=404
     )
 
     url = reverse(
         "browse-revision",
         url_args={"sha1_git": revision},
         query_params={"origin_url": new_origin.url},
     )
 
     resp = client.get(url)
     assert resp.status_code == 404
     assert_template_used(resp, "error.html")
     assert_contains(
         resp, "the origin mentioned in your request" " appears broken", status_code=404
     )
 
 
 @given(revision())
 def test_revision_uppercase(client, revision):
     url = reverse(
         "browse-revision-uppercase-checksum", url_args={"sha1_git": revision.upper()}
     )
 
     resp = client.get(url)
     assert resp.status_code == 302
 
     redirect_url = reverse("browse-revision", url_args={"sha1_git": revision})
 
     assert resp["location"] == redirect_url
 
 
 def _revision_browse_checks(
     client, archive_data, revision, origin_url=None, snapshot=None
 ):
 
     query_params = {}
     if origin_url:
         query_params["origin_url"] = origin_url
     if snapshot:
         query_params["snapshot"] = snapshot["id"]
 
     url = reverse(
         "browse-revision", url_args={"sha1_git": revision}, query_params=query_params
     )
 
     revision_data = archive_data.revision_get(revision)
 
     author_name = revision_data["author"]["name"]
     committer_name = revision_data["committer"]["name"]
     dir_id = revision_data["directory"]
 
     if origin_url:
         snapshot = archive_data.snapshot_get_latest(origin_url)
         history_url = reverse(
             "browse-origin-log", query_params={"revision": revision, **query_params},
         )
     elif snapshot:
         history_url = reverse(
             "browse-snapshot-log",
             url_args={"snapshot_id": snapshot["id"]},
             query_params={"revision": revision},
         )
     else:
         history_url = reverse("browse-revision-log", url_args={"sha1_git": revision})
 
     resp = client.get(url)
 
     assert resp.status_code == 200
     assert_template_used(resp, "browse/revision.html")
     assert_contains(resp, author_name)
     assert_contains(resp, committer_name)
     assert_contains(resp, history_url)
 
     for parent in revision_data["parents"]:
         parent_url = reverse(
             "browse-revision", url_args={"sha1_git": parent}, query_params=query_params
         )
         assert_contains(resp, '<a href="%s">%s</a>' % (escape(parent_url), parent[:7]))
 
     author_date = revision_data["date"]
     committer_date = revision_data["committer_date"]
 
     message_lines = revision_data["message"].split("\n")
 
     assert_contains(resp, format_utc_iso_date(author_date))
     assert_contains(resp, format_utc_iso_date(committer_date))
     assert_contains(resp, escape(message_lines[0]))
     assert_contains(resp, escape("\n".join(message_lines[1:])))
 
     assert_contains(resp, "vault-cook-directory")
     assert_contains(resp, "vault-cook-revision")
 
     swh_rev_id = get_swh_persistent_id("revision", revision)
     swh_rev_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_rev_id})
     assert_contains(resp, swh_rev_id)
     assert_contains(resp, swh_rev_id_url)
 
     swh_dir_id = get_swh_persistent_id("directory", dir_id)
     swh_dir_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_dir_id})
     assert_contains(resp, swh_dir_id)
     assert_contains(resp, swh_dir_id_url)
 
     if origin_url:
         assert_contains(resp, "swh-take-new-snapshot")
 
     swh_rev_id = get_swh_persistent_id(REVISION, revision)
     swh_rev_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_rev_id})
 
     if origin_url:
         browse_origin_url = reverse(
             "browse-origin", query_params={"origin_url": origin_url}
         )
-        title = (
-            f"Browse archived revision for origin\n"
-            f'<a href="{browse_origin_url}">\n'
-            f"  {origin_url}\n"
-            f"</a>"
-        )
-        indent = " " * 6
+        assert_contains(resp, f'href="{browse_origin_url}"')
     elif snapshot:
         swh_snp_id = get_swh_persistent_id("snapshot", snapshot["id"])
         swh_snp_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_snp_id})
-        title = (
-            f"Browse archived revision for snapshot\n"
-            f'<a href="{swh_snp_id_url}">\n'
-            f"  {swh_snp_id}\n"
-            f"</a>"
-        )
-        indent = " " * 6
-    else:
-        title = (
-            f"Browse archived revision\n"
-            f'<a href="{swh_rev_id_url}">\n'
-            f"  {swh_rev_id}\n"
-            f"</a>"
-        )
-        indent = " " * 4
-
-    assert_contains(
-        resp, textwrap.indent(title, indent),
-    )
+        assert_contains(resp, f'href="{swh_snp_id_url}"')
 
     swhid_context = {}
     if origin_url:
         swhid_context["origin"] = origin_url
     if snapshot:
         swhid_context["visit"] = get_swh_persistent_id(SNAPSHOT, snapshot["id"])
 
     swh_rev_id = get_swh_persistent_id(REVISION, revision, metadata=swhid_context)
     swh_rev_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_rev_id})
     assert_contains(resp, swh_rev_id)
     assert_contains(resp, swh_rev_id_url)
 
     swhid_context["anchor"] = get_swh_persistent_id(REVISION, revision)
     swhid_context["path"] = "/"
 
     swh_dir_id = get_swh_persistent_id(DIRECTORY, dir_id, metadata=swhid_context)
     swh_dir_id_url = reverse("browse-swh-id", url_args={"swh_id": swh_dir_id})
     assert_contains(resp, swh_dir_id)
     assert_contains(resp, swh_dir_id_url)