Customize lists and forms
Starting from a model registered with defaults, you will tune its list page (columns, search, order, page size, sidebar group) and its forms (read-only, hidden, password and timestamp fields).
Prerequisites
Section titled “Prerequisites”- A studio with at least one registered model (see Add an admin to an app).
1. Start from the defaults
Section titled “1. Start from the defaults”import 'package:gisila_studio/gisila_studio.dart';
studio.register<Product>(ProductTable.metadata);Defaults: the label is the table name title-cased, the list shows the first six columns (skipping password-like columns), search does nothing, rows are ordered by primary key, 25 per page, and every column except the primary key is editable.
2. Name the model and group it
Section titled “2. Name the model and group it”studio.register<Product>( ProductTable.metadata, displayName: 'Product', displayNamePlural: 'Products', group: 'Catalog',);Models with the same group share a sidebar section. Models without one appear under
“General”.
3. Choose list columns, search and order
Section titled “3. Choose list columns, search and order”studio.register<Product>( ProductTable.metadata, listDisplay: ['sku', 'name', 'priceCents', 'isActive', 'updatedAt'], searchFields: ['sku', 'name'], ordering: ['-updatedAt', 'name'], pageSize: 50,);- Use the Dart field names (
priceCents) or the column names (price_cents); both work. - Search matches each
searchFieldscolumn as text withILIKE '%term%', joined withOR. Pick indexed or short columns on big tables, since%term%cannot use a normal B-tree index. orderingis not validated; a misspelled column makes the list page fail with a database error.- There is no click-to-sort on column headers and no filter sidebar;
orderingis the only sort.
4. Lock, hide and mask form fields
Section titled “4. Lock, hide and mask form fields”studio.register<Product>( ProductTable.metadata, readonlyFields: ['id', 'createdAt', 'updatedAt'], excludeFields: ['searchVector', 'legacyData'], passwordFields: const [], // this table has a "secret_sauce" column that is not a secret);| Option | On forms | Written on save | In list |
|---|---|---|---|
readonlyFields |
Shown as text | No | If in listDisplay |
excludeFields |
Not shown | No | If in listDisplay |
passwordFields |
Masked, never pre-filled | Yes; blank on edit keeps the stored value | Hidden from the default list |
passwordFields defaults to columns whose name contains password, passwd or secret. Pass
your own list to change that, or const [] to turn it off.
5. Stamp timestamps automatically
Section titled “5. Stamp timestamps automatically”studio.register<Product>( ProductTable.metadata, readonlyFields: ['id', 'createdAt', 'updatedAt'], autoNowOnUpdateFields: ['updatedAt'],);updatedAt is set to the current UTC time on every add and edit made in the studio. Keep it in
readonlyFields so nobody edits it by hand. For a createdAt set only once, give the column a
database default (DEFAULT now()) and make it read-only; on add, read-only columns are left to
the database.
6. Understand how fields render
Section titled “6. Understand how fields render”Field types come from Postgres, not from Dart: integer columns get number inputs, boolean
checkboxes, timestamp columns a date-time picker, text/json/jsonb a textarea, everything
else a text input. A field is required when the column is NOT NULL without a default. See
How the studio works for the full mapping and
parsing rules.
Column types are cached for the life of the process; restart after migrations.
Verify it works
Section titled “Verify it works”Restart the server and open /admin/<table>/:
- the list shows your columns in order, sorted by
ordering; - typing in the search box filters rows (
?q=...in the URL); - the edit page shows read-only fields as plain text and leaves excluded fields out;
- saving updates
updated_at(check withSELECT updated_at FROM product WHERE ...).