{"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350414961", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350414961, "node_id": "IC_kwDOBm6k_c5QfbJx", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-14T05:22:00Z", "updated_at": "2022-12-14T05:22:00Z", "author_association": "OWNER", "body": "I think the next big step for this feature is for me to actually use it to build a few things.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350414402", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350414402, "node_id": "IC_kwDOBm6k_c5QfbBC", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-14T05:21:07Z", "updated_at": "2022-12-14T05:21:07Z", "author_association": "OWNER", "body": "It would be neat not to show write permissions against immutable databases too - and not hard from a performance perspective since it doesn't involve hundreds more permission checks.\r\n\r\nThat will need permissions to grow a flag for if they need a mutable database though, which is a bigger job.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350413555", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350413555, "node_id": "IC_kwDOBm6k_c5Qfazz", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-14T05:19:52Z", "updated_at": "2022-12-14T05:19:52Z", "author_association": "OWNER", "body": "Maybe I should have kept `_memory` listed for instances that are running with `--crossdb` enabled?\r\n\r\nYeah I think I should.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350409537", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350409537, "node_id": "IC_kwDOBm6k_c5QfZ1B", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-14T05:14:16Z", "updated_at": "2022-12-14T05:14:16Z", "author_association": "OWNER", "body": "New interface now live at https://latest.datasette.io/-/create-token\r\n\r\n\"image\"\r\n\r\nIt shouldn't be showing `_memory` though.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350402667", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350402667, "node_id": "IC_kwDOBm6k_c5QfYJr", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-14T05:05:10Z", "updated_at": "2022-12-14T05:05:10Z", "author_association": "OWNER", "body": "Tests can go here:\r\n\r\nhttps://github.com/simonw/datasette/blob/d98a8effb10ce8fe04a03eae42baa8a9cb0ca3f7/tests/test_auth.py#L143-L160", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350401651", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350401651, "node_id": "IC_kwDOBm6k_c5QfX5z", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-14T05:03:59Z", "updated_at": "2022-12-14T05:03:59Z", "author_association": "OWNER", "body": "I shipped a working interface. Could still do with some extra tests.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350215936", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350215936, "node_id": "IC_kwDOBm6k_c5QeqkA", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-14T01:23:42Z", "updated_at": "2022-12-14T01:23:42Z", "author_association": "OWNER", "body": "With tilde-encoding for database and table names the HTML looks like this:\r\n\r\n```html\r\n\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350148192", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350148192, "node_id": "IC_kwDOBm6k_c5QeaBg", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-14T00:19:06Z", "updated_at": "2022-12-14T00:19:06Z", "author_association": "OWNER", "body": "Another option: I could set a time limit - say 200ms - on how long I'm willing to spend calculating permissions before displaying this form\r\n\r\nFirst calculate view permissions for tables and databases (and maybe views and canned queries too).\r\n\r\nThen see if I can check every permission that I'm going to show as a checkbox on this page. If I get that done within the time limit use that to show the options.\r\n\r\nIf I run out of time show all options and maybe include a note saying that some of them may not actually be available.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350125018", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350125018, "node_id": "IC_kwDOBm6k_c5QeUXa", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-14T00:08:09Z", "updated_at": "2022-12-14T00:08:09Z", "author_association": "OWNER", "body": "Also: don't show hidden tables.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350124381", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350124381, "node_id": "IC_kwDOBm6k_c5QeUNd", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-14T00:07:51Z", "updated_at": "2022-12-14T00:07:51Z", "author_association": "OWNER", "body": "Another thing to consider in the future: once Datasette can support thousands of tables (see #417) the list on this page will turn into multiple MBs of HTML, which may cause all kinds of problems - not to mention the overhead of all of those table visibility permission checks. \r\n\r\nHopefully by then I'll have a good fix for the permission listings problem:\r\n- #1152\r\n\r\nAnd I can apply the same mechanism here.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350037572", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350037572, "node_id": "IC_kwDOBm6k_c5Qd_BE", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-13T23:27:32Z", "updated_at": "2022-12-13T23:27:32Z", "author_association": "OWNER", "body": "I'm going to ignore the permissions issue for the moment - I'll allow people to select any permissions they like in any of the databases or tables that are visible to them (don't want to leak the existence of databases/tables to users who shouldn't be able to see them).\r\n\r\nI think the value of getting this working outweights any potential confusion from not using finely grained permission checks to decide if the user should be able to apply a permission or not.\r\n\r\nThe tokens themselves won't be able to perform `insert-row` or similar if the user doesn't have the ability to do that, even if they selected that checkbox.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350019528", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350019528, "node_id": "IC_kwDOBm6k_c5Qd6nI", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-13T23:19:16Z", "updated_at": "2022-12-13T23:19:16Z", "author_association": "OWNER", "body": "Here's the checkbox prototype:\r\n```diff\r\ndiff --git a/datasette/templates/create_token.html b/datasette/templates/create_token.html\r\nindex a94881ed..1795ebaf 100644\r\n--- a/datasette/templates/create_token.html\r\n+++ b/datasette/templates/create_token.html\r\n@@ -2,11 +2,20 @@\r\n \r\n {% block title %}Create an API token{% endblock %}\r\n \r\n+{% block extra_head %}\r\n+\r\n+{% endblock %}\r\n+\r\n {% block content %}\r\n \r\n

Create an API token

\r\n \r\n-

This token will allow API access with the same abilities as your current user.

\r\n+

This token will allow API access with the same abilities as your current user, {{ request.actor.id }}

\r\n \r\n {% if errors %}\r\n {% for error in errors %}\r\n@@ -27,8 +36,39 @@\r\n \r\n \r\n \r\n- \r\n+\r\n+
\r\n+ Restrict actions that can be performed using this token\r\n+

All databases and tables

\r\n+ \r\n+\r\n+ {% for database in databases %}\r\n+

All tables in database: {{ database }}

\r\n+ \r\n+ {% endfor %}\r\n+

Specific tables

\r\n+ {% for dbt in database_with_tables %}\r\n+ {% for table in dbt.tables %}\r\n+

{{ dbt.database }}: {{ table }}

\r\n+ \r\n+ {% endfor %}\r\n+ {% endfor %}\r\n+
\r\n+\r\n \r\n+\r\n \r\n {% if token %}\r\n
\r\ndiff --git a/datasette/views/special.py b/datasette/views/special.py\r\nindex 30345d14..48357f87 100644\r\n--- a/datasette/views/special.py\r\n+++ b/datasette/views/special.py\r\n@@ -231,12 +231,37 @@ class CreateTokenView(BaseView):\r\n return await self.render(\r\n [\"create_token.html\"],\r\n request,\r\n- {\"actor\": request.actor},\r\n+ {\r\n+ \"actor\": request.actor,\r\n+ \"all_permissions\": self.ds.permissions.keys(),\r\n+ \"database_permissions\": [\r\n+ key\r\n+ for key, value in self.ds.permissions.items()\r\n+ if value.takes_database\r\n+ ],\r\n+ \"table_permissions\": [\r\n+ key\r\n+ for key, value in self.ds.permissions.items()\r\n+ if value.takes_resource\r\n+ ],\r\n+ \"databases\": [k for k in self.ds.databases.keys() if k != \"_internal\"],\r\n+ \"database_with_tables\": [\r\n+ {\r\n+ \"database\": db.name,\r\n+ \"tables\": await db.table_names(),\r\n+ }\r\n+ for db in self.ds.databases.values()\r\n+ if db.name != \"_internal\"\r\n+ ],\r\n+ },\r\n )\r\n \r\n async def post(self, request):\r\n self.check_permission(request)\r\n post = await request.post_vars()\r\n+ from pprint import pprint\r\n+\r\n+ pprint(post)\r\n errors = []\r\n duration = None\r\n if post.get(\"expire_type\"):\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350013016", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350013016, "node_id": "IC_kwDOBm6k_c5Qd5BY", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-13T23:16:24Z", "updated_at": "2022-12-13T23:17:17Z", "author_association": "OWNER", "body": "Slightly tricky thing here is that it should only show permissions that the user themselves has - on databases and tables that they have permission to access.\r\n\r\nI have a nasty feeling this may require looping through _everything_ and running every permission check, which could get very expensive if there are plugins involved that do their own storage check to resolve a permission.\r\n\r\nIt's that classic permission system problem: how to efficiently iterate through everything the user has permission to do in one go?\r\n\r\nMight be that I have to punt on that, and show the user a list of permissions to select that they might not actually have ability for.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350008636", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350008636, "node_id": "IC_kwDOBm6k_c5Qd388", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-13T23:14:33Z", "updated_at": "2022-12-13T23:14:33Z", "author_association": "OWNER", "body": "Checkbox interface looks like this. It's not beautiful but it's good enough for the moment:\r\n\r\n\"image\"\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1350002434", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1350002434, "node_id": "IC_kwDOBm6k_c5Qd2cC", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-13T23:11:50Z", "updated_at": "2022-12-13T23:11:59Z", "author_association": "OWNER", "body": "I think checkboxes will work well.\r\n\r\nHere's the data I get back from them (as `post_vars()`):\r\n\r\n```\r\n{'all:debug-menu': 'on',\r\n 'all:insert-row': 'on',\r\n 'expire_duration': '',\r\n 'expire_type': '',\r\n 'table:fixtures:delete-row': 'on',\r\n 'table:fixtures:drop-table': 'on',\r\n 'table:fixtures:view-query': 'on'}\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1349975255", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1349975255, "node_id": "IC_kwDOBm6k_c5QdvzX", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-13T23:00:11Z", "updated_at": "2022-12-13T23:00:11Z", "author_association": "OWNER", "body": "My `\r\n \r\n
\r\n+\r\n+
\r\n+ Restrict actions that can be performed using this token\r\n+

Restrict actions that can be performed using this token:

\r\n+

All databases and tables:

\r\n+

\r\n+
\r\n+\r\n \r\n \r\n {% if token %}\r\ndiff --git a/datasette/views/special.py b/datasette/views/special.py\r\nindex 30345d14..9d0fcd31 100644\r\n--- a/datasette/views/special.py\r\n+++ b/datasette/views/special.py\r\n@@ -231,7 +231,17 @@ class CreateTokenView(BaseView):\r\n return await self.render(\r\n [\"create_token.html\"],\r\n request,\r\n- {\"actor\": request.actor},\r\n+ {\r\n+ \"actor\": request.actor,\r\n+ \"all_permissions\": self.ds.permissions.keys(),\r\n+ \"database_permissions\": [key for key, value in self.ds.permissions.items() if value.takes_database],\r\n+ \"table_permissions\": [key for key, value in self.ds.permissions.items() if value.takes_resource],\r\n+ \"databases\": self.ds.databases.keys(),\r\n+ \"database_with_tables\": [{\r\n+ \"database\": db.name,\r\n+ \"tables\": await db.table_names(),\r\n+ } for db in self.ds.databases.values()],\r\n+ },\r\n )\r\n \r\n async def post(self, request):\r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1349974287", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1349974287, "node_id": "IC_kwDOBm6k_c5QdvkP", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-13T22:59:44Z", "updated_at": "2022-12-13T22:59:44Z", "author_association": "OWNER", "body": "Got an option group thing working:\r\n\r\n\"image\"\r\n\r\nBut... it strikes me that any time you're considering a `` for this.\r\n\r\nThe usability for keyboards is still pretty awful, but it's a niche enough feature that maybe that's OK for the moment?\r\n\r\n```javascript\r\nvar select = document.querySelector('select');\r\nvar selected = Array.from(temp0.options).filter(o => o.selected).map(o => o.value) \r\n```", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1347768549", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1347768549, "node_id": "IC_kwDOBm6k_c5QVVDl", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-13T05:25:56Z", "updated_at": "2022-12-13T22:29:12Z", "author_association": "OWNER", "body": "- [x] I should add a `--database` example to that help text.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1347768328", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1347768328, "node_id": "IC_kwDOBm6k_c5QVVAI", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-13T05:25:31Z", "updated_at": "2022-12-13T22:25:46Z", "author_association": "OWNER", "body": "https://latest.datasette.io/-/create-token currently looks like this:\n\n\n![Image](https://user-images.githubusercontent.com/9599/207458002-7c46940b-22c0-45d3-a668-ec7f1082588c.png)\n\n\nAs a reminder, the CLI options that this needs to provide an alternative to are:\n\nhttps://github.com/simonw/datasette/blob/d4b98d3924dec625a99236e65b1b169ff957381f/docs/cli-reference.rst#L619-L638", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1347775760", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1347775760, "node_id": "IC_kwDOBm6k_c5QVW0Q", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-13T05:38:47Z", "updated_at": "2022-12-13T05:38:47Z", "author_association": "OWNER", "body": "I'm going to hide the options for reducing the scope of the token inside a details/summary element.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1947#issuecomment-1347760109", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1947", "id": 1347760109, "node_id": "IC_kwDOBm6k_c5QVS_t", "user": {"value": 9599, "label": "simonw"}, "created_at": "2022-12-13T05:12:00Z", "updated_at": "2022-12-13T05:12:00Z", "author_association": "OWNER", "body": "For the UI: I think I'm going to dump a whole bunch of form elements on the page (so you can set up to 3 of each category of limit without any JavaScript), then add JavaScript that hides all but one of the options and gives you a \"add another\" widget that adds multiple more.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 1493390939, "label": "UI to create reduced scope tokens from the `/-/create-token` page"}, "performed_via_github_app": null}