Commit graph

656 commits

Author SHA1 Message Date
Claude
0bf3a54716
Include next_url in default table JSON keys
Table JSON responses previously only included the next pagination token
by default - the ready-to-follow next_url required ?_extra=next_url.
Both keys are now always present (null on the final page), which the
pagination documentation already claimed. The next_url extra remains
valid for backwards compatibility.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
2026-07-04 16:19:03 +00:00
Claude
e0ba8b3c6a
Return 400 for unknown _extra names on data formats
Unknown ?_extra= names (including internal HTML-only extras such as
display_rows) were silently ignored, so a typo returned the default
payload with no signal. Table, row and query data formats now return
400 "Unknown _extra: <names>". HTML pages continue to ignore unknown
names.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
2026-07-04 16:16:02 +00:00
Claude
9ee95cab3d
Schema endpoints check permission before database existence
/db/-/schema previously returned 404 for missing databases before
checking view-database, letting unauthorized actors probe for database
existence. The permission check now runs first, so actors without
view-database get a uniform 403. The table schema endpoint also now
returns 404 for an unknown database instead of an unhandled KeyError.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
2026-07-04 16:11:30 +00:00
Claude
b958d03c0f
Expose count truncation in table JSON via count_truncated extra
The count extra is computed with a limit subquery, so a count equal to
count_limit + 1 (default 10001) actually means "at least this many" -
but only the HTML view knew that. A public count_truncated extra now
reports the flag and is implicitly included whenever count is
requested, using the same logic the HTML view already used.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
2026-07-04 16:09:40 +00:00
Claude
b09dceea88
Row update return:true responds with rows list, matching insert/upsert
Row update previously returned a singular "row" object where insert and
upsert return a "rows" list. All write endpoints now use "rows".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
2026-07-04 16:07:22 +00:00
Claude
f3f5e891c9
Block API deletion of trusted stored queries
QueryUpdateView already rejected is_trusted queries but QueryDeleteView
did not, so an actor with delete-query could delete a config-defined
trusted query - which would then silently reappear on restart when the
config re-syncs. Both the POST endpoint and the HTML confirmation page
now return 403, matching update. datasette.remove_query() is unchanged
for internal use.

