Building pages & tiles
An App is a stack of pages, and each page is a grid of tiles — the same tile model dashboards use. If you’ve built a Saiku dashboard, this will feel identical; the only new layer is the App’s pages and navigation around it.
Pages
Every App starts with one page. In edit mode:
- Add a page from the navigation menu (rail or top) — the
+affordance next to the page list. - Rename a page in place; the name is what shows in the nav.
- Switch pages by clicking them in the nav. Each page remembers its own filter state as you move between them.
Order your pages to match the story you want to tell — an overview page first, detail pages after.
Adding tiles
On a page in edit mode, click + Add tile to open the tile menu. The built-in tile types are:
| Tile | What it shows |
|---|---|
| Chart | Sixteen chart types — bar / line / area / pie / donut / waterfall / treemap / sunburst / heatmap / radar / scatter / bubble / map. See The Chart tile |
| Table | Records of measure cells with row headers |
| KPI | A single measure as a big number, with an optional comparison and sparkline |
| Text / note | A Markdown annotation — no data |
| Image | A logo, diagram, or screenshot from a URL or upload |
Pick a type and the tile drops onto the grid. Placement and sizing work just like a dashboard — drag to move, drag the handle to resize.
Filters aren’t in this menu — they’re added in the page’s Filters panel, above the grid.
Binding a tile to data
Adding a tile picks its type; the ⚙ tile editor is where you give it data. Open it from the tile’s edit button. Depending on the tile type you configure:
- The cube and query — for chart, table, and KPI tiles, choose the connection / cube and build the query (measures, dimensions on rows or columns, slicers). See Where a tile’s query comes from below.
- The chart type, and behind the Chart options button a second editor with dual axes, combo series types, trend lines, sort / Top N, number formatting, reference lines and bands. A chart tile can also detect anomalies, project a forecast, and emit a cross-filter when you brush it. All of that has its own page: The Chart tile.
- The measure and comparison — for a KPI, which measure is the big
number and (optionally) what it’s compared against. Use the
$cNformat pattern for compact currency ($48.2K). See KPI comparisons below. - The content — the Markdown body for a text tile, or the URL / upload for an image tile (these two need no query).
- Conditional formatting — table tiles support per-column rules: background colour, data bars, font colour or an icon (↑ ↓ →), keyed to relative (percentile) or absolute thresholds. A table can also add a trailing sparkline column, drawing a mini chart per row from that row’s measure values — meaningful when those columns form a series (months, say), less so across unrelated measures.
- Number format (per column) — table tiles take a display pattern per
column, matched on the header caption, using the same vocabulary as the
KPI and ranked-list tiles:
$cNcompact currency,$Nplain currency,N%percent, bareNfractional digits. Worth setting on any integer measure whose cube format string carries a decimal — otherwise a unit count renders as10759.0. Columns you leave out keep the cube’s own formatting. - Auto-refresh — any query-bound tile can re-run itself every 1, 5, 15, 30 or 60 minutes, honouring active filters and pausing while the browser tab is hidden.
For ECharts-option custom tiles the editor adds display options: a live Trend / Breakdown toggle (swap the series between a line and bars over the same data), emphasise last point (an accent “current period” marker), and a value axis format. See Custom tiles.
Text and image tiles are the two that carry no query; everything else binds to a cube.
Where a tile’s query comes from
There are two ways to give a tile its query, and they sit in different places in the ⚙ editor.
Build it here. Click Edit query visually and the full Saiku query builder opens inside the tile editor: the cube tree on the left, Measures / Columns / Rows / Filter drop zones, and a live result grid underneath. It runs as you build, so you see the actual numbers before committing the tile. Apply commits the query; saving the tile persists it. This is the usual path — pick a cube first, or the button stays disabled.
Or point at something existing, under Query source:
- Saved query — pick an existing
.saikufile and the tile renders live from it. The server loads the saved query, merges any applicable dashboard filters, and re-runs it on each refresh — so one saved query can back tiles in several Apps and they all follow when you change it. - Inline JSON — see below.
Inline JSON takes an AiQueryRequest body directly. Reach for it when
you want a query shape the builder doesn’t offer — a specific hierarchy
where two share a level name, say — or when copying a query between tiles.
A hierarchy can’t be on an axis and in the filters
Put Time / Time / Month on Rows and then try to filter on
Time / Time / Year, and the query is rejected:
Hierarchy ‘Time’ is already on the rows/columns axis. Mondrian rejects the same hierarchy on two independent axes. Either move the filter members onto the axis selection’s
members[], or filter on a different hierarchy/dimension.
This is a rule of the underlying OLAP engine, not a Saiku limitation. To
scope an axis to part of a hierarchy, name the members on the axis
itself rather than filtering separately — in Inline JSON that’s the
members[] array on the row:
"rows": [{ "dimension": "Time", "hierarchy": "Time", "level": "Month", "members": ["[Time].[Time].[1998].[Q1].[January]", "…"]}]The same technique is the escape hatch when a level’s members come back in an order you don’t want: listing them explicitly fixes the sequence, since the chart tile’s Sort categories orders by measure value, not by category. The FoodMart Ops reference App uses exactly this to pin its trend chart to eight named weeks.
KPI comparisons
A KPI’s delta callout — the “+6.7% vs last month” under the number — is derived from the tile’s own time level, so it always describes the comparison the tile actually made. Query at month grain and it says “vs last month”; at week grain, “vs last week”.
Set the time level first
That time level is something you choose, not something the tile infers — and until you set it, a comparison has nothing to compare against.
Near the bottom of the KPI editor, under Time level (for comparison + sparkline), pick a Dimension, Hierarchy and Level (e.g. Time / Time / Month). Then:
- the comparison has a prior period to measure against, and
- the Sparkline checkbox becomes available — it plots the measure across that level.
You can override the wording with Delta label when a cube has its own vocabulary (“vs last trading day”), but the default can no longer disagree with the data.
Incomplete trailing periods
The newest bucket of a time series is often still filling up — the current week or month — or is a data boundary where the last period holds a couple of days. Measured against a whole prior period it produces a number that describes the calendar rather than the business: a −84% that means nothing changed except the date.
Set Incomplete trailing periods to tell the tile how many of the newest periods are still partial. Those periods:
- keep their real values — nothing is hidden, and the sparkline still plots every point
- are labelled “Week 52 · partial” under the number
- have no percentage shown against them, because there isn’t an honest one to show
Saving
Save the App from the editor. It’s persisted as a .saikuapp document
in the repository at the folder you chose when you created it. Re-open
it any time from the Apps list, or embed it on
another site — see Embedding an App.
Related
- App Builder overview — what an App is and how it differs from a dashboard.
- Custom tiles — declarative ECharts and graph renderers beyond the built-in five.
- Analyze — build and save the queries your tiles reuse.