diff --git a/datasette/facets.py b/datasette/facets.py index ff6396d726..9d95d0f378 100644 --- a/datasette/facets.py +++ b/datasette/facets.py @@ -105,7 +105,9 @@ def get_facet_size(self): facet_size = self.ds.setting("default_facet_size") max_returned_rows = self.ds.setting("max_returned_rows") custom_facet_size = self.request.args.get("_facet_size") - if custom_facet_size and custom_facet_size.isdigit(): + if custom_facet_size == "max": + facet_size = max_returned_rows + elif custom_facet_size and custom_facet_size.isdigit(): facet_size = int(custom_facet_size) return min(facet_size, max_returned_rows) diff --git a/datasette/static/app.css b/datasette/static/app.css index 617bd2b15b..7f04a16225 100644 --- a/datasette/static/app.css +++ b/datasette/static/app.css @@ -645,13 +645,20 @@ form button[type=button] { .facet-info a.cross:active { text-decoration: none; } +ul li.facet-truncated { + list-style-type: none; + position: relative; + top: -0.35em; + text-indent: 0.85em; +} + .advanced-export { margin-top: 1em; padding: 0.01em 2em 0.01em 1em; width: auto; display: inline-block; box-shadow: 1px 2px 8px 2px rgba(0,0,0,0.08); - background-color: white; + background-color: white; } .download-sqlite em { diff --git a/datasette/templates/table.html b/datasette/templates/table.html index 077332dc01..211352b507 100644 --- a/datasette/templates/table.html +++ b/datasette/templates/table.html @@ -162,7 +162,9 @@

{{ extra_wheres_for_ui|length }} extra where clause{% if extra_wheres_for_ui {% endif %} {% endfor %} {% if facet_info.truncated %} -
  • ...
  • +
  • {% if request.args._facet_size != "max" -%} + {% else -%}…{% endif %} +
  • {% endif %} diff --git a/tests/fixtures.py b/tests/fixtures.py index 0a721d3a15..5730c1bf7f 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -129,16 +129,16 @@ def make_app_client( files.append(extra_filepath) os.chdir(os.path.dirname(filepath)) config = config or {} - config.update( - { - "default_page_size": 50, - "max_returned_rows": max_returned_rows or 100, - "sql_time_limit_ms": sql_time_limit_ms or 200, - # Default is 3 but this results in "too many open files" - # errors when running the full test suite: - "num_sql_threads": 1, - } - ) + for key, value in { + "default_page_size": 50, + "max_returned_rows": max_returned_rows or 100, + "sql_time_limit_ms": sql_time_limit_ms or 200, + # Default is 3 but this results in "too many open files" + # errors when running the full test suite: + "num_sql_threads": 1, + }.items(): + if key not in config: + config[key] = value ds = Datasette( files, immutables=immutables, diff --git a/tests/test_html.py b/tests/test_html.py index 9e86ebc213..4f2cc8ad7e 100644 --- a/tests/test_html.py +++ b/tests/test_html.py @@ -1612,3 +1612,65 @@ def test_navigation_menu_links( assert ( details.find("a", {"href": link}) is None ), f"{link} found but should not have been in nav menu" + + +@pytest.mark.parametrize( + "max_returned_rows,path,expected_num_facets,expected_ellipses,expected_ellipses_url", + ( + ( + 5, + # Default should show 2 facets + "/fixtures/facetable?_facet=neighborhood", + 2, + True, + "/fixtures/facetable?_facet=neighborhood&_facet_size=max", + ), + # _facet_size above max_returned_rows should show max_returned_rows (5) + ( + 5, + "/fixtures/facetable?_facet=neighborhood&_facet_size=50", + 5, + True, + "/fixtures/facetable?_facet=neighborhood&_facet_size=max", + ), + # If max_returned_rows is high enough, should return all + ( + 20, + "/fixtures/facetable?_facet=neighborhood&_facet_size=max", + 14, + False, + None, + ), + # If num facets > max_returned_rows, show ... without a link + # _facet_size above max_returned_rows should show max_returned_rows (5) + ( + 5, + "/fixtures/facetable?_facet=neighborhood&_facet_size=max", + 5, + True, + None, + ), + ), +) +def test_facet_more_links( + max_returned_rows, + path, + expected_num_facets, + expected_ellipses, + expected_ellipses_url, +): + with make_app_client( + config={"max_returned_rows": max_returned_rows, "default_facet_size": 2} + ) as client: + response = client.get(path) + soup = Soup(response.body, "html.parser") + lis = soup.select("#facet-neighborhood ul li:not(.facet-truncated)") + facet_truncated = soup.select_one(".facet-truncated") + assert len(lis) == expected_num_facets + if not expected_ellipses: + assert facet_truncated is None + else: + if expected_ellipses_url: + assert facet_truncated.find("a")["href"] == expected_ellipses_url + else: + assert facet_truncated.find("a") is None