本文へ移動
cccskills
無料GitHub で公開

analytics-dashboard-json

Use this skill when editing CRM Analytics dashboard JSON directly to implement advanced bindings, custom SAQL/SOQL step queries, layout changes, step parameters, or cross-widget interactions. Trigger keywords: dashboard JSON, SAQL step, binding syntax, mustache binding, dashboard REST API, widget layout, step limit, datasetId, datasetVersionId. NOT for building the dashboard in the builder UI or picking chart types — use admin/analytics-dashboard-design. NOT for writing or tuning the SAQL itself — use admin/saql-query-development.

インストール方法を見る

含まれるファイル(7)

  • SKILL.md13.6 KB
  • references/examples.md5.8 KB
  • references/gotchas.md5.7 KB
  • references/llm-anti-patterns.md6.6 KB
  • references/well-architected.md4.5 KB
  • scripts/check_analytics_dashboard_json.py9.5 KB
  • templates/analytics-dashboard-json-template.md4.5 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

CRM Analytics Dashboard JSON

This skill activates when a practitioner needs to edit a CRM Analytics dashboard's JSON body directly — covering SAQL/SOQL step construction, binding syntax, layout manipulation, step parameters, and the REST API workflow for GET/PUT operations. It does not cover the standard dashboard builder UI or dataset design.


Before Starting

Gather this context before working on anything in this domain:

  • Retrieve the current dashboard JSON via GET /services/data/vXX.X/wave/dashboards/{dashboardId} and inspect the state, steps, and widgets top-level keys before making any edits.
  • Identify dataset references: practitioners commonly assume dataset name is sufficient — it is not. You need datasetId and datasetVersionId from GET /services/data/vXX.X/wave/datasets to construct portable SAQL steps.
  • Know the row limit in play: SAQL steps default to 2,000 rows. If a downstream binding or widget depends on a full population, the default will silently truncate results without any error.

Core Concepts

Dashboard JSON Structure

Every CRM Analytics dashboard body is a JSON document with three top-level sections:

steps — A map of named query definitions. Each step runs a SAQL or SOQL query against a dataset and holds its results in memory for widget binding. Steps declare their query (SAQL string or SOQL string), type (saql or soql), datasets array, and optional limit property. The limit defaults to 2,000 rows and can be raised to a maximum of 10,000 per step.

widgets — A map of named visual components. Each widget specifies its type (chart, table, filter, text, etc.), its pixel-based layout (top, left, width, height in pixels), and its parameters object which maps widget inputs (e.g., measures, dimensions, filters) to step results via binding expressions.

state — A map of global selections, active filters, and interaction state. State carries the current user selection from one widget so that other widgets can read it via bindings. State is modified at runtime by user interaction and can be pre-seeded with default values.

Binding Syntax

Bindings are mustache-delimited expressions embedded in widget parameters values. They read from either step results or selection state at render time.

The canonical cell-level binding form is:

{{cell(stepName.selection, 0, "fieldName")}}
  • stepName — the key in the steps map
  • .selection — reads the user's current selection in that step
  • 0 — the row index (zero-based)
  • "fieldName" — the field to extract

An empty binding (when the referenced cell has no value, such as when no selection has been made) returns an empty string, not an error or null. This causes silent suppression: a filter widget whose bound value is empty will produce no filter clause, which may return unintended full-population results rather than an empty result set.

Array bindings for multi-select filters use:

{{#arrayToObject}}...{{/arrayToObject}}

or the columnMap binding form for mapping multiple fields simultaneously.

Dataset References in SAQL Steps

SAQL steps reference datasets inside the datasets array of the step definition. The name field in the datasets array is the display alias used in the SAQL query body. The id and label fields, however, must use the datasetId and datasetVersionId obtained from the dataset API — not the human-readable dataset name used in the UI.

Using only the dataset name instead of the id/version pair causes the step to resolve by name lookup at render time. This works in a single org but breaks silently when the dashboard is migrated, cloned into a sandbox, or deployed via Metadata API — because dataset IDs differ across orgs and the name may not match. The SAQL step returns no results rather than an error.

REST API Versioning

CRM Analytics dashboards are versioned via the History API. Every PUT /services/data/vXX.X/wave/dashboards/{dashboardId} call that modifies the dashboard body automatically creates a new history snapshot. Previous versions are accessible at:

GET /services/data/vXX.X/wave/dashboards/{dashboardId}/histories

This means every PUT is non-destructive — the prior version is always recoverable. However, there is no built-in diff view; practitioners must compare full JSON bodies manually or via script.


Common Patterns

Cross-Widget Binding via Selection State

When to use: A filter widget (list selector, range slider) in one part of the dashboard should drive the data shown in charts or tables elsewhere, across datasets.

How it works:

  1. Define a step for the filter source dataset. Set selectionFields to the field you want to expose (e.g., ["Account.Industry"]).
  2. In the target chart step's SAQL query, add a where clause that reads the binding:
    | filter 'Industry' in ["{{#each cell(filterStep.selection, 0, "Industry")}}{{this}}{{/each}}"]
    
  3. In the target widget's parameters, bind filters to the selection state of the source step.
  4. Test with no selection (binding returns empty string) to confirm the default behavior is acceptable.

Why not hardcode values: Hardcoded filter values cannot be driven by user interaction. Faceting (automatic cross-filtering) only works within the same dataset; cross-dataset filtering requires explicit bindings in JSON.

Raising SAQL Step Row Limits

When to use: A step backing a table or export widget needs to surface more than 2,000 records, or a step used as a binding source needs a full population to avoid silent truncation.

How it works: Add the limit property to the step definition in the steps map:

"myStep": {
  "type": "saql",
  "query": "q = load \"datasetId/datasetVersionId\"; q = limit q 10000; q;",
  "datasets": [...],
  "limit": 10000
}

Both the limit property on the step object and the limit clause in the SAQL query string must be set. The platform enforces a hard maximum of 10,000 rows per step regardless of the value set.

Why not rely on default: The 2,000-row default is silently applied. There is no UI warning when results are truncated — the widget renders with partial data and no error message.


Decision Guidance

SituationRecommended ApproachReason
Filtering across two datasetsExplicit step binding using mustache cell() expressionFaceting only works within a single dataset
Dashboard migration across orgsUse datasetId + datasetVersionId in SAQL step datasets arrayName-based resolution fails silently in target org
Need more than 2,000 rows in a stepSet limit: 10000 on step AND add limit 10000 in SAQL queryBoth must be set; SAQL alone or property alone is insufficient
Recovering a prior dashboard versionGET /wave/dashboards/{id}/histories and re-PUT the desired bodyPUT auto-creates history; old versions are always accessible
Debugging an empty binding resultCheck if the source selection step has an active user selectionEmpty binding = empty string, not error; no selection = no value

Recommended Workflow

Step-by-step instructions for an AI agent or practitioner editing dashboard JSON:

  1. Retrieve the current dashboard body via GET /services/data/vXX.X/wave/dashboards/{dashboardId}. Save the full JSON response as a working copy before making any changes — the History API preserves versions after PUT, but having a local baseline is essential for diffing.
  2. Resolve dataset identifiers via GET /services/data/vXX.X/wave/datasets before constructing or modifying any SAQL step. Record the id (datasetId) and the currentVersionId (datasetVersionId) for every dataset the dashboard queries. Do not use display names.
  3. Edit steps first, then widgets, then state. Steps are referenced by name from widgets; editing in this order avoids forward-reference confusion. When adding a new step, assign it a camelCase key in the steps map and verify it is unique.
  4. Construct bindings using the exact mustache syntax {{cell(stepName.selection, 0, "fieldName")}}. Test the empty-binding case: when no selection exists, the binding returns an empty string. Decide explicitly whether an empty binding should produce no filter (full population) or a zero-result filter, and handle accordingly in the SAQL where clause.
  5. Set explicit row limits on any step where truncation matters. Add both "limit": 10000 to the step object and limit 10000 to the SAQL query string. The platform maximum is 10,000 rows per step.
  6. PUT the modified body via PUT /services/data/vXX.X/wave/dashboards/{dashboardId} with Content-Type: application/json. The platform automatically creates a history snapshot. Verify the response id and lastModifiedDate match expectations.
  7. Validate in the dashboard UI by opening the dashboard, triggering every filter interaction, and confirming that cross-widget bindings resolve correctly and no widgets show empty or unexpected results.

Review Checklist

Run through these before marking work in this area complete:

  • All SAQL steps reference datasets by datasetId and datasetVersionId, not by display name
  • All mustache binding expressions use the exact form {{cell(stepName.selection, 0, "fieldName")}}
  • Empty-binding behavior (no active selection) is explicitly handled for all filter-driven steps
  • Any step returning more than 2,000 rows has "limit" set on the step object and in the SAQL query string
  • The dashboard JSON was retrieved via REST API before editing and the full body was PUT back (not a partial update)
  • History API was confirmed to have a new snapshot after the PUT (verify via GET /histories)
  • Cross-widget filter interactions were tested end-to-end in the dashboard UI

Salesforce-Specific Gotchas

Non-obvious platform behaviors that cause real production problems:

  1. Dataset name resolution fails silently across orgs — Using the dataset display name instead of datasetId/datasetVersionId in a SAQL step's datasets array works in the authoring org but resolves by name lookup at render time. When the dashboard is deployed to another org or sandbox, the name may not exist or may point to a different dataset. The step returns no results — no error is thrown, no warning is displayed.
  2. Empty bindings return empty string, not null or error — When a binding's source step has no active user selection, {{cell(stepName.selection, 0, "fieldName")}} returns an empty string. A SAQL where clause built around this value may behave differently than intended: some constructs silently drop the filter (returning the full population) while others produce a literal empty-string comparison that returns zero rows.
  3. SAQL step row limit defaults to 2,000 with no UI warning — Truncation is silent. A step returning exactly 2,000 rows is almost always truncated. Widgets render partial data with no indicator. The maximum is 10,000, and both the step-level limit property and the SAQL limit clause must be set explicitly.

Output Artifacts

ArtifactDescription
Modified dashboard JSON bodyFull dashboard JSON ready for PUT to /wave/dashboards/{id}
SAQL step definitionsStep objects with datasetId/datasetVersionId references, explicit limits, and query strings
Binding expressionsMustache cell() expressions for cross-widget filter wiring

Related Skills

  • admin/analytics-dashboard-design — Design-level decisions (chart type selection, faceting, layout structure) that precede JSON editing

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Use this skill when writing test-first, behavior-driven acceptance criteria in Given/When/Then format for a Salesforce user story. Covers happy path, edge cases, negative paths, permission boundaries, and data-state preconditions so the AC block can drive UAT scripts and Apex test design downstream. Trigger keywords: given when then, gherkin, behavior driven AC, test first acceptance criteria, scenario outline, BDD acceptance criteria. NOT for the user-story format itself (use admin/user-story-writing-for-salesforce). NOT for UAT script writing (use admin/uat-test-case-design). NOT for Apex test method generation (use agents/test-class-generator). NOT for high-level UAT planning (use admin/uat-and-acceptance-criteria). More triggers: acceptance criteria record, ac_id, req_id on a criterion, artefact under test, negative case for a rule-type requirement, no-match fall-through criterion, oracle for a Then clause, test type apex flow manual, criteria linter, check_ac_format.py, --manifest-dir.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Task and Event objects: polymorphic WhatId/WhoId, Activity object model, ActivityHistory vs OpenActivity, activity timeline customization, bulk task creation, Einstein Activity Capture boundaries. NOT for turning on EAC or calendar sync — use admin/einstein-activity-capture-setup. NOT for Email-to-Case — use admin/case-management-setup. Covers ActivitiesSettings metadata, enableActivities, shared Task/Event custom fields and FLS, TaskStatus value sets, Shared Activities and TaskRelation/EventRelation, recurring and child activities, and partial-success bulk DML on Task.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Design Invocable Apex actions that return deterministic, agent-friendly errors instead of surfacing raw exceptions to the LLM. NOT for authoring the action itself — @InvocableMethod schema, labels, security context — use agentforce/custom-agent-actions-apex. NOT for the Apex tests that force each error branch — use agentforce/agent-action-unit-tests.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Use when designing how an Agentforce agent extracts structured input parameters (slots) from a user's natural-language utterance to invoke an action. Triggers: 'agent extract date from user', 'agent action argument extraction', 'agentforce slot filling', 'agent invocable input mapping', 'agent fails to fill required parameter'. NOT for action authoring (use agentforce/agent-actions) or for prompt-template variable binding (use agentforce/prompt-builder-templates).

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Apex test patterns for @InvocableMethod agent actions: per-reason-code branch coverage, bulk safety, callout mocking, deterministic assertions. NOT for testing whether the agent routes to the right topic or answers well — use agentforce/agent-testing-and-evaluation. NOT for designing the error envelope the tests assert on — use agentforce/agent-action-error-handling.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Designing or reviewing Agentforce actions: Flow actions, Apex invocable actions, prompt-template actions, action naming, input and output contracts, confirmation requirements, and safe error behavior. Triggers: 'agent actions', 'build an agent that can look up an order', 'make the agent able to check order status', 'give the agent a capability', 'agent that can retrieve a record', 'flow action for agent', 'agent invocable action', 'action schema design'. NOT for writing the Apex class itself — use agentforce/custom-agent-actions-apex. NOT for the reason_code error envelope that stops an agent retry loop — use agentforce/agent-action-error-handling.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

PranavNagrecha のスキルをすべて見る

このスキルの問題を報告する