Query Widget YAML
This page is the Query Widget YAML field reference. For when to use a Query Widget, creating steps, refresh behavior, and troubleshooting, see Query Widgets. Put joins and reusable SQL in a Query Dataset.
Keep query as the last top-level key.
schemaVersion: 1source: type: dataset source: 46b0bbe8-619a-4b23-bc44-f11842775640display: type: metric value: ticket_counttimezone: America/Chicagoparameters: - name: board_values filterVariable: 32b69796-14b3-48d1-a9a7-d196b91752c1drilldownQuery: |- select ticket_number, ticket_subject from source where board_name in $board_valuesquery: |- select count(*) as ticket_count from source where board_name in $board_valuesThe editor Copy AI Instructions button copies authoring guidance you can paste into a chat along with the current YAML, columns, and any preview error.
Field reference
Section titled “Field reference”| Field | Required | Notes |
|---|---|---|
schemaVersion |
yes | Must be 1 |
source |
yes | One Dataset or Query Dataset. SQL always sees it as source |
source.type |
yes | dataset or queryDataset |
source.source |
yes | UUID from Browse Sources |
display |
yes | Maps result columns to a chart, table, metric, gauge, or funnel |
timezone |
no | IANA timezone. Source datetimes are localized before the Widget Query |
parameters |
no | Filter Variable bindings |
drilldownQuery |
no | Optional detail SQL. Same source and parameter rules as query |
query |
yes | Read-only Widget Query. Keep this last |
Unknown top-level keys are rejected. Do not wrap the definition in a widget
object.
Source
Section titled “Source”Exactly one source object:
source: type: queryDataset source: 5a242d39-195c-41da-a99b-93b402a4325bsource.type |
Use when |
|---|---|
dataset |
The widget reads one synced Dataset |
queryDataset |
The widget reads a saved Query Dataset result |
modifiedDataset and joinedDataset are not valid Query Widget sources. If
you need filtered, joined, or multi-source shaping, create a Query Dataset
first.
Do not use a sources list or source aliases in a Query Widget. The Widget
Query always selects from source.
Parameters
Section titled “Parameters”Each parameter has a SQL name and a Filter Variable UUID. Use $name in SQL.
parameters: - name: board_values filterVariable: 32b69796-14b3-48d1-a9a7-d196b91752c1| Field | Required | Notes |
|---|---|---|
name |
yes | Starts with a letter or underscore; letters, numbers, underscores |
filterVariable |
yes | Filter Variable UUID for the same company |
where board_name in $board_values- Use
infor multi-select Filter Variables. - Use
=for single-select Filter Variables. - Every
$namein SQL must be declared. - Empty multi-select values become an empty list; empty single-select values become null.
- Parameters are typed values, not spliced SQL text.
{{ column_name }} placeholders do not bind filters. Those slots are for
metric text and columnLinks templates. columnLinks can also use
{{ conn.variable_name }} for non-secret values from the source integration
config. In drilldownQuery, {{ x }} is the clicked chart category.
Timezone
Section titled “Timezone”timezone is an IANA name such as America/Chicago or UTC. If you omit it,
the definition defaults to UTC (new editor drafts usually fill in your
timezone).
Datetime columns from the source are converted into this timezone before
the Widget Query runs. Date helpers such as dashboard_date_filter() use the
same timezone.
Widget Query
Section titled “Widget Query”query must be one read-only SELECT from exactly one relation named
source.
Allowed: filters, grouping, aggregates, case, ordering, limits, declared
$parameters, and dashboard date helpers.
Not allowed: joins, CTEs, subqueries, unions, selecting from anything other
than source, or changing data.
Table displays cap the main Widget Query at 1,000 rows. Drilldown is not
capped at 1,000 rows. Prefer filters, aggregates, or LIMIT so the truncated
page is the set you intend.
Date helpers
Section titled “Date helpers”| Helper | Behavior |
|---|---|
dashboard_date_filter(column) |
Uses the active dashboard date range. Allows all rows when no dashboard date filter is set |
dashboard_date_filter_or_default(column, start, end) |
Uses the dashboard date filter when present; otherwise applies the fallback start and end |
dashboard_start_date(default) |
Active dashboard start, or the default |
dashboard_end_date(default) |
Active dashboard end, or the default |
runtime_start_date('this month') |
Concrete relative start phrase such as today, this week, or this month |
runtime_end_date('this month') |
Matching relative end phrase |
Do not pass 'dashboard' to runtime_start_date or runtime_end_date. Opt
into the dashboard filter with the helpers above.
Activity and flow widgets should use the selected range. Point-in-time widgets should use the selected end date and may include history before the start date.
Drilldown
Section titled “Drilldown”drilldownQuery is optional. When set, it must follow the same Widget Query
rules: one SELECT from source, no joins or CTEs, same Query Parameters.
drilldownQuery: |- select ticket_number, ticket_subject, board_name from source where board_name = {{ x }} and dashboard_date_filter(created_at)- Mirror the main query’s filters and date window.
{{ x }}is replaced with the clickeddisplay.xvalue on charts.- Table widgets open drilldown from the footer expand control, not row clicks on the dashboard.
- Chart and metric widgets open drilldown from a click on the widget body.
- Drilldown cells stay raw until
display.columnFormatsadds design cues. That includesformat: date,datetime, andtimewithdateStyle/timeStylefor timestamp columns.
Display
Section titled “Display”display maps Widget Query result columns onto the rendered widget. It does
not reshape data. Put shaping in SQL.
display.type must be one of:
barlinepiemetrictablegaugefunnel
Column mappings use the aliases your Widget Query returns.
Bar and line
Section titled “Bar and line”Required: x and at least one y.
display: type: bar x: facility y: - open_shift_pct seriesBy: shift_type yLabel: Uncovered shift rate| Field | Required | Notes |
|---|---|---|
x |
yes | Category or time column |
y |
yes | One or more numeric result column names. A single string is allowed. Do not use series objects; put series labels in columnLabels |
seriesBy |
no | Category column that splits long-form rows into series. Bar and line only. Requires exactly one y. Must differ from x |
seriesMode |
no | grouped or stacked |
showStackTotals |
no | Stack total labels when stacked |
horizontalBars |
no | Bar charts only |
areaFill |
no | Line charts only |
barGap |
no | Bar gap string such as "30%" |
xLabel / yLabel |
no | Axis titles |
yAxisMin / yAxisMax |
no | Numeric axis bounds. Max must be greater than min |
yAxisLogScale |
no | Logarithmic y-axis |
xLabelRotation |
no | Integer from -90 to 90 |
overlay |
no | Number Overlay object for bar and line only. Omit for no overlay. Partial overlay fails validation |
Number Overlay (display.overlay)
Section titled “Number Overlay (display.overlay)”Paints one reduced number on a bar or line chart from the same Widget Query
rows. This is not a Metric Display: no comparison, icon, tone, layout, or
templates. Overlay graphic is applied after display.option so it wins.
display: type: line x: month y: - revenue overlay: value: revenue reducer: last placement: topRight size: large label: Current| Field | Required | Notes |
|---|---|---|
value |
yes | Numeric result column to reduce |
reducer |
yes | last, sum, avg, min, max, or first. first/last follow Widget Query row order; include ORDER BY when a specific row is intended. Prefer sum, avg, min, or max when order does not matter. Skips non-numeric cells |
placement |
no | center, top, right, bottom, left, topLeft, topRight (default), bottomLeft, bottomRight. Always paints; never auto-hides or auto-moves |
size |
no | small, medium (default), or large. Compact cards step down one size |
label |
no | Optional static label shown with the number |
accessibleText |
no | auto (default) or value. Independent of the visible label |
If no numeric value remains, the overlay shows a muted em dash. Truncated results still reduce the returned rows and keep the header pill.
The Widget Query must return at most one row for each (x, seriesBy) pair.
Aggregate in SQL, or use multiple y columns for wide data:
display: type: bar x: board_name y: - open_count - closed_count yLabel: TicketsPie and funnel
Section titled “Pie and funnel”Required: label and value. Do not use x or y.
display: type: pie label: status_name value: ticket_count donut: true pieLabelFormat: labelAndPercentagedisplay: type: funnel label: status_name value: ticket_count| Field | Required | Notes |
|---|---|---|
label |
yes | Slice or stage name column |
value |
yes | Numeric column |
donut |
no | Pie only. Omit or true for a donut; false for a solid pie |
pieRadius |
no | One radius string or [inner, outer] such as ["40%", "70%"] |
pieLabelFormat |
no | label, value, percentage, labelAndValue, or labelAndPercentage |
Metric
Section titled “Metric”Required: value (result column from the first result row). The column may be
numeric, text, date, time, or datetime.
display: type: metric value: ticket_count label: Tickets opened subtitle: '{{ period_label }}' icon: zap tone: info comparison: value: prev_period_count label: vs previous period rounding: 0 abbreviatedNumbers: trueClock-time metrics should put a real time on display.value. Prefer a
TIMESTAMP/TIME column with valueFormat:
display: type: metric value: estimated_finish_at valueFormat: format: time timeStyle: short hour12: trueA SQL-formatted text column such as 5:14 PM can also be display.value
with no valueFormat. format: time does not convert a decimal hour such as
17.25.
| Field | Required | Notes |
|---|---|---|
value |
yes | One result column name. Not a template, and not a literal %. May be numeric, text, date, time, or datetime |
valueFormat |
no | Metric only. Formatting for the primary value. Same fields as columnFormats (format, rounding, timeStyle, hour12, …). Does not apply to subtitle slots |
label |
no | Short Metric Label above the value. Omit it when it would repeat the widget title |
subtitle |
no | Supporting text. May include {{ column_name }} slots |
icon / iconColumn |
no | Lucide icon name, or a first-row column that chooses the icon |
tone / toneColumn |
no | positive, negative, neutral, info, or warning |
layout |
no | stacked, split, or centered. Metric only |
comparison |
no | Metric only. Needs comparison.value or comparison.text |
label, subtitle, and comparison.text can use Metric Templates:
{{ column_name }} slots filled from the first row. Shape the text in SQL;
templates do not evaluate expressions.
The widget title is the full headline. Use display.label only as a short
eyebrow when it adds meaning the title does not already carry. Put comparison
and timeframe wording in comparison.label and subtitle.
When comparison.value and display.value are both numeric, the widget shows
a percent-change chip plus the baseline. By default, an increase is positive
(green) and a decrease is negative (red). Set comparison.favorableDirection
to down when a decrease is the good outcome, such as outstanding balance or
error counts. Use comparison.tone or comparison.toneColumn for a fixed
tone that overrides automatic polarity.
Required: value.
display: type: gauge value: completion_percent min: 0 max: 100 percentSuffix: true gaugeIntervalLabels: - Low - High| Field | Required | Notes |
|---|---|---|
value |
yes | Numeric column |
min / max |
no | Literal numbers or numeric column names. Literal max must be greater than literal min |
gaugeIntervalLabels |
no | Exactly two labels, shown at the min and max ends |
percentSuffix |
no | Append % |
All table column mappings are optional. Omit columns to show every result
column. If you set columns, the list must not be empty.
display: type: table columns: - ticket_number - ticket_subject - last_email_age_minutes columnFormats: last_email_age_minutes: rounding: 0 columnLinks: ticket_number: "https://psa.example.com/tickets/{{ ticket_number }}"| Field | Required | Notes |
|---|---|---|
columns |
no | Ordered result columns to show |
columnFormats |
no | Per-column number, date, and text formats |
columnLinks |
no | Column to http(s) URL template. {{ column_name }} slots come from the row; {{ conn.variable_name }} slots come from the source integration config |
columnAutoSort |
no | alphabetical, reverseAlphabetical, calendarAscending, or calendarDescending. Off when omitted |
columnLabels |
no | Header text map for main-table and drilldown columns, including drilldown-only names. Prefer columnDefs.<column>.headerName when customizing columns |
pinnedColumns |
no | Prefer columnDefs.<column>.pinned. May name drilldown-only columns |
fitToWidth |
no | Columns stretch by default. Prefer gridOptions.autoSizeStrategy for advanced sizing |
columnLabels, columnDefs, pinnedColumns, columnFormats, and
columnLinks apply to matching columns in the main table and in drilldown,
including columns that exist only in drilldownQuery. display.columns
still lists the main Widget Query columns to show. When you omit
columnLinks on a new widget, Resplendent copies link templates from the
source Dataset—or from parent Datasets when the source is a Query Dataset—for
columns in the Widget Query or drilldownQuery. Direct source columns and URL
row slots are translated to their result aliases. A link is omitted if its
linked column or another row slot it needs is not selected in that result;
SELECT * keeps source names. Set columnLinks: {} to keep links off; that
choice is not overwritten on later saves. Non-http(s) schemes are rejected as
links at render time, so those cells remain plain text.
The main table query is capped at 1,000 rows. Use drilldownQuery for larger
detail sets.
Table displays can also pass optional gridOptions and columnDefs for
advanced grid behavior (pagination, pinned columns, cell classes). Prefer the
typed fields above unless you need that extra control.
Shared formatting
Section titled “Shared formatting”These options are fallbacks for every numeric result column used by the
display. A matching columnFormats entry overrides the global setting
wherever that column renders, including a metric primary value and numeric
{{ column }} slots.
display: type: table columnFormats: invoice_id: format: text invoice_total: format: currency currencyCode: USD rounding: 2 win_rate_pct: rounding: 1 percentSuffix: true opened_at: format: datetime dateStyle: medium timeStyle: short| Field | Notes |
|---|---|
rounding |
0 to 6 decimal places |
percentSuffix |
Append % |
abbreviatedNumbers |
1.2K / 3.4M / 5.6B |
currencyPrefix |
Compatibility boolean that prepends $. Prefer format: currency plus currencyCode |
format |
automatic, text, number, currency, percent, date, datetime, time, or scientific |
currencyCode |
Three-letter code such as USD |
prefix / suffix |
Literal affixes. Use prefix: '$' only when you want a literal dollar sign |
useGrouping |
Set false to drop thousands separators on ID-like numbers |
dateStyle / timeStyle |
short, medium, long, or full |
hour12 |
12-hour clock when formatting times |
For mixed units, format each exceptional column instead of one global format.
If the primary metric is a percentage and the subtitle contains counts, omit
global percentSuffix and set display.valueFormat.percentSuffix: true.
Shared chart options
Section titled “Shared chart options”| Field | Notes |
|---|---|
dataLabels |
Show formatted values on bars, points, slices, funnels, and gauges |
legend |
Show or hide the legend |
legendPosition |
top, right, bottom, or left |
colors |
Ordered palette. Omit to keep the product theme |
thresholds |
List of { value, color, label } entries. Label is optional |
showTitle / title |
Optional in-display title. Metric displays hide this by default; prefer the widget title |
noDataMessage |
Replaces the default empty-result text |
display.option can hold extra chart styling as JSON. Do not put result data
in option. Prefer typed display fields whenever one exists.
Dotted column names
Section titled “Dotted column names”If a source column name contains a dot, quote it in SQL:
select count(*) as ticket_countfrom sourcewhere "board.name" = $board_valuesDisplay fields use the output alias, without SQL quotes:
display: type: metric value: ticket_countAlias dotted names in a Query Dataset when you can, so widgets can use simple
names like board_name.