{"id": 314506446, "node_id": "MDU6SXNzdWUzMTQ1MDY0NDY=", "number": 214, "title": "Ability for plugins to define extra JavaScript and CSS", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2018-04-16T05:29:34Z", "updated_at": "2020-09-30T20:36:11Z", "closed_at": "2018-04-18T03:13:03Z", "author_association": "OWNER", "pull_request": null, "body": "This can hook in to the existing `extra_css_urls` and `extra_js_urls` mechanism:\r\n\r\nhttps://github.com/simonw/datasette/blob/b2955d9065ea019500c7d072bcd9d49d1967f051/datasette/app.py#L304-L305\r\n\r\nThe plugins should be able to bundle their own assets though, so it will also have to integrate with the `/static/` static mounts mechanism somehow:\r\n\r\nhttps://github.com/simonw/datasette/blob/b2955d9065ea019500c7d072bcd9d49d1967f051/datasette/app.py#L1255-L1257\r\n\r\nRefs #14", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/214/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 314847571, "node_id": "MDU6SXNzdWUzMTQ4NDc1NzE=", "number": 220, "title": "Investigate syntactic sugar for plugins", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2018-04-16T23:01:39Z", "updated_at": "2020-06-11T21:50:06Z", "closed_at": "2020-06-11T21:49:55Z", "author_association": "OWNER", "pull_request": null, "body": "Suggested by @andrewhayward on Twitter: https://twitter.com/arhayward/status/986015118965268480?s=21\r\n\r\n> Have you considered a basic abstraction on top of that, for standard hook features?\r\n\r\n```\r\n@sql_function\r\nrandom_integer(a,b):\r\n return random.randint(a,b)\r\n\r\n@template_filter\r\nuppercase(str):\r\n return str.upper()\r\n```\r\n\r\nMaybe `from datasette.plugins import template_filter`?\r\n\r\nWould have to work out how to get this to play well with pluggy", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/220/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 314506669, "node_id": "MDU6SXNzdWUzMTQ1MDY2Njk=", "number": 215, "title": "Allow plugins to define additional URL routes and views", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 5512395, "label": "Datasette 0.44"}, "comments": 14, "created_at": "2018-04-16T05:31:09Z", "updated_at": "2020-06-09T03:14:32Z", "closed_at": "2020-06-09T03:12:08Z", "author_association": "OWNER", "pull_request": null, "body": "Might be as simple as having plugins get passed the `app` after the other routes have been defined:\r\n\r\nhttps://github.com/simonw/datasette/blob/b2955d9065ea019500c7d072bcd9d49d1967f051/datasette/app.py#L1270-L1274\r\n\r\nRefs #14", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/215/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 314725342, "node_id": "MDU6SXNzdWUzMTQ3MjUzNDI=", "number": 217, "title": "Plugin support for datasette publish", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2018-04-16T16:17:14Z", "updated_at": "2018-07-26T05:33:39Z", "closed_at": "2018-07-26T05:16:00Z", "author_association": "OWNER", "pull_request": null, "body": "It should be possible to support additional deployment options by writing a plugin (see #59).\r\n\r\nAs part of this, rewrite the Heroku and Now publishers to be implemented as plugins (they will still ship with datasette by default).\r\n\r\nMaybe `datasette package` should be changed to being part of publish instead, `datasette publish docker` perhaps? \r\n\r\nRefs #14", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/217/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 314771615, "node_id": "MDU6SXNzdWUzMTQ3NzE2MTU=", "number": 218, "title": "Support custom unit display in order to handle \"$10,000\"", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-16T18:39:31Z", "updated_at": "2018-07-10T17:45:38Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "I tried to get Datasette to display `$10,000` using the new units support but we currently only display units as a suffix:\r\n\r\nhttps://github.com/simonw/datasette/blob/10a34f995c70daa37a8a2aa02c3135a4b023a24c/datasette/app.py#L563-L572\r\n\r\nIt would be neat if there was a mechanism for specifying a custom unit display - maybe something like this:\r\n\r\n```\r\n{\r\n \"custom_units\": {\r\n \"us_dollar\": {\r\n \"unit\": \"us_dollar = [] = $\",\r\n \"format\": \"${:,}\"\r\n }\r\n }\r\n}\r\n```", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/218/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 314665147, "node_id": "MDU6SXNzdWUzMTQ2NjUxNDc=", "number": 216, "title": "Bug: Sort by column with NULL in next_page URL", "user": {"value": 222245, "label": "carlmjohnson"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 15, "created_at": "2018-04-16T14:03:18Z", "updated_at": "2018-04-17T01:45:24Z", "closed_at": "2018-04-17T01:45:24Z", "author_association": "NONE", "pull_request": null, "body": "Copy-pasting from https://github.com/simonw/datasette/issues/189#issuecomment-381429213, since that issue is closed:\r\n\r\nI think I found a bug. I tried to sort by middle initial in my salaries set, and many middle initials are null. The `next_url` gets set by Datasette to:\r\n\r\nhttp://localhost:8001/salaries-d3a5631/2017+Maryland+state+salaries?_next=None%2C391&_sort=middle_initial\r\n\r\nBut then None is interpreted literally and it tries to find a name with the middle initial \"None\" and ends up skipping ahead to O on page 2.\r\n", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/216/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 314834783, "node_id": "MDU6SXNzdWUzMTQ4MzQ3ODM=", "number": 219, "title": "Expose units in the JSON API?", "user": {"value": 45057, "label": "russss"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-16T22:04:25Z", "updated_at": "2018-04-16T22:04:25Z", "closed_at": null, "author_association": "CONTRIBUTOR", "pull_request": null, "body": "From #203: it would be nice for the JSON API to (optionally) return columns rendered with units in them - if, for example, you're consuming the JSON to render the rows on a map.\r\n\r\nI'm not entirely sure how useful this will be though - at the moment my map queries are custom SQL queries (a few have joins in, the rest might be fetching large amounts of data so it makes sense to limit columns fetched). Perhaps the SQL function is a better approach in general.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/219/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 314506033, "node_id": "MDU6SXNzdWUzMTQ1MDYwMzM=", "number": 213, "title": "Documentation for plugins system", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-16T05:27:07Z", "updated_at": "2018-04-16T15:12:48Z", "closed_at": "2018-04-16T15:12:48Z", "author_association": "OWNER", "pull_request": null, "body": "Documentation for #14 - how to write plugins, how to ship plugins to PyPI and how to use the `--plugins-dir` option added in #211 ", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/213/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 314504812, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgxNzU1MjIw", "number": 212, "title": "New --plugins-dir=plugins/ option", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-16T05:19:28Z", "updated_at": "2018-04-16T05:22:18Z", "closed_at": "2018-04-16T05:22:01Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/212", "body": "Refs #211", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/212/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null} {"id": 314471743, "node_id": "MDU6SXNzdWUzMTQ0NzE3NDM=", "number": 211, "title": "Load plugins from a `--plugins-dir=plugins/` directory", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2018-04-16T01:17:43Z", "updated_at": "2018-04-16T05:22:02Z", "closed_at": "2018-04-16T05:22:02Z", "author_association": "OWNER", "pull_request": null, "body": "In #14 and 33c7c53ff87c2 I've added working support for setuptools entry_points plugins. These can be installed from PyPI using `pip install ...`.\r\n\r\nI imagine some projects will benefit from being able to add plugins without first publishing them to PyPI. Datasette already supports [loading custom templates](http://datasette.readthedocs.io/en/latest/custom_templates.html#custom-templates) like so:\r\n\r\n datasette serve --template-dir=mytemplates/ mydb.db\r\n\r\nI propose an additional option, `--plugins-dir=` which specifies a directory full of `blah.py` files which will be loaded into Datasette when the application server starts.\r\n\r\n datasette serve --plugins-dir=myplugins/ mydb.db\r\n\r\nThis will also need to be supported by `datasette publish` as those Python files should be copied up as part of the deployment.", "repo": {"value": 107914493, "label": "datasette"}, "type": "issue", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/211/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "completed"} {"id": 314469126, "node_id": "MDExOlB1bGxSZXF1ZXN0MTgxNzMxOTU2", "number": 210, "title": "Start of the plugin system, based on pluggy", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2018-04-16T00:51:30Z", "updated_at": "2018-04-16T00:56:16Z", "closed_at": "2018-04-16T00:56:16Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/210", "body": "Refs #14", "repo": {"value": 107914493, "label": "datasette"}, "type": "pull", "active_lock_reason": null, "performed_via_github_app": null, "reactions": "{\"url\": \"https://api.github.com/repos/simonw/datasette/issues/210/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 0, "state_reason": null}