{"id": 564833696, "node_id": "MDU6SXNzdWU1NjQ4MzM2OTY=", "number": 670, "title": "Prototoype for Datasette on PostgreSQL", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 15, "created_at": "2020-02-13T17:17:55Z", "updated_at": "2023-11-17T15:32:21Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "I thought this would never happen, but now that I'm deep in the weeds of running SQLite in production for Datasette Cloud I'm starting to reconsider my policy of only supporting SQLite.\r\n\r\nSome of the factors making me think PostgreSQL support could be worth the effort:\r\n- Serverless. I'm getting increasingly excited about writable-database use-cases for Datasette. If it could talk to PostgreSQL then users could easily deploy it on Heroku or other serverless providers that can talk to a managed RDS-style PostgreSQL.\r\n- Existing databases. Plenty of organizations have PostgreSQL databases. They can export to SQLite using [db-to-sqlite](https://github.com/simonw/db-to-sqlite) but that's a pretty big barrier to getting started - being able to run `datasette postgresql://connection-string` and start trying it out would be a massively better experience.\r\n- Data size. I keep running into use-cases where I want to run Datasette against many GBs of data. SQLite can do this but PostgreSQL is much more optimized for large data, especially given the existence of tools like Citus.\r\n- Marketing. Convincing people to trust their data to SQLite is potentially a big barrier to adoption. Even if I've convinced myself it's trustworthy I still have to convince everyone else.\r\n- It might not be that hard? If this required a ground-up rewrite it wouldn't be worth the effort, but I have a hunch that it may not be too hard - most of the SQL in Datasette should work on both databases since it's almost all portable SELECT statements. If Datasette did DML this would be a lot harder, but it doesn't.\r\n- Plugins! This feels like a natural surface for a plugin - at which point people could add MySQL support and suchlike in the future.\r\n\r\nThe above reasons feel strong enough to justify a prototype.", "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/670/reactions\", \"total_count\": 19, \"+1\": 14, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 5, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1978023780, "node_id": "I_kwDOBm6k_c515j9k", "number": 2205, "title": "request.post_vars() method obliterates form keys with multiple values", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 8755003, "label": "Datasette 1.0a-next"}, "comments": 3, "created_at": "2023-11-05T23:25:08Z", "updated_at": "2023-11-06T04:10:34Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "https://github.com/simonw/datasette/blob/452a587e236ef642cbc6ae345b58767ea8420cb5/datasette/utils/asgi.py#L137-L139\r\n\r\nIn GET requests you can do `?foo=1&foo=2` - you can do the same in POST requests, but the `dict()` call here eliminates those duplicates.\r\n\r\nYou can't even try calling `post_body()` and implement your own custom parsing because of:\r\n- #2204", "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/2205/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": 1978022687, "node_id": "I_kwDOBm6k_c515jsf", "number": 2204, "title": "request.post_body() can only be called once", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2023-11-05T23:22:03Z", "updated_at": "2023-11-05T23:23:23Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "This code here:\r\n\r\nhttps://github.com/simonw/datasette/blob/452a587e236ef642cbc6ae345b58767ea8420cb5/datasette/utils/asgi.py#L127-L135\r\n\r\nIt consumes the messages, which means if you try to call it a second time you won't be able to get at the body.\r\n\r\nThis is efficient - we don't end up with a `request` object property with potentially megabytes of content that we never look at again - but it's inconvenient for cases like middleware or functions where we don't know if the body has been consumed yet or not.\r\n\r\nPotential solution: set `request._body` the first time it is called, and return that on subsequent calls.\r\n\r\nPotential optimization: only do this for bodies that are shorter than a certain threshold - maybe 1MB - and raise an exception if you attempt to call `post_body()` multiple times against one of those larger bodies.\r\n\r\nI'm a bit nervous about that option though, since it could result in errors that don't show up in testing but do show up in production.", "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/2204/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": 684961449, "node_id": "MDU6SXNzdWU2ODQ5NjE0NDk=", "number": 949, "title": "Try out CodeMirror SQL hints", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 5, "created_at": "2020-08-24T20:58:21Z", "updated_at": "2023-11-03T05:28:58Z", "closed_at": "2020-11-01T03:29:48Z", "author_association": "OWNER", "pull_request": null, "body": "> It would also be interesting to try out the SQL hint mode, which can autocomplete against tables and columns. This demo shows how to configure that: https://codemirror.net/mode/sql/\r\n> \r\n> Some missing documentation: https://stackoverflow.com/questions/20023381/codemirror-how-add-tables-to-sql-hint\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/948#issuecomment-679355426_", "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/949/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": 1940346034, "node_id": "I_kwDOBm6k_c5zp1Sy", "number": 2199, "title": "Detailed upgrade instructions for metadata.yaml -> datasette.yaml", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 7, "created_at": "2023-10-12T16:21:25Z", "updated_at": "2023-10-12T22:08:42Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "> `Exception: Datasette no longer accepts plugin configuration in --metadata. Move your \"plugins\" configuration blocks to a separate file - we suggest calling that datasette..json - and start Datasette with datasette -c datasette..json. See https://docs.datasette.io/en/latest/configuration.html for more details.`\r\n>\r\n> I think we should link directly to documentation that tells people how to perform this upgrade.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/2190#issuecomment-1759947021_\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/2199/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": 777333388, "node_id": "MDU6SXNzdWU3NzczMzMzODg=", "number": 1168, "title": "Mechanism for storing metadata in _metadata tables", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 21, "created_at": "2021-01-01T18:47:27Z", "updated_at": "2023-09-28T18:29:05Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "_Original title: Perhaps metadata should all live in a `_metadata` in-memory database_\r\n\r\nInspired by #1150 - metadata should be exposed as an API, and for large Datasette instances that API may need to be paginated. So why not expose it through an in-memory database table?\r\n\r\nOne catch to this: plugins. #860 aims to add a plugin hook for metadata. But if the metadata comes from an in-memory table, how do the plugins interact with it?\r\n\r\nThe need to paginate over metadata does make a plugin hook that returns metadata for an individual table seem less wise, since we don't want to have to do 10,000 plugin hook invocations to show a list of all metadata.\r\n\r\nIf those plugins write directly to the in-memory table how can their contributions survive the server restarting?", "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/1168/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": 1907765514, "node_id": "I_kwDOBm6k_c5xtjEK", "number": 2195, "title": "`datasette publish` needs support for the new config/metadata split", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 9, "created_at": "2023-09-21T21:08:12Z", "updated_at": "2023-09-21T22:57:48Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "> ... which raises the challenge that `datasette publish` doesn't yet know what to do with a config file!\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/2194#issuecomment-1730259871_\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/2195/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": 1901416155, "node_id": "I_kwDOBm6k_c5xVU7b", "number": 2189, "title": "Server hang on parallel execution of queries to named in-memory databases", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 31, "created_at": "2023-09-18T17:23:18Z", "updated_at": "2023-09-21T22:26:21Z", "closed_at": "2023-09-21T22:26:21Z", "author_association": "OWNER", "pull_request": null, "body": "I've started to encounter a bug where queries to tables inside named in-memory databases sometimes trigger server hangs.\r\n\r\nI'm still trying to figure out what's going on here - on one occasion I managed to Ctrl+C the server and saw an exception that mentioned a thread lock, but usually hitting Ctrl+C does nothing and I have to `kill -9` the PID instead.\r\n\r\nThis is all running on my M2 Mac.\r\n\r\nI've seen the bug in the Datasette 1.0 alphas and in Datasette 0.64.3 - but reverting to 0.61 appeared to fix it.", "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/2189/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": 1662951875, "node_id": "I_kwDOBm6k_c5jHqHD", "number": 2057, "title": "DeprecationWarning: pkg_resources is deprecated as an API", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 25, "created_at": "2023-04-11T17:41:20Z", "updated_at": "2023-09-21T22:09:10Z", "closed_at": "2023-09-21T22:09:10Z", "author_association": "OWNER", "pull_request": null, "body": "Got this running tests against Python 3.11.\r\n\r\n```\r\n../../../.local/share/virtualenvs/datasette-big-local-6Yn-280V/lib/python3.11/site-packages/datasette/app.py:14: in \r\n import pkg_resources\r\n../../../.local/share/virtualenvs/datasette-big-local-6Yn-280V/lib/python3.11/site-packages/pkg_resources/__init__.py:121: in \r\n warnings.warn(\"pkg_resources is deprecated as an API\", DeprecationWarning)\r\nE DeprecationWarning: pkg_resources is deprecated as an API\r\n```\r\n\r\nI ran with `pytest -Werror --pdb -x` to get the debugger for that warning, but it turned out searching the code worked better. It's used in these two places:\r\n\r\nhttps://github.com/simonw/datasette/blob/5890a20c374fb0812d88c9b0ef26a838bfa06c76/datasette/plugins.py#L43-L50\r\n\r\nhttps://github.com/simonw/datasette/blob/5890a20c374fb0812d88c9b0ef26a838bfa06c76/datasette/app.py#L1037", "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/2057/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": 1907695234, "node_id": "I_kwDOBm6k_c5xtR6C", "number": 2194, "title": "Deploy failing with \"plugins/alternative_route.py: Not a directory\"", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 8, "created_at": "2023-09-21T20:17:49Z", "updated_at": "2023-09-21T22:08:19Z", "closed_at": "2023-09-21T22:08:19Z", "author_association": "OWNER", "pull_request": null, "body": "https://github.com/simonw/datasette/actions/runs/6266449018/job/17017460074\r\n\r\n\"CleanShot\r\n\r\nThis is a bit of a mystery, I don't think I've changed anything recently that could have broken this.", "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/2194/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": 1907655261, "node_id": "I_kwDOBm6k_c5xtIJd", "number": 2193, "title": "\"Test DATASETTE_LOAD_PLUGINS\" test shows errors but did not fail the CI run", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2023-09-21T19:49:34Z", "updated_at": "2023-09-21T21:56:43Z", "closed_at": "2023-09-21T21:56:43Z", "author_association": "OWNER", "pull_request": null, "body": "> That passed on 3.8 but should have failed: https://github.com/simonw/datasette/actions/runs/6266341481/job/17017099801 - the \"Test DATASETTE_LOAD_PLUGINS\" test shows errors but did not fail the CI run.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/2057#issuecomment-1730201226_\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/2193/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": 1903932086, "node_id": "PR_kwDOBm6k_c5aumyn", "number": 2192, "title": "Stop using parallel SQL queries for tables", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2023-09-20T01:28:43Z", "updated_at": "2023-09-20T22:10:56Z", "closed_at": "2023-09-20T22:10:55Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/2192", "body": "Refs:\r\n- #2189\r\n\r\n\r\n----\n:books: Documentation preview :books:: https://datasette--2192.org.readthedocs.build/en/2192/\n\r\n", "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/2192/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": 787098345, "node_id": "MDU6SXNzdWU3ODcwOTgzNDU=", "number": 1191, "title": "Ability for plugins to collaborate when adding extra HTML to blocks in default templates", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 12, "created_at": "2021-01-15T18:18:51Z", "updated_at": "2023-09-18T06:55:52Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "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\r\n\r\nCurrently 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.\r\n\r\nIt 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.", "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/1191/reactions\", \"total_count\": 4, \"+1\": 4, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1898927976, "node_id": "I_kwDOBm6k_c5xL1do", "number": 2186, "title": "Mechanism for register_output_renderer hooks to access full count", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 2, "created_at": "2023-09-15T18:57:54Z", "updated_at": "2023-09-15T19:27:59Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "The cause of this bug:\r\n- https://github.com/simonw/datasette-export-notebook/issues/17\r\n\r\nIs that `datasette-export-notebook` was consulting `data[\"filtered_table_rows_count\"]` in the render output plugin function in order to show the total number of rows that would be exported.\r\n\r\nThat field is no longer available by default - the `\"count\"` field is only available if `?_extra=count` was passed.\r\n\r\nIt would be useful if plugins like this could access the total count on demand, should they need to.", "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/2186/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": 1895266807, "node_id": "I_kwDOBm6k_c5w93n3", "number": 2184, "title": "Design decision - should configuration be exposed at /-/config ?", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2023-09-13T21:07:08Z", "updated_at": "2023-09-13T21:07:38Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "> This made me think. That `{\"$env\": \"ENV_VAR\"}` hack was introduced back here:\r\n>\r\n> - https://github.com/simonw/datasette/issues/538\r\n>\r\n> The problem it was solving was that metadata was visible to everyone with access to the instance at `/-/metadata` but plugins clearly needed a way to set secret settings.\r\n>\r\n> Now that this stuff is moving to config, we have some decisions to make:\r\n>\r\n> 1. Add `/-/config` to let people see the configuration of their instance, and keep the `$env` trick for secret settings.\r\n> 2. Say all configuration aside from metadata is secret and make `$env` optional or ditch it entirely.\r\n> 3. Allow plugins to announce which of their configuration options are secret so we can automatically redact them from `/-/config`\r\n>\r\n> I've found `/-/metadata` extraordinarily useful as a user of Datasette - it really helps me understand exactly what's going on if I run into any problems with a plugin, if I can quickly check what the settings look like.\r\n>\r\n> So I'm leaning towards option 1 or 3.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/pull/2183#discussion_r1325076924_\r\n\r\nAlso refs:\r\n- #2093", "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/2184/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": 1876353656, "node_id": "I_kwDOBm6k_c5v1uJ4", "number": 2168, "title": "Consider a request/response wrapping hook slightly higher level than asgi_wrapper()", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2023-08-31T21:42:04Z", "updated_at": "2023-09-10T17:54:08Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "There's a long justification for why this might be needed here:\r\n- https://github.com/simonw/datasette-auth-tokens/issues/10#issuecomment-1701820001\r\n\r\nShort version: it would be neat if it was possible to stash some data on the `request` object such that a later plugin/middleware-type-thing could use that to influence the final returned response - similar to the kinds of things you can do with Django middleware.\r\n\r\nThe `asgi_wrapper()` mechanism doesn't have access to the request or response objects - it gets `scope` and can mess around with `receive` and `send`, but those are pretty low-level primitives.\r\n\r\nSince Datasette has well-defined `request` and `response` objects now it might be nice to have a middleware layer that can manipulate those directly.", "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/2168/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": 1886791100, "node_id": "I_kwDOBm6k_c5wdiW8", "number": 2180, "title": "Plugin hook: `actors_from_ids()`", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2023-09-08T01:16:41Z", "updated_at": "2023-09-10T17:44:14Z", "closed_at": "2023-09-08T04:28:03Z", "author_association": "OWNER", "pull_request": null, "body": "In building Datasette Cloud we realized that a bunch of the features we are building need a way of resolving an actor ID to the actual actor, in order to display something more interesting than just an integer ID.\r\n\r\nSocial plugins in particular need this - comments by X, CSV uploaded by X, that kind of thing.\r\n\r\nI think the solution is a new plugin hook: `actors_from_ids(datasette, ids)` which can return a list of actor dictionaries.\r\n\r\nThe default implementation can return `[{\"id\": \"...\"}]` for the IDs passed to it.\r\n\r\nPluggy has a `firstresult=True` option which is relevant here, since this is the first plugin hook we will have implemented where only one plugin should provide an answer.", "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/2180/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": 1874255116, "node_id": "I_kwDOBm6k_c5vtt0M", "number": 2164, "title": "Ability to only load a specific list of plugins", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2023-08-30T19:33:41Z", "updated_at": "2023-09-08T04:35:46Z", "closed_at": "2023-08-30T22:12:27Z", "author_association": "OWNER", "pull_request": null, "body": "I'm going to try and get this working through an environment variable, so that you can start Datasette and it will only load a subset of plugins including those that use the `register_commands()` hook.\r\n\r\nInitial research on this:\r\n- https://github.com/pytest-dev/pluggy/issues/422", "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/2164/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": 1886812002, "node_id": "PR_kwDOBm6k_c5Z1N2L", "number": 2181, "title": "actors_from_ids plugin hook and datasette.actors_from_ids() method", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2023-09-08T01:51:07Z", "updated_at": "2023-09-08T04:24:00Z", "closed_at": "2023-09-08T04:23:59Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/2181", "body": "Refs:\r\n- #2180\r\n\r\nThis plugin hook is feature complete - including documentation and tests.\r\n\r\nI'm not going to land it in Datasette `main` until we've used it at least once though, which should happen promptly in development for [Datasette Cloud](https://www.datasette.cloud/).\r\n\r\n\r\n----\n:books: Documentation preview :books:: https://datasette--2181.org.readthedocs.build/en/2181/\n\r\n", "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/2181/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": 1886350562, "node_id": "I_kwDOBm6k_c5wb2zi", "number": 2178, "title": "Don't show foreign key links to tables the user cannot access", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 5, "created_at": "2023-09-07T17:56:41Z", "updated_at": "2023-09-07T23:28:27Z", "closed_at": "2023-09-07T23:28:27Z", "author_association": "OWNER", "pull_request": null, "body": "Spotted this problem while working on this plugin:\r\n- https://github.com/simonw/datasette-public\r\n\r\nIt's possible to make a table public to any users - but then you may end up with situations like this:\r\n\r\n\"CleanShot\r\n\r\nThat table is public, but the foreign key links go to tables that are NOT public.\r\n\r\nWe're also leaking the names of the values in those private tables here, which we shouldn't do. So this is a tiny bit of an information leak.\r\n\r\nSince this only affects people who have configured a table to be public that has foreign keys to a table that is private I don't think this is worth issuing a vulnerability report about - I very much doubt anyone is running Datasette configured in a way that could result in problems because of this.", "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/2178/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": 1886649402, "node_id": "I_kwDOBm6k_c5wc_w6", "number": 2179, "title": "Flaky test: test_hidden_sqlite_stat1_table", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2023-09-07T22:48:43Z", "updated_at": "2023-09-07T22:51:19Z", "closed_at": "2023-09-07T22:51:19Z", "author_association": "OWNER", "pull_request": null, "body": "This test here: https://github.com/simonw/datasette/blob/fbcb103c0cb6668018ace539a01a6a1f156e8d6a/tests/test_api.py#L1011-L1020\r\n\r\nIt failed for me like this:\r\n\r\n`E AssertionError: assert [('normal', False), ('sqlite_stat1', True), ('sqlite_stat4', True)] in ([('normal', False), ('sqlite_stat1', True)],)`\r\n\r\nLooks like some builds of SQLite include a `sqlite_stat4` table.", "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/2179/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": 1884408624, "node_id": "I_kwDOBm6k_c5wUcsw", "number": 2177, "title": "Move schema tables from _internal to _catalog", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2023-09-06T16:58:33Z", "updated_at": "2023-09-06T17:04:30Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "This came up in discussion over:\r\n- https://github.com/simonw/datasette/pull/2174\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/2177/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": 1884333600, "node_id": "PR_kwDOBm6k_c5Zszqk", "number": 2175, "title": "Test against Python 3.12 preview", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2023-09-06T16:09:05Z", "updated_at": "2023-09-06T16:16:28Z", "closed_at": "2023-09-06T16:16:27Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/2175", "body": "https://dev.to/hugovk/help-test-python-312-beta-1508/\r\n\r\n\r\n----\n:books: Documentation preview :books:: https://datasette--2175.org.readthedocs.build/en/2175/\n\r\n", "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/2175/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": 1883055640, "node_id": "PR_kwDOBm6k_c5ZociX", "number": 2173, "title": "click-default-group>=1.2.3", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2023-09-06T02:33:28Z", "updated_at": "2023-09-06T02:50:10Z", "closed_at": "2023-09-06T02:50:10Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/2173", "body": "Now available as a wheel:\r\n- https://github.com/click-contrib/click-default-group/issues/21\r\n\r\n\r\n----\n:books: Documentation preview :books:: https://datasette--2173.org.readthedocs.build/en/2173/\n\r\n", "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/2173/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": 336464733, "node_id": "MDU6SXNzdWUzMzY0NjQ3MzM=", "number": 328, "title": "Installation instructions, including how to use the docker image", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2018-06-28T03:59:33Z", "updated_at": "2023-09-05T14:10:39Z", "closed_at": "2018-06-28T04:02:10Z", "author_association": "OWNER", "pull_request": null, "body": "", "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/328/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": 1292370469, "node_id": "I_kwDOBm6k_c5NCAIl", "number": 1765, "title": "Document plugins providing new plugin hook-", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2022-07-03T17:05:14Z", "updated_at": "2023-08-31T23:08:24Z", "closed_at": "2023-08-31T23:06:31Z", "author_association": "OWNER", "pull_request": null, "body": "I've used this pattern twice now: https://til.simonwillison.net/datasette/register-new-plugin-hooks - in `datasette-graphql` and `datasette-low-disk-space-hook`. I should describe the pattern on https://docs.datasette.io/en/stable/writing_plugins.html", "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/1765/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": 1876407598, "node_id": "I_kwDOBm6k_c5v17Uu", "number": 2169, "title": "execute-sql on a database should imply view-database/view-permission", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2023-08-31T22:45:56Z", "updated_at": "2023-08-31T22:46:28Z", "closed_at": "2023-08-31T22:46:28Z", "author_association": "OWNER", "pull_request": null, "body": "I noticed that a token with `execute-sql` permission alone did not work, because it was not allowed to view the instance of the database.", "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/2169/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": 1875739055, "node_id": "I_kwDOBm6k_c5vzYGv", "number": 2167, "title": "Document return type of await ds.permission_allowed()", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2023-08-31T15:14:23Z", "updated_at": "2023-08-31T15:14:23Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "The return type isn't documented here: https://github.com/simonw/datasette/blob/4c3ef033110407f3b3dbce501659d523724985e0/docs/internals.rst#L327-L350\r\n\r\nOn inspecting the code I'm not 100% sure if it's possible for this. method to return `None`, or if it can only return `True` or `False`. Need to confirm that.\r\n\r\nhttps://github.com/simonw/datasette/blob/4c3ef033110407f3b3dbce501659d523724985e0/datasette/app.py#L822C15-L853", "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/2167/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": 742041667, "node_id": "MDU6SXNzdWU3NDIwNDE2Njc=", "number": 1092, "title": "Make cascading permission checks available to plugins", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2020-11-13T01:02:55Z", "updated_at": "2023-08-30T22:17:42Z", "closed_at": "2023-08-30T22:17:41Z", "author_association": "OWNER", "pull_request": null, "body": "The `BaseView` class has a method for cascading permission checks, but it's not easily accessible to plugins.\r\n\r\nhttps://github.com/simonw/datasette/blob/5eb8e9bf250b26e30b017d39a392c33973997656/datasette/views/base.py#L75-L99\r\n\r\nThis leaves plugins like `datasette-graphql` having to implement their own versions of this logic, which is bad: https://github.com/simonw/datasette-graphql/issues/65\r\n\r\n> First check `view-database` - if that says `False` then disallow access, if it says `True` then allow access. If it says `None` check `view-instance`.\r\n\r\nThis should become a supported API that plugins are encouraged to use.", "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/1092/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": 594237015, "node_id": "MDU6SXNzdWU1OTQyMzcwMTU=", "number": 718, "title": "Plugin idea: datasette-redirects", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2020-04-05T03:41:38Z", "updated_at": "2023-08-30T22:17:31Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "I just had to write a one-off custom plugin to redirect niche-musems.com to www.niche-museums.com (https://github.com/simonw/museums/issues/21) - it would be great if this kind of thing could be handled by a configurable plugin.\r\n\r\nhttps://github.com/simonw/museums/blob/6b1faf00c463b2228860d4d62d104b11935e01b1/plugins/redirect_www.py", "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/718/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": "reopened"} {"id": 1874327336, "node_id": "PR_kwDOBm6k_c5ZLMSe", "number": 2165, "title": "DATASETTE_LOAD_PLUGINS environment variable for loading specific plugins", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2023-08-30T20:33:30Z", "updated_at": "2023-08-30T22:12:25Z", "closed_at": "2023-08-30T22:12:25Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/2165", "body": "- #2164\r\n\r\nTODO:\r\n\r\n- [x] Automated tests\r\n- [ ] Documentation\r\n- [x] Make sure `DATASETTE_LOAD_PLUGINS=''` works for loading zero plugins", "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/2165/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": 1872043170, "node_id": "I_kwDOBm6k_c5vlRyi", "number": 2163, "title": "Rename core_X to catalog_X in the internals", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2023-08-29T16:45:00Z", "updated_at": "2023-08-29T17:01:31Z", "closed_at": "2023-08-29T17:01:31Z", "author_association": "OWNER", "pull_request": null, "body": "Discussed with Alex this morning. We think the American spelling is fine here (it's shorter than `catalogue`) and that it's a slightly less lazy name than `core_`.\r\n\r\nFollows:\r\n- https://github.com/simonw/datasette/issues/2157", "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/2163/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": 1805076818, "node_id": "I_kwDOBm6k_c5rl0lS", "number": 2102, "title": "API tokens with view-table but not view-database/view-instance cannot access the table", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": {"value": 9599, "label": "simonw"}, "milestone": null, "comments": 20, "created_at": "2023-07-14T15:34:27Z", "updated_at": "2023-08-29T16:32:36Z", "closed_at": "2023-08-29T16:32:35Z", "author_association": "OWNER", "pull_request": null, "body": "> Spotted a problem while working on this: if you grant a token access to view table for a specific table but don't also grant view database and view instance permissions, that token is useless.\r\n>\r\n> This was a deliberate design decision in Datasette - it's documented on https://docs.datasette.io/en/1.0a2/authentication.html#access-permissions-in-metadata\r\n>\r\n>> If a user cannot access a specific database, they will not be able to access tables, views or queries within that database. If a user cannot access the instance they will not be able to access any of the databases, tables, views or queries.\r\n>\r\n> I'm now second-guessing if this was a good decision.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette-auth-tokens/issues/7#issuecomment-1636031702_\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/2102/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": 1865281760, "node_id": "PR_kwDOBm6k_c5Ys3C5", "number": 2154, "title": "Cascade for restricted token view-table/view-database/view-instance operations", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 8, "created_at": "2023-08-24T14:24:23Z", "updated_at": "2023-08-29T16:32:35Z", "closed_at": "2023-08-29T16:32:34Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/2154", "body": "Refs:\r\n- #2102\r\n\r\nAlso includes a prototype implementation of `--actor option` which I'm using for testing this, from:\r\n- #2153\r\n\r\n\r\n----\n:books: Documentation preview :books:: https://datasette--2154.org.readthedocs.build/en/2154/\n\r\n", "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/2154/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": 1865232341, "node_id": "I_kwDOBm6k_c5vLS_V", "number": 2153, "title": "Datasette --get --actor option", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 5, "created_at": "2023-08-24T14:00:03Z", "updated_at": "2023-08-28T20:19:15Z", "closed_at": "2023-08-28T20:15:53Z", "author_association": "OWNER", "pull_request": null, "body": "I experimented with a prototype of this here:\r\n- https://github.com/simonw/datasette/issues/2102#issuecomment-1691037971_\r\n\r\nWhich lets me run requests as if they belonged to a specific actor like this:\r\n\r\n```bash\r\ndatasette fixtures.db --get '/fixtures/facetable.json' --actor '{\r\n \"_r\": {\r\n \"r\": {\r\n \"fixtures\": {\r\n \"facetable\": [\r\n \"vt\"\r\n ]\r\n }\r\n }\r\n },\r\n \"a\": \"user\"\r\n}'\r\n```\r\n\r\nReally useful for testing actors an `_r` options. Is this worth adding as a feature?", "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/2153/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": 1870345352, "node_id": "PR_kwDOBm6k_c5Y90K9", "number": 2161, "title": "-s/--setting x y gets merged into datasette.yml, refs #2143, #2156", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2023-08-28T19:30:42Z", "updated_at": "2023-08-28T20:06:15Z", "closed_at": "2023-08-28T20:06:14Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/2161", "body": "This change updates the `-s/--setting` option to `datasette serve` to allow it to be used to set arbitrarily complex nested settings in a way that is compatible with the new `-c datasette.yml` work happening in:\r\n- #2143\r\n\r\nIt will enable things like this:\r\n```\r\ndatasette data.db --setting plugins.datasette-ripgrep.path \"/home/simon/code\"\r\n```\r\nFor the moment though it just affects [settings](https://docs.datasette.io/en/1.0a4/settings.html) - so you can do this:\r\n```\r\ndatasette data.db --setting settings.sql_time_limit_ms 3500\r\n```\r\nI've also implemented a backwards compatibility mechanism, so if you use it this way (the old way):\r\n```\r\ndatasette data.db --setting sql_time_limit_ms 3500\r\n```\r\nIt will notice that the setting you passed is one of Datasette's core settings, and will treat that as if you said `settings.sql_time_limit_ms` instead.\r\n\r\n\r\n----\n:books: Documentation preview :books:: https://datasette--2161.org.readthedocs.build/en/2161/\n\r\n", "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/2161/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": 1865649347, "node_id": "I_kwDOBm6k_c5vM4zD", "number": 2156, "title": "datasette -s/--setting option for setting nested configuration options", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2023-08-24T18:09:27Z", "updated_at": "2023-08-28T19:33:05Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "> I've been thinking about what it might look like to allow command-line arguments to be used to define _any_ of the configuration options in `datasette.yml`, as alternative and more convenient syntax.\r\n>\r\n> Here's what I've come up with:\r\n> ```\r\n> datasette \\\r\n> -s settings.sql_time_limit_ms 1000 \\\r\n> -s plugins.datasette-auth-tokens.manage_tokens true \\\r\n> -s plugins.datasette-auth-tokens.manage_tokens_database tokens \\\r\n> mydatabase.db tokens.db\r\n> ```\r\n> Which would be equivalent to `datasette.yml` containing this:\r\n> ```yaml\r\n> plugins:\r\n> datasette-auth-tokens:\r\n> manage_tokens: true\r\n> manage_tokens_database: tokens\r\n> settings:\r\n> sql_time_limit_ms: 1000\r\n> ```\r\nMore details in https://github.com/simonw/datasette/issues/2143#issuecomment-1690792514\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/2156/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": 685806511, "node_id": "MDU6SXNzdWU2ODU4MDY1MTE=", "number": 950, "title": "Private/secret databases: database files that are only visible to plugins", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 6, "created_at": "2020-08-25T20:46:17Z", "updated_at": "2023-08-24T22:26:09Z", "closed_at": "2023-08-24T22:26:08Z", "author_association": "OWNER", "pull_request": null, "body": "In thinking about the best way to implement https://github.com/simonw/datasette-auth-passwords/issues/6 (SQL-backed user accounts for `datasette-auth-passwords`) I realized that there are a few different use-cases where a plugin might want to store data that isn't visible to regular Datasette users:\r\n\r\n- Storing password hashes\r\n- Storing API tokens\r\n- Storing secrets that are used for data import integrations (secrets for talking to the Twitter API for example)\r\n\r\nIdea: allow one or more private database files to be attached to Datasette, something like this:\r\n\r\n datasette github.db linkedin.db -s secrets.db -m metadata.yml\r\n\r\nThe `secrets.db` file would not be visible using any of the Datasette's usual interface or API routes - but plugins would be able to run queries against it.\r\n\r\nSo `datasette-auth-passwords` might then be configured like this:\r\n\r\n```yaml\r\nplugins:\r\n datasette-auth-passwords:\r\n database: secrets\r\n sql: \"select password_hash from passwords where username = :username\"\r\n```\r\nThe plugin could even refuse to operate against a database that hadn't been loaded as a secret database.", "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/950/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": 1863810783, "node_id": "I_kwDOBm6k_c5vF37f", "number": 2150, "title": "form label { width: 15% } is a bad default", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2023-08-23T18:22:27Z", "updated_at": "2023-08-23T18:37:18Z", "closed_at": "2023-08-23T18:35:48Z", "author_association": "OWNER", "pull_request": null, "body": "See:\r\n- https://github.com/simonw/datasette-configure-fts/issues/14\r\n- https://github.com/simonw/datasette-auth-tokens/issues/12", "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/2150/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": 1781022369, "node_id": "I_kwDOBm6k_c5qKD6h", "number": 2091, "title": "Drop support for Python 3.7", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2023-06-29T15:06:38Z", "updated_at": "2023-08-23T18:18:18Z", "closed_at": "2023-08-23T18:18:18Z", "author_association": "OWNER", "pull_request": null, "body": "It's EOL now, as of 2023-06-27 (two days ago): https://devguide.python.org/versions/\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/2091/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": 1795051447, "node_id": "I_kwDOBm6k_c5q_k-3", "number": 2097, "title": "Drop Python 3.7", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2023-07-08T18:39:44Z", "updated_at": "2023-08-23T18:18:00Z", "closed_at": "2023-08-23T18:18:00Z", "author_association": "OWNER", "pull_request": null, "body": "> I'm going to drop Python 3.7.\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/1153#issuecomment-1627455892_\r\n\r\nIt's not supported any more: https://devguide.python.org/versions/", "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/2097/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": 459509126, "node_id": "MDU6SXNzdWU0NTk1MDkxMjY=", "number": 516, "title": "Enforce import sort order with isort", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 8, "created_at": "2019-06-22T20:35:50Z", "updated_at": "2023-08-23T02:15:36Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "I want to use isort to order imports. A few steps here:\r\n\r\n- [x] Add a .isort.cfg file (see below)\r\n- [x] Use `isort -rc` to reformat existing code\r\n- [ ] Commit this change\r\n- [x] Add a unit test that ensures future changes remain isort compatible", "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/516/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": 459689615, "node_id": "MDExOlB1bGxSZXF1ZXN0MjkwOTcxMjk1", "number": 524, "title": "Sort commits using isort, refs #516", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2019-06-24T05:04:48Z", "updated_at": "2023-08-23T01:31:08Z", "closed_at": "2023-08-23T01:31:08Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/524", "body": "Also added a lint unit test to ensure they stay sorted. #516", "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/524/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": 449886319, "node_id": "MDU6SXNzdWU0NDk4ODYzMTk=", "number": 493, "title": "Rename metadata.json to config.json", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 7, "created_at": "2019-05-29T15:48:03Z", "updated_at": "2023-08-23T01:29:21Z", "closed_at": "2023-08-23T01:29:20Z", "author_association": "OWNER", "pull_request": null, "body": "It is increasingly being useful configuration options, when it started out as purely metadata.\r\n\r\nCould cause confusion with the `--config` mechanism though - maybe that should be called \"settings\" instead?", "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/493/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": 324720095, "node_id": "MDU6SXNzdWUzMjQ3MjAwOTU=", "number": 275, "title": "\"config\" section in metadata.json (root, database and table level)", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2018-05-20T16:02:28Z", "updated_at": "2023-08-23T01:28:37Z", "closed_at": "2023-08-23T01:28:37Z", "author_association": "OWNER", "pull_request": null, "body": "Split off from #274 \r\n\r\nMetadata should an optional `\"config\"` section at root, table or database level.\r\n\r\nThe TableView and RowView and DatabaseView and BaseView classes could all have a `.config(\"key\")` method which knows how to resolve the hierarchy of configs.\r\n\r\nThis will allow individual tables (or databases) to set their own config settings for things like `sql_time_limit_ms`", "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/275/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": 1857234285, "node_id": "I_kwDOBm6k_c5usyVt", "number": 2145, "title": "If a row has a primary key of `null` various things break", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 23, "created_at": "2023-08-18T20:06:28Z", "updated_at": "2023-08-21T17:30:01Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Stumbled across this while experimenting with `datasette-write-ui`. The error I got was a 500 on the `/db` page:\r\n\r\n> `'NoneType' object has no attribute 'encode'`\r\n\r\nTracked it down to this code, which assembles the URL for a row page:\r\n\r\nhttps://github.com/simonw/datasette/blob/943df09dcca93c3b9861b8c96277a01320db8662/datasette/utils/__init__.py#L120-L134\r\n\r\nThat's because `tilde_encode` can't handle `None`: https://github.com/simonw/datasette/blob/943df09dcca93c3b9861b8c96277a01320db8662/datasette/utils/__init__.py#L1175-L1178\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/2145/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": 1847201263, "node_id": "I_kwDOBm6k_c5uGg3v", "number": 2140, "title": "Remove all remaining documentation instances of '$ '", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2023-08-11T17:42:13Z", "updated_at": "2023-08-11T17:52:25Z", "closed_at": "2023-08-11T17:45:00Z", "author_association": "OWNER", "pull_request": null, "body": "For example this: https://github.com/simonw/datasette/blob/4535568f2ce907af646304d0ebce2500ebd55677/docs/authentication.rst?plain=1#L33-L35\r\n\r\nThe problem with that `$ ` prefix is that it prevents users from copying and pasting the raw command.\r\n\r\n\"image\"\r\n\r\nhttps://docs.datasette.io/en/stable/authentication.html#using-the-root-actor", "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/2140/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": 1823393475, "node_id": "I_kwDOBm6k_c5srsbD", "number": 2119, "title": "database color shows only on index page, not other pages", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 3, "created_at": "2023-07-27T00:19:39Z", "updated_at": "2023-08-11T05:25:45Z", "closed_at": "2023-08-11T05:16:24Z", "author_association": "OWNER", "pull_request": null, "body": "I think this has been a bug for a long time.\r\n\r\nhttps://latest.datasette.io/ currently shows:\r\n\r\n\"image\"\r\n\r\nThose colors are based on a hash of the database name. But when you click through to https://latest.datasette.io/fixtures\r\n\r\n\"image\"\r\n\r\nIt's red on all sub-pages too.", "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/2119/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": 1846076261, "node_id": "I_kwDOBm6k_c5uCONl", "number": 2139, "title": "border-color: ##ff0000 bug - two hashes", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 8755003, "label": "Datasette 1.0a-next"}, "comments": 2, "created_at": "2023-08-11T01:22:58Z", "updated_at": "2023-08-11T05:16:24Z", "closed_at": "2023-08-11T05:16:24Z", "author_association": "OWNER", "pull_request": null, "body": "Spotted this on https://latest.datasette.io/extra_database\r\n\r\n```html\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/2139/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": 1838469176, "node_id": "I_kwDOBm6k_c5tlNA4", "number": 2127, "title": "Context base class to support documenting the context", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 3, "created_at": "2023-08-07T00:01:02Z", "updated_at": "2023-08-10T01:30:25Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "This idea first came up here:\r\n- https://github.com/simonw/datasette/issues/2112#issuecomment-1652751140\r\n\r\nIf `datasette.render_template(...)` takes an optional `Context` subclass as an alternative to a context dictionary, I could then use dataclasses to define the context made available to specific templates - which then gives me something I can use to help document what they are.\r\n\r\nAlso refs:\r\n- https://github.com/simonw/datasette/issues/1510", "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/2127/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": 1843391585, "node_id": "I_kwDOBm6k_c5t3-xh", "number": 2134, "title": "Add writable canned query demo to latest.datasette.io", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 5, "created_at": "2023-08-09T14:31:30Z", "updated_at": "2023-08-10T01:22:46Z", "closed_at": "2023-08-10T01:05:56Z", "author_association": "OWNER", "pull_request": null, "body": "This would be useful while working on:\r\n- #2114", "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/2134/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": 1844213115, "node_id": "I_kwDOBm6k_c5t7HV7", "number": 2138, "title": "on_success_message_sql option for writable canned queries", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 8755003, "label": "Datasette 1.0a-next"}, "comments": 2, "created_at": "2023-08-10T00:20:14Z", "updated_at": "2023-08-10T00:39:40Z", "closed_at": "2023-08-10T00:34:26Z", "author_association": "OWNER", "pull_request": null, "body": "> Or... how about if the `on_success_message` option could define a SQL query to be executed to generate that message? Maybe `on_success_message_sql`.\r\n\r\n- https://github.com/simonw/datasette/issues/2134", "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/2138/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": 627794879, "node_id": "MDU6SXNzdWU2Mjc3OTQ4Nzk=", "number": 782, "title": "Redesign default .json format", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 8755003, "label": "Datasette 1.0a-next"}, "comments": 55, "created_at": "2020-05-30T18:47:07Z", "updated_at": "2023-08-10T00:07:17Z", "closed_at": "2023-08-10T00:07:17Z", "author_association": "OWNER", "pull_request": null, "body": "The default JSON just isn't right. I find myself using `?_shape=array` for almost everything I build against the API.", "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/782/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": 1843600087, "node_id": "I_kwDOBm6k_c5t4xrX", "number": 2135, "title": "Release notes for 1.0a3", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 9700784, "label": "Datasette 1.0a3"}, "comments": 3, "created_at": "2023-08-09T16:09:26Z", "updated_at": "2023-08-09T19:17:07Z", "closed_at": "2023-08-09T19:17:06Z", "author_association": "OWNER", "pull_request": null, "body": "118 commits! https://github.com/simonw/datasette/compare/1.0a2...26be9f0445b753fb84c802c356b0791a72269f25", "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/2135/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": 1843710170, "node_id": "I_kwDOBm6k_c5t5Mja", "number": 2136, "title": "Query view shouldn't return `columns`", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 9700784, "label": "Datasette 1.0a3"}, "comments": 4, "created_at": "2023-08-09T17:23:57Z", "updated_at": "2023-08-09T19:03:04Z", "closed_at": "2023-08-09T19:03:04Z", "author_association": "OWNER", "pull_request": null, "body": "I just noticed that https://latest.datasette.io/fixtures/roadside_attraction_characteristics.json?_labels=on&_size=1 returns:\r\n```json\r\n{\r\n \"ok\": true,\r\n \"next\": \"1\",\r\n \"rows\": [\r\n {\r\n \"rowid\": 1,\r\n \"attraction_id\": {\r\n \"value\": 1,\r\n \"label\": \"The Mystery Spot\"\r\n },\r\n \"characteristic_id\": {\r\n \"value\": 2,\r\n \"label\": \"Paranormal\"\r\n }\r\n }\r\n ],\r\n \"truncated\": false\r\n}\r\n```\r\nBut https://latest.datasette.io/fixtures.json?sql=select+rowid%2C+attraction_id%2C+characteristic_id+from+roadside_attraction_characteristics+order+by+rowid+limit+1 returns:\r\n```json\r\n{\r\n \"rows\": [\r\n {\r\n \"rowid\": 1,\r\n \"attraction_id\": 1,\r\n \"characteristic_id\": 2\r\n }\r\n ],\r\n \"columns\": [\r\n \"rowid\",\r\n \"attraction_id\",\r\n \"characteristic_id\"\r\n ],\r\n \"ok\": true,\r\n \"truncated\": false\r\n}\r\n```\r\nThe `columns` key in the query response is inconsistent with the table response.", "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/2136/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": 1843821954, "node_id": "I_kwDOBm6k_c5t5n2C", "number": 2137, "title": "Redesign row default JSON", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 8755003, "label": "Datasette 1.0a-next"}, "comments": 1, "created_at": "2023-08-09T18:49:11Z", "updated_at": "2023-08-09T19:02:47Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "This URL here:\r\n\r\nhttps://latest.datasette.io/fixtures/simple_primary_key/1.json?_extras=foreign_key_tables\r\n\r\n```json\r\n{\r\n \"database\": \"fixtures\",\r\n \"table\": \"simple_primary_key\",\r\n \"rows\": [\r\n {\r\n \"id\": \"1\",\r\n \"content\": \"hello\"\r\n }\r\n ],\r\n \"columns\": [\r\n \"id\",\r\n \"content\"\r\n ],\r\n \"primary_keys\": [\r\n \"id\"\r\n ],\r\n \"primary_key_values\": [\r\n \"1\"\r\n ],\r\n \"units\": {},\r\n \"foreign_key_tables\": [\r\n {\r\n \"other_table\": \"foreign_key_references\",\r\n \"column\": \"id\",\r\n \"other_column\": \"foreign_key_with_blank_label\",\r\n \"count\": 0,\r\n \"link\": \"/fixtures/foreign_key_references?foreign_key_with_blank_label=1\"\r\n },\r\n {\r\n \"other_table\": \"foreign_key_references\",\r\n \"column\": \"id\",\r\n \"other_column\": \"foreign_key_with_label\",\r\n \"count\": 1,\r\n \"link\": \"/fixtures/foreign_key_references?foreign_key_with_label=1\"\r\n },\r\n {\r\n \"other_table\": \"complex_foreign_keys\",\r\n \"column\": \"id\",\r\n \"other_column\": \"f3\",\r\n \"count\": 1,\r\n \"link\": \"/fixtures/complex_foreign_keys?f3=1\"\r\n },\r\n {\r\n \"other_table\": \"complex_foreign_keys\",\r\n \"column\": \"id\",\r\n \"other_column\": \"f2\",\r\n \"count\": 0,\r\n \"link\": \"/fixtures/complex_foreign_keys?f2=1\"\r\n },\r\n {\r\n \"other_table\": \"complex_foreign_keys\",\r\n \"column\": \"id\",\r\n \"other_column\": \"f1\",\r\n \"count\": 1,\r\n \"link\": \"/fixtures/complex_foreign_keys?f1=1\"\r\n }\r\n ],\r\n \"query_ms\": 4.226590999678592,\r\n \"source\": \"tests/fixtures.py\",\r\n \"source_url\": \"https://github.com/simonw/datasette/blob/main/tests/fixtures.py\",\r\n \"license\": \"Apache License 2.0\",\r\n \"license_url\": \"https://github.com/simonw/datasette/blob/main/LICENSE\",\r\n \"ok\": true,\r\n \"truncated\": false\r\n}\r\n```\r\n\r\nThat `?_extras=` should be `?_extra=` - plus the row JSON should be redesigned to fit the new default JSON representation.", "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/2137/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": 1822939274, "node_id": "I_kwDOBm6k_c5sp9iK", "number": 2113, "title": "Implement and document extras for the new query view page", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 8755003, "label": "Datasette 1.0a-next"}, "comments": 3, "created_at": "2023-07-26T18:24:01Z", "updated_at": "2023-08-09T17:35:22Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "- #2109 ", "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/2113/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": 1560662739, "node_id": "I_kwDOBm6k_c5dBdLT", "number": 2007, "title": "`render_cell()` hook should take an optional `request` argument", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2023-01-28T03:13:00Z", "updated_at": "2023-08-09T17:15:03Z", "closed_at": "2023-01-28T03:34:26Z", "author_association": "OWNER", "pull_request": null, "body": "From Discord: https://discordapp.com/channels/823971286308356157/996877076982415491/1068227071156965486", "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/2007/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": 1840417903, "node_id": "I_kwDOBm6k_c5tsoxv", "number": 2131, "title": "Refactor code that supports templates_considered comment", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 1, "created_at": "2023-08-08T01:28:36Z", "updated_at": "2023-08-09T15:27:41Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "I ended up duplicating it here: https://github.com/simonw/datasette/blob/7532feb424b1dce614351e21b2265c04f9669fe2/datasette/views/database.py#L164-L167\r\n\r\nI think it should move to `datasette.render_template()` - and maybe have a renamed template variable too.", "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/2131/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": 1822940263, "node_id": "I_kwDOBm6k_c5sp9xn", "number": 2114, "title": "Implement canned queries against new query JSON work", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 9700784, "label": "Datasette 1.0a3"}, "comments": 3, "created_at": "2023-07-26T18:24:50Z", "updated_at": "2023-08-09T15:26:58Z", "closed_at": "2023-08-09T15:26:57Z", "author_association": "OWNER", "pull_request": null, "body": "- #2109 ", "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/2114/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": 1841343173, "node_id": "I_kwDOBm6k_c5twKrF", "number": 2132, "title": "Get form fields on query page working again ", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 9700784, "label": "Datasette 1.0a3"}, "comments": 1, "created_at": "2023-08-08T13:39:05Z", "updated_at": "2023-08-08T13:45:10Z", "closed_at": "2023-08-08T13:45:09Z", "author_association": "OWNER", "pull_request": null, "body": "Caused by:\r\n- #2112\r\n\r\nhttps://latest.datasette.io/fixtures?sql=select+pk1%2C+pk2%2C+pk3%2C+content+from+compound_three_primary_keys+where+%22pk1%22+%3D+%3Ap0+order+by+pk1%2C+pk2%2C+pk3+limit+101&p0=b\r\n\r\n\"image\"\r\n\r\nThe `:p0` form field is missing. Submitting the form results in this error:\r\n\r\n\"image\"\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/2132/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": 1840324765, "node_id": "I_kwDOBm6k_c5tsSCd", "number": 2129, "title": "CSV ?sql= should indicate errors", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 1, "created_at": "2023-08-07T23:13:04Z", "updated_at": "2023-08-08T02:02:21Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "> https://latest.datasette.io/_memory.csv?sql=select+blah is a blank page right now:\r\n\r\n```bash\r\ncurl -I 'https://latest.datasette.io/_memory.csv?sql=select+blah'\r\n```\r\n```\r\nHTTP/2 200 \r\naccess-control-allow-origin: *\r\naccess-control-allow-headers: Authorization, Content-Type\r\naccess-control-expose-headers: Link\r\naccess-control-allow-methods: GET, POST, HEAD, OPTIONS\r\naccess-control-max-age: 3600\r\ncontent-type: text/plain; charset=utf-8\r\nx-databases: _memory, _internal, fixtures, fixtures2, extra_database, ephemeral\r\ndate: Mon, 07 Aug 2023 23:12:15 GMT\r\nserver: Google Frontend\r\n```\r\n\r\n_Originally posted by @simonw in https://github.com/simonw/datasette/issues/2118#issuecomment-1668688947_", "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/2129/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": 1822982933, "node_id": "I_kwDOBm6k_c5sqIMV", "number": 2117, "title": "Figure out what to do about `DatabaseView.name`", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 9700784, "label": "Datasette 1.0a3"}, "comments": 1, "created_at": "2023-07-26T18:58:06Z", "updated_at": "2023-08-08T02:02:07Z", "closed_at": "2023-08-08T02:02:07Z", "author_association": "OWNER", "pull_request": null, "body": "In the old code:\r\n\r\nhttps://github.com/simonw/datasette/blob/08181823990a71ffa5a1b57b37259198eaa43e06/datasette/views/database.py#L34-L35\r\n\r\nThis `name` class attribute was later used by some of the plugin hooks, passed as `view_name`: https://github.com/simonw/datasette/blob/18dd88ee4d78fe9d760e9da96028ae06d938a85c/datasette/hookspecs.py#L50-L54\r\n\r\nFigure out how that should work once I've refactored those classes to view functions instead.\r\n\r\nRefs:\r\n- #2109 ", "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/2117/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": 1822940964, "node_id": "I_kwDOBm6k_c5sp98k", "number": 2115, "title": "Ensure all tests pass against new query view JSON", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 9700784, "label": "Datasette 1.0a3"}, "comments": 0, "created_at": "2023-07-26T18:25:20Z", "updated_at": "2023-08-08T02:01:39Z", "closed_at": "2023-08-08T02:01:38Z", "author_association": "OWNER", "pull_request": null, "body": "- #2109 ", "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/2115/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": 1822938661, "node_id": "I_kwDOBm6k_c5sp9Yl", "number": 2112, "title": "Build HTML version of /content?sql=...", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 9700784, "label": "Datasette 1.0a3"}, "comments": 5, "created_at": "2023-07-26T18:23:34Z", "updated_at": "2023-08-08T02:01:09Z", "closed_at": "2023-08-08T02:01:01Z", "author_association": "OWNER", "pull_request": null, "body": "This will help make the hook as robust as possible.\r\n- #2109 ", "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/2112/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": 1822937426, "node_id": "I_kwDOBm6k_c5sp9FS", "number": 2111, "title": "Implement new /content.json?sql=...", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 9700784, "label": "Datasette 1.0a3"}, "comments": 4, "created_at": "2023-07-26T18:22:39Z", "updated_at": "2023-08-08T02:00:37Z", "closed_at": "2023-08-08T02:00:22Z", "author_association": "OWNER", "pull_request": null, "body": "This will be the base that the remaining work builds on top of. Refs:\r\n- #2109 ", "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/2111/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": 1840329615, "node_id": "I_kwDOBm6k_c5tsTOP", "number": 2130, "title": "Render plugin mechanism needs `error` and `truncated` fields", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 9700784, "label": "Datasette 1.0a3"}, "comments": 2, "created_at": "2023-08-07T23:19:19Z", "updated_at": "2023-08-08T01:51:54Z", "closed_at": "2023-08-08T01:47:42Z", "author_association": "OWNER", "pull_request": null, "body": "While working on:\r\n- https://github.com/simonw/datasette/pull/2118\r\n\r\nIt became clear that the `render` callback function documented here: https://docs.datasette.io/en/0.64.3/plugin_hooks.html#register-output-renderer-datasette\r\n\r\nNeeds to grow the ability to be told if an error occurred (an `error` string) and if the results were truncated (a `truncated` boolean).", "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/2130/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": 1823352380, "node_id": "PR_kwDOBm6k_c5Wfgd9", "number": 2118, "title": "New JSON design for query views", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 9700784, "label": "Datasette 1.0a3"}, "comments": 11, "created_at": "2023-07-26T23:29:21Z", "updated_at": "2023-08-08T01:47:40Z", "closed_at": "2023-08-08T01:47:39Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/2118", "body": "WIP. Refs:\r\n- #2109 \r\n\r\n\r\n----\n:books: Documentation preview :books:: https://datasette--2118.org.readthedocs.build/en/2118/\n\r\n", "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/2118/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": 1823428714, "node_id": "I_kwDOBm6k_c5sr1Bq", "number": 2120, "title": "Add __all__ to datasette/__init__.py", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2023-07-27T01:07:10Z", "updated_at": "2023-07-27T01:07:10Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Currently looks like this: https://github.com/simonw/datasette/blob/08181823990a71ffa5a1b57b37259198eaa43e06/datasette/__init__.py#L1-L6\r\n\r\nAdding `__all__ = [\"Permission\", \"Forbidden\"...]` would let me get rid of those `# noqa` comments.", "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/2120/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": 1822934563, "node_id": "I_kwDOBm6k_c5sp8Yj", "number": 2109, "title": "Plan for getting the new JSON format query views working", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 9700784, "label": "Datasette 1.0a3"}, "comments": 5, "created_at": "2023-07-26T18:20:18Z", "updated_at": "2023-07-27T00:24:47Z", "closed_at": "2023-07-26T18:25:34Z", "author_association": "OWNER", "pull_request": null, "body": "I've been stuck on this for too long. I'm breaking it down into a full milestone:\r\n\r\nhttps://github.com/simonw/datasette/milestone/29", "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/2109/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": 1822936521, "node_id": "I_kwDOBm6k_c5sp83J", "number": 2110, "title": "Merge database index page and query view", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 9700784, "label": "Datasette 1.0a3"}, "comments": 1, "created_at": "2023-07-26T18:21:57Z", "updated_at": "2023-07-26T19:53:25Z", "closed_at": "2023-07-26T19:53:25Z", "author_association": "OWNER", "pull_request": null, "body": "Refs:\r\n- #2109\r\n\r\nThe idea here is that hitting `/content` without a `?sql=` will show an empty result set AND default to including a bunch of extras about the list of tables in the database.\r\n\r\nThen I won't have to think about `/content` and `/content?sql=` as separate pages any more.", "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/2110/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": 1822949756, "node_id": "I_kwDOBm6k_c5sqAF8", "number": 2116, "title": "Turn DatabaseDownload into an async view function", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": {"value": 9700784, "label": "Datasette 1.0a3"}, "comments": 3, "created_at": "2023-07-26T18:31:59Z", "updated_at": "2023-07-26T18:44:00Z", "closed_at": "2023-07-26T18:44:00Z", "author_association": "OWNER", "pull_request": null, "body": "A minor refactor, but it is a good starting point for this new branch. Refs:\r\n- #2109", "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/2116/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": 1656432059, "node_id": "PR_kwDOBm6k_c5NuBNG", "number": 2053, "title": "WIP new JSON for queries", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 12, "created_at": "2023-04-05T23:26:15Z", "updated_at": "2023-07-26T18:28:59Z", "closed_at": "2023-07-26T18:26:45Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/2053", "body": "Refs:\r\n- #2049\r\n\r\nTODO:\r\n\r\n- [x] Read queries JSON\r\n- Implement error display with `\"ok\": false` and an errors key\r\n- Read queries HTML\r\n- Read queries other formats (plugins)\r\n- Canned read queries (dispatched to from table)\r\n- Write queries (a canned query thing)\r\n- Implement different shapes, refactoring to share code with table\r\n- Implement a sensible subset of extras, also refactoring to share code with table\r\n- Get all tests passing\r\n\r\n\r\n----\r\n:books: Documentation preview :books:: https://datasette--2053.org.readthedocs.build/en/2053/\r\n\r\n", "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/2053/reactions\", \"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": 1, "state_reason": null} {"id": 1816857442, "node_id": "I_kwDOBm6k_c5sSwti", "number": 2106, "title": "`datasette install -e` option", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2023-07-22T18:33:42Z", "updated_at": "2023-07-26T18:28:33Z", "closed_at": "2023-07-22T18:42:54Z", "author_association": "OWNER", "pull_request": null, "body": "As seen in LLM and now in `sqlite-utils` too:\r\n- https://github.com/simonw/sqlite-utils/issues/570\r\n\r\nUseful for developing plugins, see tutorial at https://llm.datasette.io/en/stable/plugins/tutorial-model-plugin.html", "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/2106/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": 1808215339, "node_id": "I_kwDOBm6k_c5rxy0r", "number": 2104, "title": "Tables starting with an underscore should be treated as hidden", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2023-07-17T17:13:53Z", "updated_at": "2023-07-18T22:41:37Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Plugins can then take advantage of this pattern, for example:\r\n- https://github.com/simonw/datasette-auth-tokens/pull/8", "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/2104/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": 1808116827, "node_id": "I_kwDOBm6k_c5rxaxb", "number": 2103, "title": "data attribute on Datasette tables exposing the primary key of the row", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2023-07-17T16:18:25Z", "updated_at": "2023-07-17T16:18:25Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Maybe put it on the `` but probably better to go on the `td.type-pk`.", "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/2103/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": 1765870617, "node_id": "I_kwDOBm6k_c5pQQwZ", "number": 2087, "title": "`--settings settings.json` option", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2023-06-20T17:48:45Z", "updated_at": "2023-07-14T17:02:03Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "https://discord.com/channels/823971286308356157/823971286941302908/1120705940728066080\r\n\r\n> May I add a request to the whole metadata / settings ? Allow to pass `--settings path/to/settings.json` instead of having to rely exclusively on directory mode to centralize settings (this would reflect the behavior of providing metadata)", "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/2087/reactions\", \"total_count\": 1, \"+1\": 1, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "draft": null, "state_reason": null} {"id": 1803264272, "node_id": "I_kwDOBm6k_c5re6EQ", "number": 2101, "title": "alter: true support for JSON write API", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 1, "created_at": "2023-07-13T15:24:11Z", "updated_at": "2023-07-13T15:24:18Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Requested here: https://discord.com/channels/823971286308356157/823971286941302908/1129034187073134642\r\n\r\n> The former datasette-insert plugin had an option `?alter=1` to auto-add new columns. Does the JSON write API also have this?", "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/2101/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": 771202454, "node_id": "MDU6SXNzdWU3NzEyMDI0NTQ=", "number": 1153, "title": "Use YAML examples in documentation by default, not JSON", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 22, "created_at": "2020-12-18T22:20:15Z", "updated_at": "2023-07-08T20:09:48Z", "closed_at": "2023-07-08T20:08:13Z", "author_association": "OWNER", "pull_request": null, "body": "YAML configuration is much better for multi-line strings, and I'm increasingly adding configuration options to Datasette that benefit from that - fragments of HTML in `description_html` or SQL queries used to configure things like https://github.com/simonw/datasette-atom for example.\r\n\r\nRather than confusing things by showing both in the documentation, I should switch all of the default examples to use YAML instead.", "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/1153/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": 1355148385, "node_id": "I_kwDOBm6k_c5Qxexh", "number": 1796, "title": "Research an upgrade to CodeMirror 6", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2022-08-30T04:27:46Z", "updated_at": "2023-07-03T04:58:21Z", "closed_at": "2023-07-03T04:58:21Z", "author_association": "OWNER", "pull_request": null, "body": "There are still a bunch of bugs in CodeMirror 5 that affect various mobile browsers - see Datasette Discord report here: https://discord.com/channels/823971286308356157/823971286941302908/1013878624992108645\r\n\r\nhttps://user-images.githubusercontent.com/9599/187349269-7b7c0c8c-3894-4810-82f0-de7c1eb940b3.mp4\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/1796/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": 1781047747, "node_id": "I_kwDOBm6k_c5qKKHD", "number": 2092, "title": "test_homepage intermittent failure", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2023-06-29T15:20:37Z", "updated_at": "2023-06-29T15:26:28Z", "closed_at": "2023-06-29T15:24:13Z", "author_association": "OWNER", "pull_request": null, "body": "e.g. in https://github.com/simonw/datasette/actions/runs/5413590227/jobs/9839373852\r\n\r\n```\r\n=================================== FAILURES ===================================\r\n________________________________ test_homepage _________________________________\r\n[gw0] linux -- Python 3.7.17 /opt/hostedtoolcache/Python/3.7.17/x64/bin/python\r\n\r\nds_client = \r\n\r\n @pytest.mark.asyncio\r\n async def test_homepage(ds_client):\r\n response = await ds_client.get(\"/.json\")\r\n assert response.status_code == 200\r\n assert \"application/json; charset=utf-8\" == response.headers[\"content-type\"]\r\n data = response.json()\r\n assert data.keys() == {\"fixtures\": 0}.keys()\r\n d = data[\"fixtures\"]\r\n assert d[\"name\"] == \"fixtures\"\r\n assert d[\"tables_count\"] == 24\r\n assert len(d[\"tables_and_views_truncated\"]) == 5\r\n assert d[\"tables_and_views_more\"] is True\r\n # 4 hidden FTS tables + no_primary_key (hidden in metadata)\r\n assert d[\"hidden_tables_count\"] == 6\r\n # 201 in no_primary_key, plus 6 in other hidden tables:\r\n> assert d[\"hidden_table_rows_sum\"] == 207, data\r\nE AssertionError: {'fixtures': {'color': '9403e5', 'hash': None, 'hidden_table_rows_sum': 0, 'hidden_tables_count': 6, ...}}\r\nE assert 0 == 207\r\n```\r\nMy guess is that this is a timing error, where very occasionally the \"count rows but stop counting if it exceeds a time limit\" thing fails.", "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/2092/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": 1781005740, "node_id": "I_kwDOBm6k_c5qJ_2s", "number": 2090, "title": "Adopt ruff for linting", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2023-06-29T14:56:43Z", "updated_at": "2023-06-29T15:05:04Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "https://beta.ruff.rs/docs/", "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/2090/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": 1780973290, "node_id": "I_kwDOBm6k_c5qJ37q", "number": 2089, "title": "codespell test failure", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 5, "created_at": "2023-06-29T14:40:10Z", "updated_at": "2023-06-29T14:48:11Z", "closed_at": "2023-06-29T14:48:10Z", "author_association": "OWNER", "pull_request": null, "body": "https://github.com/simonw/datasette/actions/runs/5413443676/jobs/9838999356\r\n```\r\n codespell docs/*.rst --ignore-words docs/codespell-ignore-words.txt\r\n codespell datasette -S datasette/static --ignore-words docs/codespell-ignore-words.txt\r\n shell: /usr/bin/bash -e {0}\r\n env:\r\n pythonLocation: /opt/hostedtoolcache/Python/3.9.17/x64\r\n LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.9.17/x64/lib\r\ndocs/metadata.rst:192: displaing ==> displaying\r\n```\r\nThis failure is legit, it found a spelling mistake: https://github.com/simonw/datasette/blob/ede62036180993dbd9d4e5d280fc21c183cda1c3/docs/metadata.rst#L192", "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/2089/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": 1054244712, "node_id": "I_kwDOBm6k_c4-1n9o", "number": 1510, "title": "Datasette 1.0 documented template context (maybe via API docs)", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 3, "created_at": "2021-11-15T23:23:58Z", "updated_at": "2023-06-28T02:05:21Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Documented context plus protective unit tests. Goal is that custom templates built for 1.x will not break without a 2.x release.", "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/1510/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": 323223872, "node_id": "MDU6SXNzdWUzMjMyMjM4NzI=", "number": 260, "title": "Validate metadata.json on startup", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 7, "created_at": "2018-05-15T13:42:56Z", "updated_at": "2023-06-21T12:51:22Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "It's easy to misspell the name of a database or table and then be puzzled when the metadata settings silently fail.\r\n\r\nTo avoid this, let's sanity check the provided metadata.json on startup and quit with a useful error message if we find any obvious mistakes.", "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/260/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": 1764792125, "node_id": "I_kwDOBm6k_c5pMJc9", "number": 2086, "title": "Show information on startup in directory configuration mode", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2023-06-20T07:13:33Z", "updated_at": "2023-06-20T07:13:33Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "https://discord.com/channels/823971286308356157/823971286941302908/1120516587036889098\r\n\r\n> One thing that would be helpful would be message at launch indicating a metadata.json is getting picked up. I'm using directory mode and was editing the wrong file for awhile before I realize nothing I was doing was having any effect.", "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/2086/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": 1726236847, "node_id": "I_kwDOBm6k_c5m5Eiv", "number": 2078, "title": "Resolve the difference between `wrap_view()` and `BaseView`", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 16, "created_at": "2023-05-25T17:44:32Z", "updated_at": "2023-05-26T00:18:46Z", "closed_at": "2023-05-26T00:18:46Z", "author_association": "OWNER", "pull_request": null, "body": "There are two patterns for implementing views in Datasette at the moment. I want to combine those.\r\n\r\nPart of:\r\n- #2053", "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/2078/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": 1726603778, "node_id": "PR_kwDOBm6k_c5RYvTU", "number": 2080, "title": "New View base class", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 3, "created_at": "2023-05-25T23:22:55Z", "updated_at": "2023-05-26T00:18:45Z", "closed_at": "2023-05-26T00:18:44Z", "author_association": "OWNER", "pull_request": "simonw/datasette/pulls/2080", "body": "Refs:\r\n\r\n- #2078\r\n\r\nTODO:\r\n\r\n- [x] Teach router layer how to handle this\r\n- [x] Use it for something\r\n\r\n\r\n----\r\n:books: Documentation preview :books:: https://datasette--2080.org.readthedocs.build/en/2080/\r\n\r\n", "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/2080/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": 1726531350, "node_id": "I_kwDOBm6k_c5m6McW", "number": 2079, "title": "Datasette should serve Access-Control-Max-Age", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 8, "created_at": "2023-05-25T21:50:50Z", "updated_at": "2023-05-25T22:56:28Z", "closed_at": "2023-05-25T22:08:35Z", "author_association": "OWNER", "pull_request": null, "body": "Currently the CORS headers served are:\r\n\r\nhttps://github.com/simonw/datasette/blob/9584879534ff0556e04e4c420262972884cac87b/datasette/utils/__init__.py#L1139-L1143\r\n\r\nServing `Access-Control-Max-Age: 600` would allow browsers to cache that for 10 minutes, avoiding additional CORS pre-flight OPTIONS requests during that time.", "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/2079/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": 1708030220, "node_id": "I_kwDOBm6k_c5lznkM", "number": 2073, "title": "Faceting doesn't work against integer columns in views", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2023-05-12T18:20:10Z", "updated_at": "2023-05-12T18:24:07Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Spotted this issue here: https://til.simonwillison.net/datasette/baseline\r\n\r\nI had to do this workaround:\r\n```sql\r\ncreate view baseline as select\r\n _key,\r\n spec,\r\n '' || json_extract(status, '$.is_baseline') as is_baseline,\r\n json_extract(status, '$.since') as baseline_since,\r\n json_extract(status, '$.support.chrome') as baseline_chrome,\r\n json_extract(status, '$.support.edge') as baseline_edge,\r\n json_extract(status, '$.support.firefox') as baseline_firefox,\r\n json_extract(status, '$.support.safari') as baseline_safari,\r\n compat_features,\r\n caniuse,\r\n usage_stats,\r\n status\r\nfrom\r\n [index]\r\n```\r\nI think the core issue here is that, against a table, `select * from x where integer_column = '1'` works correctly, due to some kind of column type conversion mechanism... but this mechanism doesn't work against views.", "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/2073/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": 1702354223, "node_id": "I_kwDOBm6k_c5ld90v", "number": 2070, "title": "Mechanism for deploying a preview of a branch using Vercel", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 2, "created_at": "2023-05-09T16:21:45Z", "updated_at": "2023-05-09T16:25:00Z", "closed_at": "2023-05-09T16:24:31Z", "author_association": "OWNER", "pull_request": null, "body": "I prototyped that here: https://github.com/simonw/one-off-actions/blob/main/.github/workflows/deploy-datasette-branch-preview.yml\r\n\r\nIt deployed the `json-extras-query` branch here: https://datasette-preview-json-extras-query.vercel.app/", "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/2070/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": 1686033652, "node_id": "I_kwDOBm6k_c5kftT0", "number": 2065, "title": "Datasette cannot be installed with Rye", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 4, "created_at": "2023-04-27T03:35:42Z", "updated_at": "2023-04-27T05:09:36Z", "closed_at": "2023-04-27T05:09:36Z", "author_association": "OWNER", "pull_request": null, "body": "https://github.com/mitsuhiko/rye\r\n\r\nI tried this:\r\n\r\n rye install datasette\r\n\r\nBut now:\r\n\r\n```\r\n% ~/.rye/shims/datasette\r\nTraceback (most recent call last):\r\n File \"/Users/simon/.rye/shims/datasette\", line 5, in \r\n from datasette.cli import cli\r\n File \"/Users/simon/.rye/tools/datasette/lib/python3.11/site-packages/datasette/cli.py\", line 17, in \r\n from .app import (\r\n File \"/Users/simon/.rye/tools/datasette/lib/python3.11/site-packages/datasette/app.py\", line 14, in \r\n import pkg_resources\r\nModuleNotFoundError: No module named 'pkg_resources'\r\n```\r\nI think that's because `setuptools` is not included in Rye.", "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/2065/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": 1686042269, "node_id": "I_kwDOBm6k_c5kfvad", "number": 2066, "title": "Failing test: httpx.InvalidURL: URL too long", "user": {"value": 9599, "label": "simonw"}, "state": "closed", "locked": 0, "assignee": null, "milestone": null, "comments": 10, "created_at": "2023-04-27T03:48:47Z", "updated_at": "2023-04-27T04:27:50Z", "closed_at": "2023-04-27T04:27:50Z", "author_association": "OWNER", "pull_request": null, "body": "https://github.com/simonw/datasette/actions/runs/4815723640/jobs/8574667731\r\n```\r\n def urlparse(url: str = \"\", **kwargs: typing.Optional[str]) -> ParseResult:\r\n # Initial basic checks on allowable URLs.\r\n # ---------------------------------------\r\n \r\n # Hard limit the maximum allowable URL length.\r\n if len(url) > MAX_URL_LENGTH:\r\n> raise InvalidURL(\"URL too long\")\r\nE httpx.InvalidURL: URL too long\r\n\r\n/opt/hostedtoolcache/Python/3.7.16/x64/lib/python3.7/site-packages/httpx/_urlparse.py:155: InvalidURL\r\n=========================== short test summary info ============================\r\nFAILED tests/test_csv.py::test_max_csv_mb - httpx.InvalidURL: URL too long\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/2066/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": 1663399821, "node_id": "I_kwDOBm6k_c5jJXeN", "number": 2058, "title": "500 \"attempt to write a readonly database\" error caused by \"PRAGMA schema_version\"", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 9, "created_at": "2023-04-11T23:57:50Z", "updated_at": "2023-04-13T16:35:21Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "I've not been able to replicate this myself yet, but I've seen log files from a user affected by it.\r\n\r\n```\r\nFile \"/usr/local/lib/python3.11/site-packages/datasette/views/base.py\", line 89, in dispatch_request\r\nawait self.ds.refresh_schemas()\r\nFile \"/usr/local/lib/python3.11/site-packages/datasette/app.py\", line 371, in refresh_schemas\r\nawait self._refresh_schemas()\r\nFile \"/usr/local/lib/python3.11/site-packages/datasette/app.py\", line 386, in _refresh_schemas\r\nschema_version = (await db.execute(\"PRAGMA schema_version\")).first()[0]\r\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\nFile \"/usr/local/lib/python3.11/site-packages/datasette/database.py\", line 267, in execute\r\nresults = await self.execute_fn(sql_operation_in_thread)\r\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\nFile \"/usr/local/lib/python3.11/site-packages/datasette/database.py\", line 213, in execute_fn\r\nreturn await asyncio.get_event_loop().run_in_executor(\r\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\nFile \"/usr/local/lib/python3.11/concurrent/futures/thread.py\", line 58, in run\r\nresult = self.fn(*self.args, **self.kwargs)\r\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\nFile \"/usr/local/lib/python3.11/site-packages/datasette/database.py\", line 211, in in_thread\r\nreturn fn(conn)\r\n^^^^^^^^\r\nFile \"/usr/local/lib/python3.11/site-packages/datasette/database.py\", line 237, in sql_operation_in_thread\r\ncursor.execute(sql, params if params is not None else {})\r\nsqlite3.OperationalError: attempt to write a readonly database\r\n```\r\nThat's running the official Datasette Docker image on https://fly.io/ - it's causing 500 errors on every page of their site.", "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/2058/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": 1665510265, "node_id": "I_kwDOBm6k_c5jRat5", "number": 2060, "title": "Clean up a bunch of warnings from ruff", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2023-04-13T01:23:02Z", "updated_at": "2023-04-13T01:23:02Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "See:\r\n- #2056\r\n\r\n`ruff` spots a bunch of warnings about things like unused variables - would be good to clean up as many of these as possible.", "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/2060/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": 1657861026, "node_id": "I_kwDOBm6k_c5i0POi", "number": 2054, "title": "Make detailed notes on how table, query and row views work right now", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 13, "created_at": "2023-04-06T18:21:09Z", "updated_at": "2023-04-07T20:14:38Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Research to help influence the following:\r\n- #2049 \r\n- #2053 \r\n- #2050 \r\n- #262 ", "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/2054/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": 1646734246, "node_id": "I_kwDOBm6k_c5iJyum", "number": 2049, "title": "Custom SQL queries should use new JSON ?_extra= format", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 8755003, "label": "Datasette 1.0a-next"}, "comments": 4, "created_at": "2023-03-30T00:42:53Z", "updated_at": "2023-04-05T23:29:27Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Related:\r\n- #262\r\n\r\nI've made the change to the table view, now I need the new format to work for arbitrary SQL queries too.\r\n\r\nNote that this incorporates both arbitrary SQL queries and canned queries.", "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/2049/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": 1649791661, "node_id": "I_kwDOBm6k_c5iVdKt", "number": 2050, "title": "Row page JSON should use new ?_extra= format", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 8755003, "label": "Datasette 1.0a-next"}, "comments": 1, "created_at": "2023-03-31T17:56:53Z", "updated_at": "2023-03-31T17:59:49Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "https://latest.datasette.io/fixtures/facetable/2.json\r\n\r\nRelated:\r\n- #2049\r\n- #1709 ", "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/2050/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": 1649793525, "node_id": "I_kwDOBm6k_c5iVdn1", "number": 2051, "title": "`?_extra=row_urls` for table pages", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": null, "comments": 0, "created_at": "2023-03-31T17:58:36Z", "updated_at": "2023-03-31T17:58:36Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "Provides URLs to the JSON version of those rows. Maybe it persists the `?_shape=` option too? Not sure about that.", "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/2051/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": 1615692818, "node_id": "I_kwDOBm6k_c5gTYQS", "number": 2035, "title": "Potential feature: special support for `?a=1&a=2` on the query page", "user": {"value": 9599, "label": "simonw"}, "state": "open", "locked": 0, "assignee": null, "milestone": {"value": 3268330, "label": "Datasette 1.0"}, "comments": 14, "created_at": "2023-03-08T18:05:03Z", "updated_at": "2023-03-31T16:09:08Z", "closed_at": null, "author_association": "OWNER", "pull_request": null, "body": "From a discussion on Discord: https://discord.com/channels/823971286308356157/996877076982415491/1082789517062320138\r\n\r\nThe key idea is to make it easier for people to implement `where id in (...)` that's populated from query string arguments.\r\n\r\nWhat if you could add `?id=11&id=32&id=62` to the URL and have that made available as a list that can be used in the query?", "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/2035/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}