CnChartWidget
ApexCharts wrapper for dashboard and detail page widgets. Supports area, line, bar, pie, donut, and radialBar chart types with Nextcloud-themed defaults. The chart library is a peer dependency — consuming apps must install apexcharts and vue-apexcharts.
Try it
Usage
<!-- Area chart with categories -->
<CnChartWidget
type="area"
:series="[{ name: 'Requests', data: [10, 41, 35, 51, 49, 62] }]"
:categories="['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun']"
:height="250" />
<!-- Pie chart -->
<CnChartWidget
type="pie"
:series="[44, 55, 13, 33]"
:labels="['Active', 'Pending', 'Closed', 'Draft']" />
<!-- Bar chart with custom options -->
<CnChartWidget
type="bar"
:series="barSeries"
:options="{ plotOptions: { bar: { horizontal: true } } }" />
When ApexCharts is not available a fallback slot or unavailableLabel is shown:
<CnChartWidget type="area" :series="series">
<template #fallback>
<p>Charts require the apexcharts package.</p>
</template>
</CnChartWidget>
Manifest usage (recommended)
When CnDashboardPage resolves a widget definition with type: "chart", it mounts CnChartWidget automatically. Manifest authors do NOT mount this component themselves — declare a chart widget in pages[].config.widgets[] instead:
{
"id": "sla-trend",
"title": "myapp.sla_trend",
"type": "chart",
"props": {
"chartKind": "line",
"series": [{ "name": "SLA %", "data": [82, 88, 91, 93] }],
"categories": ["Q1", "Q2", "Q3", "Q4"],
"options": { "stroke": { "width": 3 } }
}
}
The dispatcher forwards props.chartKind as the apex type and passes through series, categories, labels, options, colors, toolbar, legend, height, width, unavailableLabel.
dataSource — resolving series + categories from OpenRegister
CnChartWidget accepts a dataSource block that resolves series / categories / labels from a GraphQL query against OpenRegister. Three shapes are supported:
Count shorthand
dataSource: {
schema: 'meeting',
filter: { lifecycle: 'review' },
aggregate: 'count',
}
// → { count: 4 } (use the raw `graphql:` form for chart series)
Bucket shorthand (time series)
Emits OpenRegister's groupBy argument with a time interval and returns { series, categories } ready to feed into a line/bar chart:
dataSource: {
schema: 'call_log',
filter: { status: 'error' },
bucket: {
field: 'created',
interval: 'day', // case-insensitive → DAY
fromVar: 'from', // default 'from'
toVar: 'to', // default 'to'
staticRange: { // fallback when no dashboard range
from: '2026-05-01T00:00:00.000Z',
to: '2026-05-22T00:00:00.000Z',
},
},
}
When mounted under a CnDashboardPage with dateRange.enabled, the widget injects cnDashboardDateRange and uses the dashboard's currently-selected { from, to } for the GraphQL variables — every chart on the page tracks the same range. If no dashboard range is available the widget falls back to bucket.staticRange; if neither is available no query is fired and the chart shows its fallback / unavailable state.
Non-count metrics are supported via metric ('sum' | 'avg' | 'min' | 'max', case-insensitive) + a required metricField:
bucket: {
field: 'created',
interval: 'week',
metric: 'sum',
metricField: 'amount',
staticRange: { from: '…', to: '…' },
}
Raw GraphQL
dataSource: {
graphql: {
query: 'query { meeting { groups { key value } } }',
selectors: {
series: 'meeting.groups[].value',
categories: 'meeting.groups[].key',
},
},
}
The selector path syntax supports dot-paths with optional [] flat-maps. See selectByPath for the full path grammar.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
type | String | 'area' | Chart type: 'area', 'line', 'bar', 'pie', 'donut', 'radialBar' |
series | Array | [] | Data series. Format: [{ name, data[] }] for cartesian charts; number[] for pie/donut |
categories | Array | [] | X-axis category labels (line, area, bar charts) |
labels | Array | [] | Segment labels (pie, donut charts) |
height | Number | String | 250 | Chart height in pixels |
width | Number | String | '100%' | Chart width (defaults to full container width) |
options | Object | {} | Custom ApexCharts options deep-merged with Nextcloud defaults |
colors | Array | [] | Color palette — defaults to Nextcloud CSS variable colors |
toolbar | Boolean | false | Show/hide the ApexCharts toolbar (zoom, download) |
legend | Boolean | true | Show/hide the chart legend |
unavailableLabel | String | 'Chart library not available' | Text shown when ApexCharts is not installed |
dataSource | Object | null | Optional OpenRegister GraphQL block — see dataSource above |
Slots
| Slot | Description |
|---|---|
fallback | Content rendered when ApexCharts is not available |
Reference (auto-generated)
The tables below are generated from the SFC source via vue-docgen-cli. They reflect what's actually in CnChartWidget.vue and update automatically whenever the component changes.
Props
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
type | string | 'area' | Chart type: area, line, bar, pie, donut, radialBar | |
series | Array | [] | Chart data series. Format depends on chart type. For line/area/bar: [{ name: string, data: number[] }] For pie/donut: number[] | |
categories | Array<string> | [] | X-axis categories (for line, area, bar charts) | |
labels | Array<string> | [] | Labels (for pie, donut charts) | |
height | union | 250 | Chart height in pixels. Use 'auto' for container-based sizing. | |
width | union | '100%' | Chart width. Defaults to '100%' (fills container). | |
options | object | \{\} | Custom ApexCharts options (deep-merged with defaults). | |
colors | Array<string> | [] | Chart color palette. Defaults to Nextcloud theme colors. | |
toolbar | boolean | false | Show or hide the toolbar (zoom, download, etc.) | |
legend | boolean | true | Show or hide the legend | |
unavailableLabel | string | () => t('nextcloud-vue', 'Chart library not available') | Label shown when ApexCharts is not available | |
dataSource | object | null | Manifest dataSource block. When set, series / categories / labels are resolved from the GraphQL response via the dataSource selectors and override the static props of the same names. Static props remain the fallback while the query is loading or when no dataSource is configured. Supported shapes (one of): - Count shorthand: { register?, schema, filter?, aggregate: 'count' } - Bucket shorthand: { register?, schema, filter?, bucket: { field, interval, metric?, metricField?, fromVar?, toVar?, staticRange? } } — emits OR's groupBy argument. When mounted under a CnDashboardPage with dateRange.enabled, from / to come from the injected cnDashboardDateRange ref; otherwise they come from bucket.staticRange. If neither is available no query is fired and the chart shows its fallback. - Raw GraphQL: { graphql: { query, variables?, selectors } }. | |
widgetId | string | '' | Widget id used to match cn:widget:refresh event-bus events (broadcast by CnWidgetWrapper's Refresh action). When the bus fires with a matching widgetId, the chart re-queries its dataSource. Passed by CnDashboardPage from the layout item. Empty disables bus-driven refresh (the chart still refetches reactively when its dataSource / range changes). |
Slots
| Name | Bindings | Description |
|---|---|---|
fallback | — |
Refresh wiring
| Prop | Type | Default | Description |
|---|---|---|---|
widgetId | String | '' | Matches cn:widget:refresh event-bus events (broadcast by CnWidgetWrapper's Refresh); on a matching id the chart re-queries its dataSource. |