home / github

Menu
  • Search all tables
  • GraphQL API

issues

Table actions
  • GraphQL API for issues

2 rows where state = "closed" and user = 9020979 sorted by updated_at descending

✖
✖
✖

✎ View and edit SQL

This data as json, CSV (advanced)

Suggested facets: created_at (date), updated_at (date), closed_at (date)

type 2

  • issue 1
  • pull 1

state 1

  • closed · 2 ✖

repo 1

  • datasette 2
id node_id number title user state locked assignee milestone comments created_at updated_at ▲ closed_at author_association pull_request body repo type active_lock_reason performed_via_github_app reactions draft state_reason
1651082214 PR_kwDOBm6k_c5NcFCf 2052 feat: Javascript Plugin API (Custom panels, column menu items with JS actions) hydrosquall 9020979 closed 0 simonw 9599   20 2023-04-02T20:23:44Z 2023-10-14T17:49:03Z 2023-10-13T00:00:27Z CONTRIBUTOR simonw/datasette/pulls/2052

Motivation

  • Allow plugins that add data visualizations datasette-vega, datasette-leaflet, and datasette-nteract-data-explorer to co-exist safely
  • Standardize APIs / hooks to ease development for new JS plugin developers (better compat with datasette-lite) through standardized DOM selectors, methods for extending the existing Table UI. This has come up as a feature request several times (see research notes for examples)
  • Discussion w/ @simonw about a general-purpose Datasette JS API

Changes

Summary: Provide 2 new surface areas for Datasette JS plugin developers. See alpha documentation

  1. Custom column header items: https://a.cl.ly/Kou97wJr
  2. Basic "panels" controlled by buttons: https://a.cl.ly/rRugWobd

User Facing Changes

  • Allow creating menu items under table header that triggers JS (instead of opening hrefs per the existing menu_link hook). Items can respond to any column metadata provided by the column header (e.g. label). The proof of concept plugins log data to the console, or copy the column name to clipboard.
  • Allow plugins to register UI elements in a panel controller. The parent component handles switching the visibility of active plugins.
  • Because native button elements are used, the panel is keyboard-accessible - use tab / shift-tab to cycle through tab options, and enter to select.
  • There's room to improve the styling, but the focus of this PR is on the API rather than the UX.

(plugin) Developer Facing Changes

  • Dispatch a datasette_init CustomEvent when the datasetteManager is finished loading.
  • Provide manager.registerPlugin API for adding new functionality that coordinates with Datasette lifecycle events.
  • Provide a manager.selectors map of DOM elements that users may want to hook into.
  • Updated table.js to use refer to these to motivating keeping things in sync
  • Allow plugins to register themselves with 2 hooks:
  • makeColumnActions: Add items to menu in table column headers. Users can provide a label, and either href or onClick with full access to the metadata for the clicked column (name, type, misc. booleans)
  • makeAboveTablePanelConfigs: Add items to the panel. Each panel has a unique ID (namespaced within that plugin), a render function, and a string label.

See this file for example plugin usage.

Core Developer Facing Changes

  • Modified table.js to make use of the datasetteManager API.
  • Added example plugins to the demos/plugins folder, and stored the test js in the statics/ folder

Testing

For Datasette plugin developers, please see the alpha-level documentation .

To run the examples:

bash datasette serve fixtures.db --plugins-dir=demos/plugins/

Open local server: http://127.0.0.1:8001/fixtures/facetable

Open to all feedback on this PR, from API design to variable naming, to what additional hooks might be useful for the future.

My focus was more on the general shape of the API for developers, rather than on the UX of the test plugins.

