diff --git a/swh/web/ui/static/css/style.css b/swh/web/ui/static/css/style.css --- a/swh/web/ui/static/css/style.css +++ b/swh/web/ui/static/css/style.css @@ -28,4 +28,39 @@ .file-found { color: #23BA49; } .file-notfound { color: #FF4747; } + +/* Bootstrap custom styling */ +.input-group-field { + display: table-cell; + vertical-align: middle; + border-radius:4px; + min-width:1%; + white-space: nowrap; +} + +.input-group-field .form-control { + border-radius: inherit !important; +} + +.input-group-field:not(:first-child):not(:last-child) { + border-radius:0; +} + +.input-group-field:not(:first-child):not(:last-child) .form-control { + border-left-width: 0; + border-right-width: 0; +} + +.input-group-field:last-child { + border-top-left-radius:0; + border-bottom-left-radius:0; +} + +.input-group > span:not(:last-child) > button { + border-radius: 0; +} + +.multi-input-group > .input-group-btn { + vertical-align: bottom; + padding: 0; } \ No newline at end of file diff --git a/swh/web/ui/templates/api.html b/swh/web/ui/templates/api.html --- a/swh/web/ui/templates/api.html +++ b/swh/web/ui/templates/api.html @@ -1,5 +1,5 @@ {% extends "layout.html" %} -{% block title %}Software Heritage API Overview{% endblock %} +{% block title %}API Overview{% endblock %} {% block content %}
{% for route, doc in doc_routes %} diff --git a/swh/web/ui/templates/browse.html b/swh/web/ui/templates/browse.html new file mode 100644 --- /dev/null +++ b/swh/web/ui/templates/browse.html @@ -0,0 +1,56 @@ +{% extends "layout.html" %} +{% block title %}Browse{% endblock %} +{% block content %} + +
+
+ + + +
+ +
+
+ You can refer to a content (i.e. a file that we have in our database) as its SHA1 or SHA256 + checksum. If you have files to input, you can drag and drop them below to have their hashes + calculated and searched in SWH. Files with the same checksum will automatically be ignored. +
+
+ {% include 'includes/search-form.html' %} +
+
+ + +
+ {% include 'includes/home-revision.html' %} +
+ + +
+ {% include 'includes/home-origin.html' %} +
+ + +
+ {% include 'includes/home-directory.html' %} +
+
+ +
+
+ + +{% endblock %} diff --git a/swh/web/ui/templates/home.html b/swh/web/ui/templates/home.html --- a/swh/web/ui/templates/home.html +++ b/swh/web/ui/templates/home.html @@ -1,9 +1,12 @@ {% extends "layout.html" %} {% block title %}Home{% endblock %} {% block content %} + + {% endblock %} diff --git a/swh/web/ui/templates/includes/home-directory.html b/swh/web/ui/templates/includes/home-directory.html new file mode 100644 --- /dev/null +++ b/swh/web/ui/templates/includes/home-directory.html @@ -0,0 +1,111 @@ + +
+
+ Advanced search +
+ diff --git a/swh/web/ui/templates/includes/home-origin.html b/swh/web/ui/templates/includes/home-origin.html new file mode 100644 --- /dev/null +++ b/swh/web/ui/templates/includes/home-origin.html @@ -0,0 +1,57 @@ + +
+
+ Advanced search +
+ diff --git a/swh/web/ui/templates/includes/home-revision.html b/swh/web/ui/templates/includes/home-revision.html new file mode 100644 --- /dev/null +++ b/swh/web/ui/templates/includes/home-revision.html @@ -0,0 +1,66 @@ + +
+
+ Advanced search +
+ diff --git a/swh/web/ui/templates/search-form.html b/swh/web/ui/templates/includes/search-form.html rename from swh/web/ui/templates/search-form.html rename to swh/web/ui/templates/includes/search-form.html --- a/swh/web/ui/templates/search-form.html +++ b/swh/web/ui/templates/includes/search-form.html @@ -1,5 +1,5 @@ -

Search with SHA-1 or SHA-256:

+
+ type="text" class="form-control" + name="q" + placeholder="SHA-1 or SHA-256 checksum" />
-

Search with files

+
+ id="file-hash-input" + class="form-control" + multiple + name="filename" + value="" + style="display:none" + placeholder="File(s) to hash and search" />
Drag and drop or click here to hash files and search for them. Your files will NOT be uploaded, hashing is done locally. @@ -58,15 +58,13 @@ - - - - - +{% for fname in ['lib/core.js', 'lib/lib-typedarrays.js', 'lib/sha1.js', 'lib/sha256.js', 'js/search.js'] %} + +{% endfor %} diff --git a/swh/web/ui/templates/layout.html b/swh/web/ui/templates/layout.html --- a/swh/web/ui/templates/layout.html +++ b/swh/web/ui/templates/layout.html @@ -1,37 +1,57 @@ - - - - - {% block title %}{% endblock %} - The Software Heritage Archive - - - - - - - - - - - -
-
-

{{ self.title() }}

+ + + + + {% block title %}{% endblock %} - The Software Heritage Archive + + + + + + + + + + + +
+
+

{{ self.title() }}

+ +
-
- {% with messages = get_flashed_messages(with_categories=true) %} + {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} -
- {% for category, message in messages %} - - {% endfor %} -
+
+ {% for category, message in messages %} + + {% endfor %} +
{% endif %} - {% endwith %} -
- {% block content %}{% endblock %} -
- + {% endwith %} +
+ {% block content %}{% endblock %} +
+ diff --git a/swh/web/ui/templates/origin.html b/swh/web/ui/templates/origin.html --- a/swh/web/ui/templates/origin.html +++ b/swh/web/ui/templates/origin.html @@ -3,38 +3,46 @@ {% block content %} {% if message is not none %} - {{ message }} +{{ message }} {% endif %} {% if origin is not none %} - - - - - -
Details on origin {{ origin['id'] }}: -
-
-
-
-
+ + +{% for fname in ['js/calendar.js', 'lib/jquery.flot.min.js', 'lib/jquery.flot.time.min.js', 'lib/jquery.flot.selection.min.js', 'lib/jquery.flot.tooltip.min.js'] %} + +{% endfor %} + + +

Origin visit history

+
+
+
+
- {% for key in ['type', 'lister', 'project', 'url'] %} - {% if origin[key] is not none %} -
-
{{ key }}
-
{{ origin[key] }}
-
- {% endif %} - {% endfor %} - {% if 'decoding_failures' in content %} -
-
(some decoding errors)
-
- {% endif %}
- + + +

Origin information

+
Details on origin {{ origin['id'] }}: + {% for key in ['type', 'lister', 'project', 'url'] %} + {% if origin[key] is not none %} +
+
{{ key }}
+
{{ origin[key] }}
+
+ {% endif %} + {% endfor %} + {% if 'decoding_failures' in content %} +
+
(some decoding errors)
+
+ {% endif %} +
+ + + {% endif %} {% endblock %} diff --git a/swh/web/ui/templates/search.html b/swh/web/ui/templates/search.html --- a/swh/web/ui/templates/search.html +++ b/swh/web/ui/templates/search.html @@ -4,7 +4,7 @@
- {% include 'search-form.html' %} + {% include 'includes/search-form.html' %} {% if search_res is not none %} diff --git a/swh/web/ui/tests/views/test_browse.py b/swh/web/ui/tests/views/test_browse.py --- a/swh/web/ui/tests/views/test_browse.py +++ b/swh/web/ui/tests/views/test_browse.py @@ -19,6 +19,39 @@ self.filename = filename +class StaticViews(test_app.SWHViewTestCase): + render_template = False + + @patch('swh.web.ui.apidoc.APIUrls') + @istest + def browse_api_doc(self, mock_api_urls): + # given + endpoints = { + '/a/doc/endpoint/': 'relevant documentation', + '/some/other/endpoint/': 'more docstrings'} + mock_api_urls.apidoc_routes = endpoints + + # when + rv = self.client.get('/api/') + + # then + self.assertEquals(rv.status_code, 200) + self.assertIsNotNone( + self.get_context_variable('doc_routes'), + sorted(endpoints.items()) + ) + self.assert_template_used('api.html') + + @istest + def browse_archive(self): + # when + rv = self.client.get('/browse/') + + # then + self.assertEquals(rv.status_code, 200) + self.assert_template_used('browse.html') + + class SearchRedirectsView(test_app.SWHViewTestCase): render_template = False @@ -116,26 +149,6 @@ class SearchView(test_app.SWHViewTestCase): render_template = False - @patch('swh.web.ui.apidoc.APIUrls') - @istest - def browse_api_doc(self, mock_api_urls): - # given - endpoints = { - '/a/doc/endpoint/': 'relevant documentation', - '/some/other/endpoint/': 'more docstrings'} - mock_api_urls.apidoc_routes = endpoints - - # when - rv = self.client.get('/api/1/doc/') - - # then - self.assertEquals(rv.status_code, 200) - self.assertIsNotNone( - self.get_context_variable('doc_routes'), - sorted(endpoints.items()) - ) - self.assert_template_used('api.html') - @istest def search_default(self): # when diff --git a/swh/web/ui/tests/views/test_main.py b/swh/web/ui/tests/views/test_main.py --- a/swh/web/ui/tests/views/test_main.py +++ b/swh/web/ui/tests/views/test_main.py @@ -5,30 +5,20 @@ from nose.tools import istest -from unittest.mock import patch - from .. import test_app class MainViewTestCase(test_app.SWHViewTestCase): render_template = False - @patch('flask.flash') @istest - def homepage(self, mock_flash): - # given - mock_flash.return_value = 'something' - + def homepage(self): # when rv = self.client.get('/') # then - self.assertEquals(rv.status_code, 200) - self.assert_template_used('home.html') - - mock_flash.assert_called_once_with( - 'This Web app is still work in progress, use at your own risk', - 'warning') + self.assertEquals(rv.status_code, 302) + self.assertRedirects(rv, '/browse/') @istest def info(self): diff --git a/swh/web/ui/views/browse.py b/swh/web/ui/views/browse.py --- a/swh/web/ui/views/browse.py +++ b/swh/web/ui/views/browse.py @@ -118,7 +118,14 @@ return render_template('search.html', **env) -@app.route('/api/1/doc/') +@app.route('/browse/') +def browse(): + """Render the user-facing browse view + """ + return render_template('browse.html') + + +@app.route('/api/') def browse_api_doc(): """Render the API's documentation. """ diff --git a/swh/web/ui/views/main.py b/swh/web/ui/views/main.py --- a/swh/web/ui/views/main.py +++ b/swh/web/ui/views/main.py @@ -13,9 +13,7 @@ """Home page """ - flask.flash('This Web app is still work in progress, use at your own risk', - 'warning') - return flask.render_template('home.html') + return flask.redirect(flask.url_for('browse')) @app.route('/about/')