The docs already claimed this behavior ("Trusted stored queries cannot
be edited or deleted through the web interface or the JSON API") - the
code now matches them.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
2026-07-04 15:49:49 +00:00
Claude
ea9c1b1524
Return 400 for query data formats when ?sql= is missing
GET /db/-/query.json with no (or blank) ?sql= previously returned 200
with empty rows, masking caller bugs, while the .csv format returned
400 "?sql= is required" for the same request. All data formats now
return the 400; the HTML SQL editor page is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
2026-07-04 15:39:11 +00:00
Claude
b2cdc81d34
Return 400 instead of 500 for row delete write failures
Row delete previously returned 500 when the write failed (for example
a constraint violation raised by a trigger or foreign key), while row
update and every other write endpoint report the same failure class as
400. Delete now matches.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
2026-07-04 14:55:41 +00:00
Claude
e8048e023f
Return 400 for write canned-query SQL failures
POST to a write canned query previously returned HTTP 200 with
{"ok": false, "message": ...} when the SQL failed to execute, so JSON
clients (and anything that trusts HTTP status) recorded success for
failed writes. SQL failures now return 400 with the canonical error
shape plus the "redirect" context key from on_error_redirect; the
QueryWriteRejected 403 branch uses the canonical shape too. Successful
executions and the HTML flash-message flow are unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
2026-07-04 14:35:54 +00:00
Claude
f091b6dab1
Filter /-/databases by view-database permission
/-/databases previously listed every attached database (including
filesystem paths and sizes) to any actor with view-instance, while the
homepage and every other endpoint filtered by view-database. The
endpoint now only lists databases the current actor is allowed to view.

JsonDataView data callbacks may now be async.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
2026-07-04 14:00:42 +00:00
Claude
089e96a437
Add "ok": true to every JSON object success response
JsonDataView now injects "ok": true into dict responses, covering
/-/versions, /-/settings, /-/config, /-/threads and /-/actor. The
homepage JSON, /-/jump, the three /-/schema endpoints, /-/allowed,
/-/rules, /-/check, POST /-/permissions and the table /-/autocomplete
endpoint set it explicitly.

The remaining top-level array endpoints (/-/plugins, /-/databases,
/-/actions) will be converted to objects in separate commits.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
2026-07-04 13:40:05 +00:00
Claude
bc51c00724
Remove legacy .jsono format extension
The homepage routes now only accept .json, and the row view no longer
redirects .jsono to .json?_shape=objects. The .jsono extension was
superseded by ?_shape= and returned output identical to .json.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
2026-07-04 05:10:26 +00:00
Claude
0679e04bd3
Unify JSON error responses into one canonical shape
All JSON error responses now use a single format built by the new
datasette.utils.error_body() helper:

    {"ok": false, "error": "...", "errors": ["..."], "status": 400}

- error is all messages joined with '; ', errors is the full list,
  status always matches the HTTP status code
- The exception handler no longer emits the legacy title key in JSON
  (it is still available to the HTML error template)
- The permission debug endpoints (/-/allowed, /-/rules, /-/check,
  POST /-/permissions) no longer return bare {"error": ...} objects
- JSON renderer SQL errors keep their rows/truncated context keys but
  now include the canonical keys as well
- _shape=object misuse (queries or tables without primary keys) now
  returns HTTP 400 instead of 200 with an error body
- Method-not-allowed 405 responses use the canonical shape

Adds tests/test_error_shape.py covering all four previous shape
producers, updates affected tests, and documents the format in a new
'Error responses' section of docs/json_api.rst.

Implements section 1 of stable-api-recommendations.md.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GrHZSypDfMnym1tM5XJAFZ
2026-07-04 03:12:15 +00:00
Ritesh Kewlani
463eea2bd0
Fix _col=<pk> producing duplicate column in output (#2774)
Closes #1975
2026-06-23 14:18:49 -07:00
Simon Willison
8276879997 Construct table context explicitly 2026-06-23 12:24:42 -07:00
Simon Willison
0d1c097396 Document database views and queries as dataclasses 2026-06-23 12:16:42 -07:00
Simon Willison
34d9a3bf33 Use dataclasses for database table context 2026-06-23 12:11:26 -07:00
Simon Willison
59ab0c0ca0 Clarify template context metadata names 2026-06-23 11:30:30 -07:00
Simon Willison
a43e76c31a Construct row template context explicitly 2026-06-23 09:08:40 -07:00
Simon Willison
cda8f7bbef Remove DataView base class 2026-06-23 09:02:11 -07:00
Simon Willison
17ec88503e Document table mutation UI context 2026-06-23 07:36:07 -07:00
Simon Willison
4ac795e20c Expand template context field documentation 2026-06-23 07:30:04 -07:00
Simon Willison
4d031c8562 Add count_truncated template context 2026-06-22 19:47:21 -07:00
Simon Willison
49b1adba7b Merge remote-tracking branch 'origin/main' into template-context-docs
# Conflicts:
#	datasette/views/row.py
2026-06-22 18:44:37 -07:00
Simon Willison
f0645c6ddf
Create table, alter table - APIs and modal dialog UI
* Add create table UI

Adds a permission-gated database action that opens a create table modal on database pages, backed by the existing create-table JSON API.

The modal starts with an id integer primary key column plus a blank text column, supports SQLite type selection, and shows custom column type controls only when the actor can set column types.

Selected custom column types are applied after table creation with follow-up set-column-type API calls. Includes styling plus HTML and Playwright coverage for the action payload and create-table flow.

* Add alter table JSON API

- Add POST /<database>/<table>/-/alter with Pydantic validation and dry-run support.
- Support add, rename, alter, drop, primary-key and reorder operations, including allow-listed default expressions.
- Document the endpoint and cover schema changes, validation, permissions, events and dry runs.

Refs #2788

* Add alter table modal

- Register a built-in table action and expose alter-table metadata to table pages.
- Build the client-side modal for editing columns, defaults, ordering, primary keys, and custom column types.
- Add a review/apply confirmation flow with HTML and Playwright coverage.

Refs #2788

* Ran Prettier

* Isolate Unix domain socket test server paths

- Use a per-process socket path for the UDS test fixture.
- Clean up stale socket files before and after the fixture runs.
- Close the HTTP client and wait for the Datasette subprocess to exit.

* Precompute action permissions for table pages

- Extract reusable helpers for database and table action permission preloading.
- Precompute those permissions before building table-page HTML data.
- Document the default table actions plugin.

* Test against pyodide/v314.0.0

Now that we depend on pydantic we need a more recent
pyodide in order to load the emscripten build
of pydantic-core.

Refs https://github.com/simonw/datasette/pull/2789#issuecomment-4733412763

* Split table create and alter views

- Move create-table and alter-table API views into table_create_alter.py.
- Keep create and alter schema-editing constants and helpers together.
- Rename the create table modal context helper.

* Add foreign keys to create table API

- Add fk_table and optional fk_column support to create-table columns.
- Validate create-table requests with Pydantic while preserving existing errors.
- Document the API and cover inferred primary-key and validation cases.
Refs https://github.com/simonw/datasette/pull/2789#issuecomment-4733544452

* Add foreign keys to alter table API

- Add add_foreign_key, drop_foreign_key, and set_foreign_keys operations.
- Validate flat fk_table and fk_column arguments with Pydantic.
- Document the API and cover inferred primary-key and validation cases.

* /db/table/-/foreign-key-suggestions API

Improved version of the implementation datasette-edit-schema

* /<database>/-/foreign-key-targets API endpoint

Returns a list of tables with a single primary key, and for each one
the name of that primary key column and its SQLite type affinity.

This will be used by the create table UI to suggest foreign keys.

* Expose foreign key targets to create table UI

- Add foreignKeyTargetsPath to create table page data
- Filter hidden tables from database-level foreign key target results
- Update JSON API docs and tests for filtered targets

* Add foreign key controls to create table dialog

- Add create table advanced controls for foreign keys and first-column primary keys
- Share schema dialog row helpers between create and alter dialogs
- Move custom type into advanced options and add Add column icons

* More robust test_datasette_https_server.sh test

* Make custom type and foreign key mutually exclusive

In the create table dialog a column can now have either a custom display
type or a foreign key target, but not both - a foreign key column's type
is determined by the referenced primary key, so a custom type doesn't
apply. Setting one clears and disables the other, and the foreign key
select stays disabled on the primary key column and when no targets exist.

Also add "Controls how Datasette displays and edits this column" help
text (with aria-describedby) under the custom type selector in both the
create and alter dialogs, and style the alter dialog help text.

* Drop table button in alter dialog

* Object not chain of ifs

Refs https://github.com/simonw/datasette/pull/2789/changes#r3453964430

* Fix broken Playwright tests

* Keyword arguments for readability

* Ran prettier

* Removed the alter table dry run feature

It works by doing conn.backup(memory_conn) which could use
a lot of memory for a large database.

* sqlite-utils>=3.30,<4.0

So we don't get test failures from reformatted SQL.

* not_null, default and default_exr support for create table API columns

* Alter table API can now rename tables, refs #2788

Refs https://github.com/simonw/datasette/pull/2789#issuecomment-4771774289

* Fix for Safari select box heights

Refs https://github.com/simonw/datasette/pull/2789#issuecomment-4772241681

* Expose foreign key data to alter table UI

Include current foreign key metadata in the alter table page data and allow the foreign-key-targets endpoint to be read by actors with alter-table permission for a specific table.

Add API and HTML data tests for the new alter-table foreign key support.

* Unify create and alter table modal controls

Share default value controls between the create and alter table dialogs and expose create-table default expressions to the frontend.

Add create-table not-null/default handling and align the shared foreign key picker behavior across both dialogs.

* Add rename table controls to alter table dialog

Add a collapsed rename-table section to the alter table modal and include rename_table operations in the review/apply flow.

Redirect to the renamed table URL after applying changes and cover the review text in Playwright.

* current_unixtime and current_unixtime_ms default_expr options

Plus tweaked how alter table changing those works a bit.

* Draft changelog for create/alter table UI, refs #2787, #2788
2026-06-22 13:54:36 -07:00
Simon Willison
b932d0dc78 current_unixtime and current_unixtime_ms default_expr options
Plus tweaked how alter table changing those works a bit.
2026-06-22 13:42:35 -07:00
Copilot
1717ab02f7 Replace row edit icon SVG in table.py
Closes #2796
2026-06-22 13:23:18 -07:00
Simon Willison
fa43aba309 Unify create and alter table modal controls
Share default value controls between the create and alter table dialogs and expose create-table default expressions to the frontend.

Add create-table not-null/default handling and align the shared foreign key picker behavior across both dialogs.
2026-06-22 12:50:57 -07:00
Simon Willison
063b04ad83 Expose foreign key data to alter table UI
Include current foreign key metadata in the alter table page data and allow the foreign-key-targets endpoint to be read by actors with alter-table permission for a specific table.

Add API and HTML data tests for the new alter-table foreign key support.
2026-06-22 12:47:02 -07:00
Simon Willison
4b219be8bd Alter table API can now rename tables, refs #2788
Refs https://github.com/simonw/datasette/pull/2789#issuecomment-4771774289
2026-06-22 12:09:07 -07:00
Simon Willison
87354cf94e not_null, default and default_exr support for create table API columns 2026-06-22 11:04:19 -07:00
Simon Willison
084df1fba2 Removed the alter table dry run feature
It works by doing conn.backup(memory_conn) which could use
a lot of memory for a large database.
2026-06-22 10:18:01 -07:00
Simon Willison
17876ccf45 Keyword arguments for readability 2026-06-22 10:11:56 -07:00
Simon Willison
354780a136 Drop table button in alter dialog 2026-06-22 10:11:56 -07:00
Simon Willison
21c156dfb1 Expose foreign key targets to create table UI
- Add foreignKeyTargetsPath to create table page data
- Filter hidden tables from database-level foreign key target results
- Update JSON API docs and tests for filtered targets
2026-06-22 10:11:56 -07:00
Simon Willison
a6ef65f90d /<database>/-/foreign-key-targets API endpoint
Returns a list of tables with a single primary key, and for each one
the name of that primary key column and its SQLite type affinity.

This will be used by the create table UI to suggest foreign keys.
2026-06-22 10:11:56 -07:00
Simon Willison
2900efb32d /db/table/-/foreign-key-suggestions API
Improved version of the implementation datasette-edit-schema
2026-06-22 10:11:56 -07:00
Simon Willison
9d9a2d3ff3 Add foreign keys to alter table API
- Add add_foreign_key, drop_foreign_key, and set_foreign_keys operations.
- Validate flat fk_table and fk_column arguments with Pydantic.
- Document the API and cover inferred primary-key and validation cases.
2026-06-22 10:11:56 -07:00
Simon Willison
9766a9c087 Add foreign keys to create table API
- Add fk_table and optional fk_column support to create-table columns.
- Validate create-table requests with Pydantic while preserving existing errors.
- Document the API and cover inferred primary-key and validation cases.
Refs https://github.com/simonw/datasette/pull/2789#issuecomment-4733544452
2026-06-22 10:11:56 -07:00
Simon Willison
1972ba8952 Split table create and alter views
- Move create-table and alter-table API views into table_create_alter.py.
- Keep create and alter schema-editing constants and helpers together.
- Rename the create table modal context helper.
2026-06-22 10:11:56 -07:00
Simon Willison
4115213e17 Precompute action permissions for table pages
- Extract reusable helpers for database and table action permission preloading.
- Precompute those permissions before building table-page HTML data.
- Document the default table actions plugin.
2026-06-22 10:11:56 -07:00
Simon Willison
fdd1b61a3e Add alter table modal
- Register a built-in table action and expose alter-table metadata to table pages.
- Build the client-side modal for editing columns, defaults, ordering, primary keys, and custom column types.
- Add a review/apply confirmation flow with HTML and Playwright coverage.

Refs #2788
2026-06-22 10:11:56 -07:00
Simon Willison
b40665dd14 Add alter table JSON API
- Add POST /<database>/<table>/-/alter with Pydantic validation and dry-run support.
- Support add, rename, alter, drop, primary-key and reorder operations, including allow-listed default expressions.
- Document the endpoint and cover schema changes, validation, permissions, events and dry runs.

Refs #2788
2026-06-22 10:11:56 -07:00
Simon Willison
2d3c85dfc0 Add create table UI
Adds a permission-gated database action that opens a create table modal on database pages, backed by the existing create-table JSON API.

The modal starts with an id integer primary key column plus a blank text column, supports SQLite type selection, and shows custom column type controls only when the actor can set column types.

Selected custom column types are applied after table creation with follow-up set-column-type API calls. Includes styling plus HTML and Playwright coverage for the action payload and create-table flow.
2026-06-22 10:11:56 -07:00
Simon Willison
f673e7416f
Add create table execute-write template (#2794)
Add a Create table starter template to the execute-write page, alongside the existing table-specific insert/update/delete templates.

Keep template button clicks in-page by updating CodeMirror and the URL without collapsing the template controls.

Refresh schema metadata after successful schema-changing execute-write statements so newly created tables appear immediately.
2026-06-19 17:14:33 -07:00
Simon Willison
49362a9b20 await request.json() method, closes #2767 2026-06-14 17:00:12 -07:00
Simon Willison
82c95a1a13 Refactor edit/delete tools to work on row pages too
Refs https://github.com/simonw/datasette/pull/2781#issuecomment-4703303274

Refs #2780
2026-06-14 16:05:42 -07:00
Simon Willison
841a2536ea Tighten row edit field plugin API
Replace the value/valueType/originalValue/originalValueType fields on makeColumnField() contexts with an explicit field object API for reading, writing, resetting, comparing and validating field values.

Normalize columnType to {type, config}, rename the SQLite default metadata so it is clearly SQLite-specific, and document that plugins submit only string, number, boolean or null values. Plugins that need structured data should serialize it themselves instead of relying on Datasette to special-case JSON.

Move the built-in json column type behavior onto the same plugin API used by external plugins: validate the textarea with field.setValidity() as the value changes, but submit plain text. Harden row edit value comparison so fixing invalid JSON in an existing row is not blocked by the original invalid value.

Update the JavaScript plugin documentation and Node-based tests for the revised field contract.
2026-06-14 13:58:55 -07:00
Simon Willison
b2de8b5d2e First draft of makeColumnField() plugin hook 2026-06-14 11:57:13 -07:00
Simon Willison
35d7e3cab8 Fixed some tests for the new autocomplete work 2026-06-14 08:03:28 -07:00