diff --git a/datasette/app.py b/datasette/app.py index c0ceb320..fe65cc43 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -617,6 +617,18 @@ class TableView(RowTableShared): forward_querystring=False ) + # Spot ?_sort_by_desc and redirect to _sort_desc=(_sort) + if '_sort_by_desc' in special_args: + return self.redirect( + request, + path_with_added_args(request, { + '_sort_desc': special_args.get('_sort'), + '_sort_by_desc': None, + '_sort': None, + }), + forward_querystring=False + ) + filters = Filters(sorted(other_args.items())) where_clauses, params = filters.build_where_clauses() @@ -836,6 +848,7 @@ class TableView(RowTableShared): 'display_columns': display_columns, 'filter_columns': filter_columns, 'display_rows': display_rows, + 'is_sortable': any(c['sortable'] for c in display_columns), 'path_with_added_args': path_with_added_args, 'request': request, 'sort': sort, diff --git a/datasette/static/app.css b/datasette/static/app.css index eb70dc67..21faa7a7 100644 --- a/datasette/static/app.css +++ b/datasette/static/app.css @@ -103,6 +103,10 @@ form label { display: inline-block; width: 15%; } +label.sort_by_desc { + width: auto; + padding-right: 1em; +} form input[type=text], form input[type=search] { border: 1px solid #ccc; @@ -216,10 +220,6 @@ form input[type=submit] { .filters input.filter-value { width: 140px; } - form input[type=submit] { - display: block; - margin-top: 0.6em; - } } a.not-underlined { diff --git a/datasette/templates/table.html b/datasette/templates/table.html index 034cab53..5a02fdb9 100644 --- a/datasette/templates/table.html +++ b/datasette/templates/table.html @@ -66,7 +66,22 @@ {% endfor %} - + +
+ {% if is_sortable %} +
+ +
+ + {% endif %} +
diff --git a/tests/test_html.py b/tests/test_html.py index 417fd2ce..31928a34 100644 --- a/tests/test_html.py +++ b/tests/test_html.py @@ -135,6 +135,19 @@ def test_empty_search_parameter_gets_removed(app_client): ) +def test_sort_by_desc_redirects(app_client): + path_base = app_client.get( + '/test_tables/sortable', allow_redirects=False, gather_request=False + ).headers['Location'] + path = path_base + '?' + urllib.parse.urlencode({ + '_sort': 'sortable', + '_sort_by_desc': '1', + }) + response = app_client.get(path, allow_redirects=False, gather_request=False) + assert response.status == 302 + assert response.headers['Location'].endswith('?_sort_desc=sortable') + + @pytest.mark.parametrize('path,expected_classes', [ ('/', ['index']), ('/test_tables', ['db', 'db-test_tables']),