Skip to content

Business widgets

Business widgets are Organisms under organisms/widgets/ — one flat folder per Figma master pattern. They compose a chart primitive (or a table) with a header, optional objective footer, loading / error / empty states, and a filters popover. They are props-driven skeletons: no fetch, no store.

Live demos

The links below open each widget's Storybook page on Chromatic. Run Storybook locally with bun run storybook (default http://localhost:6006).

Master widgets

WidgetRolePrimitiveStorybook
RoKPIWidgetKPI value + sparkline (compact 1x1 variant)sparklineOpen
RoGaugeWidgetGauge toward an objective (SLA, CSAT, QoS)RoGaugeOpen
RoDonutWidgetProportional breakdownRoDonutChartOpen
RoBarChartWidgetComparison by period / categoryRoBarChartOpen
RoLineChartWidgetTemporal trendRoLineChartOpen
RoHeatmapWidgetDay x hour intensityRoHeatmapOpen
RoTableWidgetMulti-column table (sort, filters, virtualization)RoTable (ringo-ui)Open
RoLeaderboardWidgetAgent / group rankingOpen
RoSankeyWidgetFlow between stages (IVR -> group -> agent)RoSankeyOpen
RoWorldMapWidgetGeographic distributionRoWorldMapOpen
RoTextWidgetRich text / team note (TipTap)Open
RoTimelineWidgetAgent activity timeline (daily gantt-style view)Open
RoCallActivityWidgetCompact 1x1 single-metric tileOpen
RoQueueListWidgetQueue waiting KPI + breakdownOpen
RoAgentIrregularitiesWidgetAgent irregularities tableOpen

Catalog types are not components

Platform catalog types (kpi-calls, service-level, omnichannel-view, …) are serialized configurations in saved views, not distinct components. The app's COMPONENT_BY_TYPE registry maps each type to one of the master widgets above. The library never sees catalog types — it receives display props. See Architecture.

Widget shell contract

Every widget composes RoWidgetCard for chrome. Hosts drive the shell through these props / slots:

Prop / slotPurpose
titleWidget title.
availableFiltersBusiness filter kinds for the kebab popover; the shell auto-derives the header meta line.
menuItemsOverflow menu items (buildWidgetMenuItems([...])).
objectiveOptional RoObjectiveFooter payload { label, progress, progressLabel?, level? }.
loading, errorMessage, emptyData-state flags — the shell renders the matching state.
#actions slotInline header chips / range pickers.
showExpandButton / @expandOptional header expand button (default false; table-style widgets opt in).
#filters slotFilters form inside the popover; receives { close }.
v-model:filtersOpenExternal control of the filters popover.

RoWidgetCard owns the chrome: padding 12 / 20 / 32 (top / horizontal / bottom), 1px border, 16px radius, position: relative, overflow: hidden, and the four interaction states (enable / hover / focused / focus+hover). Widget organisms ship no chrome CSS of their own.

Filters, channels and alerts

  • Channel = stats domain. A channel maps to a POST /statistics domain (calls, sms, whatsapp, videoconference), not a where[] predicate. The channels filter only surfaces on multi-domain (omnichannel) widgets; the library hides it when fewer than 2 channel options exist.
  • Alerts. Widgets carry a rich RoAlertConfig (operators, two severities, cooldown). evaluateRoAlert(config, value) returns 'warning' | 'critical' | null; RoWidgetCard paints the matching ring on the tile.

Sizing

Widgets are sized in cols on the 8-column dashboard grid. See Grid sizing for the canonical slots and exported pixel values.

RoKPIWidget is polymorphic: variant: 'standard' | 'compact'. The host picks the variant via the prop — standard renders with a sparkline, compact is the 1×1 tile without one.