mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
Standard arguments for extra_ plugin hooks, closes #939
This commit is contained in:
parent
41ddc19756
commit
e3639247cd
5 changed files with 258 additions and 161 deletions
|
|
@ -709,14 +709,19 @@ class Datasette:
|
||||||
template = self.jinja_env.select_template(templates)
|
template = self.jinja_env.select_template(templates)
|
||||||
body_scripts = []
|
body_scripts = []
|
||||||
# pylint: disable=no-member
|
# pylint: disable=no-member
|
||||||
for script in pm.hook.extra_body_script(
|
for extra_script in pm.hook.extra_body_script(
|
||||||
template=template.name,
|
template=template.name,
|
||||||
database=context.get("database"),
|
database=context.get("database"),
|
||||||
table=context.get("table"),
|
table=context.get("table"),
|
||||||
view_name=view_name,
|
view_name=view_name,
|
||||||
|
request=request,
|
||||||
datasette=self,
|
datasette=self,
|
||||||
):
|
):
|
||||||
body_scripts.append(Markup(script))
|
if callable(extra_script):
|
||||||
|
extra_script = extra_script()
|
||||||
|
if asyncio.iscoroutine(extra_script):
|
||||||
|
extra_script = await extra_script
|
||||||
|
body_scripts.append(Markup(extra_script))
|
||||||
|
|
||||||
extra_template_vars = {}
|
extra_template_vars = {}
|
||||||
# pylint: disable=no-member
|
# pylint: disable=no-member
|
||||||
|
|
@ -748,8 +753,12 @@ class Datasette:
|
||||||
"body_scripts": body_scripts,
|
"body_scripts": body_scripts,
|
||||||
"format_bytes": format_bytes,
|
"format_bytes": format_bytes,
|
||||||
"show_messages": lambda: self._show_messages(request),
|
"show_messages": lambda: self._show_messages(request),
|
||||||
"extra_css_urls": self._asset_urls("extra_css_urls", template, context),
|
"extra_css_urls": await self._asset_urls(
|
||||||
"extra_js_urls": self._asset_urls("extra_js_urls", template, context),
|
"extra_css_urls", template, context, request, view_name
|
||||||
|
),
|
||||||
|
"extra_js_urls": await self._asset_urls(
|
||||||
|
"extra_js_urls", template, context, request, view_name
|
||||||
|
),
|
||||||
"base_url": self.config("base_url"),
|
"base_url": self.config("base_url"),
|
||||||
"csrftoken": request.scope["csrftoken"] if request else lambda: "",
|
"csrftoken": request.scope["csrftoken"] if request else lambda: "",
|
||||||
},
|
},
|
||||||
|
|
@ -762,20 +771,26 @@ class Datasette:
|
||||||
|
|
||||||
return await template.render_async(template_context)
|
return await template.render_async(template_context)
|
||||||
|
|
||||||
def _asset_urls(self, key, template, context):
|
async def _asset_urls(self, key, template, context, request, view_name):
|
||||||
# Flatten list-of-lists from plugins:
|
# Flatten list-of-lists from plugins:
|
||||||
seen_urls = set()
|
seen_urls = set()
|
||||||
for url_or_dict in itertools.chain(
|
collected = []
|
||||||
itertools.chain.from_iterable(
|
for hook in getattr(pm.hook, key)(
|
||||||
getattr(pm.hook, key)(
|
template=template.name,
|
||||||
template=template.name,
|
database=context.get("database"),
|
||||||
database=context.get("database"),
|
table=context.get("table"),
|
||||||
table=context.get("table"),
|
datasette=self,
|
||||||
datasette=self,
|
view_name=view_name,
|
||||||
)
|
request=request,
|
||||||
),
|
|
||||||
(self.metadata(key) or []),
|
|
||||||
):
|
):
|
||||||
|
if callable(hook):
|
||||||
|
hook = hook()
|
||||||
|
if asyncio.iscoroutine(hook):
|
||||||
|
hook = await hook
|
||||||
|
collected.extend(hook)
|
||||||
|
collected.extend(self.metadata(key) or [])
|
||||||
|
output = []
|
||||||
|
for url_or_dict in collected:
|
||||||
if isinstance(url_or_dict, dict):
|
if isinstance(url_or_dict, dict):
|
||||||
url = url_or_dict["url"]
|
url = url_or_dict["url"]
|
||||||
sri = url_or_dict.get("sri")
|
sri = url_or_dict.get("sri")
|
||||||
|
|
@ -786,9 +801,10 @@ class Datasette:
|
||||||
continue
|
continue
|
||||||
seen_urls.add(url)
|
seen_urls.add(url)
|
||||||
if sri:
|
if sri:
|
||||||
yield {"url": url, "sri": sri}
|
output.append({"url": url, "sri": sri})
|
||||||
else:
|
else:
|
||||||
yield {"url": url}
|
output.append({"url": url})
|
||||||
|
return output
|
||||||
|
|
||||||
def app(self):
|
def app(self):
|
||||||
"Returns an ASGI app function that serves the whole of Datasette"
|
"Returns an ASGI app function that serves the whole of Datasette"
|
||||||
|
|
|
||||||
|
|
@ -26,17 +26,17 @@ def prepare_jinja2_environment(env):
|
||||||
|
|
||||||
|
|
||||||
@hookspec
|
@hookspec
|
||||||
def extra_css_urls(template, database, table, datasette):
|
def extra_css_urls(template, database, table, view_name, request, datasette):
|
||||||
"Extra CSS URLs added by this plugin"
|
"Extra CSS URLs added by this plugin"
|
||||||
|
|
||||||
|
|
||||||
@hookspec
|
@hookspec
|
||||||
def extra_js_urls(template, database, table, datasette):
|
def extra_js_urls(template, database, table, view_name, request, datasette):
|
||||||
"Extra JavaScript URLs added by this plugin"
|
"Extra JavaScript URLs added by this plugin"
|
||||||
|
|
||||||
|
|
||||||
@hookspec
|
@hookspec
|
||||||
def extra_body_script(template, database, table, view_name, datasette):
|
def extra_body_script(template, database, table, view_name, request, datasette):
|
||||||
"Extra JavaScript code to be included in <script> at bottom of body"
|
"Extra JavaScript code to be included in <script> at bottom of body"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,17 +82,23 @@ You can now use this filter in your custom templates like so::
|
||||||
|
|
||||||
.. _plugin_hook_extra_css_urls:
|
.. _plugin_hook_extra_css_urls:
|
||||||
|
|
||||||
extra_css_urls(template, database, table, datasette)
|
extra_css_urls(template, database, table, view_name, request, datasette)
|
||||||
----------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
``template`` - string
|
``template`` - string
|
||||||
The template that is being rendered, e.g. ``database.html``
|
The template that is being rendered, e.g. ``database.html``
|
||||||
|
|
||||||
``database`` - string or None
|
``database`` - string or None
|
||||||
The name of the database
|
The name of the database, or ``None`` if the page does not correspond to a database (e.g. the root page)
|
||||||
|
|
||||||
``table`` - string or None
|
``table`` - string or None
|
||||||
The name of the table
|
The name of the table, or ``None`` if the page does not correct to a table
|
||||||
|
|
||||||
|
``view_name`` - string
|
||||||
|
The name of the view being displayed. (``index``, ``database``, ``table``, and ``row`` are the most important ones.)
|
||||||
|
|
||||||
|
``request`` - object or None
|
||||||
|
The current HTTP :ref:`internals_request`. This can be ``None`` if the request object is not available.
|
||||||
|
|
||||||
``datasette`` - :ref:`internals_datasette`
|
``datasette`` - :ref:`internals_datasette`
|
||||||
You can use this to access plugin configuration options via ``datasette.plugin_config(your_plugin_name)``
|
You can use this to access plugin configuration options via ``datasette.plugin_config(your_plugin_name)``
|
||||||
|
|
@ -126,17 +132,32 @@ Or a list of dictionaries defining both a URL and an
|
||||||
'sri': 'sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4',
|
'sri': 'sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4',
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
This function can also return an awaitable function, useful if it needs to run any async code:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from datasette import hookimpl
|
||||||
|
|
||||||
|
@hookimpl
|
||||||
|
def extra_css_urls(datasette):
|
||||||
|
async def inner():
|
||||||
|
db = datasette.get_database()
|
||||||
|
results = await db.execute("select url from css_files")
|
||||||
|
return [r[0] for r in results]
|
||||||
|
|
||||||
|
return inner
|
||||||
|
|
||||||
Examples: `datasette-cluster-map <https://github.com/simonw/datasette-cluster-map>`_, `datasette-vega <https://github.com/simonw/datasette-vega>`_
|
Examples: `datasette-cluster-map <https://github.com/simonw/datasette-cluster-map>`_, `datasette-vega <https://github.com/simonw/datasette-vega>`_
|
||||||
|
|
||||||
.. _plugin_hook_extra_js_urls:
|
.. _plugin_hook_extra_js_urls:
|
||||||
|
|
||||||
extra_js_urls(template, database, table, datasette)
|
extra_js_urls(template, database, table, view_name, request, datasette)
|
||||||
---------------------------------------------------
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
Same arguments as ``extra_css_urls``.
|
Same arguments as ``extra_css_urls``.
|
||||||
|
|
||||||
This works in the same way as ``extra_css_urls()`` but for JavaScript. You can
|
This works in the same way as ``extra_css_urls()`` but for JavaScript. You can
|
||||||
return either a list of URLs or a list of dictionaries:
|
return a list of URLs, a list of dictionaries or an awaitable function that returns those things:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
|
@ -164,6 +185,120 @@ you have one:
|
||||||
|
|
||||||
Examples: `datasette-cluster-map <https://github.com/simonw/datasette-cluster-map>`_, `datasette-vega <https://github.com/simonw/datasette-vega>`_
|
Examples: `datasette-cluster-map <https://github.com/simonw/datasette-cluster-map>`_, `datasette-vega <https://github.com/simonw/datasette-vega>`_
|
||||||
|
|
||||||
|
.. _plugin_hook_extra_body_script:
|
||||||
|
|
||||||
|
extra_body_script(template, database, table, view_name, request, datasette)
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Extra JavaScript to be added to a ``<script>`` block at the end of the ``<body>`` element on the page.
|
||||||
|
|
||||||
|
``template`` - string
|
||||||
|
The template that is being rendered, e.g. ``database.html``
|
||||||
|
|
||||||
|
``database`` - string or None
|
||||||
|
The name of the database, or ``None`` if the page does not correspond to a database (e.g. the root page)
|
||||||
|
|
||||||
|
``table`` - string or None
|
||||||
|
The name of the table, or ``None`` if the page does not correct to a table
|
||||||
|
|
||||||
|
``view_name`` - string
|
||||||
|
The name of the view being displayed. (``index``, ``database``, ``table``, and ``row`` are the most important ones.)
|
||||||
|
|
||||||
|
``request`` - object or None
|
||||||
|
The current HTTP :ref:`internals_request`. This can be ``None`` if the request object is not available.
|
||||||
|
|
||||||
|
``datasette`` - :ref:`internals_datasette`
|
||||||
|
You can use this to access plugin configuration options via ``datasette.plugin_config(your_plugin_name)``
|
||||||
|
|
||||||
|
The ``template``, ``database``, ``table`` and ``view_name`` options can be used to return different code depending on which template is being rendered and which database or table are being processed.
|
||||||
|
|
||||||
|
The ``datasette`` instance is provided primarily so that you can consult any plugin configuration options that may have been set, using the ``datasette.plugin_config(plugin_name)`` method documented above.
|
||||||
|
|
||||||
|
The string that you return from this function will be treated as "safe" for inclusion in a ``<script>`` block directly in the page, so it is up to you to apply any necessary escaping.
|
||||||
|
|
||||||
|
You can also return an awaitable function that returns a string.
|
||||||
|
|
||||||
|
Example: `datasette-cluster-map <https://github.com/simonw/datasette-cluster-map>`_
|
||||||
|
|
||||||
|
.. _plugin_hook_extra_template_vars:
|
||||||
|
|
||||||
|
extra_template_vars(template, database, table, view_name, request, datasette)
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Extra template variables that should be made available in the rendered template context.
|
||||||
|
|
||||||
|
``template`` - string
|
||||||
|
The template that is being rendered, e.g. ``database.html``
|
||||||
|
|
||||||
|
``database`` - string or None
|
||||||
|
The name of the database, or ``None`` if the page does not correspond to a database (e.g. the root page)
|
||||||
|
|
||||||
|
``table`` - string or None
|
||||||
|
The name of the table, or ``None`` if the page does not correct to a table
|
||||||
|
|
||||||
|
``view_name`` - string
|
||||||
|
The name of the view being displayed. (``index``, ``database``, ``table``, and ``row`` are the most important ones.)
|
||||||
|
|
||||||
|
``request`` - object or None
|
||||||
|
The current HTTP :ref:`internals_request`. This can be ``None`` if the request object is not available.
|
||||||
|
|
||||||
|
``datasette`` - :ref:`internals_datasette`
|
||||||
|
You can use this to access plugin configuration options via ``datasette.plugin_config(your_plugin_name)``
|
||||||
|
|
||||||
|
This hook can return one of three different types:
|
||||||
|
|
||||||
|
Dictionary
|
||||||
|
If you return a dictionary its keys and values will be merged into the template context.
|
||||||
|
|
||||||
|
Function that returns a dictionary
|
||||||
|
If you return a function it will be executed. If it returns a dictionary those values will will be merged into the template context.
|
||||||
|
|
||||||
|
Function that returns an awaitable function that returns a dictionary
|
||||||
|
You can also return a function which returns an awaitable function which returns a dictionary.
|
||||||
|
|
||||||
|
Datasette runs Jinja2 in `async mode <https://jinja.palletsprojects.com/en/2.10.x/api/#async-support>`__, which means you can add awaitable functions to the template scope and they will be automatically awaited when they are rendered by the template.
|
||||||
|
|
||||||
|
Here's an example plugin that adds a ``"user_agent"`` variable to the template context containing the current request's User-Agent header:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@hookimpl
|
||||||
|
def extra_template_vars(request):
|
||||||
|
return {
|
||||||
|
"user_agent": request.headers.get("user-agent")
|
||||||
|
}
|
||||||
|
|
||||||
|
This example returns an awaitable function which adds a list of ``hidden_table_names`` to the context:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@hookimpl
|
||||||
|
def extra_template_vars(datasette, database):
|
||||||
|
async def hidden_table_names():
|
||||||
|
if database:
|
||||||
|
db = datasette.databases[database]
|
||||||
|
return {"hidden_table_names": await db.hidden_table_names()}
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
return hidden_table_names
|
||||||
|
|
||||||
|
And here's an example which adds a ``sql_first(sql_query)`` function which executes a SQL statement and returns the first column of the first row of results:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@hookimpl
|
||||||
|
def extra_template_vars(datasette, database):
|
||||||
|
async def sql_first(sql, dbname=None):
|
||||||
|
dbname = dbname or database or next(iter(datasette.databases.keys()))
|
||||||
|
return (await datasette.execute(dbname, sql)).rows[0][0]
|
||||||
|
return {"sql_first": sql_first}
|
||||||
|
|
||||||
|
You can then use the new function in a template like so::
|
||||||
|
|
||||||
|
SQLite version: {{ sql_first("select sqlite_version()") }}
|
||||||
|
|
||||||
|
Examples: `datasette-search-all <https://github.com/simonw/datasette-search-all>`_, `datasette-template-sql <https://github.com/simonw/datasette-template-sql>`_
|
||||||
|
|
||||||
.. _plugin_hook_publish_subcommand:
|
.. _plugin_hook_publish_subcommand:
|
||||||
|
|
||||||
publish_subcommand(publish)
|
publish_subcommand(publish)
|
||||||
|
|
@ -293,115 +428,6 @@ If the value matches that pattern, the plugin returns an HTML link element:
|
||||||
|
|
||||||
Examples: `datasette-render-binary <https://github.com/simonw/datasette-render-binary>`_, `datasette-render-markdown <https://github.com/simonw/datasette-render-markdown>`_
|
Examples: `datasette-render-binary <https://github.com/simonw/datasette-render-binary>`_, `datasette-render-markdown <https://github.com/simonw/datasette-render-markdown>`_
|
||||||
|
|
||||||
.. _plugin_hook_extra_body_script:
|
|
||||||
|
|
||||||
extra_body_script(template, database, table, view_name, datasette)
|
|
||||||
------------------------------------------------------------------
|
|
||||||
|
|
||||||
Extra JavaScript to be added to a ``<script>`` block at the end of the ``<body>`` element on the page.
|
|
||||||
|
|
||||||
``template`` - string
|
|
||||||
The template that is being rendered, e.g. ``database.html``
|
|
||||||
|
|
||||||
``database`` - string or None
|
|
||||||
The name of the database, or ``None`` if the page does not correspond to a database (e.g. the root page)
|
|
||||||
|
|
||||||
``table`` - string or None
|
|
||||||
The name of the table, or ``None`` if the page does not correct to a table
|
|
||||||
|
|
||||||
``view_name`` - string
|
|
||||||
The name of the view being displayed. (`index`, `database`, `table`, and `row` are the most important ones.)
|
|
||||||
|
|
||||||
``datasette`` - :ref:`internals_datasette`
|
|
||||||
You can use this to access plugin configuration options via ``datasette.plugin_config(your_plugin_name)``
|
|
||||||
|
|
||||||
The ``template``, ``database`` and ``table`` options can be used to return different code depending on which template is being rendered and which database or table are being processed.
|
|
||||||
|
|
||||||
The ``datasette`` instance is provided primarily so that you can consult any plugin configuration options that may have been set, using the ``datasette.plugin_config(plugin_name)`` method documented above.
|
|
||||||
|
|
||||||
The string that you return from this function will be treated as "safe" for inclusion in a ``<script>`` block directly in the page, so it is up to you to apply any necessary escaping.
|
|
||||||
|
|
||||||
Example: `datasette-cluster-map <https://github.com/simonw/datasette-cluster-map>`_
|
|
||||||
|
|
||||||
.. _plugin_hook_extra_template_vars:
|
|
||||||
|
|
||||||
extra_template_vars(template, database, table, view_name, request, datasette)
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Extra template variables that should be made available in the rendered template context.
|
|
||||||
|
|
||||||
``template`` - string
|
|
||||||
The template that is being rendered, e.g. ``database.html``
|
|
||||||
|
|
||||||
``database`` - string or None
|
|
||||||
The name of the database, or ``None`` if the page does not correspond to a database (e.g. the root page)
|
|
||||||
|
|
||||||
``table`` - string or None
|
|
||||||
The name of the table, or ``None`` if the page does not correct to a table
|
|
||||||
|
|
||||||
``view_name`` - string
|
|
||||||
The name of the view being displayed. (`index`, `database`, `table`, and `row` are the most important ones.)
|
|
||||||
|
|
||||||
``request`` - object
|
|
||||||
The current HTTP :ref:`internals_request`.
|
|
||||||
|
|
||||||
``datasette`` - :ref:`internals_datasette`
|
|
||||||
You can use this to access plugin configuration options via ``datasette.plugin_config(your_plugin_name)``
|
|
||||||
|
|
||||||
This hook can return one of three different types:
|
|
||||||
|
|
||||||
Dictionary
|
|
||||||
If you return a dictionary its keys and values will be merged into the template context.
|
|
||||||
|
|
||||||
Function that returns a dictionary
|
|
||||||
If you return a function it will be executed. If it returns a dictionary those values will will be merged into the template context.
|
|
||||||
|
|
||||||
Function that returns an awaitable function that returns a dictionary
|
|
||||||
You can also return a function which returns an awaitable function which returns a dictionary.
|
|
||||||
|
|
||||||
Datasette runs Jinja2 in `async mode <https://jinja.palletsprojects.com/en/2.10.x/api/#async-support>`__, which means you can add awaitable functions to the template scope and they will be automatically awaited when they are rendered by the template.
|
|
||||||
|
|
||||||
Here's an example plugin that adds a ``"user_agent"`` variable to the template context containing the current request's User-Agent header:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
@hookimpl
|
|
||||||
def extra_template_vars(request):
|
|
||||||
return {
|
|
||||||
"user_agent": request.headers.get("user-agent")
|
|
||||||
}
|
|
||||||
|
|
||||||
This example returns an awaitable function which adds a list of ``hidden_table_names`` to the context:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
@hookimpl
|
|
||||||
def extra_template_vars(datasette, database):
|
|
||||||
async def hidden_table_names():
|
|
||||||
if database:
|
|
||||||
db = datasette.databases[database]
|
|
||||||
return {"hidden_table_names": await db.hidden_table_names()}
|
|
||||||
else:
|
|
||||||
return {}
|
|
||||||
return hidden_table_names
|
|
||||||
|
|
||||||
And here's an example which adds a ``sql_first(sql_query)`` function which executes a SQL statement and returns the first column of the first row of results:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
@hookimpl
|
|
||||||
def extra_template_vars(datasette, database):
|
|
||||||
async def sql_first(sql, dbname=None):
|
|
||||||
dbname = dbname or database or next(iter(datasette.databases.keys()))
|
|
||||||
return (await datasette.execute(dbname, sql)).rows[0][0]
|
|
||||||
return {"sql_first": sql_first}
|
|
||||||
|
|
||||||
You can then use the new function in a template like so::
|
|
||||||
|
|
||||||
SQLite version: {{ sql_first("select sqlite_version()") }}
|
|
||||||
|
|
||||||
Examples: `datasette-search-all <https://github.com/simonw/datasette-search-all>`_, `datasette-template-sql <https://github.com/simonw/datasette-template-sql>`_
|
|
||||||
|
|
||||||
.. _plugin_register_output_renderer:
|
.. _plugin_register_output_renderer:
|
||||||
|
|
||||||
register_output_renderer(datasette)
|
register_output_renderer(datasette)
|
||||||
|
|
|
||||||
|
|
@ -26,16 +26,30 @@ def prepare_connection(conn, database, datasette):
|
||||||
|
|
||||||
|
|
||||||
@hookimpl
|
@hookimpl
|
||||||
def extra_css_urls(template, database, table, datasette):
|
def extra_css_urls(template, database, table, view_name, request, datasette):
|
||||||
return [
|
async def inner():
|
||||||
"https://plugin-example.com/{}/extra-css-urls-demo.css".format(
|
return [
|
||||||
base64.b64encode(
|
"https://plugin-example.com/{}/extra-css-urls-demo.css".format(
|
||||||
json.dumps(
|
base64.b64encode(
|
||||||
{"template": template, "database": database, "table": table,}
|
json.dumps(
|
||||||
).encode("utf8")
|
{
|
||||||
).decode("utf8")
|
"template": template,
|
||||||
)
|
"database": database,
|
||||||
]
|
"table": table,
|
||||||
|
"view_name": view_name,
|
||||||
|
"request_path": request.path
|
||||||
|
if request is not None
|
||||||
|
else None,
|
||||||
|
"added": (
|
||||||
|
await datasette.get_database().execute("select 3 * 5")
|
||||||
|
).first()[0],
|
||||||
|
}
|
||||||
|
).encode("utf8")
|
||||||
|
).decode("utf8")
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
return inner
|
||||||
|
|
||||||
|
|
||||||
@hookimpl
|
@hookimpl
|
||||||
|
|
@ -47,19 +61,27 @@ def extra_js_urls():
|
||||||
|
|
||||||
|
|
||||||
@hookimpl
|
@hookimpl
|
||||||
def extra_body_script(template, database, table, datasette):
|
def extra_body_script(template, database, table, view_name, request, datasette):
|
||||||
return "var extra_body_script = {};".format(
|
async def inner():
|
||||||
json.dumps(
|
return "var extra_body_script = {};".format(
|
||||||
{
|
json.dumps(
|
||||||
"template": template,
|
{
|
||||||
"database": database,
|
"template": template,
|
||||||
"table": table,
|
"database": database,
|
||||||
"config": datasette.plugin_config(
|
"table": table,
|
||||||
"name-of-plugin", database=database, table=table,
|
"config": datasette.plugin_config(
|
||||||
),
|
"name-of-plugin", database=database, table=table,
|
||||||
}
|
),
|
||||||
|
"view_name": view_name,
|
||||||
|
"request_path": request.path if request is not None else None,
|
||||||
|
"added": (
|
||||||
|
await datasette.get_database().execute("select 3 * 5")
|
||||||
|
).first()[0],
|
||||||
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
return inner
|
||||||
|
|
||||||
|
|
||||||
@hookimpl
|
@hookimpl
|
||||||
|
|
|
||||||
|
|
@ -56,14 +56,38 @@ def test_plugin_prepare_connection_arguments(app_client):
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"path,expected_decoded_object",
|
"path,expected_decoded_object",
|
||||||
[
|
[
|
||||||
("/", {"template": "index.html", "database": None, "table": None}),
|
(
|
||||||
|
"/",
|
||||||
|
{
|
||||||
|
"template": "index.html",
|
||||||
|
"database": None,
|
||||||
|
"table": None,
|
||||||
|
"view_name": "index",
|
||||||
|
"request_path": "/",
|
||||||
|
"added": 15,
|
||||||
|
},
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"/fixtures/",
|
"/fixtures/",
|
||||||
{"template": "database.html", "database": "fixtures", "table": None},
|
{
|
||||||
|
"template": "database.html",
|
||||||
|
"database": "fixtures",
|
||||||
|
"table": None,
|
||||||
|
"view_name": "database",
|
||||||
|
"request_path": "/fixtures",
|
||||||
|
"added": 15,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"/fixtures/sortable",
|
"/fixtures/sortable",
|
||||||
{"template": "table.html", "database": "fixtures", "table": "sortable"},
|
{
|
||||||
|
"template": "table.html",
|
||||||
|
"database": "fixtures",
|
||||||
|
"table": "sortable",
|
||||||
|
"view_name": "table",
|
||||||
|
"request_path": "/fixtures/sortable",
|
||||||
|
"added": 15,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
@ -207,6 +231,9 @@ def test_plugin_config_file(app_client):
|
||||||
"database": None,
|
"database": None,
|
||||||
"table": None,
|
"table": None,
|
||||||
"config": {"depth": "root"},
|
"config": {"depth": "root"},
|
||||||
|
"view_name": "index",
|
||||||
|
"request_path": "/",
|
||||||
|
"added": 15,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
|
@ -216,6 +243,9 @@ def test_plugin_config_file(app_client):
|
||||||
"database": "fixtures",
|
"database": "fixtures",
|
||||||
"table": None,
|
"table": None,
|
||||||
"config": {"depth": "database"},
|
"config": {"depth": "database"},
|
||||||
|
"view_name": "database",
|
||||||
|
"request_path": "/fixtures",
|
||||||
|
"added": 15,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
|
|
@ -225,6 +255,9 @@ def test_plugin_config_file(app_client):
|
||||||
"database": "fixtures",
|
"database": "fixtures",
|
||||||
"table": "sortable",
|
"table": "sortable",
|
||||||
"config": {"depth": "table"},
|
"config": {"depth": "table"},
|
||||||
|
"view_name": "table",
|
||||||
|
"request_path": "/fixtures/sortable",
|
||||||
|
"added": 15,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue