:::note Generated reference Generated from honeyframeapi 0.1.8 — do not edit by hand. :::
honeyframeapi.dashboard
Dashboard + card handles — build dashboards from code.
The ergonomic replacement for a hand-rolled requests upload script:
dash = project.create_dashboard("Spending & Cost Saving")
dash.add_card("Total Spending", "kpi",
"SELECT SUM(net_value) AS total FROM marts.fact_purchase_order_item",
card_config={"color_theme": "ocean"}, size_x=6, size_y=2)
dash.add_card("Monthly Spend", "stacked_bar", SQL,
card_config={"xField": "year_month", "yField": "total"})
results = dash.execute_all() # {card_id: {columns, rows, ...}}
card_type ∈ table|bar|line|pie|kpi|donut|area|stacked_bar|horizontal_bar|
combo|pivot|text|section_divider. config (a.k.a. card_config) is
chart-specific: bar/horizontal_bar → {xField, yField}, pie/donut →
{nameField, valueField}, kpi → {color_theme}. Card SQL may use
Looker-style {{param}} tokens that execute_all(parameters=...) binds.
class Card
Card(dashboard: Dashboard, data: dict)
A single card on a dashboard.
Card.card_id
property
card_id: int
Card.title
property
title: str
Card.card_type
property
card_type: str
Card.execute()
execute(params: Optional[dict] = None) -> dict
Run just this card; returns {columns, rows, row_count, …}.
Card.update()
update(**fields) -> dict
Patch card fields (title, sql_query, card_config, grid_, size_, …).
Card.delete()
delete() -> None
Card.unlink_template()
unlink_template() -> dict
Detach this card from its CardTemplate — future template edits
no longer fan out to it. Idempotent. Returns {card_id, template_id: None, message}.
class Dashboard
Dashboard.reload()
reload() -> Dashboard
Fetch the dashboard detail (incl. cards) and cache it.
Dashboard.title
property
title: str
Dashboard.cards
property
cards: list[Card]
The dashboard's cards (call reload first if stale).
Dashboard.update()
update(**fields) -> dict
Patch dashboard fields (title, description, is_public, config, …).
Dashboard.add_card()
add_card(title: str, card_type: str, sql: str = '', *, config: Optional[dict] = None, card_config: Optional[dict] = None, description: Optional[str] = None, grid_col: int = 0, grid_row: int = -1, size_x: int = 12, size_y: int = 4, page_number: int = 1) -> Card
Add a card and return its handle.
card_config is the chart-specific settings dict. config is a
deprecated alias for it (still honoured, with a
DeprecationWarning). grid_row=-1 lets the server
auto-place the card.
Dashboard.add_cards()
add_cards(cards: list[dict]) -> list[Card]
Bulk-add cards from a list of dicts (each = add_card kwargs).
Accepts the plain card-dict shape (title, card_type, sql_query, …)
({"title", "card_type", "sql_query", "card_config", "grid_col", …})
so existing definitions port over unchanged.
Dashboard.execute_all()
execute_all(*, parameters: Optional[dict] = None, filters: Optional[list] = None, timeout: Optional[float] = None) -> dict
Run every card; returns {results: {card_id: {...}}, …}.
timeout (seconds) overrides the client's default for this call —
a large dashboard can take longer than one card.
Dashboard.execute_batch()
execute_batch(card_ids: list[int], *, params: Optional[dict] = None, asset_id: Optional[int] = None) -> dict
Run a named SUBSET of this dashboard's cards in ONE round-trip.
POST /{id}/cards/execute-batch. Each card runs exactly the way
Card.execute would — same gate, same :name bind merge, same
masking — so this is the batched form of the single-card path, NOT of
execute_all (which takes {{param}}/filters instead).
params is one dict applied to every card; a card that doesn't
reference a key just ignores it.
Returns {card_id: {card_id, columns, rows, row_count, execution_ms, error, bound_params}}. The keys arrive as JSON object keys, i.e.
strings — index with res[str(cid)]. A failing card reports
in-band via its own error and never sinks the batch.
card_ids is the scope: pass the cards of the one page you are
rendering. An unscoped batch would run every card on the dashboard, and
a dashboard behind a multi-page webapp can carry hundreds. asset_id
serves the pinned version of a published asset (the same snapshot the
app serves); a cross-org or unknown id degrades server-side to a live,
unpinned run rather than erroring.
page = [c.card_id for c in dash.cards[:5]]
res = dash.execute_batch(page, params={"start": "2026-01-01"})
print(res[str(page[0])]["row_count"])
Dashboard.public_links()
public_links() -> list[dict]
List this dashboard's public share links (metadata only — never the token). Ephemeral server-side-PDF render tokens are hidden.
Dashboard.create_public_link()
create_public_link(*, label: Optional[str] = None, expires_days: Optional[int] = PUBLIC_LINK_DEFAULT_DAYS) -> dict
Mint a token-gated public share link. The raw token and a relative
share_url are in the returned dict and are shown once — store
them.
The link expires after expires_days (default 30; 1..365 allowed).
expires_days=0 makes a link that never expires — opt in only when
you mean it. Any other value raises ValueError (the server would
silently make it never-expiring). None still means never but is
deprecated in favour of 0.
Dashboard.revoke_public_link()
revoke_public_link(link_id: int) -> None
Revoke a share link (idempotent; 404 if it belongs to another dashboard).
Dashboard.move_to_collection()
move_to_collection(collection_id: Optional[int]) -> dict
Move this dashboard into a collection (collection_id), or pass
None/0 to uncategorize it.
Dashboard.shares()
shares() -> list[dict]
This dashboard's share grants (owner-only).
Dashboard.add_share()
add_share(*, user_id: Optional[int] = None, role: Optional[str] = None, access_level: str = 'view') -> dict
Grant access to a user OR a role (exactly one). access_level ∈
view | edit. Upserts by target. Returns {share_id}.
Dashboard.update_share()
update_share(share_id: int, access_level: str) -> dict
Change a share's access_level (view | edit).
Dashboard.remove_share()
remove_share(share_id: int) -> dict
Dashboard.revisions()
revisions() -> list[dict]
Revision history, newest first ({revision_number, author_user_id, change_note, created_at, author_name} — no snapshot payload).
Dashboard.create_revision()
create_revision(change_note: Optional[str] = None) -> dict
Force a named snapshot now (bypasses the autosave rate limit).
Returns {revision_number}.
Dashboard.get_revision()
get_revision(revision_number: int) -> dict
One revision incl. its snapshot (the full card/page layout).
Dashboard.diff_revisions()
diff_revisions(a: int, b: int) -> dict
Diff two revisions — {a, b, cards: {added, removed, changed, …}, dashboard: {fields}}.
Dashboard.restore_revision()
restore_revision(revision_number: int) -> dict
Restore the dashboard to a revision (auto-snapshots current state
first, so it's reversible). Returns {ok, restored_revision}.
Dashboard.undo()
undo() -> dict
Undo the last change (restore the most recent prior revision). 409 if
there's nothing to undo. Returns {ok, restored_revision, undone_change_note}.
Dashboard.undo_card()
undo_card(card_id: int, *, revision_number: Optional[int] = None) -> dict
Undo the last change to ONE card (restore/delete/revert it from the
most recent Before: snapshot, or an explicit revision_number).
Returns {ok, card_id, action, restored_from_revision, new_revision}.
Dashboard.export_pdf()
export_pdf(path, *, paper_size: str = 'A4', orientation: str = 'portrait', current_page_only: bool = False, page_number: Optional[int] = None, file_type: str = 'pdf', width: Optional[int] = None, height: Optional[int] = None, scale: Optional[float] = None, timeout: Optional[float] = None) -> str
Render this dashboard via the server's headless Chromium and write it
to local path (returns the path).
paper_size ∈ a4|a3|letter|screen_16_9, orientation ∈
portrait|landscape (case-insensitive). current_page_only + optional
page_number export a single dashboard page.
file_type ∈ pdf|png, width/height are render-window pixels
(320–4096; either one alone keeps the paper's other axis) and scale
is the device-pixel-ratio (0.5–3.0, raster only) — the same options as
the UI's export dialog. All four default to the pre-existing A4 PDF behavior, so an
unchanged call sends an unchanged request body.
Raises HoneyframeError when the platform host has no headless
Chromium (the server returns 503) — fall back to the browser's in-page
export there.
Dashboard.delete()
delete() -> None
Dashboard.url
property
url: str
The browser URL for this dashboard.
class CardTemplate
An org-level reusable card template (the Card Library).
Create one from a proven card, then stamp it onto dashboards — either
one-shot (insert_into) or as a live link (link_into) whose
cards track future template edits. Reach it via the client:
tpl = client.create_card_template("Margin KPI", "kpi",
sql="SELECT margin_pct FROM marts.fact_margin")
tpl.link_into(dashboard_id=10) # edits to tpl fan out to this card
client.list_card_templates()
CardTemplate.name
property
name: Optional[str]
CardTemplate.update()
update(**fields) -> dict
Patch the template (name, description, card_type, sql_query,
card_config, tags, param_defaults, folder, visibility). Changes to
card_type/sql_query/card_config/description fan out to every linked
card. Returns {**template, linked_cards_updated}.
CardTemplate.delete()
delete() -> dict
CardTemplate.insert_into()
insert_into(dashboard_id: int, *, title: Optional[str] = None, grid_col: int = 0, grid_row: int = -1, page_number: int = 1) -> dict
Stamp a ONE-SHOT copy onto a dashboard (the card is NOT linked — later template edits won't touch it). Returns the new card row.
CardTemplate.link_into()
link_into(dashboard_id: int, *, title: Optional[str] = None, grid_col: int = 0, grid_row: int = -1, page_number: int = 1) -> dict
Stamp a LINKED card onto a dashboard — future update edits fan
out to it (Card.unlink_template severs the link). Returns the
new card row.
CardTemplate.preview()
preview(*, params: Optional[dict] = None) -> dict
Execute the template's SQL (masked, row-limited) with optional
params merged over its defaults. Returns {template_id, card_type, card_config, columns, rows, row_count, execution_ms, error}. Needs a
project-scoped client (its query runs under the caller's project).
CardTemplate.duplicate()
duplicate(*, name: Optional[str] = None) -> dict
Copy this template into the caller's org (owner = caller, render_count
reset). Returns {template_id, name, source_template_id, message}.
CardTemplate.versions()
versions() -> list[dict]
Edit history, newest first ({version_num, edited_by, edited_at, edit_summary, editor_email, editor_name} — no snapshot payload).
CardTemplate.get_version()
get_version(version_num: int) -> dict
One version incl. its snapshot (the template state at that point).
CardTemplate.restore_version()
restore_version(version_num: int) -> dict
Restore the template to a prior version (records a new history entry;
fans out to linked cards). Returns {template_id, restored_from_version, template, message}.
Functions
dashboard_filter()
dashboard_filter(column: str, *, operator: str = 'between', value: Optional[str] = None, start: Optional[str] = None, end: Optional[str] = None, values: Optional[list] = None, ftype: Optional[str] = None) -> dict
A global dashboard filter. operator ∈ between (needs start+end) |
eq | gte | lte (need value) | in (needs values). ftype ∈ categorical |
explicit | numeric_range | date_relative coerces the bind value's type.
filter_between()
filter_between(column: str, start: str, end: str, *, ftype: Optional[str] = None) -> dict
A range filter: start <= column <= end.
filter_compare()
filter_compare(column: str, operator: str, value: str, *, ftype: Optional[str] = None) -> dict
A scalar comparison filter (operator ∈ eq | gte | lte).
filter_in()
filter_in(column: str, values: list, *, ftype: Optional[str] = None) -> dict
A set-membership filter: column IN (values…).
Verified against honeyframeapi 0.1.8.