{"html_url": "https://github.com/simonw/datasette/issues/1165#issuecomment-752828851", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1165", "id": 752828851, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MjgyODg1MQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T03:19:38Z", "updated_at": "2020-12-31T03:19:38Z", "author_association": "OWNER", "body": "I got Cypress working! I added the `datasette.plugins` code to the table template and ran a test called `plugins.spec.js` using the following:\r\n```javascript\r\ncontext('datasette.plugins API', () => {\r\n beforeEach(() => {\r\n cy.visit('/fixtures/compound_three_primary_keys')\r\n });\r\n it('should exist', () => {\r\n let datasette;\r\n cy.window().then(win => {\r\n datasette = win.datasette;\r\n }).then(() => {\r\n expect(datasette).to.exist;\r\n expect(datasette.plugins).to.exist;\r\n });\r\n });\r\n it('should register and execute plugins', () => {\r\n let datasette;\r\n cy.window().then(win => {\r\n datasette = win.datasette;\r\n }).then(() => {\r\n expect(datasette.plugins.call('numbers')).to.deep.equal([]);\r\n // Register a plugin\r\n datasette.plugins.register(\"numbers\", (a, b) => a + b, ['a', 'b']);\r\n var result = datasette.plugins.call(\"numbers\", {a: 1, b: 2});\r\n expect(result).to.deep.equal([3]);\r\n // Second plugin\r\n datasette.plugins.register(\"numbers\", (a, b) => a * b, ['a', 'b']);\r\n var result2 = datasette.plugins.call(\"numbers\", {a: 1, b: 2});\r\n expect(result2).to.deep.equal([3, 2]);\r\n });\r\n });\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": 776635426, "label": "Mechanism for executing JavaScript unit tests"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1165#issuecomment-752839433", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1165", "id": 752839433, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MjgzOTQzMw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T04:29:40Z", "updated_at": "2020-12-31T04:29:40Z", "author_association": "OWNER", "body": "Important to absorb the slightly bizarre assertion syntax from Chai - docs here https://www.chaijs.com/api/bdd/", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 776635426, "label": "Mechanism for executing JavaScript unit tests"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1165#issuecomment-752846267", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1165", "id": 752846267, "node_id": "MDEyOklzc3VlQ29tbWVudDc1Mjg0NjI2Nw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T05:10:41Z", "updated_at": "2020-12-31T05:13:14Z", "author_association": "OWNER", "body": "https://github.com/PostHog/posthog/tree/master/cypress/integration has some useful examples, linked from this article: https://posthog.com/blog/cypress-end-to-end-tests\r\n\r\nAlso useful: their workflow https://github.com/PostHog/posthog/blob/master/.github/workflows/e2e.yml", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 776635426, "label": "Mechanism for executing JavaScript unit tests"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1166#issuecomment-753193475", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1166", "id": 753193475, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MzE5MzQ3NQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T21:33:00Z", "updated_at": "2020-12-31T21:33:00Z", "author_association": "OWNER", "body": "I want a CI check that confirms that files conform to prettier - but only `datasette/static/*.js` files that are not already minified.\r\n\r\nThis seems to do the job:\r\n\r\n npx prettier --check 'datasette/static/*[!.min].js'\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 777140799, "label": "Adopt Prettier for JavaScript code formatting"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1166#issuecomment-753195905", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1166", "id": 753195905, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MzE5NTkwNQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T21:34:46Z", "updated_at": "2020-12-31T21:34:46Z", "author_association": "OWNER", "body": "This action looks good - tag 3.2 is equivalent to this commit hash: https://github.com/creyD/prettier_action/tree/bb361e2979cff283ca7684908deac8f95400e779", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 777140799, "label": "Adopt Prettier for JavaScript code formatting"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1166#issuecomment-753197957", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1166", "id": 753197957, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MzE5Nzk1Nw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T21:36:14Z", "updated_at": "2020-12-31T21:36:14Z", "author_association": "OWNER", "body": "Maybe not that action actually - I wanted to use a pre-built action to avoid installing Prettier every time, but that's what it seems to do: https://github.com/creyD/prettier_action/blob/bb361e2979cff283ca7684908deac8f95400e779/entrypoint.sh#L28-L37", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 777140799, "label": "Adopt Prettier for JavaScript code formatting"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1166#issuecomment-753200580", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1166", "id": 753200580, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MzIwMDU4MA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T21:38:06Z", "updated_at": "2020-12-31T21:38:06Z", "author_association": "OWNER", "body": "I think this should work:\r\n```\r\n- uses: actions/cache@v2\r\n with:\r\n path: ~/.npm\r\n key: ${{ runner.os }}-node-${{ hashFiles('**/prettier.yml' }}\r\n```\r\nI'll use the `prettier.yml` workflow that I'm about to create as the cache key for the NPM cache.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 777140799, "label": "Adopt Prettier for JavaScript code formatting"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1166#issuecomment-753209192", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1166", "id": 753209192, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MzIwOTE5Mg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T21:44:22Z", "updated_at": "2020-12-31T21:44:22Z", "author_association": "OWNER", "body": "Tests passed in https://github.com/simonw/datasette/runs/1631677726?check_suite_focus=true\r\n\r\nI'm going to try submitting a pull request with badly formatted JavaScript to see if it gets caught.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 777140799, "label": "Adopt Prettier for JavaScript code formatting"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1166#issuecomment-753210536", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1166", "id": 753210536, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MzIxMDUzNg==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T21:45:19Z", "updated_at": "2020-12-31T21:45:19Z", "author_association": "OWNER", "body": "Oops, committed that bad formatting test to `main` instead of a branch!", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 777140799, "label": "Adopt Prettier for JavaScript code formatting"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1166#issuecomment-753211535", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1166", "id": 753211535, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MzIxMTUzNQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T21:46:04Z", "updated_at": "2020-12-31T21:46:04Z", "author_association": "OWNER", "body": "https://github.com/simonw/datasette/runs/1631682372?check_suite_focus=true failed!\r\n\r\n\"Trying_out_bad_formatting__refs__1166_\u00b7_simonw_datasette_8087091\"\r\n", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 777140799, "label": "Adopt Prettier for JavaScript code formatting"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/1166#issuecomment-753214664", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/1166", "id": 753214664, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MzIxNDY2NA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T21:58:04Z", "updated_at": "2020-12-31T21:58:04Z", "author_association": "OWNER", "body": "Wrote a TIL about this: https://til.simonwillison.net/github-actions/prettier-github-actions", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 777140799, "label": "Adopt Prettier for JavaScript code formatting"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/983#issuecomment-753215545", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/983", "id": 753215545, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MzIxNTU0NQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T22:05:41Z", "updated_at": "2020-12-31T22:05:41Z", "author_association": "OWNER", "body": "Using object destructuring like that is a great idea. I'm going to play with your version - it's delightfully succinct.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 712260429, "label": "JavaScript plugin hooks mechanism similar to pluggy"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/983#issuecomment-753215761", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/983", "id": 753215761, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MzIxNTc2MQ==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T22:07:31Z", "updated_at": "2020-12-31T22:07:31Z", "author_association": "OWNER", "body": "I think I need to keep the mechanism whereby a plugin can return `undefined` in order to indicate that it has nothing to say for that specific item - that's borrowed from Pluggy and I've used it a bunch in my Python plugins. That makes the code a bit longer.\r\n\r\nI'll write some example plugins to help me decide if the filtering-out-of-undefined mechanism is needed or not.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 712260429, "label": "JavaScript plugin hooks mechanism similar to pluggy"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/987#issuecomment-753217127", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/987", "id": 753217127, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MzIxNzEyNw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T22:16:46Z", "updated_at": "2020-12-31T22:16:46Z", "author_association": "OWNER", "body": "I'm going to use `class=\"plugin-content-pre-table\"` rather than `id=` - just because I still want to be able to display all of this stuff on the single https://latest.datasette.io/-/patterns page so duplicate IDs are best avoided.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 712984738, "label": "Documented HTML hooks for JavaScript plugin authors"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/983#issuecomment-753217714", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/983", "id": 753217714, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MzIxNzcxNA==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T22:21:33Z", "updated_at": "2020-12-31T22:21:33Z", "author_association": "OWNER", "body": "Eventually I'd like to provide a whole bunch of other `datasette.X` utility functions that plugins can use - things like `datasette.addTabbedContentPane()` or similar.\r\n\r\nBut I don't want to inline those into the page.\r\n\r\nSo... I think the basic plugin system remains inline - maybe from an inlined file called `plugins-bootstrap.js`. Then a separate `plugins.js` contains the rest of the API functionality.\r\n\r\nIf a plugin wants to take advantage of those APIs, maybe it registers itself using `datasette.plugins.register('load', () => ...)` - that `load` hook can then be fired once the bulkier plugin code has been loaded.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 712260429, "label": "JavaScript plugin hooks mechanism similar to pluggy"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/983#issuecomment-753217917", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/983", "id": 753217917, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MzIxNzkxNw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T22:23:29Z", "updated_at": "2020-12-31T22:23:36Z", "author_association": "OWNER", "body": "If I'm going to do that, it would be good if subsequent plugins that register against the `load` event are executed straight away. That's a bit of a weird edge-case in plugin world - it would involve the bulkier code that gets loaded redefining how `datasette.plugins.register` works to special-case the `'load'` hook.\r\n\r\nMaybe the tiny bootstrap code could define a `datasette.plugins.onload(callbackFunction)` method which gets upgraded later into something that fires straight away? Would add more bytes though.", "reactions": "{\"total_count\": 0, \"+1\": 0, \"-1\": 0, \"laugh\": 0, \"hooray\": 0, \"confused\": 0, \"heart\": 0, \"rocket\": 0, \"eyes\": 0}", "issue": {"value": 712260429, "label": "JavaScript plugin hooks mechanism similar to pluggy"}, "performed_via_github_app": null} {"html_url": "https://github.com/simonw/datasette/issues/983#issuecomment-753219407", "issue_url": "https://api.github.com/repos/simonw/datasette/issues/983", "id": 753219407, "node_id": "MDEyOklzc3VlQ29tbWVudDc1MzIxOTQwNw==", "user": {"value": 9599, "label": "simonw"}, "created_at": "2020-12-31T22:38:45Z", "updated_at": "2020-12-31T22:39:10Z", "author_association": "OWNER", "body": "You'll be able to add JavaScript plugins using a bunch of different mechanisms:\r\n\r\n- In a custom template, dropping the code in to a `