You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Don't make users define redundant mappings. Lean into the structure that SQL provides us.
Use SQL foreign keys and CHECK constraints to define what is permissible and drive UI control selection.
Because SQLite is untyped, we'll have to sniff rows and/or use heuristics in some cases.
Things we'll aim to support:
you can't edit primary keys
foreign keys
CHECK constraints of the form x IN (...)
ISO dates
ISO timestamps
DEFAULT values (eg, when inserting a row, we'll try to prepopulate with what the DEFAULT would be, to hint that you don't need to fill it in)
JSON string arrays
You can declare a SQL VIEW to further control the user experience. Imagine that you have:
CREATETABLEreviews(
id integerprimary key,
url textnot null,
review textnot null,
rating text (check rating in ('negative', 'positive')),
rated_at text,
rated_by text
)
You'd like to have some contractors fill out the rating field. They shouldn't have access to the url field. They should only have access to rows that still need a rating. When they rate something, you'd like to automatically track who rated it and when. Oh, and you'd like to give some instructions.
You can do this by creating a view, and giving them access to that:
CREATEVIEWneeds_ratingAS/* set rated_by=current_actor() *//* set rated_at=datetime() */SELECT
id,
'What is the sentiment of the review? If unsure, choose positive.'AS instructions,
review AS review_readonly,
rating
FROM reviews
WHERE rating IS NULL
Only two unaliased columns from the base table are present, and thus candidates to be editable. id, however, is part of the primary key, and so only rating is editable.
When the user submits their entry, the set statements are automatically executed, tracking who edited the row, and when.
Pluggable
We'll try to render sensible controls. Sometimes we might get it wrong -- perhaps we'll render an input field that expects a number, when it really ought to have been a checkbox that stored 1 for checked and 0 for unchecked.
You can override us by implementing a plugin hook:
ShoutyControl must be a JavaScript class that is available to the page. This can be a pre-defined one provided by datasette-ui-extras or one you author via a file loaded by extra_js_urls or inlined by extra_body_script
The class should conform to this interface:
classShoutyControl{constructor(db,table,column,initialValue){this.initialValue=initialValue;this.el=null;}// Return a DOM element that will be shown to the user to edit this column's valuecreateControl(){this.el=document.createElement('input');this.el.value=this.initialValue;returnthis.el;}getvalue(){// Be shouty.returnthis.el.value.toUpperCase();}}
TODO: consider if the interface should have an isValid function, and a way to signal that its value has changed (for example, to permit "autocommit on blur" modes)
TODO: document how you might reference other columns. eg, say you have text The quick brown fox jumped over the lazy red dog. in column A, and you want the user to annotate it and have those annotations show up in column B as [{"substring": "jumped", "label": "verb"}]
User friendly
We'll try to show a good control. For small, closed sets, we'll use a drop-down. For larger sets or open sets, an autocomplete combobox.
For the turker use case, we might render a space-inefficient control that has key-bindings that permit you to quickly advance through a dataset, eg from https://prodi.gy:
Use cases
The use cases don't assume any particular access scheme. Some scenarios may be only authenticated users, some may permit anonymous users (eg forms). See the Authentication, authorization and auditing section for more.
These are imagined as alternative layouts for the row view, eg the pages located at /db/table/1, /db/table/2 and so on.
Traditional (add new + edit existing)
It's the typical vertical layout of column name, UI-control-to-specify value.
You might be in auto commit mode, or you might have to click an explicit Save button.
Clicking Save keeps you on the current row page.
Example: curation of detailed data, ability to deep-link in workflows.
Forms (add new)
You can submit new rows, but not read, edit or delete existing rows.
After submitting you are redirected to a customizable URL. By default, you are sent to the new form submission page.
Example: collecting feedback from the general public.
Turker (edit existing)
You can edit a subset of fields on a subset of existing rows, but can not read or delete other rows.
After submitting an edit, you are advanced to the next row that needs editing.
You might want affordances to enable very fast editing -- for example, focus the first control, permit keyboard shortcuts to auto-select an answer and move on.
Example: contractors who are doing piecemeal data entry, trusted internal staff doing manual annotations.
Authentication, authorization, auditing
This is all delegated to other systems.
Authentication is handled by Datasette's actor system.
There's no built-in support for auditing. If you'd like to track which users created/updated rows, use the datasette-current-actor plugin and create suitable DEFAULT values or trigger functions.
Open questions
Implementation notes
You can configure which tables are editable by default in metadata.json, or activate edit mode with ?_dux_edit=1
We'll need a hook to create/update INSTEAD OF triggers for editable views.
Rejected ideas
Spreadsheet mode
The table view would let you update values in-place, without navigating to the row page for each entry.
Rejected because I think I can't do a sufficiently good job on the UI: it likely won't be an actual spreadsheet view with a seamless grid and resizeable columns. More likely, it would have inline controls that automatically commit changes via ajax.
The text was updated successfully, but these errors were encountered:
This issue lays out the vision for the editing UI that
datasette-ui-extras
will provide. See #54 for the DDL version.Editing is only for SQLite databases, not DuckDB.
Editing will use the write API introduced in Datasette 1.0, so you'll need to be on Datasette 1.0.
My goal is to bring an automatic, pluggable, user-friendly UI that enables these use cases: traditional data entry, turker mode, and forms.
Non-goals: supporting JavaScript-disabled browsers.
UI Attributes
Automatic
Don't make users define redundant mappings. Lean into the structure that SQL provides us.
Use SQL foreign keys and CHECK constraints to define what is permissible and drive UI control selection.
Because SQLite is untyped, we'll have to sniff rows and/or use heuristics in some cases.
Things we'll aim to support:
x IN (...)
You can declare a SQL VIEW to further control the user experience. Imagine that you have:
You'd like to have some contractors fill out the
rating
field. They shouldn't have access to theurl
field. They should only have access to rows that still need a rating. When they rate something, you'd like to automatically track who rated it and when. Oh, and you'd like to give some instructions.You can do this by creating a view, and giving them access to that:
Only two unaliased columns from the base table are present, and thus candidates to be editable.
id
, however, is part of the primary key, and so onlyrating
is editable.When the user submits their entry, the
set
statements are automatically executed, tracking who edited the row, and when.Pluggable
We'll try to render sensible controls. Sometimes we might get it wrong -- perhaps we'll render an input field that expects a number, when it really ought to have been a checkbox that stored 1 for checked and 0 for unchecked.
You can override us by implementing a plugin hook:
ShoutyControl
must be a JavaScript class that is available to the page. This can be a pre-defined one provided bydatasette-ui-extras
or one you author via a file loaded byextra_js_urls
or inlined byextra_body_script
The class should conform to this interface:
TODO: consider if the interface should have an
isValid
function, and a way to signal that its value has changed (for example, to permit "autocommit on blur" modes)TODO: document how you might reference other columns. eg, say you have text
The quick brown fox jumped over the lazy red dog.
in column A, and you want the user to annotate it and have those annotations show up in column B as[{"substring": "jumped", "label": "verb"}]
User friendly
We'll try to show a good control. For small, closed sets, we'll use a drop-down. For larger sets or open sets, an autocomplete combobox.
For the turker use case, we might render a space-inefficient control that has key-bindings that permit you to quickly advance through a dataset, eg from https://prodi.gy:
Use cases
The use cases don't assume any particular access scheme. Some scenarios may be only authenticated users, some may permit anonymous users (eg forms). See the Authentication, authorization and auditing section for more.
These are imagined as alternative layouts for the row view, eg the pages located at
/db/table/1
,/db/table/2
and so on.Traditional (add new + edit existing)
It's the typical vertical layout of column name, UI-control-to-specify value.
You might be in auto commit mode, or you might have to click an explicit Save button.
Clicking Save keeps you on the current row page.
Example: curation of detailed data, ability to deep-link in workflows.
Forms (add new)
You can submit new rows, but not read, edit or delete existing rows.
After submitting you are redirected to a customizable URL. By default, you are sent to the new form submission page.
Example: collecting feedback from the general public.
Turker (edit existing)
You can edit a subset of fields on a subset of existing rows, but can not read or delete other rows.
After submitting an edit, you are advanced to the next row that needs editing.
You might want affordances to enable very fast editing -- for example, focus the first control, permit keyboard shortcuts to auto-select an answer and move on.
Example: contractors who are doing piecemeal data entry, trusted internal staff doing manual annotations.
Authentication, authorization, auditing
This is all delegated to other systems.
Authentication is handled by Datasette's actor system.
Authorization is handled by Datasette's permission system.
There's no built-in support for auditing. If you'd like to track which users created/updated rows, use the datasette-current-actor plugin and create suitable DEFAULT values or trigger functions.
Open questions
Implementation notes
You can configure which tables are editable by default in metadata.json, or activate edit mode with
?_dux_edit=1
We'll need a hook to create/update
INSTEAD OF
triggers for editable views.Rejected ideas
Spreadsheet mode
The table view would let you update values in-place, without navigating to the row page for each entry.
Rejected because I think I can't do a sufficiently good job on the UI: it likely won't be an actual spreadsheet view with a seamless grid and resizeable columns. More likely, it would have inline controls that automatically commit changes via ajax.
The text was updated successfully, but these errors were encountered: