Lewati ke konten utama
Versi: v0.0.31

Dashboards

A dashboard is a layout of cards that visualize one or more SQL queries. Each card is a chart, table, KPI, or text block driven by a SQL statement against the project's datasets. Operators build dashboards in a drag-and-drop editor, organize them into pages and collections, apply dashboard-level filters, and share them with users or via public links.

Authoring

To create a dashboard:

  1. Open the project's Dashboards page.
  2. Click + New Dashboard, give it a name, optionally pick a Collection (folder) and a Template.
  3. The dashboard opens in design mode. The canvas is a free-form grid; the left rail is the card palette.
  4. + Add Card opens the card editor. Pick a card type, write the SQL, configure the visualization, save.
  5. Drag cards to position and resize. The layout (x, y, width, height) persists per card.
  6. Save. The dashboard is now visible to anyone with dashboard.read (legacy: viewer or higher).

Dashboards can have multiple pages (tabs). Pages are independent layouts; cards do not move between pages without an explicit duplicate.

Card types

Each card is one of:

TypeWhat it renders
tableSortable, paginated table over the SQL result.
bar, line, area, pie, donutStandard chart types over a {x, y, series?} mapping.
comboBar + line on a shared axis.
kpiSingle-metric card with optional comparison delta.
pivotPivot table — choose rows, columns, measures, aggregation.
textStatic markdown text block.
notebook_cellEmbeds the cached output of a notebook cell — the notebook must have been executed for the cell to render.
embedIframe embed — for external BI tiles or other Honeyframe surfaces.

Each card has a card_config object whose shape varies by type — column mappings, color palettes, axis labels, formatters. The card editor renders a form against the schema; programmatic creation should mirror what the form generates.

Filters

A dashboard can declare filters that flow into every card's SQL. Each filter has a column, an operator (=, !=, >, <, >=, <=, IN, BETWEEN, LIKE, IS NULL, IS NOT NULL), and a value.

The platform rewrites each card's SQL at query time to apply matching filters as WHERE clauses. A card opts out of a filter by name in its config — useful for "context" cards that should always show the full picture.

For dropdown / autocomplete filter inputs, POST /api/dashboards/{id}/filter-options returns the distinct values for the filter column from the underlying dataset.

Sharing

Dashboards are organization-private by default. To extend access, open Share:

Share typeURLAuth
PrivateSame as the platform URLPlatform login required; recipient must have dashboard.read.
Public link/public/dashboards/{share_id}None — anyone with the link views it.

Each share link is a row in dashboard_shares with a unique share_id. Revoke from the same modal — revocation is immediate; the URL returns 410 Gone afterward.

Public visibility is org-admin opt-in. There is no public path until an org admin enables public sharing for the project.

Collections

Collections are folders for organizing dashboards. They nest (parent → child → grandchild) and a dashboard belongs to exactly one collection (or none, in which case it sits at the project root).

Use collections for:

  • By audienceExecutive, Operations, Engineering.
  • By domainSales, Operations, Inventory.
  • By lifecycleProduction, Drafts, Archive.

Collections affect organization only. They do not gate access; permissions are still per-dashboard.

Permissions

Two permission strings cover the dashboard surface:

  • dashboard.read — view a dashboard and run its cards.
  • dashboard.edit — modify layout, cards, filters, sharing.

The legacy require_role("viewer") / require_role("editor") checks are honored during the migration. See Permissions Reference.

Card execution

Each card runs its SQL independently. The platform caches results in-memory per process with a TTL — repeat loads of the same card with the same filter set hit the cache. Cache size is bounded (~500 entries per process) and is not shared across replicas, so a horizontally-scaled deployment may see different cache hit rates per request depending on which replica handles it.

Two execution endpoints:

  • POST /api/dashboards/{id}/cards/{card_id}/execute — run one card with the given filters.
  • POST /api/dashboards/{id}/execute-all — run every card on the active page in parallel. Returns when all cards have finished or errored.

Masking

PII masking from the Datasets layer applies to dashboard card output. Masking is applied at the Python layer after SQL execution, before JSON serialization — sensitive columns are redacted in the response, but the underlying SELECT still reads the raw column. Operators without data.read_unmasked see only the masked value.

AI generation

Two experimental endpoints lower the cost of building a dashboard from scratch:

  • POST /api/dashboards/generate — provide a natural-language description and a target dataset; the platform proposes a dashboard with several cards. Review and save or discard.
  • POST /api/dashboards/ai-chat — chat-style refinement of an existing dashboard. "Add a bar chart showing weekly signups by region" → patches the dashboard with the new card.

These hit the configured LLM connector. They are scaffolding, not authoring — review the generated SQL before publishing.

Templates

Built-in templates are the fastest way to start. + New Dashboard → From template lists the catalog (GET /api/dashboards/templates); pick one, point it at a dataset, and the platform clones the template with the dataset's column names substituted into the cards' SQL.

Custom templates are admin-only — there is no end-user "save as template" flow today.

Publishing to a SaaS app

Dashboards can be published as part of a Honeyframe app — a customer-facing bundle that lives on the SaaS surface. Publishing assigns the dashboard a stable URL on the SaaS frontend and freezes its config so further edits don't immediately propagate.

Lifecycle:

  1. Author the dashboard on the Platform (platform.your-domain.com/dashboards).
  2. Add it to a publishable app via Publish Manager.
  3. The published version lands on the SaaS surface (app.your-domain.com/dashboards/<slug>).
  4. Subsequent edits on the Platform stay in draft; promote with Publish.

The author-on-PaaS, view-on-SaaS split keeps the design surface separate from the live audience surface.

API reference

EndpointDescription
GET /api/dashboardsList dashboards visible to the caller.
GET /api/dashboards/templatesList built-in templates.
GET /api/dashboards/{id}Full dashboard config including cards, layout, filters, pages.
POST /api/dashboardsCreate.
PATCH /api/dashboards/{id}Update title, description, collection, visibility.
DELETE /api/dashboards/{id}Delete.
POST /api/dashboards/{id}/duplicateClone the dashboard (cards + layout + filters; not shares).
POST /api/dashboards/{id}/cardsAdd a card.
PATCH /api/dashboards/{id}/cards/{card_id}Update card SQL, type, config, title.
DELETE /api/dashboards/{id}/cards/{card_id}Remove a card.
POST /api/dashboards/{id}/cards/{card_id}/executeRun one card.
POST /api/dashboards/{id}/execute-allRun all cards on the active page in parallel.
POST /api/dashboards/{id}/filter-optionsDistinct values for a filter column.
POST /api/dashboards/{id}/pagesAdd a page.
PATCH /api/dashboards/{id}/pages/{page_number}Rename a page.
DELETE /api/dashboards/{id}/pages/{page_number}Remove a page.
PATCH /api/dashboards/{id}/layoutSave card positions and sizes.
GET /api/dashboards/{id}/sharesList share links.
POST /api/dashboards/{id}/sharesCreate a public or private share link.
DELETE /api/dashboards/{id}/shares/{share_id}Revoke a share.
POST /api/dashboards/collectionsCreate a collection.
GET /api/dashboards/public/{share_id}View a public dashboard (no auth).
POST /api/dashboards/generateAI-generate from a natural-language description. Experimental.
POST /api/dashboards/ai-chatChat-style dashboard refinement. Experimental.

Performance

Heavy dashboards (10+ cards over large datasets) benefit from:

  • Materialized intermediates — replace a prepare → group_by chain in the source Flow with a single dbt-built aggregate dataset. Card queries against the aggregate are sub-second.
  • Result caching — the in-memory cache covers identical (SQL, filter) pairs. Cards that share a dataset and filter set share a cache hit.
  • Pagination on tablestable cards default to 100 rows. Lower the page size in card config for at-a-glance dashboards.
  • Parallel executionexecute-all parallelises cards on the same page; the wall-clock is bounded by the slowest card, not the sum.

Gotchas

  • Cache is per-process. Behind a load balancer, two requests for the same dashboard may take different cache paths. Don't rely on cache hit rates for SLA budgeting.
  • Filter rewriting is column-name based. A filter on created_at rewrites every card whose SQL SELECTs a created_at column. Cards that should ignore the filter must opt out by name in their config.
  • Public dashboards cannot filter by user. They have no caller identity. For row-level access control, use private shares.
  • Notebook cells render cached output. If the notebook hasn't been run, the card is empty until the next notebook execution.
  • Custom templates are admin-only. Users cannot promote their own dashboards to templates today.