Step 3-8 min

Author your first dashboard

Learn the anatomy of a DAC dashboard - rows, widgets, filters, queries, templating - in both YAML and TSX. Write one against any table in your own database.

Author your first dashboard

What you'll do

Learn the building blocks of a DAC dashboard - filters, rows, widgets, queries, templating - so you can write one against your own tables without leaning on the starter.

Why this matters

Every DAC dashboard is the same recipe: a connection, some filters, a grid of widgets, and the SQL behind each one. Once you can read one, you can review one in a PR. Once you can write one, every dashboard in your org becomes a diff instead of a meeting.

The vocabulary

Five primitives make up every dashboard:

  • Dashboard - the top-level definition: name, connection, optional shared queries, and a list of rows.
  • Filter - a user input (select, date-range, text) that rewrites widget SQL via Jinja templating.
  • Row - a horizontal band that holds one or more widgets.
  • Widget - a single visual element. Each widget declares its type, its col width, and the SQL it pulls from.
  • Query - the SQL that produces a widget's data. Inline under a widget, named under a top-level queries: block, or referenced from a .sql file in queries/.

The grid is 12 columns wide. The col values inside a row must add up to 12.

Widget types

typeRendersRequired fields
metricA single number with optional prefix/suffixsql, column, format
chartline, bar, area, pie, scatter, ...sql, chart, x, y (array)
tableA scrollable result grid with column labelssql (or query), columns
textMarkdown contentcontent
imageA static imagesrc, alt
dividerVisual separator(none)

chart: accepts the full ECharts catalogue - line, bar, area, pie, scatter, bubble, funnel, sankey, heatmap, boxplot, waterfall, and more.

Filter types

typeWhat the user seesUseful defaults
selectDrop-down of values (static list or query-driven)"All"
date-rangeDate picker with presets"last_30_days", "all_time"
textFree-form input""

Reference filters in your SQL with Jinja: {{ filters.region }} and {% if filters.region != 'All' %}...{% endif %}. A date-range filter exposes .start and .end (e.g. {{ filters.date_range.start }}).

Anatomy of a dashboard file

DAC reads two formats from dashboards/: *.yml / *.yaml and *.tsx. Same logical structure, different syntax. Pick the one that fits how your team works - YAML for declarative, TSX for programmatic (loops, conditionals, shared components).

name: <Dashboard Name>
description: <one-line summary>
connection: <connection name from .bruin.yml>

filters:
  - name: <filter name>
    type: select
    default: All
    options:
      values: [All, <option_a>, <option_b>]

queries:                              # optional - shared queries by name
  <query_name>:
    sql: |
      SELECT ... FROM <your_table>
      {% if filters.<filter name> != 'All' %}
        WHERE <column> = '{{ filters.<filter name> }}'
      {% endif %}

rows:
  - widgets:
      - name: <Metric Title>
        type: metric
        col: 4                         # 12-column grid
        column: value                  # which column of the result is the number
        prefix: "$"
        format: number
        sql: |
          SELECT SUM(<column>) AS value FROM <your_table>

      - name: <Chart Title>
        type: chart
        chart: line
        col: 8
        sql: |
          SELECT <x_col>, SUM(<y_col>) AS <y_alias>
          FROM <your_table>
          GROUP BY 1 ORDER BY 1
        x: <x_col>
        y: [<y_alias>]

Tip

TSX files accept plain JSX-style code too - if you don't want types, just leave them off. The file extension still has to be .tsx for DAC to discover it; .jsx files are not recognised.

Templating cheatsheet

The same Jinja runtime works in YAML and inside TSX sql={\...`}` strings.

  • {{ filters.X }} - inserts the value of filter X.
  • {{ filters.date_range.start }} / {{ filters.date_range.end }} - fields on a date-range.
  • {% if filters.X != 'All' %}...{% endif %} - skip a WHERE when the user picked the default.
  • {% if filters.X == '<value>' %}...{% else %}...{% endif %} - branch on a value.

Validate before you serve

Three commands, in order:

dac ls --dir .
dac validate --dir .
dac check --dir .
  • dac ls - shows what DAC discovered. Use this when a new file isn't being picked up.
  • dac validate - checks structure and schema only (no DB hit). Fast.
  • dac check - runs every query against the live connection. Run this before dac serve to catch a bad column or table name without opening a browser.

What just happened

You now have the vocabulary and the schema to write a DAC dashboard against any table in any connection - and the validation pipeline to catch mistakes before they reach the browser.