datasette icon indicating copy to clipboard operation
datasette copied to clipboard

Ability for plugins to collaborate when adding extra HTML to blocks in default templates

Open simonw opened this issue 3 years ago • 11 comments

Sometimes a plugin may want to add content to an existing default template - for example datasette-search-all adds a new search box at the top of index.html. I also want datasette-upload-csvs to add a CTA on the database.html page: https://github.com/simonw/datasette-upload-csvs/issues/18

Currently plugins can do this by providing a new version of the index.html template - but if multiple plugins try to do that only one of them will succeed.

It would be better if there were known areas of those templates which plugins could add additional content to, such that multiple plugins can use the same spot.

simonw avatar Jan 15 '21 18:01 simonw

This relates to #987 (documented HTML hooks for JavaScript plugins) but is not quite the same thing.

simonw avatar Jan 15 '21 18:01 simonw

Also related: #857 (comprehensive documentation of variables available to templates) - since then the plugin hook could be fed the full template context and use that to do its thing.

Or maybe the plugin hooks gets to return the name of a template that should be {% include %} into the page at that point? But the plugin may want to add extra context that is available to that template include.

simonw avatar Jan 15 '21 18:01 simonw

Plugins that want to provide extra context to the template can already do so using the extra_template_vars() plugin hook.

So this hook could work by returning a list of template filenames to be included. Those templates can be bundled with the plugin. Since they are included they will have access to the template context and to any extra_template_vars() values.

simonw avatar Jan 17 '21 00:01 simonw

I think this ends up being a whole collection of new plugin hooks, something like:

  • include_table_top
  • include_table_bottom
  • include_row_top
  • include_row_bottom
  • include_database_top
  • include_database_bottom
  • include_query_bottom
  • include_query_bottom
  • include_index_bottom
  • include_index_bottom

simonw avatar Jan 17 '21 00:01 simonw

I'm going to prototype this in a branch.

simonw avatar Jan 17 '21 00:01 simonw

I'm going to try using Jinja macros to implement this: https://jinja.palletsprojects.com/en/2.11.x/templates/#macros

Maybe using one of these tricks to auto-load the macro? http://codyaray.com/2015/05/auto-load-jinja2-macros

simonw avatar Jan 17 '21 00:01 simonw

Another potential use for this: plugins that provide authentication (like datasette-auth-passwords and datasette-auth-github) could use it to add a chunk of HTML to the "permission denied" page that links to their mechanism of authenticating.

simonw avatar Jan 22 '21 23:01 simonw

I can combine this with #987 - each of these areas of the page can be wrapped in a <div> with a class that matches the name of the plugin hook, that way JavaScript plugins can append their content in the same place as Python plugins.

simonw avatar Jan 25 '21 00:01 simonw

I've got a good prototype working now, but I'm dropping this from the Datasette 0.54 milestone because it requires a bunch of additional work to make sure it is really well tested and documented.

simonw avatar Jan 25 '21 03:01 simonw

More work can happen in the PR: #1204

simonw avatar Jan 25 '21 03:01 simonw

I've got a URL shortening plugin that I would like to embed on the query page but I'd like avoid capturing the entire query.html template. A feature like this would solve it. Where's this at and how can I help?

brandonrobertz avatar Aug 01 '22 05:08 brandonrobertz

One note here: this feature could be called "slots", similar to Layout Slots in Vitepress.

In Vitepress, you can add custom components/widget/gadgets into determined named "slots", like so:

doc-top
doc-bottom
doc-footer-before
doc-before
doc-after
...

Would be great to do in both Python and Javascript, with the upcoming JavaScript API #2052. In datasette-write-ui, all we do is add a few "Insert row" and "edit this row" buttons and that required completely capturing the table.html template, which isn't great for other plugins. But having "slots" like table-footer-before or table-row-id or something would be great to work with.

asg017 avatar Sep 18 '23 06:09 asg017

Thinking about this again. I think it only needs the top slots for the moment (I do like the term slots). So maybe:

  • slot_homepage_top
  • slot_database_top
  • slot_table_top
  • slot_row_top
  • slot_query_top

I'm not sure the word slot is necessary there. Could do this instead:

  • top_homepage
  • top_database
  • top_table
  • top_row
  • top_query

simonw avatar Jan 30 '24 23:01 simonw

Originally I thought about having some kind of accompanying template mechanism where you can have a template called top_homepage.html which gets inserted automatically. That could still happen, using a default plugin.

simonw avatar Jan 30 '24 23:01 simonw

i should probably distinguish between the canned query results page, the database index page and the /database?sql=... page that displays the results of an arbitrary SQL query.

simonw avatar Jan 30 '24 23:01 simonw

OK, I have a working prototype of the top_homepage() hook now.

Here's a plugin that uses a top_homepage.html template:

from datasette import hookimpl
import jinja2


@hookimpl
def top_homepage(datasette, request):
    async def inner():
        try:
            return await datasette.render_template("top_homepage.html", request=request)
        except jinja2.exceptions.TemplatesNotFound:
            return None

    return inner

simonw avatar Jan 30 '24 23:01 simonw

Moving development to this PR:

  • https://github.com/simonw/datasette/pull/2238

simonw avatar Jan 30 '24 23:01 simonw

Preview of the documentation, showing all of the planned hooks: https://datasette--2238.org.readthedocs.build/en/2238/plugin_hooks.html#top-homepage-datasette-request

simonw avatar Jan 30 '24 23:01 simonw

i should probably distinguish between the canned query results page, the database index page and the /database?sql=... page that displays the results of an arbitrary SQL query.

I'm going to go with top_query and top_canned_query.

simonw avatar Jan 31 '24 00:01 simonw

Better documentation: https://datasette--2238.org.readthedocs.build/en/2238/plugin_hooks.html#template-slots

simonw avatar Jan 31 '24 03:01 simonw