From 5db7ae3ce165ded57c7fb1cfbdb3258b1cf06c10 Mon Sep 17 00:00:00 2001 From: Simon Willison Date: Sat, 24 Oct 2020 17:13:14 -0700 Subject: [PATCH] Link to BLOB downloads, closes #1046 --- datasette/app.py | 8 ++++++++ datasette/static/app.css | 11 +++++++++++ datasette/views/table.py | 11 +++++++++-- tests/test_html.py | 4 ++-- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/datasette/app.py b/datasette/app.py index da62934efc..5b50294f0b 100644 --- a/datasette/app.py +++ b/datasette/app.py @@ -1303,3 +1303,11 @@ def table(self, database, table): def query(self, database, query): return "{}/{}".format(self.database(database), urllib.parse.quote_plus(query)) + + def row(self, database, table, row_path): + return "{}/{}".format(self.table(database, table), row_path) + + def row_blob(self, database, table, row_path, column): + return self.table(database, table) + "/-/blob/{}/{}.blob".format( + row_path, urllib.parse.quote_plus(column) + ) diff --git a/datasette/static/app.css b/datasette/static/app.css index 9b699a9dcd..f7b3551633 100644 --- a/datasette/static/app.css +++ b/datasette/static/app.css @@ -457,6 +457,17 @@ svg.dropdown-menu-icon { top: 1px; } +.blob-download { + display: block; + white-space: nowrap; + padding-right: 20px; + position: relative; + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNiAxNiIgd2lkdGg9IjE2IiBoZWlnaHQ9IjE2Ij48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik03LjQ3IDEwLjc4YS43NS43NSAwIDAwMS4wNiAwbDMuNzUtMy43NWEuNzUuNzUgMCAwMC0xLjA2LTEuMDZMOC43NSA4LjQ0VjEuNzVhLjc1Ljc1IDAgMDAtMS41IDB2Ni42OUw0Ljc4IDUuOTdhLjc1Ljc1IDAgMDAtMS4wNiAxLjA2bDMuNzUgMy43NXpNMy43NSAxM2EuNzUuNzUgMCAwMDAgMS41aDguNWEuNzUuNzUgMCAwMDAtMS41aC04LjV6Ij48L3BhdGg+PC9zdmc+"); + background-size: 16px 16px; + background-position: right; + background-repeat: no-repeat; +} + .anim-scale-in { animation-name: scale-in; animation-duration: 0.15s; diff --git a/datasette/views/table.py b/datasette/views/table.py index b8c9ba556f..717341ae1d 100644 --- a/datasette/views/table.py +++ b/datasette/views/table.py @@ -167,8 +167,15 @@ async def display_columns_and_rows( display_value = plugin_display_value elif isinstance(value, bytes): display_value = jinja2.Markup( - "<Binary data: {} byte{}>".format( - len(value), "" if len(value) == 1 else "s" + '<Binary: {} byte{}>'.format( + self.ds.urls.row_blob( + database, + table, + path_from_row_pks(row, pks, not pks), + column, + ), + len(value), + "" if len(value) == 1 else "s", ) ) elif isinstance(value, dict): diff --git a/tests/test_html.py b/tests/test_html.py index 29c1984494..3af9816f10 100644 --- a/tests/test_html.py +++ b/tests/test_html.py @@ -1231,12 +1231,12 @@ def test_binary_data_display(app_client): [ '1', '1', - '<Binary\xa0data:\xa07\xa0bytes>', + '<Binary:\xa07\xa0bytes>', ], [ '2', '2', - '<Binary\xa0data:\xa07\xa0bytes>', + '<Binary:\xa07\xa0bytes>', ], ] assert expected_tds == [