Skip to main content

dashboard-management

Create, lay out, organize, or share Analytics dashboards and panels: sources, placement, folders, verification, chart markers. Use to create a dashboard, to move, reorder, or lay out panels, or to add a key date or data note; a small edit of one existing panel needs no skill.

ソース情報

リポジトリ
BuilderIO/agent-native
ソースの最終更新活動
2026年10月19日 14:10
検出された SKILL.md の言語
英語
スター
7,449
フォーク
681

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
dashboard-management
description
Create, lay out, organize, or share Analytics dashboards and panels: sources, placement, folders, verification, chart markers. Use to create a dashboard, to move, reorder, or lay out panels, or to add a key date or data note; a small edit of one existing panel needs no skill.
# Dashboard Management Dashboards are the canonical SQL-backed Analytics resources. New dashboards, saved analyses, reports, and bespoke extensions are represented as dashboard artifacts—not as separate user-facing Analytics objects. Legacy analysis tables and actions remain available only for compatibility. ## Storage Current storage: | Table | Purpose | | ------------------------- | -------------------------------------------- | | `dashboards` | Explorer and SQL dashboard records | | `dashboard_folders` | Personal and shared SQL dashboard folders | | `dashboard_views` | Saved filter presets per dashboard | | `dashboard_shares` | Standard framework share grants | | `dashboard_folder_shares` | Standard folder share grants | | `dashboard_revisions` | Bounded dashboard history snapshots | | `analyses` | Saved ad-hoc analysis records | | `analysis_revisions` | Bounded analysis history snapshots | | `analysis_shares` | Standard framework share grants for analyses | Legacy settings keys such as `u:<email>:dashboard-*`, `u:<email>:sql-dashboard-*`, `o:<orgId>:sql-dashboard-*`, and `adhoc-analysis-*` are still read as a fallback and copied into SQL on access. Do not create new dashboard settings rows. ## Dashboard folders Dashboard folders are SQL-backed, access-scoped containers for organizing SQL dashboards from `/dashboards`: - `personal` folders are private to their owner. - `shared` folders are organization-visible and require an active organization. - Use `list-dashboard-folders`, `create-dashboard-folder`, and `set-dashboard-folder` for folder reads and membership changes. - A folder never expands dashboard access. A personal folder can contain only an owned private dashboard; a shared folder can contain only an org-visible dashboard. Use the normal dashboard sharing actions separately. For organization-wide consolidation, use `migrate-analytics-artifacts` first with `dryRun: true`. The write requires an organization owner/admin and the exact confirmation token `MIGRATE_ANALYTICS_ARTIFACTS`. It materializes organization-scoped legacy settings, creates dashboard blocks for saved analyses and standalone extensions, archives exact duplicates, copies shares, and removes legacy settings keys only after SQL rows are materialized. Source rows remain recoverable. Private member-only rows are intentionally outside this organization-scoped operation. Use `mutate-dashboard` for existing dashboard edits. It resolves the current user/org context, validates the resulting config, writes the SQL-backed record, syncs collab, and returns a compact result with a `verified` flag. Use `update-dashboard` for new full-config saves, UI full-config saves, or explicitly requested low-level JSON-pointer edits. Every meaningful dashboard save snapshots the previous state into `dashboard_revisions`. Use `list-dashboard-revisions` to inspect available undo points and `restore-dashboard-revision` to restore one; restore snapshots the current state first, then syncs open dashboard editors. Each revision's `changes` names what the save that left it behind changed (`panel-added`, `column-resized`, `filter-changed`, `version-restored`, and so on), so restoring it undoes that change and every later one. To answer "undo the column I widened", pick the revision whose `changes` match instead of guessing from times. `changesStatus` is `absent` for revisions saved before changes were recorded and `unreadable` when the stored list is corrupt; say you can't tell what those changed rather than treating them as empty. On the page, an editor's own saves show a toast that names the change its Undo takes back, says "Saved for everyone" (org or public visibility; "Saved" when private), and counts the others who have the dashboard open. That Undo restores the revision its save left (a full-config `update-dashboard` save returns it as `revisionId`), but only while the dashboard is as that save left it: once someone else has saved, it fails rather than taking their change back. For "undo my last change" in chat, restore the newest revision from `list-dashboard-revisions`. The History panel shows each revision's first change with "+N more". Saved analyses follow the same undo model with `analysis_revisions`, `list-analysis-revisions`, and `restore-analysis-revision`. Dashboards open in View mode. An editor switches the header toggle to Edit before drags, panel resizing, renames, column edits, and adding, editing, showing or hiding key dates and data notes on the page save for everyone; the chat context reports the current mode. A table column width dragged in View mode is stored only in that person's browser, so "widen this column for me" is a drag in View mode, not a dashboard change. `config.columns[].width` is the shared width everyone sees; set it only when asked to change the dashboard itself. Never use `db-patch`, raw SQL, or settings-key edits to create or modify a dashboard config. Those bypass the dashboard action's access checks, SQL validation, collab sync, and verification. If a dashboard action fails because the argument shape was wrong, fix that action's arguments and retry once — do not switch to db-patch or raw SQL. ### GitHub folder sync A linked folder mirrors its SQL dashboards to `<path>/<dashboardId>.json` in a GitHub repo. Read `docs/dashboard-github-folder-sync.md` before changing or explaining it. - Run `preview-dashboard-folder-github-sync` before any sync. It writes nothing. - `apply-dashboard-folder-github-sync` pulls from GitHub. It writes only the panels, order, and settings that changed on the GitHub side. - `export-dashboard-folder-to-github` opens one PR with the app's changes. It refuses while an earlier export PR is still open. - `configure-dashboard-folder-github-sync` links or unlinks a folder. It stores no credentials. - A unit changed on both sides is a conflict. It is reported and not applied. Do not resolve it by overwriting either side without asking the user. - Explorer dashboards, sharing, and deletions never sync. A synced dashboard cannot be permanently deleted; archive it or unlink its folder first. ## Valid Panel Sources `panel.source` is a backend selector, not a table name. It must be one of: | Source | Query shape | | ------------- | -------------------------------------------------------------------------------------------------------- | | `bigquery` | Literal warehouse SQL. Table names belong inside the SQL string. | | `ga4` | JSON descriptor for the Google Analytics Data API. | | `amplitude` | JSON descriptor for an Amplitude query. | | `first-party` | Read-only SQL over this template's `analytics_events` table, usually via `query-agent-native-analytics`. | Do not use `app-db` as a dashboard source. For first-party events collected through `/track`, use `source: "first-party"` or the `query-agent-native-analytics` action rather than raw internal `db-query`. There is no dbt Semantic Layer panel source. For a Semantic Layer metric, answer in chat with `query-dbt-semantic-metric`; build a warehouse panel only on a table the owner names. AI-generated first-party panels are dashboard-time-bound by default. Set `config.timeScope` to `"dashboard"` and include the matching dashboard time filter in the SQL. The allowed values are: - `dashboard`: use the dashboard-selected time range; the default for ordinary metrics. - `fixed-window`: use an explicit bounded window independent of the dashboard filter. - `cohort-history`: use the bounded history of an explicitly defined cohort. - `all-time`: scan all available history; use only when the user requests it and put `all-time`, `lifetime`, or `historical` in the title or description. `{{timeRange}}` requires an explicit matching `filters` entry with `id: "timeRange"` and `type: "select"`. `{{<id>Start}}` and `{{<id>End}}` require a matching `filters` entry with that id and `type: "date-range"`. Do not rely on undeclared time variables. Server validation rejects unbound first-party SQL, so declare the filter or choose an explicit non-dashboard scope before saving. **A bound anywhere in the SQL is not the same as every CTE having its own bound.** If a panel has multiple top-level CTEs (`WITH a AS (...), b AS (...)`) and more than one of them reads `analytics_events`, EVERY one of those CTEs needs its own `{{timeRange}}`/`{{<id>Start}}`/`{{<id>End}}` reference or literal date bound — not just the final `SELECT` or one sibling CTE. A CTE that computes something like "this user's first-ever active day" by scanning `analytics_events` with no bound at all will full-table-scan on every render even though the panel _looks_ time-bound overall (root cause of a 2026-07-25 production incident: several dashboards had exactly this shape). Server validation checks each top-level CTE independently now, so this fails at save time — but write it right the first time: bound every CTE, or use `config.timeScope: "cohort-history"` only for a CTE that is genuinely defining a cohort (e.g. a first-seen date), never as a way to skip bounding an ordinary activity scan. ## Creating A Dashboard When the user asks for a dashboard: 1. Start from the preloaded `<resource scope="analytics-catalog">` references (catalog-first), else one `find-data`. If a relevant entry exists, use its `table`, `columns`, `queryTemplate`, and gotchas verbatim. 2. If a metric definition, date range, or grain is ambiguous and the choice would change the panel's numbers, use the `ask-question` clarifying tool once before building. Skip it when the dictionary or the user already settled it. 3. If a metric is not documented, do not guess column names and do not ask the user for them. Find the table and columns with `search-bigquery-schema` (or the provider's own schema action), then propose a dictionary entry with `save-data-dictionary-entry`. 4. Build a complete `SqlDashboardConfig` with `name` and `panels`. Optionally set top-level `columns` (1–6, default 2) to control how many grid columns the panels before any section use. 5. Every panel needs `id`, `title`, `source`, `chartType`, `width`, and `sql`. `width` is the number of grid columns the panel spans (1..6, clamped to the active section's column count). `height` is optional; when set, it is 1–6 units of 180px, and when omitted the panel sizes to its content. Section panels skip `source` and `sql` and may set their own `columns` (1–6) to override the dashboard default for the panels following the section. Extension panels (`chartType: "extension"`) also skip `source` and `sql`; use `config.extensionId` for ordinary author-selected shared embeds. Use `config.extensionSlotId` only when the user explicitly asks for a personal/per-viewer slot (see "Embedding An Extension As A Panel"). 6. Persist with `update-dashboard` (load it with `tool-search` — it is not on the initial tool surface), not raw SQL or settings writes. For a large first-party dashboard, load `compose-dashboard` the same way in one `tool-search` call. 7. Navigate to it with `pnpm action navigate --view=adhoc --dashboardId=<id>`. An explicit dashboard request authorizes the complete non-destructive build in the same turn. After querying or scaffolding, continue through extension-data seeding/refresh, dashboard save/embed, and navigation; do not ask whether to proceed or leave an empty Custom Block shell. Ask only when metric scope/grain is materially ambiguous, the change is destructive, or it has an external side effect such as sending email or outreach. Layout is always **1 column when the available content width is below the `md` threshold** (panels stack), then expands to the configured column count at/above it. The grid uses a container query, so it also stacks when the agent sidebar narrows the content pane — not only at narrow viewports. So picking 3 or 4 columns is fine — the renderer keeps narrow layouts readable automatically. In Edit mode, drag a panel's right edge to change its grid width and its bottom edge to set a fixed height. Width is saved as grid columns; height is saved in 180px units. Existing panels without `height` keep content-based height until resized. ```bash pnpm action update-dashboard --dashboardId weekly-metrics --config '<full json>' pnpm action navigate --view=adhoc --dashboardId=weekly-metrics ``` The save path dry-runs BigQuery panels before persisting. If validation returns a provider error, fix the query and retry. Never work around validation by writing directly to a table. ### Replicating Or Adapting Another Dashboard When the user asks to replicate, clone, or adapt an existing dashboard into a new one, call `search-dashboard-references` with focused terms first. It searches accessible active saved dashboards (ids, names, descriptions, serialized config), including legacy ones. Inspect each result with `get-sql-dashboard` when `kind` is `sql`, or `get-explorer-dashboard` when it is `explorer`. A result is a reference, not proof its source is authoritative for the new request: check the provider and scope the user asked for before copying its source semantics, and do not route a replication request to first-party Analytics by default. This applies to a new dashboard, not to editing the dashboard that is already open. ## Dual-Axis Charts `line`, `area`, and `bar` panels can plot series against two y-axes. Reach for this whenever series share an x-axis but not a unit — a count next to a rate, or revenue next to a conversion percent. On a single axis the smaller series flattens into the baseline and reads as "no data." ```json { "id": "signups-vs-conversion", "title": "Signups vs conversion rate", "source": "first-party", "chartType": "line", "width": 1, "sql": "SELECT day, signups, conversion_rate FROM ...", "config": { "timeScope": "dashboard", "xKey": "day", "yKeys": ["signups", "conversion_rate"], "yFormatter": "number", "rightYKeys": ["conversion_rate"], "rightYFormatter": "percent" } } ``` - `rightYKeys` names series from `yKeys`; everything unnamed stays on the left. - `rightYFormatter` defaults to `yFormatter` when omitted. - Each axis is labelled with its series names (up to two per side), and tooltip values use the formatter of the axis the series belongs to. - At least one series must remain on the left. If `rightYKeys` names every series, or names a column the query never returned, the panel falls back to a single axis and shows a config warning rather than dropping the series. - Scheduled email reports render the same two scales, so a dual-axis panel is safe to put on a subscribed dashboard. ## Key-Date Event Markers Key dates mark a launch, release, or product change on `line`, `area`, `bar`, and `combo` charts with a date x-axis. Do not add a fake series or an extension for this. They live in two places: - **Key-date sets** hold moments that matter across charts, such as Launches or Product changes. A set belongs to the organization (to the user when there is no organization) and draws on every time chart of every dashboard. Read sets with `list-key-dates`, passing `dashboardId` for the ones a dashboard draws; add or edit a date with `save-key-date` (name the set with `setName` and it is created if missing); rename or create a set with `save-key-date-set`; remove with `delete-key-date` or `delete-key-date-set`. Prefer a set to copying one date into many panels. - **Panel events** in `config.events` hold a date that matters to one chart only, in the same shape: ```json "config": { "events": [ { "date": "2026-10-14", "time": "00:01", "timeZone": "America/Los_Angeles", "label": "Product Hunt live" }, { "date": "2026-10-14", "time": "12:00", "timeZone": "America/New_York", "label": "Launch posts on X, LinkedIn" } ] } ``` A dashboard leaves sets off its charts with `config.annotations`, set through `mutate-dashboard`'s `setDashboard({ annotations: { hiddenKeyDateSets: [setId, ...] } })`. The list replaces the sets already hidden, so include those that stay hidden; the hidden data notes are kept. In Edit mode, people do the same from the dashboard header's Annotations menu, which also adds and edits key dates and sets. - Each event is `{ date: "YYYY-MM-DD", label, time?: "HH:MM", timeZone?, color? }`; `color` accepts SVG-safe hex values: `#RGB`, `#RGBA`, `#RRGGBB`, or `#RRGGBBAA`. Numeric x-axis timestamps use Unix epoch milliseconds. multiple are allowed. `date` is the calendar date in the event's own zone. Give `time` when the moment matters (a launch hour); `timeZone` is an IANA zone and needs a `time`. Without a zone, the time is UTC. - A badge sits on the x-axis at the date with a faint dashed guide line. Hovering the badge lists every event on that day with its time, shown in the event's own zone ("12:01 AM PT"). It adds no legend entry and does not change the series tooltip. - Events on the same day share one badge; on an hourly axis each timed event sits in its own hour, and an event without a time sits on the first hour shown for its date. - On a daily or coarser axis, a date missing from the data snaps to the nearest x value. On an hourly axis, an event without a time whose date has no hours shown is hidden. A date outside the visible range is hidden; a non-date x-axis shows nothing. - A set's date that a panel also lists in `config.events` draws once. - `mutate-dashboard` rejects malformed events and other chart types. - Scheduled email reports draw key dates and panel events: the guide line, badge, and label text, including on combo charts. Labels sit in rows above the plot: same-day labels join, a long one wraps at words, and days that find no room are counted, not cut. - A dashboard and its report emails draw the key dates of its owner's organization, minus the sets it hides, even for a viewer or reviewer in another organization. There `list-key-dates` returns `editable: false`, without member emails or, unless you can edit the dashboard, the hidden sets, and no sets at all when no chart there draws key dates: a date you save lands in your own organization's sets, not on that dashboard. For a Human Review preview, pass `list-key-dates` and `list-data-notes` the `dashboardId` and the same `reviewPreview` and `reviewOrgId` as `get-sql-dashboard`. ## Data Notes A data note says the numbers on a chart are wrong or unusual for a stretch of time: an incident (`kind: "incident"`) or a tracking problem (`kind: "data"`). Use one instead of a key date whenever the point is "don't trust this range". Notes belong to the organization, like key-date sets, and a dashboard draws its owner organization's. Read them with `list-data-notes`, passing `dashboardId` for the ones a dashboard draws; add or change one with `save-data-note` (pass `id` to change only the fields given); remove with `delete-data-note`. - `matchEvents` lists the event names the problem affects. A note shows on every chart whose SQL filters on one of them: either side of `=` (in `WHERE` or
GitHubで見る
この SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る