Design notes

  • The manager tab panel could be a separate plugin if the implementation is too custom.
  • The makeColumnHeaderItems benefits from hooking into the logic of table.js
  • I wanted to offer this to the Datasette core, since the datasette-manager would be more powerful if it were connected to lifecycle and JS events that are part of the existing table.js.
  • Non-goals:
  • Dependency management (for now) - there's no "build" step, we don't know when new plugins will be added. While there are some valid use cases (for example, allow multiple plugins to wait for a global leaflet object to be loaded), I don't see enough use-cases to justify doing this yet.
  • Enabling single-page-app features - for now, most datasette actions lead to a new page being loaded. SPA development offers some benefits (no page jumping after clicking on a link), but also complexity that doesn't need to be in the core Datasette project.

Research Notes

  • Relocated to a comment, as this isn't required to review when evaluating the plugin. Including it just for those who are curious.
datasette 107914493 pull    
{
    "url": "https://api.github.com/repos/simonw/datasette/issues/2052/reactions",
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
0  
1181432624 I_kwDOBm6k_c5Gazsw 1688 [plugins][documentation] Is it possible to serve per-plugin static folders when writing one-off (single file) plugins? hydrosquall 9020979 closed 0     3 2022-03-26T01:17:44Z 2022-03-27T01:01:14Z 2022-03-26T21:34:47Z CONTRIBUTOR  

I'm trying to make a small plugin that depends on static assets, by following the guide here. I made a plugins/ directory with datasette_nteract_data_explorer.py.

I am trying to follow the example of datasette_vega, and serving static assets. I created a statics/ directory within plugins/ to serve my JS and CSS.

https://github.com/simonw/datasette-vega/blob/00de059ab1ef77394ba9f9547abfacf966c479c4/datasette_vega/init.py#L13

Unfortunately, datasette doesn't seem to be able to find my assets.

Input:

bash datasette ~/Library/Safari/History.db --plugins-dir=plugins/

Output:

I suspect this issue might go away if I move away from "one-off" plugin mode, but it's been a while since I created a new python package so I'm not sure how much work there is to go between "one off" and "packaged for PyPI". I'd like to try to avoid needing to repackage a new tar.gz file and or reinstall my library repeatedly when developing new python code.

  1. Is there a way to serve a static assets when using the plugins/ directory method instead of installing plugins as a new python package?
  2. If not, is there a way I can work on developing a plugin without creating and repackaging tar.gz files after every change, or is that the recommended path?

Thanks for your help!

datasette 107914493 issue    
{
    "url": "https://api.github.com/repos/simonw/datasette/issues/1688/reactions",
    "total_count": 0,
    "+1": 0,
    "-1": 0,
    "laugh": 0,
    "hooray": 0,
    "confused": 0,
    "heart": 0,
    "rocket": 0,
    "eyes": 0
}
  completed

Advanced export

JSON shape: default, array, newline-delimited, object

CSV options:

CREATE TABLE [issues] (
   [id] INTEGER PRIMARY KEY,
   [node_id] TEXT,
   [number] INTEGER,
   [title] TEXT,
   [user] INTEGER REFERENCES [users]([id]),
   [state] TEXT,
   [locked] INTEGER,
   [assignee] INTEGER REFERENCES [users]([id]),
   [milestone] INTEGER REFERENCES [milestones]([id]),
   [comments] INTEGER,
   [created_at] TEXT,
   [updated_at] TEXT,
   [closed_at] TEXT,
   [author_association] TEXT,
   [pull_request] TEXT,
   [body] TEXT,
   [repo] INTEGER REFERENCES [repos]([id]),
   [type] TEXT
, [active_lock_reason] TEXT, [performed_via_github_app] TEXT, [reactions] TEXT, [draft] INTEGER, [state_reason] TEXT);
CREATE INDEX [idx_issues_repo]
                ON [issues] ([repo]);
CREATE INDEX [idx_issues_milestone]
                ON [issues] ([milestone]);
CREATE INDEX [idx_issues_assignee]
                ON [issues] ([assignee]);
CREATE INDEX [idx_issues_user]
                ON [issues] ([user]);
Powered by Datasette · Queries took 36.6ms · About: github-to-sqlite
  • Sort ascending
  • Sort descending
  • Facet by this
  • Hide this column
  • Show all columns
  • Show not-blank rows