TotalBase
Widgets

SQL Conventions

Metadata columns a query can return: row colors, badge colors and more.

In the admin: a Dashboard › a widget › Edit

Presentation that depends on the data, such as an overdue row in red, is written in the query, as extra columns with agreed names. There are no rule builders or conditional formatting screens: a CASE in SQL does the job, and PostgreSQL computes it.

The overdue orders table: priority badges from _priority_color and red rows from _color.
The overdue orders table: priority badges from _priority_color and red rows from _color.

Metadata columns: the _ prefix

A result column whose name starts with _ is a metadata column. It travels with the row but is never displayed as data, and no role ever picks it on its own. The prefix is reserved so a helper can't collide with a real column: status_color could be one, _status_color can't.

ColumnMeaning
_colorthe row's color
_<column>_colorin a Table, shows <column> as colored badges
any other _*a free helper: an order key (_step), a key for a click (_id). Never shown

A click's formulas can read them: Open a record with {{row._id}} opens the clicked row's record.

Row color: _color

Where a row is one mark, _color colors it. A widget's Color column setting can name another column instead.

WidgetWhat _color colors
Tablethe row's background tint
Mapthe point
Leaderboardthe bar
Pie, Donut, Funnelthe slice or step
Treemap, Sunbursta leaf: the innermost rectangle or the outer ring's segment
Bar chart, Horizontal barthe bar, only with a single value column. With several series a row is a group
Line, Area, KPI, Gaugedoesn't apply: a line has one color

A Table also hides its Color column, even when its name has no _.

Badges: _<column>_color

In a Table, when the result has _<column>_color beside <column>, each cell of that column shows as a badge in the row's color:

SELECT wo.number, wo.status, wo.priority,
       CASE wo.status
         WHEN 'COMPLETED' THEN 'emerald'
         WHEN 'WAITING_PARTS' THEN 'amber'
         WHEN 'CANCELLED' THEN 'neutral'
       END AS _status_color,
       CASE WHEN wo.due_at < now() THEN 'red' END AS _color
FROM work_orders wo
ORDER BY wo.reported_at DESC
LIMIT 50

A NULL or a value that isn't a palette color leaves the cell as plain text.

The palette, and why it's safe

The valid colors are the palette's names, the same as roles and menu entries use:

red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose.

  • A color from SQL is data, not styling. Only these names pass; a hex code, a CSS value or a typo is ignored and the widget falls back to its Color, or the theme's primary.
  • The shade adapts to light and dark mode.
  • In the example above, 'neutral' isn't in the palette, so a cancelled order's status reads as plain text.
A column's own colors don't need SQL. The colors of a CHECK list set in Database (Urgent in red) already color a pie's slices and a chart's series. Use _color when the color depends on more than one value.

Other conventions

  • Order and LIMIT belong in the query. Widgets never re-sort or cut rows. The only exception is a Table's header sort, over the rows already loaded.
  • Time series go oldest first. A KPI's trend, a Line and an Area read the last row as "now".
  • Optional filters use ($VAR.x IS NULL OR column = $VAR.x): no value, no filter. The drawer's Optional filter writes it for you.
  • Per-user rows use $USER.<column>: WHERE branch = $USER.branch. A $VAR filters; only $USER restricts.
  • Locations are a point: point(lng, lat) builds one.
  • Slow aggregates over a large table belong in a materialized view refreshed on a schedule by a workflow, not a longer timeout.

Next steps