Work with tasks in generated screens
View as MarkdownThe project and task schemas from the previous page already describe an ordinary record workflow. This page traces that metadata into generated list, create, detail, and edit screens, then follows the matching requests in the browser. You will create related records, edit and find a task, and navigate from a project to its tasks without adding a project-owned React route. The same pattern supplies the first usable workflow for other table-shaped application data.
Use the generated project and task screens with me. I want to create related records, edit a task, search it, and confirm the browser uses the generated table API.Read the screen from the schema
Section titled “Read the screen from the schema”The generated experience follows the types, Drizzle foreign key, and Sapporta metadata defined on the previous page:
rowLabelColumns: ["name"]displays project names in task lookups.select()options render status and priority as searchable, clearable comboboxes.date()renders a date editor and preserves the canonicalYYYY-MM-DDwire value.search.columnsactivates search across task title and description.- the project’s
childrenentry adds a Tasks collection to project detail. - row-scope columns and managed timestamps stay out of ordinary forms and grids.
Presentation metadata does not authorize data. Generated lookups, lists, gets, and writes still run through the current request’s abilities and row-visibility policy on the server.
Create a project and task
Section titled “Create a project and task”Start the app and inspect the generated create operations before using the screens:
pnpm devpnpm exec sapporta endpoints show "POST /api/tables/projects"pnpm exec sapporta endpoints show "POST /api/tables/tasks"Open /tables/projects in an authenticated browser and create a project named
Website Relaunch. Then open /tables/tasks/new and enter:
| Field | Value |
|---|---|
| Title | Publish launch checklist |
| Project | Website Relaunch |
| Status | in_progress |
| Priority | medium |
| Due date | 2026-08-01 |
| Description | Prepare the release list |
The Project field stores the numeric project ID and displays the project name. Its picker reads the generated lookup route:
GET /api/tables/projects/_lookup?q=Website{ "entries": [ { "value": 1, "label": "Website Relaunch", "meta": { "id": 1, "name": "Website Relaunch" } } ]}Lookup values preserve the referenced primary-key type. This project uses an
integer key, so the task request sends project_id as a JSON number.
Status and priority use local option lists from their select() column
declarations. Text entered in either combobox filters those options and does not
become the saved value. The chosen option remains the exact declared string.
Open the browser Network panel before saving. The generated form sends this
request under the framework /api prefix:
POST /api/tables/tasksContent-Type: application/json
{ "project_id": 1, "title": "Publish launch checklist", "description": "Prepare the release list", "status": "in_progress", "priority": "medium", "due_date": "2026-08-01"}The form decodes its draft on submit. It preserves invalid field text when local decoding fails and sends finite numbers or canonical date values only after a successful decode. The server then adds trusted scope values, runs visible-reference checks, performs authoritative structural and application validation, writes the parsed row, and returns HTTP 201. The relevant response fields are:
{ "data": { "id": 1, "project_id": 1, "title": "Publish launch checklist", "description": "Prepare the release list", "status": "in_progress", "priority": "medium", "due_date": "2026-08-01" }}The request body omits IDs, timestamps, and scope columns. Clients do not choose workspace, owner, role, or scope values. The API derives them from request authority.
Edit, search, and follow the relationship
Section titled “Edit, search, and follow the relationship”Open the saved task and change its status to open. The browser sends a
generated update request with a patch-shaped body even though the HTTP method is
PUT:
PUT /api/tables/tasks/1Content-Type: application/json
{ "status": "open" }{ "data": { "id": 1, "project_id": 1, "title": "Publish launch checklist", "status": "open", "priority": "medium", "due_date": "2026-08-01" }}Generated row updates use PUT, not PATCH. The server applies the update to
the requested ID and the active row-visibility predicate in the same write.
Return to /tables/tasks and search for launch. Filter status to open
with the searchable multi-value combobox and confirm the saved task remains. The
chosen value appears as a removable chip; the combobox query itself is not part
of the filter. Then open Website Relaunch and find the task in its Tasks
child collection. The lookup, task list, task detail, and child list all use
generated routes with the same row boundary.
The task app now has a complete generated record loop: create, validate, edit, search, lookup, detail, and parent-child navigation. The browser requests show that these screens are clients of the same generated CRUD API, and hidden fields remain presentation rather than authorization. Continue to Query tasks through the generated API to call those routes directly. The record screens and forms guide and generated record surfaces reference describe the available generated behavior in more depth.