Skip to content

Dashboard Templates & End-to-End Workflow

Skill: databricks-aibi-dashboards

A complete dashboard from schema inspection to a published URL — following the mandatory validation workflow. Your AI coding assistant inspects table schemas, tests every SQL query via execute_sql, builds the dashboard JSON with datasets, pages, widgets, and filters, then deploys it through manage_dashboard. These templates show the full pattern you can adapt to your own tables.

“Create a dashboard from the NYC taxi sample data with trip count, average fare, and average distance KPIs, a bar chart of top pickup ZIPs, and a detail table.”

{
"datasets": [
{
"name": "summary",
"displayName": "Summary Stats",
"queryLines": [
"SELECT COUNT(*) as trips, AVG(fare_amount) as avg_fare, ",
"AVG(trip_distance) as avg_distance ",
"FROM samples.nyctaxi.trips"
]
},
{
"name": "by_zip",
"displayName": "Trips by ZIP",
"queryLines": [
"SELECT pickup_zip, COUNT(*) as trip_count ",
"FROM samples.nyctaxi.trips ",
"GROUP BY pickup_zip ",
"ORDER BY trip_count DESC ",
"LIMIT 10"
]
}
],
"pages": [{
"name": "overview",
"displayName": "NYC Taxi Overview",
"pageType": "PAGE_TYPE_CANVAS",
"layout": [
{
"widget": {
"name": "title",
"multilineTextboxSpec": {"lines": ["## NYC Taxi Dashboard"]}
},
"position": {"x": 0, "y": 0, "width": 6, "height": 1}
},
{
"widget": {
"name": "subtitle",
"multilineTextboxSpec": {"lines": ["Trip statistics and analysis"]}
},
"position": {"x": 0, "y": 1, "width": 6, "height": 1}
},
{
"widget": {
"name": "total-trips",
"queries": [{
"name": "main_query",
"query": {
"datasetName": "summary",
"fields": [{"name": "trips", "expression": "`trips`"}],
"disaggregated": true
}
}],
"spec": {
"version": 2,
"widgetType": "counter",
"encodings": {
"value": {"fieldName": "trips", "displayName": "Total Trips"}
},
"frame": {"title": "Total Trips", "showTitle": true}
}
},
"position": {"x": 0, "y": 2, "width": 2, "height": 3}
},
{
"widget": {
"name": "avg-fare",
"queries": [{
"name": "main_query",
"query": {
"datasetName": "summary",
"fields": [{"name": "avg_fare", "expression": "`avg_fare`"}],
"disaggregated": true
}
}],
"spec": {
"version": 2,
"widgetType": "counter",
"encodings": {
"value": {"fieldName": "avg_fare", "displayName": "Avg Fare"}
},
"frame": {"title": "Average Fare", "showTitle": true}
}
},
"position": {"x": 2, "y": 2, "width": 2, "height": 3}
},
{
"widget": {
"name": "avg-distance",
"queries": [{
"name": "main_query",
"query": {
"datasetName": "summary",
"fields": [{"name": "avg_distance", "expression": "`avg_distance`"}],
"disaggregated": true
}
}],
"spec": {
"version": 2,
"widgetType": "counter",
"encodings": {
"value": {"fieldName": "avg_distance", "displayName": "Avg Distance"}
},
"frame": {"title": "Average Distance", "showTitle": true}
}
},
"position": {"x": 4, "y": 2, "width": 2, "height": 3}
},
{
"widget": {
"name": "trips-by-zip",
"queries": [{
"name": "main_query",
"query": {
"datasetName": "by_zip",
"fields": [
{"name": "pickup_zip", "expression": "`pickup_zip`"},
{"name": "trip_count", "expression": "`trip_count`"}
],
"disaggregated": true
}
}],
"spec": {
"version": 3,
"widgetType": "bar",
"encodings": {
"x": {"fieldName": "pickup_zip", "scale": {"type": "categorical"}, "displayName": "ZIP"},
"y": {"fieldName": "trip_count", "scale": {"type": "quantitative"}, "displayName": "Trips"}
},
"frame": {"title": "Trips by Pickup ZIP", "showTitle": true}
}
},
"position": {"x": 0, "y": 5, "width": 6, "height": 5}
},
{
"widget": {
"name": "zip-table",
"queries": [{
"name": "main_query",
"query": {
"datasetName": "by_zip",
"fields": [
{"name": "pickup_zip", "expression": "`pickup_zip`"},
{"name": "trip_count", "expression": "`trip_count`"}
],
"disaggregated": true
}
}],
"spec": {
"version": 2,
"widgetType": "table",
"encodings": {
"columns": [
{"fieldName": "pickup_zip", "displayName": "ZIP Code"},
{"fieldName": "trip_count", "displayName": "Trip Count"}
]
},
"frame": {"title": "Top ZIP Codes", "showTitle": true}
}
},
"position": {"x": 0, "y": 10, "width": 6, "height": 5}
}
]
}]
}

Key decisions:

  • One dataset per domainsummary for aggregate KPIs, by_zip for dimensional breakdown. Datasets own their SQL; widgets just reference columns.
  • disaggregated: true for pre-aggregated data — the summary dataset returns one row, so counters use disaggregated: true and reference the column directly. No widget-level aggregation needed.
  • LIMIT 10 in the dataset SQL — the bar chart and table both reference by_zip. Capping at 10 keeps the chart readable and avoids rendering thousands of bars.
  • Layout fills width 6 at every row — three KPIs at width 2 (2+2+2=6), chart and table at full width 6. No gaps allowed in the grid.

