Skip to content

Data Dashboard

Build an admin dashboard that displays summary statistics, data tables, and aggregated metrics using Math nodes and Combine.

Database Tables

Assume you have these tables:

orders:

ColumnType
idint
customer_namevarchar
totaldecimal
statusvarchar
created_atdatetime

customers:

ColumnType
idint
namevarchar
emailvarchar
created_atdatetime

UI Layout

Container (flex, column, gap: 24px)
  ├── Heading ("Dashboard")
  ├── Container (flex, row, gap: 16px)    ← Stats Row
  │   ├── Card ("Total Revenue")          ← Stat Card 1
  │   ├── Card ("Orders")                 ← Stat Card 2
  │   ├── Card ("Avg Order")              ← Stat Card 3
  │   └── Card ("Customers")              ← Stat Card 4
  ├── Heading ("Recent Orders", h2)
  └── Repeater (orders)                   ← Orders Table
      └── Container (flex, row)
          ├── Text ("`{ {row.customer_name}}`")
          ├── Text ("$`{ {number_format(row.total, 2)}}`")
          ├── Badge ("`{ {row.status}}`")
          └── Text ("`{ {date_format(row.created_at, 'M j, Y')}}`")

Set the entire page visibility to user_can('manage_options') for admin-only access.

Data Source Pipeline (Stats)

Build a pipeline that aggregates data for the stats cards:

Table Query (orders)   → Math (sum, field: "total")    → Combine (var1: "revenue")
Table Query (orders)   → Math (count, field: "id")     → Combine (var2: "order_count")
Table Query (orders)   → Math (avg, field: "total")    → Combine (var3: "avg_order")
Table Query (customers) → Math (count, field: "id")    → Combine (var4: "customer_count")

                                                              Result

Stat Card Bindings

Total Revenue card:

$`{ {number_format(row.revenue, 2)}}`

Orders card:

`{ {row.order_count}}`

Average Order card:

$`{ {number_format(row.avg_order, 2)}}`

Customers card:

`{ {row.customer_count}}`

Data Source Pipeline (Orders Table)

Table Query (orders, orderBy: "created_at", order: "DESC", limit: 20) → Result

Stat Card Styling

Style each stat card:

backgroundColor: #ffffff
borderRadius: 8px
borderWidth: 1px
borderColor: #e0e0e0
padding: 20px
display: flex
flexDirection: column
gap: 8px
width: 25%

On mobile, set width: 100% to stack cards vertically.

Stats row responsive

PropertyDesktopMobile
flexDirectionrowcolumn
flexWrapwrapnowrap

Variations

Add date range filtering

Add a Date Filter widget above the dashboard. Modify the orders query to use whereField: "created_at" with dynamic date values.

Add status breakdown

Use Group By on the orders to create a status breakdown:

Table Query (orders) → Group By (field: "status") → Result

Display as a list:

`{ {row._group_key}}`: `{ {row._group_count}}` orders

Add a chart

Use a third-party chart library (Chart.js) via an HTML Block widget. Pass aggregated data as JSON:

Table Query → Group By (field: "status") → JSON Stringify → Result

Bind the JSON output to a <canvas> element with Chart.js initialization.

TIP

For dashboards with many statistics, create separate components for each stat card and reference them with Component Ref widgets. This keeps the main layout clean and the individual stat pipelines manageable.