Skip to main content

Dashboards

Gateway prefix: ${API_BASE}/metadata/dashboards/...

Dashboard configuration can be stored in DB (jsonb) with classpath fallback. Backend controller: DashboardController (/api/v1/dashboards).

Save/update dashboard configuration (upsert by code)

  • POST /dashboards
  • Permissions: admin / tenant:admin
  • Description: save or update (upsert) by code in the configuration. Request body field is config, whose value is the full dashboard configuration JSON string.
  • Headers:
    • Authorization: Bearer <token>
    • Content-Type: application/json
    • X-Tenant-Id: <tenantId> (optional, recommended in multi-tenant scenarios)
  • Reference config: ai-daas-metadata-service/src/main/resources/dashboards/analytics.json

Example structure (excerpt):

{
"code": "analytics",
"title": "Business Cockpit",
"grid": { "cols": 12, "rowHeight": 40, "gutter": 12 },
"widgets": [
{ "id": "kpi_revenue_30d", "type": "kpi", "title": "Revenue (last 30 days)" },
{ "id": "trend_revenue_30d", "type": "chart", "title": "Revenue (last 30 days)" }
]
}

Example call (simplified with manual escaping):

curl -X POST "${API_BASE}/metadata/dashboards" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "X-Tenant-Id: <tenantId>" \
-d '{
"config": "{ \"code\": \"analytics\", \"title\": \"Business Cockpit\", \"grid\": { \"cols\": 12 }, \"widgets\": [] }"
}'

Recommended call (use file content and let jq escape):

curl -X POST "${API_BASE}/metadata/dashboards" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "X-Tenant-Id: <tenantId>" \
--data "{\"config\": \"$(jq -Rs . < ai-daas-metadata-service/src/main/resources/dashboards/analytics.json)\"}"

Example response:

{
"success": true,
"message": "Dashboard saved",
"data": {
"id": "<id>",
"code": "analytics",
"title": "Business Cockpit",
"config": "{ ... }",
"tenantId": "<tenantId>",
"createdAt": "2024-10-01T12:00:00Z",
"updatedAt": "2024-10-01T12:00:00Z"
}
}

Note: data.config in the response is a JSON string (the server stores and returns it as a pretty-printed string).

Update by code via PUT (optional)

  • PUT /dashboards/{code}
  • Permissions: admin / tenant:admin
  • Description: upsert by path parameter code, body is DashboardDto where config is the full JSON string.

Example:

curl -X PUT "${API_BASE}/metadata/dashboards/analytics" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "X-Tenant-Id: <tenantId>" \
-d "{ \"config\": \"{
\"code\": \"analytics\",
\"title\": \"Business Cockpit\",
\"grid\": { \"cols\": 12, \"rowHeight\": 40, \"gutter\": 12 },
\"widgets\": [
{
\"id\": \"kpi_revenue_30d\",
\"type\": \"kpi\",
\"title\": \"Revenue (last 30 days)\",
\"grid\": { \"x\": 0, \"y\": 0, \"w\": 3, \"h\": 2 },
\"style\": { \"unit\": \"¥\", \"valueFormat\": \",0.00\" },
\"dataSource\": { \"type\": \"view\", \"viewId\": \"metric.revenue_30d\" }
},
{
\"id\": \"trend_revenue_30d\",
\"type\": \"chart\",
\"title\": \"Revenue (last 30 days)\",
\"grid\": { \"x\": 3, \"y\": 0, \"w\": 6, \"h\": 6 },
\"chart\": { \"kind\": \"line\", \"xField\": \"date\", \"yField\": \"amount\", \"area\": true, \"smooth\": true },
\"dataSource\": { \"type\": \"view\", \"viewId\": \"view.revenue_by_day\" }
},
{
\"id\": \"top5_customers\",
\"type\": \"chart\",
\"title\": \"Top 5 Customers by Revenue\",
\"grid\": { \"x\": 9, \"y\": 0, \"w\": 3, \"h\": 6 },
\"chart\": { \"kind\": \"bar\", \"categoryField\": \"customer\", \"valueField\": \"amount\", \"orientation\": \"horizontal\", \"limit\": 5, \"sort\": \"-value\" },
\"dataSource\": { \"type\": \"view\", \"viewId\": \"view.revenue_by_customer\" }
},
{
\"id\": \"table_orders\",
\"type\": \"table\",
\"title\": \"Orders table (example)\",
\"grid\": { \"x\": 0, \"y\": 6, \"w\": 12, \"h\": 6 },
\"table\": {
\"columns\": [
{ \"key\": \"order_id\", \"title\": \"Order\", \"width\": 100, \"align\": \"left\" },
{ \"key\": \"customer\", \"title\": \"Customer\", \"width\": 160, \"align\": \"left\" },
{ \"key\": \"date\", \"title\": \"Date\", \"width\": 120, \"align\": \"center\" },
{ \"key\": \"amount\", \"title\": \"Amount\", \"width\": 120, \"align\": \"right\" }
],
\"rowHeight\": 32,
\"autoScroll\": true,
\"scroll\": { \"step\": 1, \"interval\": 16, \"pauseMs\": 1200 }
},
\"dataSource\": { \"type\": \"view\", \"viewId\": \"view.orders_recent\" }
}
]
}\" }"

Get dashboard by code

  • GET /dashboards/by-code/{code}
  • Permissions: admin / tenant:admin / read

Headers:

  • Authorization: Bearer <token>
  • X-Tenant-Id: <tenantId> (optional)

Example:

curl -X GET "${API_BASE}/metadata/dashboards/by-code/analytics" \
-H "Authorization: Bearer <token>" \
-H "X-Tenant-Id: <tenantId>"

Example response:

{
"success": true,
"message": "Dashboard found",
"data": {
"id": "<id>",
"code": "analytics",
"title": "Business Cockpit",
"config": "{ ... }"
}
}

Remarks:

  • PUT /dashboards/{code} is also supported for save/update (same effect as POST, body is DashboardDto with JSON string config). POST is generally recommended.
  • See backend controller reference: ai-daas-metadata-service/src/main/java/com/aidaas/metadata/controller/DashboardController.java#L36-44 for reading by code, and the @PostMapping/@PutMapping in the same file for saving.
  • Full sample configuration: ai-daas-metadata-service/src/main/resources/dashboards/analytics.json

Get dashboard by ID

  • GET /dashboards/{id}
  • Permissions: admin / tenant:admin / read

Paginated list of dashboards

  • GET /dashboards?page=1&pageSize=20
  • Permissions: admin / tenant:admin / read
  • Returns: ApiResponse<PageResponse<DashboardDto>>

Configuration structure (based on analytics.json)

  • code: unique dashboard identifier (required)
  • title: display title
  • grid: layout configuration (cols number of columns, rowHeight row height, gutter spacing)
  • widgets: widget list, each item:
    • id: widget ID
    • type: kpi | chart | table
    • title: widget title
    • grid: widget’s position and size (x, y, w, h)
    • style/chart/table: display/chart/table configuration by type
    • dataSource: data source (for example { "type": "view", "viewId": "view.revenue_by_day" })