Deploy this template:

manage_dashboard(
action="create_or_update",
display_name="NYC Taxi Dashboard",
parent_path="/Workspace/Users/me/dashboards",
serialized_dashboard='<the JSON above>',
warehouse_id="<your_warehouse_id>"
)

“Build a sales dashboard with revenue, orders, and margin KPIs, a revenue trend area chart, breakdowns by department and region, a product table, and global filters for date, region, and department.”

The full sales analytics template includes global filters that cross-cut all datasets:

{
"datasets": [
{
"name": "ds_daily_sales",
"displayName": "Daily Sales",
"queryLines": [
"SELECT sale_date, region, department, total_orders, ",
"total_units, total_revenue, total_cost, profit_margin ",
"FROM catalog.schema.gold_daily_sales ",
"ORDER BY sale_date"
]
},
{
"name": "ds_products",
"displayName": "Product Performance",
"queryLines": [
"SELECT product_name, department, region, ",
"units_sold, revenue, cost, profit ",
"FROM catalog.schema.gold_product_performance"
]
}
],
"pages": [
{
"name": "sales_overview",
"displayName": "Sales Overview",
"pageType": "PAGE_TYPE_CANVAS",
"layout": []
},
{
"name": "global_filters",
"displayName": "Filters",
"pageType": "PAGE_TYPE_GLOBAL_FILTERS",
"layout": [
{
"widget": {
"name": "filter_date_range",
"queries": [{
"name": "ds_sales_date",
"query": {
"datasetName": "ds_daily_sales",
"fields": [{"name": "sale_date", "expression": "`sale_date`"}],
"disaggregated": false
}
}],
"spec": {
"version": 2,
"widgetType": "filter-date-range-picker",
"encodings": {
"fields": [{"fieldName": "sale_date", "displayName": "Date", "queryName": "ds_sales_date"}]
},
"frame": {"showTitle": true, "title": "Date Range"}
}
},
"position": {"x": 0, "y": 0, "width": 2, "height": 2}
},
{
"widget": {
"name": "filter_region",
"queries": [
{"name": "ds_sales_region", "query": {"datasetName": "ds_daily_sales", "fields": [{"name": "region", "expression": "`region`"}], "disaggregated": false}},
{"name": "ds_products_region", "query": {"datasetName": "ds_products", "fields": [{"name": "region", "expression": "`region`"}], "disaggregated": false}}
],
"spec": {
"version": 2,
"widgetType": "filter-multi-select",
"encodings": {
"fields": [
{"fieldName": "region", "displayName": "Region", "queryName": "ds_sales_region"},
{"fieldName": "region", "displayName": "Region", "queryName": "ds_products_region"}
]
},
"frame": {"showTitle": true, "title": "Region"}
}
},
"position": {"x": 2, "y": 0, "width": 2, "height": 2}
},
{
"widget": {
"name": "filter_department",
"queries": [
{"name": "ds_sales_dept", "query": {"datasetName": "ds_daily_sales", "fields": [{"name": "department", "expression": "`department`"}], "disaggregated": false}},
{"name": "ds_products_dept", "query": {"datasetName": "ds_products", "fields": [{"name": "department", "expression": "`department`"}], "disaggregated": false}}
],
"spec": {
"version": 2,
"widgetType": "filter-multi-select",
"encodings": {
"fields": [
{"fieldName": "department", "displayName": "Department", "queryName": "ds_sales_dept"},
{"fieldName": "department", "displayName": "Department", "queryName": "ds_products_dept"}
]
},
"frame": {"showTitle": true, "title": "Department"}
}
},
"position": {"x": 4, "y": 0, "width": 2, "height": 2}
}
]
}
]
}

The layout array on the canvas page holds KPIs, charts, and tables (shown in full in the JSON Reference page). The filter page binds region and department across both datasets. A filter only applies to datasets that include the filter column — if you add a dataset without a region column, the region filter ignores it automatically.

“Deploy the dashboard, then publish it so the team can view it.”

# Create or update
result = manage_dashboard(
action="create_or_update",
display_name="Sales Analytics",
parent_path="/Workspace/Users/me/dashboards",
serialized_dashboard=dashboard_json,
warehouse_id=warehouse_id,
publish=True
)
# Later: get current state
manage_dashboard(action="get", dashboard_id=result["dashboard_id"])
# Unpublish for maintenance
manage_dashboard(action="unpublish", dashboard_id=result["dashboard_id"])
# Republish after updates
manage_dashboard(action="publish", dashboard_id=result["dashboard_id"], warehouse_id=warehouse_id)

Use publish=True on create_or_update to publish immediately. For updates to a published dashboard, call create_or_update again with the same display_name and parent_path — it overwrites the existing dashboard. Use action="list" to find dashboard IDs across your workspace.

  • Skipping query validation — always test every dataset SQL via execute_sql before building the JSON. Untested queries cause “Invalid widget definition” errors at render time, not at deploy time. The dashboard deploys successfully but shows broken widgets.
  • queryLines must be an array — not a single string. "queryLines": "SELECT ..." causes a parse failure. Use ["SELECT ... ", "FROM ... "] with each line as an array element.
  • Grid gaps — every row must sum to width 6. Three KPIs at width 2 (6 total) is correct. Two KPIs at width 2 (4 total) leaves a gap and breaks the layout.
  • Percent values in data — counter widgets with number-percent format expect values between 0 and 1, not 0 and 100. A profit margin of 0.45 displays as 45%. A value of 45 displays as 4,500%.