Dashboards & charts
Charts and dashboards are how ad-hoc analysis becomes something the whole workspace looks at. The pieces stack: a saved query produces rows, a chart gives one query a visual shape, a dashboard arranges charts and query tables on a grid, and the workspace home page can pin those same tiles as the first thing everyone sees. Each layer is a separate, reusable object — change the query and every chart, dashboard, and home-page tile built on it updates with it.
If you only remember one thing: a dashboard never carries data or grants access to it. Every tile runs its query as the person viewing it, at the moment they view it. Sharing a dashboard shares the definition, not the results — a viewer whose record visibility is restricted sees “Not available for your access level” where the numbers would be.
Who can do what
Section titled “Who can do what”| Capability | Action | Default roles |
|---|---|---|
| View charts | charts:read |
Admin, Member, Reader |
| Create/edit/delete charts | charts:manage |
Admin, Member |
| View dashboards | dashboards:read |
Admin, Member, Reader |
| Create/edit/delete dashboards | dashboards:manage |
Admin, Member |
| View saved queries (chart sources) | savedQueries:read |
Admin, Member, Reader |
| See the data behind a tile | query:execute + unrestricted record visibility |
See below |
| Configure the workspace home page | customization:manage |
Admin |
| Open the chart editor page | builder:access |
Admin (grantable via custom roles) |
Charts, dashboards, and saved queries have no per-object ownership or sharing controls: every one of them is visible workspace-wide to anyone holding the read action, and editable by anyone holding the manage action. The creator is recorded but grants no special rights. If you need a private-to-me analysis, keep it as SQL in the query editor rather than saving it as a shared object.
Charts
Section titled “Charts”Charts are authored on the Charts page in the builder area
(Admin → Charts, behind builder:access). A chart is three things:
- A data source — either a saved query (recommended: reusable, centrally editable) or inline SQL written just for this chart. A chart backed by a saved query inherits the query’s template variables; an inline-SQL chart carries its own variable definitions.
- A chart type —
bar,line,area, orpie. - Display configuration — for bar/line/area: which column is the X axis and one or more Y series, each with its own colour and optional label (multiple series plot side by side with a legend). For pie: which column supplies the segment labels and which the values.
The editor previews the chart live against real query results, so you shape
the SQL and the axes together — GROUP BY in the query typically supplies the
X axis, aggregates supply the Y series. Date-like columns are detected and
formatted as dates on the axis automatically.
Chart cards on the Charts page run their query for a live preview, and show usage chips listing the dashboards each chart appears on. Duplicate copies a chart when you want to change one without touching the dashboards built on the original.
API: GET /charts, POST /charts, PUT /charts/{chartId},
DELETE /charts/{chartId}.
Dashboards
Section titled “Dashboards”Dashboards live in the end-user area at Dashboards — no builder access
needed to view or (with dashboards:manage) to compose them.
A dashboard is a named grid of tiles. Each tile is one of:
- Chart — renders a saved chart.
- Query table — renders a saved query’s rows directly as a table.
Composition is in-place: Edit puts the dashboard in draft mode, Add tile picks a chart or saved query, and tiles are dragged and resized on a 12-column grid (each row unit is about 80px). A tile can override its title; otherwise it shows the underlying chart or query name. Nothing is stored until Save writes the whole draft back — Cancel discards it.
References from tiles to charts and queries are soft: deleting a chart or query doesn’t break the dashboard, its tile just shows “This chart no longer exists” until re-pointed.
Dashboard variables
Section titled “Dashboard variables”A dashboard can declare its own variables, bound by name to the
{{placeholder}}s in the SQL behind its tiles: one region control at the
top of the dashboard filters every tile whose query references
{{region}}. A variable left on “All” is unset, dropping the [[ ... ]]
optional blocks that reference it — see
template variables. The variables
dialog suggests every placeholder name it finds in the tiles’ SQL, copying the
definition from the underlying query when one exists. For placeholders a
dashboard does not declare, the tile falls back to the underlying query’s
own default values.
Refresh behaviour
Section titled “Refresh behaviour”Tiles fetch their data when the dashboard opens, and re-run automatically when a variable value changes. Each tile also has a manual Refresh button. There is no timed auto-refresh — a dashboard left open on a wall screen shows the numbers from when it loaded until something re-runs it.
API: GET /dashboards, POST /dashboards,
PUT /dashboards/{dashboardId}, DELETE /dashboards/{dashboardId}.
Whose permissions does a dashboard use?
Section titled “Whose permissions does a dashboard use?”The viewer’s — always. A dashboard stores only definitions (which chart, which query, where on the grid). When someone opens it, each tile calls the query engine with that person’s credentials, so:
- What a viewer sees is exactly what they could get by running the tile’s SQL themselves. The author’s permissions are irrelevant at view time; there is no “run as author” mode and no way for a dashboard to leak data its viewer couldn’t query.
- Because ad-hoc SQL requires unrestricted record visibility, a viewer whose visibility is restricted on any private table (or by a private field) gets no tile data at all. This shows as a quiet “Not available for your access level.” on each tile rather than an error — deliberate, since a configured page full of red errors reads as breakage.
- Viewing also requires the ordinary read actions (
dashboards:read,charts:read,savedQueries:read) to load the definitions; all three are in every built-in role.
The workspace home page
Section titled “The workspace home page”Every member lands on Home. Out of the box it’s a built-in default (quick links to your tables plus the viewer’s recent items). An admin can replace it with a configured home page: the same tile grid as a dashboard, with a wider set of tile kinds — this is how a workspace pins its key dashboardable content as the landing experience.
Editing is in place: the Customize button (shown to holders of
customization:manage) opens draft mode seeded with starter tiles matching
the default page, so customising feels like taking over the default rather
than starting from nothing. Reset to default discards the configuration
entirely (DELETE /workspace/homepage).
Tile kinds:
| Kind | Shows | Configuration |
|---|---|---|
chart |
A saved chart | Chart id |
table |
A saved query’s rows as a table | Query id |
quickLinks |
A list of in-app links | Curated picks, or the built-in permission-aware set |
recentRecords |
The newest records in one table | Table id, row count (default 5, max 50) |
myRecents |
The viewer’s own recently visited items | None (per-viewer) |
markdown |
A block of admin-authored text | Up to 4,000 characters |
Notes on the pieces:
- Quick links name real in-app destinations (a table’s records, sheet or
board, a specific dashboard, the builder pages) chosen from a picker — not
free-text URLs — so links can’t drift off-product or break with routing
changes. Without a label override, a link shows its destination’s live name:
rename the table, the link renames itself. In
builtInmode the tile recomputes the same permission-aware link set the default page shows, per viewer. Links to builder pages render only for viewers holdingbuilder:access. - Chart and table tiles are the same tiles dashboards use, with the same viewer-permission behaviour: restricted viewers see “Not available for your access level” instead of data — expected, since a home page targets the whole workspace.
- A page holds up to 40 tiles; a quick-links tile up to 24 curated links.
- Graceful degradation is built in: a viewer whose role lacks
customization:read(or a fetch failure) gets the built-in default page rather than an error, and a tile kind a client doesn’t recognise is skipped, not mangled — old app versions won’t delete a newer tile when they edit.
API: GET /workspace/homepage, PUT /workspace/homepage (full replace of
the tile list, validated on write), DELETE /workspace/homepage. Reading is
customization:read (all roles); writing is customization:manage
(admin-only by default).
The AI dashboard assistant
Section titled “The AI dashboard assistant”The Dashboards page includes an AI dashboard assistant: describe the
dashboard you want, and it drafts a complete plan — new saved queries, charts,
and the dashboard that arranges them, reusing existing queries and charts
where they fit. The SQL in a plan is validated against your workspace’s real
tables before you see it, and nothing is created until you press Apply:
the plan is then created atomically (everything or nothing) via
POST /dashboard-plans/apply, producing ordinary queries, charts, and
dashboards you can edit like any other. Plans are additive only — they never
modify or delete existing objects. Validating a plan requires only
dashboards:read; applying one requires dashboards:manage. See
AI assistants.
Q: Can I share a dashboard with just one team, or make one private?
Not currently. All dashboards (and charts, and saved queries) are workspace-visible to anyone with the read action, and editable by anyone with the manage action. What you can control is the data: tiles show each viewer only what their own permissions allow (which for dashboards is all-or-nothing — see above).
Q: A colleague opens my dashboard and every tile says “Not available for your access level”.
Their record visibility is restricted somewhere in the workspace (a private table where their scope is narrower than workspace-wide, or a private field they can’t read), so the query engine refuses to run tiles for them. This is the deliberate all-or-nothing rule for raw SQL — see Queries & exports.
Q: Someone edited a chart and it changed on three dashboards. Expected?
Yes — charts are shared objects referenced by id, so an edit lands everywhere at once. Use Duplicate (on charts and on saved queries) when a change should not propagate; the usage chips show which dashboards a chart feeds before you edit it.
Q: Do dashboards auto-refresh?
No. Tiles load on open and re-run on variable changes or the per-tile Refresh button. There is no polling interval.
Q: Members can edit dashboards but can’t open the Charts page — why?
Dashboards live in the end-user area, gated only by dashboards:manage. The
Charts page (and the Query page) are builder surfaces behind
builder:access, admin-only by default. Grant a member builder:access
through a custom role to let them author charts; composing existing charts
into dashboards needs no builder access at all.
Q: Can a home-page tile show a whole dashboard?
Not embedded — chart and table tiles pin individual pieces. To point people at a full dashboard, add a quick link whose target is that dashboard.