Skip to content

Stats Banner

The Stats Banner displays rich visual statistics above List and Kanban views. It supports sparkline trends, aging breakdowns, activity heatmaps, and progress rings.

Stats are configured as an array of stat objects, either at the view level (in the list/kanban view arch) or at the action level (in the window action’s action_ctx). Action-level stats take priority over view-level stats.

Stats load after the main view data to avoid blocking the page. The banner is hidden when there are no records.

WidgetDescriptionVisual
trendSparkline area chart with value + change indicatorMetric + mini chart
agingStacked horizontal bar with time-based bucketsColor-coded bar segments
heatmapCalendar activity density gridGitHub-style heatmap
progressRing progress showing completion rateRing + percentage

Add a stats array at the top level of your list/kanban view arch:

- data_type: UiView
identifier: sale_order_list_view
type: List
model: SaleOrder
arch:
- stats:
- type: stat
name: total
properties:
widget: trend
label: Revenue
aggregate: sum
format: currency
date_field: date
- type: stat
properties:
widget: progress
label: Invoiced
filter: Q(invoice_status__eq='Fully Invoiced')
color: teal
content:
- type: field
name: name
# ... rest of columns
FieldTypeDescription
typestringAlways "stat"
namestringField name to aggregate (required for sum/avg, optional for count)
propertiesobjectWidget configuration (see below)

Shows a value with sparkline chart and period-over-period change percentage.

- type: stat
name: total
properties:
widget: trend
label: Revenue
aggregate: sum
format: currency
date_field: date
filter: Q(state__eq='Posted')
PropertyTypeDefaultDescription
widgetstringrequired"trend"
labelstringrequiredDisplay label (e.g., “Revenue”, “Orders”)
aggregatestring"sum"Aggregation: sum, count, or avg
formatstring"number"Value format: "currency" or "number"
date_fieldstringrequiredDate/DateTime field for time series
filterstringQ-expression to scope the stat (e.g., only posted records)
colorstringprimaryMantine color for the sparkline
  1. Value: Aggregates the field over the filtered dataset
  2. Sparkline: Groups data by day/week/month (auto-detected from date span) and plots an area chart
  3. Change badge: Compares current period vs. previous period of equal length, shows ↑/↓ percentage

The grouping interval is chosen automatically:

  • < 60 days of data → group by day
  • 60–365 days → group by week
  • > 365 days → group by month

When format: currency, the stat automatically filters to the user’s default company (cid) to ensure single-currency aggregation. The company’s currency symbol and position are included in the response.

Trend cards with a filter property are clickable — clicking toggles that filter on the list/kanban view. An active filter is shown with a highlighted border.

Shows a stacked horizontal bar chart with 5 standard aging buckets based on a date field.

- type: stat
name: total_due
properties:
widget: aging
label: Aging
date_field: due_date
filter: Q(state__eq='Posted')
PropertyTypeDefaultDescription
widgetstringrequired"aging"
labelstringrequiredDisplay label
namestringMonetary field to sum per bucket. If omitted, counts records
date_fieldstringrequiredDate field to age from (e.g., due_date)
filterstringQ-expression to scope the stat

The aging widget uses 5 fixed buckets calculated from today’s date:

BucketColorCondition
Currentgreendate_field >= today
1-30dyellowtoday - 30 <= date_field < today
31-60dorangetoday - 60 <= date_field < today - 30
61-90dred.4today - 90 <= date_field < today - 60
90d+red.8date_field < today - 90

Hover over the bar to see per-bucket values in a tooltip.

Shows a calendar-style activity density grid (like GitHub contribution graphs).

- type: stat
properties:
widget: heatmap
label: Expected Closings
aggregate: count
date_field: expected_close_date
months: 6
PropertyTypeDefaultDescription
widgetstringrequired"heatmap"
labelstringrequiredDisplay label
aggregatestring"count""count" or "sum"
namestringField to sum (required when aggregate is sum)
date_fieldstringrequiredDate field for the calendar
monthsnumber6Number of months to display

Shows a ring progress indicator with done/total counts.

- type: stat
properties:
widget: progress
label: Invoiced
filter: Q(invoice_status__eq='Fully Invoiced')
scope: Q(state__eq='Confirmed')
color: teal
PropertyTypeDefaultDescription
widgetstringrequired"progress"
labelstringrequiredDisplay label
filterstringrequiredQ-expression for “done” records
scopestringQ-expression applied to both done and total counts
colorstringprimaryRing color (Mantine color name)
  • filter: Defines which records count as “done” (numerator only)
  • scope: Narrows both the total and done counts (denominator + numerator)

Example: To show what percentage of posted invoices are paid:

- type: stat
properties:
widget: progress
label: Collected
filter: Q(payment_status__eq='Paid') # done = posted + paid
scope: Q(state__eq='Posted') # total = posted only
color: teal

Without scope, the total would include Draft records, making the percentage misleading.

When multiple menu items share the same list view (e.g., Invoices and Credit Notes use customer_invoice_list_view, Bills and Debit Notes use vendor_bill_list_view), you can define different stats per action using action_ctx.stats:

- data_type: WindowAction
identifier: financial_document_customer_invoice_action
name: Invoices
model: FinancialDocument
action_ctx:
default_type: Customer Invoice
stats:
- type: stat
name: amount_company_currency
properties:
widget: trend
label: Revenue
aggregate: sum
format: currency
date_field: date
filter: Q(state__eq='Posted')
- type: stat
name: total_due
properties:
widget: aging
label: Aging
date_field: due_date
filter: Q(state__eq='Posted')
- type: stat
properties:
widget: progress
label: Collected
filter: Q(payment_status__eq='Paid')
scope: Q(state__eq='Posted')
color: teal
global_filter: (Q(type__eq='Customer Invoice'))

Action-level stats (action_ctx.stats) override any stats defined in the view arch.

Alongside stats, list views support group_aggregates for showing totals in grouped rows:

arch:
- group_aggregates:
- field: total
type: sum
stats:
- type: stat
# ...
content:
- type: field
# ...
PropertyDescription
fieldField name to aggregate
typeAggregation type: sum

A sales order list view with 4 stat cards:

- data_type: UiView
identifier: sale_order_list_view
type: List
model: SaleOrder
arch:
- group_aggregates:
- field: total
type: sum
stats:
- type: stat
name: total
properties:
widget: trend
label: Revenue
aggregate: sum
format: currency
date_field: date
- type: stat
properties:
widget: trend
label: Orders
aggregate: count
date_field: date
- type: stat
name: total
properties:
widget: trend
label: Avg Order Value
aggregate: avg
format: currency
date_field: date
- type: stat
properties:
widget: progress
label: Invoiced
filter: Q(invoice_status__eq='Fully Invoiced')
color: teal
content:
- type: field
name: name
properties:
widget: Text
label: Number
fw: 600
# ... remaining columns