Improved UI for CSV/JSON export, closes #266

csv-stream
Simon Willison 2018-06-17 23:03:22 -07:00
rodzic b15f412e04
commit 6204ebb7d5
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 17E2DEA2588B7F52
7 zmienionych plików z 78 dodań i 14 usunięć

Wyświetl plik

@ -118,6 +118,13 @@ form label {
display: inline-block;
width: 15%;
}
.advanced-export form label {
width: auto;
}
.advanced-export input[type=submit] {
font-size: 0.6em;
margin-left: 1em;
}
label.sort_by_desc {
width: auto;
padding-right: 1em;
@ -272,3 +279,10 @@ a.not-underlined {
.facet-info a.cross:active {
text-decoration: none;
}
.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);
}

Wyświetl plik

@ -40,7 +40,7 @@
</form>
{% if rows %}
<p class="export-links">This data as <a href="{{ url_json }}">JSON</a>, <a href="{{ url_csv }}">CSV</a> (<a href="{{ url_csv_dl }}">download CSV</a>)</p>
<p class="export-links">This data as <a href="{{ url_json }}">JSON</a>, <a href="{{ url_csv }}">CSV</a> (<a href="#export">advanced</a>)</p>
<table class="rows-and-columns">
<thead>
<tr>

Wyświetl plik

@ -92,7 +92,7 @@
<p><a class="not-underlined" title="{{ query.sql }}" href="/{{ database }}-{{ database_hash }}?{{ {'sql': query.sql}|urlencode|safe }}{% if query.params %}&amp;{{ query.params|urlencode|safe }}{% endif %}">&#x270e; <span class="underlined">View and edit SQL</span></a></p>
{% endif %}
<p class="export-links">This data as <a href="{{ url_json }}">JSON</a>, <a href="{{ url_csv }}">CSV</a> (<a href="{{ url_csv_dl }}">download CSV</a>)</p>
<p class="export-links">This data as <a href="{{ url_json }}">JSON</a>{% if display_rows %}, <a href="{{ url_csv }}">CSV</a> (<a href="#export">advanced</a>){% endif %}</p>
{% if suggested_facets %}
<p class="suggested-facets">
@ -137,6 +137,27 @@
<p><a href="{{ next_url }}">Next page</a></p>
{% endif %}
{% if display_rows %}
<div id="export" class="advanced-export">
<h3>Advanced export</h3>
<p>JSON shape: <a href="{{ url_json }}">default</a>, <a href="{{ append_querystring(url_json, '_shape=array') }}">array</a>{% if primary_keys %}, <a href="{{ append_querystring(url_json, '_shape=object') }}">object</a>{% endif %}</p>
<form action="{{ url_csv_path }}" method="get">
<p>
CSV options:
<label><input type="checkbox" name="_dl"> download file</label>
{% if expandable_columns %}<label><input type="checkbox" name="_labels"> expand labels</label>{% endif %}
{% if next_url %}<label><input type="checkbox" name="_stream"> stream all records</label>{% endif %}
<input type="submit" value="Export CSV">
{% for key, value in url_csv_args.items() %}
{% if key != "_labels" %}
<input type="hidden" name="{{ key }}" value="{{ value }}">
{% endif %}
{% endfor %}
</p>
</form>
</div>
{% endif %}
{% if table_definition %}
<pre>{{ table_definition }}</pre>
{% endif %}

Wyświetl plik

@ -170,6 +170,13 @@ def validate_sql_select(sql):
raise InvalidSql(msg)
def append_querystring(url, querystring):
op = "&" if ("?" in url) else "?"
return "{}{}{}".format(
url, op, querystring
)
def path_with_added_args(request, args, path=None):
path = path or request.path
if isinstance(args, dict):

Wyświetl plik

@ -382,6 +382,12 @@ class BaseView(RenderMixin):
url_labels_extra = {}
if data.get("expandable_columns"):
url_labels_extra = {"_labels": "on"}
url_csv_args = {
"_size": "max",
**url_labels_extra
}
url_csv = path_with_format(request, "csv", url_csv_args)
url_csv_path = url_csv.split('?')[0]
context = {
**data,
**extras,
@ -389,15 +395,9 @@ class BaseView(RenderMixin):
"url_json": path_with_format(request, "json", {
**url_labels_extra,
}),
"url_csv": path_with_format(request, "csv", {
"_size": "max",
**url_labels_extra
}),
"url_csv_dl": path_with_format(request, "csv", {
"_dl": "1",
"_size": "max",
**url_labels_extra
}),
"url_csv": url_csv,
"url_csv_path": url_csv_path,
"url_csv_args": url_csv_args,
"extra_css_urls": self.ds.extra_css_urls(),
"extra_js_urls": self.ds.extra_js_urls(),
"datasette_version": __version__,

Wyświetl plik

@ -10,6 +10,7 @@ from datasette.utils import (
CustomRow,
Filters,
InterruptedError,
append_querystring,
compound_keys_after_sql,
escape_sqlite,
filters_should_redirect,
@ -748,6 +749,7 @@ class TableView(RowTableShared):
"is_sortable": any(c["sortable"] for c in display_columns),
"path_with_replaced_args": path_with_replaced_args,
"path_with_removed_args": path_with_removed_args,
"append_querystring": append_querystring,
"request": request,
"sort": sort,
"sort_desc": sort_desc,

Wyświetl plik

@ -274,9 +274,10 @@ def test_table_html_simple_primary_key(app_client):
] == [[str(td) for td in tr.select('td')] for tr in table.select('tbody tr')]
def test_table_csv_json_export_links(app_client):
def test_table_csv_json_export_interface(app_client):
response = app_client.get('/fixtures/simple_primary_key')
assert response.status == 200
# The links at the top of the page
links = Soup(response.body, "html.parser").find("p", {
"class": "export-links"
}).findAll("a")
@ -284,9 +285,28 @@ def test_table_csv_json_export_links(app_client):
expected = [
"simple_primary_key.json",
"simple_primary_key.csv?_size=max",
"simple_primary_key.csv?_dl=1&_size=max"
"#export"
]
assert expected == actual
# And the advaced export box at the bottom:
div = Soup(response.body, "html.parser").find("div", {
"class": "advanced-export"
})
json_links = [a["href"].split("/")[-1] for a in div.find("p").findAll("a")]
assert [
"simple_primary_key.json",
"simple_primary_key.json?_shape=array",
"simple_primary_key.json?_shape=object"
] == json_links
# And the CSV form
form = div.find("form")
assert form["action"].endswith("/simple_primary_key.csv")
inputs = [str(input) for input in form.findAll("input")]
assert [
'<input name="_dl" type="checkbox"/>',
'<input type="submit" value="Export CSV"/>',
'<input name="_size" type="hidden" value="max"/>'
] == inputs
def test_csv_json_export_links_include_labels_if_foreign_keys(app_client):
@ -299,7 +319,7 @@ def test_csv_json_export_links_include_labels_if_foreign_keys(app_client):
expected = [
"facetable.json?_labels=on",
"facetable.csv?_labels=on&_size=max",
"facetable.csv?_dl=1&_labels=on&_size=max"
"#export"
]
assert expected == actual