render_cell(value, column, table, database, datasette)

The render_cell plugin hook previously was only passed value.

It is now passed (value, column, table, database, datasette).
This commit is contained in:
Simon Willison 2018-08-28 03:03:01 -07:00
commit 2e836f72d9
No known key found for this signature in database
GPG key ID: 17E2DEA2588B7F52
10 changed files with 127 additions and 25 deletions

View file

@ -146,6 +146,12 @@ METADATA = {
'simple_primary_key': {
'description_html': 'Simple <em>primary</em> key',
'title': 'This <em>HTML</em> is escaped',
"plugins": {
"name-of-plugin": {
"depth": "table",
"special": "this-is-simple_primary_key"
}
}
},
'sortable': {
'sortable_columns': [
@ -199,6 +205,7 @@ METADATA = {
PLUGIN1 = '''
from datasette import hookimpl
import pint
import json
ureg = pint.UnitRegistry()
@ -226,7 +233,6 @@ def extra_js_urls():
@hookimpl
def extra_body_script(template, database, table, datasette):
import json
return 'var extra_body_script = {};'.format(
json.dumps({
"template": template,
@ -239,6 +245,23 @@ def extra_body_script(template, database, table, datasette):
)
})
)
@hookimpl
def render_cell(value, column, table, database, datasette):
# Render some debug output in cell with value RENDER_CELL_DEMO
if value != "RENDER_CELL_DEMO":
return None
return json.dumps({
"column": column,
"table": table,
"database": database,
"config": datasette.plugin_config(
"name-of-plugin",
database=database,
table=table,
)
})
'''
PLUGIN2 = '''
@ -256,7 +279,7 @@ def extra_js_urls():
@hookimpl
def render_cell(value):
def render_cell(value, database):
# Render {"href": "...", "label": "..."} as link
if not isinstance(value, str):
return None
@ -277,10 +300,13 @@ def render_cell(value):
or href.startswith("https://")
):
return None
return jinja2.Markup('<a href="{href}">{label}</a>'.format(
href=jinja2.escape(data["href"]),
label=jinja2.escape(data["label"] or "") or "&nbsp;"
))
return jinja2.Markup(
'<a data-database="{database}" href="{href}">{label}</a>'.format(
database=database,
href=jinja2.escape(data["href"]),
label=jinja2.escape(data["label"] or "") or "&nbsp;"
)
)
'''
TABLES = '''
@ -487,6 +513,7 @@ VALUES
INSERT INTO simple_primary_key VALUES (1, 'hello');
INSERT INTO simple_primary_key VALUES (2, 'world');
INSERT INTO simple_primary_key VALUES (3, '');
INSERT INTO simple_primary_key VALUES (4, 'RENDER_CELL_DEMO');
INSERT INTO primary_key_multiple_columns VALUES (1, 'hey', 'world');
INSERT INTO primary_key_multiple_columns_explicit_label VALUES (1, 'hey', 'world2');

View file

@ -242,7 +242,7 @@ def test_database_page(app_client):
}, {
'columns': ['id', 'content'],
'name': 'simple_primary_key',
'count': 3,
'count': 4,
'hidden': False,
'foreign_keys': {
'incoming': [{
@ -383,7 +383,8 @@ def test_custom_sql(app_client):
assert [
{'content': 'hello'},
{'content': 'world'},
{'content': ''}
{'content': ''},
{'content': 'RENDER_CELL_DEMO'}
] == data['rows']
assert ['content'] == data['columns']
assert 'fixtures' == data['database']
@ -457,6 +458,9 @@ def test_table_json(app_client):
}, {
'id': '3',
'content': '',
}, {
'id': '4',
'content': 'RENDER_CELL_DEMO',
}]
@ -490,6 +494,7 @@ def test_table_shape_arrays(app_client):
['1', 'hello'],
['2', 'world'],
['3', ''],
['4', 'RENDER_CELL_DEMO'],
] == response.json['rows']
@ -500,7 +505,7 @@ def test_table_shape_arrayfirst(app_client):
'_shape': 'arrayfirst'
})
)
assert ['hello', 'world', ''] == response.json
assert ['hello', 'world', '', 'RENDER_CELL_DEMO'] == response.json
def test_table_shape_objects(app_client):
@ -516,6 +521,9 @@ def test_table_shape_objects(app_client):
}, {
'id': '3',
'content': '',
}, {
'id': '4',
'content': 'RENDER_CELL_DEMO',
}] == response.json['rows']
@ -532,6 +540,9 @@ def test_table_shape_array(app_client):
}, {
'id': '3',
'content': '',
}, {
'id': '4',
'content': 'RENDER_CELL_DEMO',
}] == response.json
@ -563,6 +574,10 @@ def test_table_shape_object(app_client):
'3': {
'id': '3',
'content': '',
},
'4': {
'id': '4',
'content': 'RENDER_CELL_DEMO',
}
} == response.json
@ -826,6 +841,7 @@ def test_searchable_invalid_column(app_client):
('/fixtures/simple_primary_key.json?content__contains=o', [
['1', 'hello'],
['2', 'world'],
['4', 'RENDER_CELL_DEMO'],
]),
('/fixtures/simple_primary_key.json?content__exact=', [
['3', ''],
@ -833,6 +849,7 @@ def test_searchable_invalid_column(app_client):
('/fixtures/simple_primary_key.json?content__not=world', [
['1', 'hello'],
['3', ''],
['4', 'RENDER_CELL_DEMO'],
]),
])
def test_table_filter_queries(app_client, path, expected_rows):
@ -866,6 +883,9 @@ def test_view(app_client):
}, {
'upper_content': '',
'content': '',
}, {
'upper_content': 'RENDER_CELL_DEMO',
'content': 'RENDER_CELL_DEMO',
}]

View file

@ -8,6 +8,7 @@ EXPECTED_TABLE_CSV = '''id,content
1,hello
2,world
3,
4,RENDER_CELL_DEMO
'''.replace('\n', '\r\n')
EXPECTED_CUSTOM_CSV = '''content

View file

@ -372,7 +372,7 @@ def test_css_classes_on_body(app_client, path, expected_classes):
def test_table_html_simple_primary_key(app_client):
response = app_client.get('/fixtures/simple_primary_key')
response = app_client.get('/fixtures/simple_primary_key?_size=3')
assert response.status == 200
table = Soup(response.body, 'html.parser').find('table')
assert table['class'] == ['rows-and-columns']
@ -381,7 +381,7 @@ def test_table_html_simple_primary_key(app_client):
for expected_col, th in zip(('content',), ths[1:]):
a = th.find('a')
assert expected_col == a.string
assert a['href'].endswith('/simple_primary_key?_sort={}'.format(
assert a['href'].endswith('/simple_primary_key?_size=3&_sort={}'.format(
expected_col
))
assert ['nofollow'] == a['rel']
@ -613,13 +613,13 @@ def test_compound_primary_key_with_foreign_key_references(app_client):
def test_view_html(app_client):
response = app_client.get("/fixtures/simple_view")
response = app_client.get("/fixtures/simple_view?_size=3")
assert response.status == 200
table = Soup(response.body, "html.parser").find("table")
ths = table.select("thead th")
assert 2 == len(ths)
assert ths[0].find("a") is not None
assert ths[0].find("a")["href"].endswith("/simple_view?_sort=content")
assert ths[0].find("a")["href"].endswith("/simple_view?_size=3&_sort=content")
assert ths[0].find("a").string.strip() == "content"
assert ths[1].find("a") is None
assert ths[1].string.strip() == "upper_content"

View file

@ -72,7 +72,7 @@ def test_plugins_with_duplicate_js_urls(app_client):
)
def test_plugins_render_cell(app_client):
def test_plugins_render_cell_link_from_json(app_client):
sql = """
select '{"href": "http://example.com/", "label":"Example"}'
""".strip()
@ -86,9 +86,25 @@ def test_plugins_render_cell(app_client):
a = td.find("a")
assert a is not None, str(a)
assert a.attrs["href"] == "http://example.com/"
assert a.attrs["data-database"] == "fixtures"
assert a.text == "Example"
def test_plugins_render_cell_demo(app_client):
response = app_client.get("/fixtures/simple_primary_key?id=4")
soup = Soup(response.body, "html.parser")
td = soup.find("td", {"class": "col-content"})
assert {
"column": "content",
"table": "simple_primary_key",
"database": "fixtures",
"config": {
"depth": "table",
"special": "this-is-simple_primary_key"
}
} == json.loads(td.string)
def test_plugin_config(app_client):
assert {"depth": "table"} == app_client.ds.plugin_config(
"name-of-plugin", database="fixtures", table="sortable"
@ -138,7 +154,7 @@ def test_plugin_config(app_client):
),
],
)
def test_extra_body_script(app_client, path, expected_extra_body_script):
def test_plugins_extra_body_script(app_client, path, expected_extra_body_script):
r = re.compile(r"<script>var extra_body_script = (.*?);</script>")
json_data = r.search(app_client.get(path).body.decode("utf8")).group(1)
actual_data = json.loads(json_data)