@salesforce/afv-skills 1.59.0 → 1.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/agentforce-architecture-analyze/SKILL.md +66 -17
- package/skills/agentforce-architecture-analyze/assets/cli/show_access_token.yaml +4 -7
- package/skills/agentforce-architecture-analyze/references/contract.json +1 -1
- package/skills/agentforce-architecture-analyze/scripts/emit_env.py +2 -2
- package/skills/agentforce-architecture-analyze/scripts/main.py +40 -44
- package/skills/agentforce-architecture-analyze/scripts/rest_client.py +11 -3
- package/skills/agentforce-architecture-analyze/scripts/sf_cli.py +77 -10
- package/skills/agentforce-architecture-analyze/scripts/tests/test_end_to_end_fixture.py +1 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_flow_children_inflation.py +1 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_main_pipeline.py +53 -2
- package/skills/agentforce-architecture-analyze/scripts/tests/test_resolve_creds.py +184 -36
- package/skills/agentforce-architecture-analyze/scripts/tests/test_rest_client.py +17 -0
- package/skills/agentforce-architecture-analyze/scripts/tests/test_sf_cli.py +165 -11
- package/skills/agentforce-architecture-analyze/scripts/tests/test_skill_md_pipeline_block.py +319 -0
- package/skills/agentforce-d360-analyze/SKILL.md +28 -10
- package/skills/agentforce-d360-analyze/scripts/dc.py +200 -50
- package/skills/agentforce-d360-analyze/scripts/discover_sessions.py +10 -6
- package/skills/agentforce-d360-analyze/scripts/fetch_dc.py +22 -6
- package/skills/agentforce-d360-analyze/scripts/resolve_session.py +21 -13
- package/skills/agentforce-d360-analyze/scripts/tests/test_dc_and_resolve_session.py +298 -76
- package/skills/agentforce-d360-analyze/scripts/tests/test_default_target_org.py +432 -0
- package/skills/agentforce-d360-analyze/scripts/tests/test_discover_sessions.py +1 -1
- package/skills/agentforce-d360-analyze/scripts/tests/test_resolve_session_main.py +9 -3
- package/skills/agentforce-d360-analyze/scripts/tests/test_skill_md_prefix_block.py +176 -0
- package/skills/consumer-goods-accruals-datakit-deploy/SKILL.md +17 -27
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/setup.js +7 -17
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/00-check-prerequisites.js +47 -63
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/01-download-static-resource.js +10 -13
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/02-replace-org-id.js +46 -46
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/03-deploy-metadata.js +4 -21
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/06-create-dataspace.js +58 -82
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/07-deploy-accruals-reports.js +16 -315
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/08-deploy-ui.js +9 -24
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/09-completion.js +44 -44
- package/skills/consumer-goods-accruals-datakit-deploy/scripts/steps/utils.js +11 -63
- package/skills/consumer-goods-rtr-datacloud-export-configure/SKILL.md +2 -1
- package/skills/consumer-goods-tpe-dashboard-configure/SKILL.md +2 -1
- package/skills/consumer-goods-tpe-dashboard-custom-kpi-configure/SKILL.md +2 -1
- package/skills/consumer-goods-tpe-datakit-deploy/SKILL.md +2 -1
- package/skills/data360-schema-get/SKILL.md +3 -3
- package/skills/design-systems-slds-validate/references/report-format.md +1 -1
- package/skills/dx-org-manage/SKILL.md +1 -0
- package/skills/dx-org-shape-manage/SKILL.md +1 -0
- package/skills/dx-org-snapshot-manage/SKILL.md +172 -0
- package/skills/dx-org-snapshot-manage/examples/create_error_output.json +16 -0
- package/skills/dx-org-snapshot-manage/examples/create_success_output.json +19 -0
- package/skills/dx-org-snapshot-manage/examples/delete_output.json +9 -0
- package/skills/dx-org-snapshot-manage/examples/get_output.json +19 -0
- package/skills/dx-org-snapshot-manage/examples/list_output.json +36 -0
- package/skills/dx-org-snapshot-manage/references/cli_flags.md +179 -0
- package/skills/dx-org-snapshot-manage/references/snapshot_usage.md +55 -0
- package/skills/dx-org-trial-expiration-check/SKILL.md +1 -1
- package/skills/dx-org-trial-expiration-check/scripts/check_expiration.sh +2 -2
- package/skills/education-cloud-student-recruitment-agent-configure/SKILL.md +7 -5
- package/skills/education-cloud-student-recruitment-agent-configure/references/prerequisites.md +11 -11
- package/skills/experience-content-media-image-generate/SKILL.md +83 -0
- package/skills/experience-content-media-image-generate/scripts/download-image.sh +84 -0
- package/skills/external-diagram-mermaid-generate/SKILL.md +12 -12
- package/skills/field-service-data-capture-migrate/references/component-mapping.md +1 -1
- package/skills/field-service-data-capture-migrate/references/fsm-dc-capability-catalog.md +1 -2
- package/skills/field-service-data-capture-migrate/references/known-deploy-errors.md +1 -0
- package/skills/field-service-data-capture-migrate/references/transformer-rules.md +1 -1
- package/skills/field-service-data-capture-migrate/scripts/transform_flow.py +12 -1
- package/skills/field-service-data-capture-migrate/scripts/vendor/build_flow.py +4 -1
- package/skills/field-service-setup-orchestrator-get/SKILL.md +0 -1
- package/skills/insurance-brokerage-agency-billing-configure/SKILL.md +233 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/accounting-setup.md +117 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/billing-rules-config.md +237 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/billing-settings.md +271 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/demo-policy-config.md +138 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/org-defaults.md +64 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/permissions-config.md +226 -0
- package/skills/insurance-brokerage-agency-billing-configure/references/prerequisites.md +142 -0
- package/skills/life-sciences-fieldsalesrep-coordinate/SKILL.md +3 -2
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-execution-state-and-recovery.md +3 -3
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-overview.md +68 -45
- package/skills/life-sciences-fieldsalesrep-coordinate/references/stage-5-visit-creation-visit-creation-data.md +17 -18
- package/skills/life-sciences-kam-coordinate/references/stage-5-data-and-plan-templates-overview.md +16 -3
- package/skills/life-sciences-kam-coordinate/references/stage-5-data-creation-data.md +16 -13
- package/skills/marketing-message-test/SKILL.md +194 -0
- package/skills/marketing-message-test/references/api-contract.md +333 -0
- package/skills/omnistudio-callable-apex-generate/SKILL.md +3 -3
- package/skills/omnistudio-datamapper-generate/SKILL.md +6 -6
- package/skills/omnistudio-datapacks-deploy/SKILL.md +11 -11
- package/skills/omnistudio-dependencies-analyze/SKILL.md +5 -5
- package/skills/omnistudio-epc-catalog-generate/SKILL.md +6 -6
- package/skills/omnistudio-flexcard-generate/SKILL.md +6 -6
- package/skills/omnistudio-integration-procedure-generate/SKILL.md +6 -6
- package/skills/omnistudio-omniscript-generate/SKILL.md +6 -5
- package/skills/platform-apex-logs-debug/SKILL.md +1 -0
- package/skills/platform-metadata-deploy/SKILL.md +1 -0
- package/skills/platform-models-api-configure/SKILL.md +5 -5
- package/skills/platform-soql-query/SKILL.md +1 -0
- package/skills/service-itsm-agentic-setup-cmdb-coordinate/SKILL.md +17 -6
- package/skills/service-itsm-agentic-setup-incident-sla-configure/SKILL.md +107 -192
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/attach-milestone-action.json +6 -6
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/milestone-patterns.md +49 -20
- package/skills/service-itsm-agentic-setup-incident-sla-configure/examples/output-templates.md +4 -4
- package/skills/service-itsm-agentic-setup-incident-sla-configure/references/mcp-invocation.md +224 -290
- package/skills/service-itsm-agentic-setup-incident-sla-configure/references/workflow.md +295 -0
- package/skills/service-itsm-incident-priority-configure/SKILL.md +1 -1
- package/skills/service-itsm-slack-itservice-configure/SKILL.md +2 -1
- package/skills/service-itsm-slack-itservice-configure/references/manage-slack-connection.md +2 -2
- package/skills/service-omni-channel-setup-coordinate/SKILL.md +20 -13
- package/skills/service-omni-channel-setup-coordinate/scripts/integration-driver.sh +5 -55
- package/skills/service-omni-channel-setup-coordinate/scripts/tests/test_omni_contracts.py +0 -38
- package/skills/service-omni-command-center-analyze/SKILL.md +2 -3
- package/skills/service-omni-command-center-analyze/scripts/analyze.sh +3 -3
- package/skills/tableau-next-asset-create/README.md +65 -0
- package/skills/tableau-next-asset-create/SKILL.md +409 -0
- package/skills/tableau-next-asset-create/references/admin-users.md +149 -0
- package/skills/tableau-next-asset-create/references/ai-readiness.md +355 -0
- package/skills/tableau-next-asset-create/references/alerts.md +111 -0
- package/skills/tableau-next-asset-create/references/build-workflow.md +819 -0
- package/skills/tableau-next-asset-create/references/dashboard-authoring.md +302 -0
- package/skills/tableau-next-asset-create/references/dashboard-design-principles.md +352 -0
- package/skills/tableau-next-asset-create/references/data-transform-gotchas.md +210 -0
- package/skills/tableau-next-asset-create/references/data-understanding.md +387 -0
- package/skills/tableau-next-asset-create/references/deep-reference-index.md +74 -0
- package/skills/tableau-next-asset-create/references/destructive-operations.md +62 -0
- package/skills/tableau-next-asset-create/references/edit-dashboard.md +273 -0
- package/skills/tableau-next-asset-create/references/edit-visualization.md +529 -0
- package/skills/tableau-next-asset-create/references/empty-source-handling.md +104 -0
- package/skills/tableau-next-asset-create/references/ingest-and-metric-gotchas.md +638 -0
- package/skills/tableau-next-asset-create/references/insight-bundle.md +69 -0
- package/skills/tableau-next-asset-create/references/large-flat-file-handling.md +331 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/_envelope.json +54 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/_shared-widget-fields.json +122 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/add_page.json +29 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/delete_page.json +27 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/discard_dashboard.json +11 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/move_widget.json +30 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/move_widget_to_page.json +30 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/place_widget_on_page.json +30 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/remove_widget_from_dashboard.json +16 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/remove_widget_from_page.json +26 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/rename_page.json +28 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/save_dashboard.json +18 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/undo.json +11 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_button_widget.json +69 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_container_widget.json +88 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_filter_widget.json +146 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_metric_widget.json +78 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_navigation_widget.json +80 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_parameter_widget.json +160 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_text_widget.json +103 -0
- package/skills/tableau-next-asset-create/references/schemas/edit-dashboard/upsert_visualization_widget.json +68 -0
- package/skills/tableau-next-asset-create/references/sdm-tool-reference.md +721 -0
- package/skills/tableau-next-asset-create/references/semantic-query-and-enrichment.md +355 -0
- package/skills/tableau-next-asset-create/references/shared-gates.md +322 -0
- package/skills/tableau-next-asset-create/references/sharing-and-promotion.md +306 -0
- package/skills/tableau-next-asset-create/references/tasks/ai-readiness-audit.md +51 -0
- package/skills/tableau-next-asset-create/references/tasks/analyze-data.md +48 -0
- package/skills/tableau-next-asset-create/references/tasks/build-dashboard.md +66 -0
- package/skills/tableau-next-asset-create/references/tasks/build-end-to-end.md +73 -0
- package/skills/tableau-next-asset-create/references/tasks/create-data-transform.md +51 -0
- package/skills/tableau-next-asset-create/references/tasks/create-viz.md +58 -0
- package/skills/tableau-next-asset-create/references/tasks/edit-dashboard.md +80 -0
- package/skills/tableau-next-asset-create/references/tasks/edit-sdm.md +106 -0
- package/skills/tableau-next-asset-create/references/tasks/edit-viz.md +40 -0
- package/skills/tableau-next-asset-create/references/tasks/enrich-model.md +68 -0
- package/skills/tableau-next-asset-create/references/tasks/ingest-flat-file.md +68 -0
- package/skills/tableau-next-asset-create/references/tasks/manage-alert.md +35 -0
- package/skills/tableau-next-asset-create/references/tasks/profile-dataset.md +47 -0
- package/skills/tableau-next-asset-create/references/tasks/promote-or-reuse.md +46 -0
- package/skills/tableau-next-asset-create/references/tasks/provision-user.md +39 -0
- package/skills/tableau-next-asset-create/references/tasks/query-model.md +92 -0
- package/skills/tableau-next-asset-create/references/tasks/review-verified-questions.md +42 -0
- package/skills/tableau-next-asset-create/references/tasks/share-asset.md +37 -0
- package/skills/tableau-next-asset-create/references/verified-questions.md +125 -0
- package/skills/tableau-next-asset-create/references/viz-authoring.md +992 -0
- package/skills/service-de-channel-consent-configure/SKILL.md +0 -230
- package/skills/service-itsm-agentic-setup-incident-sla-configure/assets/predefined-incident-policy.json +0 -102
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
# Dashboard Authoring — Tool Guide & Verified Payloads
|
|
2
|
+
|
|
3
|
+
Load this for **Step 11** (build the dashboard). Covers dashboard creation,
|
|
4
|
+
widget placement grid, metric/viz widgets, text/label widgets, and critical gotchas.
|
|
5
|
+
|
|
6
|
+
> **Before placing widgets on the 48-col grid:** design the narrative and
|
|
7
|
+
> visual hierarchy first — see `references/dashboard-design-principles.md`
|
|
8
|
+
> (KPIs top/left, F/Z eye-path, story order: KPIs → Trends → Breakdowns →
|
|
9
|
+
> Correlations). Grid placement below is the mechanics; the design doc is
|
|
10
|
+
> the intent.
|
|
11
|
+
|
|
12
|
+
## Contents
|
|
13
|
+
|
|
14
|
+
- 1. Create the Empty Dashboard
|
|
15
|
+
- 2. Grid Specification
|
|
16
|
+
- 3. Editing Widgets — `edit_dashboard` (primary path)
|
|
17
|
+
- 4. Gotchas Summary
|
|
18
|
+
- 5. Global Filters — `add_global_filter_to_dashboard`
|
|
19
|
+
- 6. Deleting a Dashboard — `delete_dashboard`
|
|
20
|
+
- 7. Preflight before deleting a viz or dashboard — `list_asset_dependencies`
|
|
21
|
+
- 8. Show a dashboard vs metadata-only — `render_dashboard` / `get_dashboard`
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 1. Create the Empty Dashboard
|
|
26
|
+
|
|
27
|
+
Always start with an empty shell, then populate it with widgets.
|
|
28
|
+
|
|
29
|
+
```jsonc
|
|
30
|
+
{
|
|
31
|
+
"name": "Brightleaf_Sales_Overview",
|
|
32
|
+
"label": "Brightleaf Sales Overview",
|
|
33
|
+
"workspaceIdOrApiName": "brightleaf_demo",
|
|
34
|
+
"description": "Overview of Brightleaf sales performance by region and product",
|
|
35
|
+
"widgets": {},
|
|
36
|
+
"layouts": [{
|
|
37
|
+
"columnCount": 48,
|
|
38
|
+
"rowHeight": 20,
|
|
39
|
+
"maxWidth": 1200,
|
|
40
|
+
"style": { "backgroundColor": "#ffffff", "gutterColor": "#f3f3f3", "cellSpacingX": 4, "cellSpacingY": 4 },
|
|
41
|
+
"pages": [{ "name": "page_1", "label": "Overview", "widgets": [] }]
|
|
42
|
+
}],
|
|
43
|
+
"minorVersion": -1
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This seeded-`page_1` shell is the **default** shape — see the decision rule
|
|
48
|
+
below for when `layouts: []` is the right call instead.
|
|
49
|
+
|
|
50
|
+
**`workspaceIdOrApiName` is an id like `1Dyxx...` or apiName from `list_workspaces`. NOT the workspace label with spaces — that 404s.**
|
|
51
|
+
|
|
52
|
+
**Silent name transforms — always read `name` back.** `create_dashboard` mutates the
|
|
53
|
+
`name` you send with no warning: a duplicate name in the org gets a numeric suffix,
|
|
54
|
+
non-ASCII/unicode characters are silently stripped, names past ~78-80 characters are
|
|
55
|
+
silently truncated, and spaces are silently converted to underscores. Never assume
|
|
56
|
+
the requested `name` was stored verbatim — read the response back before referencing
|
|
57
|
+
it (e.g. in a widget's `source` or a navigation target).
|
|
58
|
+
|
|
59
|
+
**Don't call `create_dashboard` with just `{name, label, workspaceIdOrApiName}`.**
|
|
60
|
+
That leaks a raw Java NPE (`Cannot invoke "java.util.Map.values()" ...getWidgets()`).
|
|
61
|
+
`widgets: {}` and a `layouts` value (`[]` or seeded, per the decision rule below)
|
|
62
|
+
are de-facto required even when empty — never omit either.
|
|
63
|
+
|
|
64
|
+
**Pick one create recipe based on what happens next — verified live
|
|
65
|
+
(2026-09-13):**
|
|
66
|
+
|
|
67
|
+
- **You will `edit_dashboard` immediately after — the common "create, then
|
|
68
|
+
place widgets" flow.** Seed one layout with an empty `page_1` (full `style`
|
|
69
|
+
block + `columnCount`, as in the shell above), then `edit_dashboard`.
|
|
70
|
+
`add_page`/`place_widget_on_page` operate *within* an existing layout — they
|
|
71
|
+
do not create the first one. A `create_dashboard` done with `layouts: []`
|
|
72
|
+
yields a dashboard with **no layout at all**, and the next `edit_dashboard`
|
|
73
|
+
`add_page` fails: `INVALID_INPUT: "Dashboard has no layout to add the page
|
|
74
|
+
to"`.
|
|
75
|
+
- **You will NOT edit/populate the dashboard next** (e.g. handing off a bare
|
|
76
|
+
shell). `layouts: []` is fine — there's nothing to place yet anyway.
|
|
77
|
+
|
|
78
|
+
If you do seed a page up front, give every layout a full `style` block and
|
|
79
|
+
`columnCount` — omitting `style` at create time renders an **unstyled
|
|
80
|
+
dashboard** (no crash), and omitting `columnCount` breaks grid math for every
|
|
81
|
+
widget placed later.
|
|
82
|
+
|
|
83
|
+
**Workspace cascade on delete.** `delete_workspace` cascade-deletes every
|
|
84
|
+
workspace-asset row whose `assetUsageType="Created"`, and that delete propagates
|
|
85
|
+
to the underlying asset — confirmed for `AnalyticsVisualization`, `SemanticModel`,
|
|
86
|
+
AND `AnalyticsDashboard` (not just dashboards). Assets added with
|
|
87
|
+
`assetUsageType="Referenced"` are NOT deleted — only their workspace association
|
|
88
|
+
is removed. `create_dashboard` and `create_*_viz` each auto-create a `"Created"`
|
|
89
|
+
workspace-asset row for the new asset, so any chart or dashboard authored in that
|
|
90
|
+
workspace will be swept up. ALWAYS call `list_workspace_assets` first to inventory
|
|
91
|
+
`Created`-typed assets before deleting a workspace — there's no undo.
|
|
92
|
+
|
|
93
|
+
**Scope and response shape.** `create_dashboard` creates in the current org only —
|
|
94
|
+
it does not copy a dashboard from another org. Verified live (2026-08-30): as
|
|
95
|
+
observed through this tool, `create_dashboard`'s response is a **flat JSON
|
|
96
|
+
object**, NOT double-wrapped. `edit_dashboard` and
|
|
97
|
+
`delete_dashboard`, by contrast, ARE double-wrapped as
|
|
98
|
+
`{"defaultExc": "<stringified JSON>", "responseCode": <number>}` (parse
|
|
99
|
+
`JSON.parse(response.defaultExc)`; see §6 for `delete_dashboard`'s success-path
|
|
100
|
+
exception). The wrapping is per-tool, don't assume it's family-wide.
|
|
101
|
+
|
|
102
|
+
**`minorVersion` must be sent explicitly.** The schema shows `minorVersion:
|
|
103
|
+
-1` as a default, but omitting it can surface a live client-visible error:
|
|
104
|
+
`ILLEGAL_QUERY_PARAMETER_VALUE: Illegal value for query parameter
|
|
105
|
+
'minorVersion': ''`. Always pass `minorVersion: -1` on `create_dashboard` (and
|
|
106
|
+
on `edit_dashboard` — `edit-dashboard.md` §1).
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 2. Grid Specification
|
|
111
|
+
|
|
112
|
+
The grid is **48 columns** (`columnCount: 48`), `rowHeight 20`, `maxWidth 1200`.
|
|
113
|
+
Plan colspans in 48ths (a half-width chart = 24, a quarter KPI = 12).
|
|
114
|
+
`columnCount` is required on every layout at create time, alongside a full
|
|
115
|
+
`style` block (§1).
|
|
116
|
+
|
|
117
|
+
**Always name AND label every page.** If you seed a non-empty `layouts` block
|
|
118
|
+
on `create_dashboard`, each `layouts[].pages[]` entry needs both `name` (API
|
|
119
|
+
id, e.g. `page_1`) and `label` (display name) set explicitly — `create_dashboard`
|
|
120
|
+
does **not** auto-derive `page_N`. An omitted `name` is stored empty (any
|
|
121
|
+
navigation widget targeting it by `page_N` won't resolve) and an omitted
|
|
122
|
+
`label` renders a blank page tab. Set both at create time rather than fixing
|
|
123
|
+
page one up later via `edit_dashboard`'s `rename_page`.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## 3. Editing Widgets — `edit_dashboard` (primary path)
|
|
128
|
+
|
|
129
|
+
**Use `edit_dashboard` for all widget/page editing on an existing dashboard** —
|
|
130
|
+
add, replace, move, or remove a widget of any kind (metric, visualization, text,
|
|
131
|
+
button, container, filter, parameter, navigation), and add/rename/delete a
|
|
132
|
+
page. It is the only supported tool for this purpose — never hand-build a
|
|
133
|
+
dashboard-JSON PATCH.
|
|
134
|
+
|
|
135
|
+
Full operation-type table, the widget-identity rule (`widget.name`/`widget.id`
|
|
136
|
+
vs. `placement.name`), grid placement, draft-vs-persist mechanics
|
|
137
|
+
(`save_dashboard`/`undo`/`discard_dashboard`), and full widget deletion via
|
|
138
|
+
`remove_widget_from_dashboard` are all in **`edit-dashboard.md`**
|
|
139
|
+
(task guide: `tasks/edit-dashboard.md`).
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 4. Gotchas Summary
|
|
144
|
+
|
|
145
|
+
`create_dashboard` gotchas below. For `edit_dashboard` (§3, primary path)
|
|
146
|
+
gotchas, see `edit-dashboard.md` §7.
|
|
147
|
+
|
|
148
|
+
| Gotcha | Rule |
|
|
149
|
+
|---|---|
|
|
150
|
+
| Omitting `minorVersion` on `create_dashboard` | Client-visible `ILLEGAL_QUERY_PARAMETER_VALUE` on an empty value — always send `minorVersion: -1` explicitly |
|
|
151
|
+
| `create_dashboard` response wrapping | Flat JSON, NOT double-wrapped (verified live) — don't apply the `defaultExc`/`responseCode` parse to it |
|
|
152
|
+
| `&` in text labels | HTML-encodes to `&` in round-trip — use "and" or "/" |
|
|
153
|
+
| `create_dashboard` `name` mutated silently | Dup → suffix; non-ASCII stripped; ~78-80 char truncation; spaces → underscores — always read `name` back |
|
|
154
|
+
| `create_dashboard` with no `widgets`/`layouts` | Leaks a raw NPE — always pass `widgets: {}` and a `layouts` value (`[]` or seeded) at minimum |
|
|
155
|
+
| `add_page`/`place_widget_on_page` right after `create_dashboard` with `layouts: []` | Fails `INVALID_INPUT: "Dashboard has no layout to add the page to"` (verified live 2026-09-13) — seed one layout with an empty `page_1` in `create_dashboard` instead when you'll edit immediately (§1) |
|
|
156
|
+
| Missing `layouts[].style`/`columnCount` on `create_dashboard` bulk-create | Renders an unstyled dashboard (no runtime crash at create time) — always include a full `style` block and `columnCount` |
|
|
157
|
+
| Bulk-create pages with no `name`/`label` | `create_dashboard` does NOT auto-derive `page_N` — set both explicitly on every page at create time |
|
|
158
|
+
| `delete_workspace` on a workspace with `Created`-typed assets | Cascades — deletes every viz/SDM/dashboard whose workspace-asset row is `assetUsageType="Created"` (`Referenced` rows only lose their association, asset itself survives); list workspace assets first |
|
|
159
|
+
| `delete_visualization` / `delete_dashboard` without `list_asset_dependencies` | Preflight first (§7) — returns **counts not ids**; if `analyticsdashboard` > 0, widgets are not cleaned (`source` silently nulled) — `remove_widget_from_dashboard` first |
|
|
160
|
+
| `workspaceIdOrApiName` is the workspace label with spaces | 404s — pass the id (`1Dyxx...`) or apiName from `list_workspaces`, NOT the label |
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 5. Global Filters — `add_global_filter_to_dashboard`
|
|
165
|
+
|
|
166
|
+
A global filter is **dashboard-wide**, not baked into one chart — it drives every
|
|
167
|
+
viz/metric widget on the dashboard that shares the filtered field's semantic model
|
|
168
|
+
and object. This is a different mechanism from `create_visualization`'s own
|
|
169
|
+
per-chart `filters` array (`viz-authoring.md`) or an `edit_visualization`
|
|
170
|
+
`addFilter` op (`edit-visualization.md`), which each scope to one visualization
|
|
171
|
+
only. Ask which the user means when it's ambiguous ("filter this chart" vs. "filter
|
|
172
|
+
the dashboard").
|
|
173
|
+
|
|
174
|
+
**Self-contained.** This tool builds the full filter-widget JSON and places it
|
|
175
|
+
on the grid internally — no separate read/replace round trip needed. Required
|
|
176
|
+
inputs: `dashboardIdOrApiName`, `semanticModelIdOrName`, `objectName`,
|
|
177
|
+
`fieldName`, and a grid `placement` (48-col grid, same conventions as §2; a
|
|
178
|
+
common size is full-width `colspan: 48, rowspan: 4` or half-width
|
|
179
|
+
`colspan: 24, rowspan: 4`).
|
|
180
|
+
|
|
181
|
+
**Value-matching rule of thumb:**
|
|
182
|
+
|
|
183
|
+
- **Relative-date presets** (e.g. "default to current quarter") — pass `operator`
|
|
184
|
+
alone (`CurrentQuarter`, `CurrentMonth`, `PreviousMonth`, `LastNDays`, …); omit
|
|
185
|
+
`initialValues`.
|
|
186
|
+
- **Exact/contains/range matching** — pass `operator` (`Equals`, `In`, `Contains`,
|
|
187
|
+
`GreaterThan`, …) **and** `initialValues` as a JSON array, even for one value
|
|
188
|
+
(`["West"]`, not `"West"`). Use a multi-element array for `In`.
|
|
189
|
+
|
|
190
|
+
One line each: `dataType` (`Text`/`Number`/`Date`/`Boolean`/`measure`) is
|
|
191
|
+
case-sensitive and defaults to `Text`; `selectionType` (`single`/`multiple`) defaults
|
|
192
|
+
to `multiple`; `filterLabel` (optional display label) defaults to `fieldName`;
|
|
193
|
+
`widgetName` (optional unique name) auto-generates as `filter_N` when omitted.
|
|
194
|
+
A global filter is just a widget under the hood — `edit_dashboard`'s
|
|
195
|
+
`remove_widget_from_page` only unplaces it; to fully remove one, use
|
|
196
|
+
`remove_widget_from_dashboard` with its `widgetName` (`edit-dashboard.md` §6).
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 6. Deleting a Dashboard — `delete_dashboard`
|
|
201
|
+
|
|
202
|
+
`delete_dashboard` permanently removes a dashboard. **Destructive, no undo** —
|
|
203
|
+
always get explicit user confirmation first (`SKILL.md` lifecycle bullets).
|
|
204
|
+
|
|
205
|
+
**Inputs:** `dashboardIdOrApiName` only (the id or apiName from
|
|
206
|
+
`list_dashboards`/`browse_data_assets`). Scope is the current org only.
|
|
207
|
+
|
|
208
|
+
**Response shape — verified live (2026-08-30):** double-wrapped as
|
|
209
|
+
`{"defaultExc": "<stringified JSON>", "responseCode": <number>}`. On the
|
|
210
|
+
success path (`responseCode: 204`), `defaultExc` is an **empty string** (`""`)
|
|
211
|
+
— NOT the literal string `"204"`, and not JSON-parseable either way. Branch on
|
|
212
|
+
`responseCode === 204` for success; don't try to parse `defaultExc` on that
|
|
213
|
+
path.
|
|
214
|
+
|
|
215
|
+
**Not idempotent.** A second `delete_dashboard` call against an
|
|
216
|
+
already-deleted (or never-existent) id returns a 404:
|
|
217
|
+
`RESOURCE_NOT_FOUND: "We couldn't find dashboard."` Treat that specific error
|
|
218
|
+
as success-equivalent if your flow might double-call delete.
|
|
219
|
+
|
|
220
|
+
**No cascade to referenced assets.** Deleting a dashboard does not delete the
|
|
221
|
+
visualizations/metrics it displayed — only the dashboard and its widget
|
|
222
|
+
placements. Compare `delete_workspace`'s cascade behavior (§1), which is a
|
|
223
|
+
different, broader operation.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## 7. Preflight before deleting a viz or dashboard — `list_asset_dependencies`
|
|
228
|
+
|
|
229
|
+
Call this before `delete_visualization` or `delete_dashboard`. Distinct from
|
|
230
|
+
`list_semantic_model_dependencies` (in-model calc/metric graph; see
|
|
231
|
+
`sdm-tool-reference.md`).
|
|
232
|
+
|
|
233
|
+
- **`assetId` is the 18-char id only** — an apiName returns a misleading
|
|
234
|
+
workspace error.
|
|
235
|
+
- Returns **COUNTS by type**, not dependent ids/names — you cannot name which
|
|
236
|
+
dashboards will break. `totalCount`/`nextOffset` page the queried-asset list,
|
|
237
|
+
not the dependents.
|
|
238
|
+
- Show the counts, then **end the turn and wait for a new unambiguous yes**.
|
|
239
|
+
A prior "delete" in the same request is a plan, not confirmation.
|
|
240
|
+
- `delete_visualization` does NOT clean dashboard widgets. If
|
|
241
|
+
`dependentAssets.analyticsdashboard` is nonzero, N dashboards will keep a
|
|
242
|
+
broken widget (`source` silently nulled). Prefer
|
|
243
|
+
`remove_widget_from_dashboard` first (`edit-dashboard.md` §6) for a clean
|
|
244
|
+
remove.
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## 8. Show a dashboard vs metadata-only — `render_dashboard` / `get_dashboard`
|
|
249
|
+
|
|
250
|
+
**If the user wants to see, open, view, display, render, bring up, pull up,
|
|
251
|
+
load, or look at a dashboard** (its charts, filters, or layout) — including
|
|
252
|
+
when they name or id a dashboard and want to see it — call `render_dashboard`.
|
|
253
|
+
That is the dashboard analog of `get_visualization` for
|
|
254
|
+
charts. **`get_dashboard` does not render.**
|
|
255
|
+
|
|
256
|
+
Do **not** call `get_dashboard` just because the skill already uses it for
|
|
257
|
+
`edit_dashboard` prep. Metadata-only is for inspect / `edit_dashboard` prep.
|
|
258
|
+
Current org only.
|
|
259
|
+
|
|
260
|
+
### `render_dashboard` — inline render
|
|
261
|
+
|
|
262
|
+
Retrieves the dashboard's full metadata **bundled with its referenced
|
|
263
|
+
assets** (semantic models and visualizations) so visualization / filter /
|
|
264
|
+
parameter widgets can render immediately — no extra per-asset fetches.
|
|
265
|
+
|
|
266
|
+
**Required inputs** (live sidecar — always send all four flags):
|
|
267
|
+
|
|
268
|
+
- `dashboardIdOrApiName` — id or apiName from `list_dashboards` or
|
|
269
|
+
`browse_data_assets`
|
|
270
|
+
- `addVisualization=true` — so visualization tiles can render
|
|
271
|
+
- `addSdm=true` — so filter / parameter widgets that need SDM metadata can
|
|
272
|
+
render
|
|
273
|
+
- `showDraft=true` — include an in-progress `edit_dashboard` draft;
|
|
274
|
+
`get_dashboard` will not show that draft
|
|
275
|
+
- `minorVersion=-1` — latest **Salesforce API** minor version, **not** a
|
|
276
|
+
dashboard revision
|
|
277
|
+
|
|
278
|
+
**Optional:** `pageName` (page GUID), `customViewId`, `height` (viewport
|
|
279
|
+
pixels — when passed, only assets visible within that height are included).
|
|
280
|
+
|
|
281
|
+
**Returns:** `{dashboard, bundledAssets}`. `dashboard` is the full metadata
|
|
282
|
+
(layout, widgets, owning workspace, `url`). `bundledAssets` is a map of
|
|
283
|
+
asset id → referenced semantic model / visualization. Read them at
|
|
284
|
+
`response.dashboard` and `response.bundledAssets`.
|
|
285
|
+
|
|
286
|
+
### `get_dashboard` — metadata only (cheaper, no bundled assets)
|
|
287
|
+
|
|
288
|
+
Use when you need `label` / `widgets` / `layout` / owning workspace
|
|
289
|
+
programmatically, to diff two dashboards, or to prepare an `edit_dashboard`
|
|
290
|
+
batch. Do **not** use it when the intent is to *see* the dashboard — for that,
|
|
291
|
+
call `render_dashboard` above.
|
|
292
|
+
|
|
293
|
+
**Inputs:** `dashboardIdOrApiName`. Optional `minorVersion` is the Salesforce
|
|
294
|
+
API version (e.g. `67.42`), **not** a dashboard revision — invalid values
|
|
295
|
+
produce `Invalid version`.
|
|
296
|
+
|
|
297
|
+
**Returns:** fields **directly** on the response (`label`, `widgets`,
|
|
298
|
+
`layout`, `folder`, `url`) — flat, like `create_dashboard`; unlike
|
|
299
|
+
`edit_dashboard` / `delete_dashboard`, which double-wrap (§6, `edit-dashboard.md`
|
|
300
|
+
§1). `url` is a canonical **external**
|
|
301
|
+
Analytics-app link — it does not render the dashboard inline. For inline
|
|
302
|
+
rendering, call `render_dashboard`.
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
# Dashboard Design Principles — Supported Practices Mapped to MCP Tools
|
|
2
|
+
|
|
3
|
+
Load this alongside `viz-authoring.md` (Step 10) and `dashboard-authoring.md`
|
|
4
|
+
(Step 11). This file covers the **design layer** — narrative, visual
|
|
5
|
+
hierarchy, naming, field selection, color, filters, and the data-presence
|
|
6
|
+
gate — translated from universal dashboard design best practices to what the
|
|
7
|
+
`tableau-next-pilot` MCP tools **actually** expose.
|
|
8
|
+
|
|
9
|
+
> **No named templates/patterns exist.** The MCP surface is a small set of
|
|
10
|
+
> generic primitives: `create_visualization` (`marks.panes.type` ∈ `Bar`,
|
|
11
|
+
> `Line`, `Circle`, `Square`, `Text`, `Donut`; `layout` ∈ `Vizql`, `Radial`,
|
|
12
|
+
> `Table`), a raw 48-column dashboard grid (`create_dashboard` +
|
|
13
|
+
> `edit_dashboard`'s `upsert_*_widget`/`place_widget_on_page` batch),
|
|
14
|
+
> `add_global_filter_to_dashboard`,
|
|
15
|
+
> and the `list_/get_semantic_model_*` discovery tools. Every principle below
|
|
16
|
+
> is achieved by combining these primitives by hand — never invent a template,
|
|
17
|
+
> script, or param name that isn't in `viz-authoring.md` §11/§12 or
|
|
18
|
+
> `dashboard-authoring.md`.
|
|
19
|
+
|
|
20
|
+
## Contents
|
|
21
|
+
|
|
22
|
+
- 1. Think Like a Business User (before any `create_*` call)
|
|
23
|
+
- 2. Design the Narrative Before Picking Charts (REQUIRED)
|
|
24
|
+
- 3. Visual Storytelling Flow — KPIs → Trends → Breakdowns → Correlations
|
|
25
|
+
- 4. Visual Hierarchy — F-Pattern, Z-Pattern, Progressive Disclosure, Color, White Space
|
|
26
|
+
- 5. Business-Question → Chart-Type Mapping
|
|
27
|
+
- 6. Naming Conventions
|
|
28
|
+
- 7. Field Selection Priority
|
|
29
|
+
- 8. Color Encoding — Real Mechanism, Not `color_dim`/`stack_dim`
|
|
30
|
+
- 9. Filters — Dimensions Not Measures
|
|
31
|
+
- 10. Data-Presence Gate — Hard Stop Before Any Viz
|
|
32
|
+
- 11. Dashboard Quality Checklist (MCP Reality)
|
|
33
|
+
- Not supported by the tableau-next-pilot MCP (do not attempt)
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 1. Think Like a Business User (before any `create_*` call)
|
|
38
|
+
|
|
39
|
+
Before calling `create_visualization` or `create_dashboard`, answer three
|
|
40
|
+
questions in your own reasoning — no tool enforces this:
|
|
41
|
+
|
|
42
|
+
1. **What question does this chart answer?** If you can't state it in one
|
|
43
|
+
sentence, don't build it.
|
|
44
|
+
2. **What action will the viewer take from this?** A chart with no
|
|
45
|
+
actionable follow-up is decoration.
|
|
46
|
+
3. **Can a non-technical user read every label?** No raw field apiNames, no
|
|
47
|
+
`_Clc`/`_mtc` suffixes, no bare object names.
|
|
48
|
+
|
|
49
|
+
This discipline feeds directly into `create_visualization`'s `label`/`title`
|
|
50
|
+
and the dashboard's `label` — pull field labels from `list_semantic_model_dimensions`
|
|
51
|
+
/ `list_semantic_model_measures` (their `label`, not `fieldName`), and cross-check
|
|
52
|
+
against the SDM's own `description` via `get_semantic_model`. This is pure
|
|
53
|
+
pre-authoring judgement; nothing downstream validates it for you.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 2. Design the Narrative Before Picking Charts (REQUIRED)
|
|
58
|
+
|
|
59
|
+
Before the first `create_visualization` call, write out — even briefly:
|
|
60
|
+
|
|
61
|
+
- The business questions the dashboard must answer.
|
|
62
|
+
- The logical flow between them (what should the eye see first, second, third).
|
|
63
|
+
- Friendly names for every field you intend to use.
|
|
64
|
+
- Which dimensions are actually meaningful (not IDs, not descriptions).
|
|
65
|
+
- What action the viewer takes after seeing each section.
|
|
66
|
+
|
|
67
|
+
This is a hard **gate on Step 9** in SKILL.md — do not call
|
|
68
|
+
`create_visualization` until `run_semantic_query` (or `run_query`) has
|
|
69
|
+
returned real, non-empty rows for every source you plan to chart (§9 below).
|
|
70
|
+
The narrative is realized entirely through **intentional sequencing** of
|
|
71
|
+
`create_visualization` calls and widget placement — there is no
|
|
72
|
+
narrative/flow object to configure.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 3. Visual Storytelling Flow — KPIs → Trends → Breakdowns → Correlations
|
|
77
|
+
|
|
78
|
+
There is no flow abstraction in the MCP. Realize the sequence by widget type
|
|
79
|
+
and grid row, top to bottom:
|
|
80
|
+
|
|
81
|
+
| Story beat | MCP realization | Placement guidance |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| **KPIs** | `edit_dashboard`'s `upsert_metric_widget` + `place_widget_on_page` (`parameters.metricOption.{sdmApiName, sdmId}`; `source` optionally references the metric) | Row 0, spanning the top band |
|
|
84
|
+
| **Trends** | `create_visualization` with `marks.panes.type: "Line"` | Immediately below the KPI band |
|
|
85
|
+
| **Breakdowns** | `create_visualization` with `marks.panes.type: "Bar"` (plain, stacked, or Donut for <5 categories) | Below trends |
|
|
86
|
+
| **Correlations** | `create_visualization` with `marks.panes.type: "Circle"` (scatter) | Bottom of the grid |
|
|
87
|
+
|
|
88
|
+
Sequence widgets top-to-bottom by **ascending `placement.row`** on the
|
|
89
|
+
48-column grid — that ascending-row order *is* the story order. There is no
|
|
90
|
+
server-side flow validation; if you place the scatter chart at `row: 0` and
|
|
91
|
+
the KPIs at `row: 40`, the story reads backwards with no warning.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 4. Visual Hierarchy — F-Pattern, Z-Pattern, Progressive Disclosure, Color, White Space
|
|
96
|
+
|
|
97
|
+
No `f_layout` / `z_layout` pattern objects exist. Build the eye-path by hand
|
|
98
|
+
with `placement.{row,column,rowspan,colspan}` on the 48-column grid
|
|
99
|
+
(`rowHeight: 20`, `maxWidth: 1200`).
|
|
100
|
+
|
|
101
|
+
**F-pattern (metrics-left/top-heavy scan):**
|
|
102
|
+
|
|
103
|
+
```jsonc
|
|
104
|
+
// KPI band across the top
|
|
105
|
+
{ "row": 0, "column": 0, "rowspan": 8, "colspan": 12 } // metric 1
|
|
106
|
+
{ "row": 0, "column": 12, "rowspan": 8, "colspan": 12 } // metric 2
|
|
107
|
+
{ "row": 0, "column": 24, "rowspan": 8, "colspan": 12 } // metric 3
|
|
108
|
+
{ "row": 0, "column": 36, "rowspan": 8, "colspan": 12 } // metric 4
|
|
109
|
+
// Primary trend, full width, second scan line
|
|
110
|
+
{ "row": 8, "column": 0, "rowspan": 18, "colspan": 48 }
|
|
111
|
+
// Secondary breakdowns, left-weighted third scan line
|
|
112
|
+
{ "row": 26, "column": 0, "rowspan": 16, "colspan": 24 }
|
|
113
|
+
{ "row": 26, "column": 24, "rowspan": 16, "colspan": 24 }
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Z-pattern (left→right, then diagonal down to left→right again):**
|
|
117
|
+
|
|
118
|
+
```jsonc
|
|
119
|
+
{ "row": 0, "column": 0, "rowspan": 8, "colspan": 24 } // top-left
|
|
120
|
+
{ "row": 0, "column": 24, "rowspan": 8, "colspan": 24 } // top-right
|
|
121
|
+
{ "row": 8, "column": 0, "rowspan": 18, "colspan": 24 } // bottom-left
|
|
122
|
+
{ "row": 8, "column": 24, "rowspan": 18, "colspan": 24 } // bottom-right
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Progressive disclosure:** put the single most important KPI/chart at
|
|
126
|
+
`row: 0, column: 0` with the largest `colspan`/`rowspan`; secondary detail
|
|
127
|
+
(tables, drill-down breakdowns) go further down the grid. There is no
|
|
128
|
+
drill-down/expand mechanism — "progressive disclosure" here just means
|
|
129
|
+
"important things occupy the first screen's worth of rows."
|
|
130
|
+
|
|
131
|
+
**Color consistency:** the same category must map to the same color across
|
|
132
|
+
every chart on the dashboard. The only lever is the `Color` encoding
|
|
133
|
+
fieldKey in `marks.panes.encodings` — pick the *same underlying dimension*
|
|
134
|
+
(same `objectName`+`fieldName`) for the Color encoding on every chart that
|
|
135
|
+
breaks down by that category. There is no shared palette/legend registry;
|
|
136
|
+
consistency is achieved by field-binding discipline, not a setting.
|
|
137
|
+
|
|
138
|
+
**White space:** don't tile every grid cell. Leave gaps between widget
|
|
139
|
+
groups (skip a row or two between `placement.row` bands) and set
|
|
140
|
+
`layouts[].style.cellSpacingX` / `cellSpacingY` (verified default: `4`) on
|
|
141
|
+
the dashboard's `style` block — see `dashboard-authoring.md`. Overcrowding
|
|
142
|
+
the 48-column grid (i.e. every row fully packed edge-to-edge) is a real
|
|
143
|
+
readability failure with no tool-level guard; watch it yourself.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## 5. Business-Question → Chart-Type Mapping
|
|
148
|
+
|
|
149
|
+
Every row maps to an achievable `marks.panes.type` / `layout` combination —
|
|
150
|
+
no named templates. See `viz-authoring.md` §2–3 for the full decision matrix
|
|
151
|
+
and verified payloads; summarized here with the MCP-native mechanism:
|
|
152
|
+
|
|
153
|
+
| Business question | Data pattern | `marks.panes.type` / `layout` | Mechanism |
|
|
154
|
+
|---|---|---|---|
|
|
155
|
+
| Trending over time | Date + measure | `Line` / `Vizql` | Date on columns with `DateTruncMonth` (Continuous); measure on rows |
|
|
156
|
+
| Trend by category | Date + measure + dim | `Line` / `Vizql` | + `Color` encoding on the breakdown dimension |
|
|
157
|
+
| Best/worst performers | Dim + measure | `Bar` / `Vizql` | Server auto-sorts descending; override with `sortIntent` |
|
|
158
|
+
| Composition (<5 categories) | Dim (<5 vals) + measure | `Donut` / `Radial` | Measure on **`Angle`** encoding (not `rows`); dim on `Color` |
|
|
159
|
+
| Composition (≥5 categories) | Dim (≥5 vals) + measure | `Bar` / `Vizql` | Donut is unreadable beyond ~4 slices |
|
|
160
|
+
| Breakdown by two dimensions | 2 dims + measure | `Bar` / `Vizql` | + `Color` on 2nd dim + `stack: {isAutomatic:false, isStacked:true}` |
|
|
161
|
+
| Compare multiple measures | Dim + 2+ measures | `Bar` / `Vizql` | `MeasureNames`/`MeasureValues` synthetic fields, or both measures in `columns` |
|
|
162
|
+
| Performance hotspots | 2 dims + measure | `Square` / `Vizql` | Two dims on rows/columns; measure on `Color` encoding |
|
|
163
|
+
| Correlation | 2 measures | `Circle` / `Vizql` | X-measure on columns, Y-measure on rows; point dim on `Color`/`Detail` |
|
|
164
|
+
| Detailed rankings | Multiple dims + measures | `Text` / `Table` | Dims in `groups` (outer→inner), measures in `rows` |
|
|
165
|
+
| YoY comparison | Date + measure + year | `Line` / `Vizql` | `DatePartMonth` on axis, `DatePartYear` on `Color` — period overlay, not a continuous timeline |
|
|
166
|
+
|
|
167
|
+
**Map (point/geographic) and Flow (Sankey) are not on this table because
|
|
168
|
+
they are unsupported** — no matching mark type exists. See the closing
|
|
169
|
+
section for fallbacks.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 6. Naming Conventions
|
|
174
|
+
|
|
175
|
+
**The mechanical rules — suffix stripping (`_Clc`/`_mtc`/`_MTC`/`_CLC`),
|
|
176
|
+
≥3-word business-friendly titles, never exposing a raw suffixed apiName like
|
|
177
|
+
`Region4`/`Amount7` — live in `viz-authoring.md` §4. Follow them.** The
|
|
178
|
+
design-layer points on top of those mechanics:
|
|
179
|
+
|
|
180
|
+
- **Pull display labels from the SDM's own `label`** (via
|
|
181
|
+
`list_semantic_model_dimensions` / `list_semantic_model_measures`, or
|
|
182
|
+
`get_semantic_model`) — there is no `sdm_fields[field]['label']` accessor —
|
|
183
|
+
and cross-check the intent against the SDM `description`. The label should
|
|
184
|
+
answer the business question, not just rename the field.
|
|
185
|
+
- **Read the transformed name back.** `create_dashboard` and
|
|
186
|
+
`create_visualization` auto-transform the `name`/apiName you send
|
|
187
|
+
(spaces → `_`, truncation, unicode stripped) — after creation, read back
|
|
188
|
+
the actual stored `name` rather than assuming your input string survived
|
|
189
|
+
unchanged.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## 7. Field Selection Priority
|
|
194
|
+
|
|
195
|
+
**The priority ladder (CLC/calculated → meaningful categorical → geographic/org
|
|
196
|
+
→ name fields → avoid generic text → never ID fields), the cardinality
|
|
197
|
+
thresholds (≤4 Donut / 5–50 Bar / 50+ Top-N), and the CLC + `UserAgg`
|
|
198
|
+
no-double-aggregation rule all live in `viz-authoring.md` §5 and §7.** The
|
|
199
|
+
design-layer framing on top of those mechanics:
|
|
200
|
+
|
|
201
|
+
- Field selection is a **judgement call, not an enforced check** — nothing
|
|
202
|
+
downstream stops you from charting an ID field or a raw description, and
|
|
203
|
+
there is no `recommend_diverse_chart_types()` scoring function. Apply the
|
|
204
|
+
ladder yourself when choosing among fields returned by
|
|
205
|
+
`list_semantic_model_*`.
|
|
206
|
+
- **Prefer CLC business-ready fields** precisely because they encode the
|
|
207
|
+
business definition — discover them via
|
|
208
|
+
`list_semantic_model_calculated_measures` /
|
|
209
|
+
`list_semantic_model_calculated_dimensions` before falling back to raw
|
|
210
|
+
fields.
|
|
211
|
+
- Binding note: a calculated measure takes `fieldName` only (**omit
|
|
212
|
+
`objectName`** — including it on a calculated measure throws
|
|
213
|
+
`UNKNOWN_EXCEPTION`) with `function: "UserAgg"`.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## 8. Color Encoding — Real Mechanism, Not `color_dim`/`stack_dim`
|
|
218
|
+
|
|
219
|
+
*(Encoding mechanics and the verified stacked-bar / `colorScale` payloads are
|
|
220
|
+
in `viz-authoring.md` §6 and §11 — this section covers the design intent and
|
|
221
|
+
the named-parameter myths.)*
|
|
222
|
+
|
|
223
|
+
**`color_dim` and `stack_dim` do not exist as parameters anywhere in the MCP
|
|
224
|
+
surface.** There is no automatic coloring for "templates when 2+ dimensions
|
|
225
|
+
are present" — nothing is automatic. Color is always an explicit encoding
|
|
226
|
+
entry:
|
|
227
|
+
|
|
228
|
+
```jsonc
|
|
229
|
+
"marks": {
|
|
230
|
+
"panes": {
|
|
231
|
+
"type": "Bar",
|
|
232
|
+
"encodings": [{ "type": "Color", "fieldKey": "<dim_field_key>" }]
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
- **Stacked bar** is NOT a `stack_dim` param — it is `type: "Bar"` +
|
|
238
|
+
a `Color` encoding on the second dimension + an explicit
|
|
239
|
+
`stack: { "isAutomatic": false, "isStacked": true }` block in `marks.panes`.
|
|
240
|
+
- **Any chart with a second dimension available** — add it as a `Color`
|
|
241
|
+
encoding by hand. When 2+ dimensions exist and you skip this, the chart
|
|
242
|
+
silently stays single-series; nothing warns you.
|
|
243
|
+
- **Diverging color scale** for signed / around-a-target measures (profit
|
|
244
|
+
variance, YoY change): set `"colorScale": "Diverging"` on the
|
|
245
|
+
Color-encoded measure's field binding. This is a real, verified param —
|
|
246
|
+
use it only when the measure is genuinely centered on zero or a target;
|
|
247
|
+
on all-positive data it misleads.
|
|
248
|
+
|
|
249
|
+
Cross-chart color coordination (same category → same color everywhere) is a
|
|
250
|
+
manual field-binding discipline (§4 above), not a dashboard-level setting.
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## 9. Filters — Dimensions Not Measures
|
|
255
|
+
|
|
256
|
+
**Filter on dimensions, never on measures**, use business-friendly labels,
|
|
257
|
+
avoid ID fields, and prefer filter fields that also appear as encodings in
|
|
258
|
+
the vizzes on the same dashboard (so the filter visibly affects what the
|
|
259
|
+
user is looking at).
|
|
260
|
+
|
|
261
|
+
Two mechanisms, both real:
|
|
262
|
+
|
|
263
|
+
1. **Per-viz filters** — `create_visualization`'s `filters[]` array:
|
|
264
|
+
`{ "fieldKey": ..., "type": "Dimension", "include": [...] }` (or
|
|
265
|
+
`exclude`) for categorical filters; `ValueRange`/`DateRange` for
|
|
266
|
+
continuous fields. A filter on a raw field is a WHERE (row filter); a
|
|
267
|
+
filter on an aggregated measure becomes a HAVING (group filter) — the
|
|
268
|
+
bucket is derived from the field, not chosen by you.
|
|
269
|
+
2. **Global dashboard filters** — `add_global_filter_to_dashboard`, which
|
|
270
|
+
constructs the full filter-widget JSON and places it in one call
|
|
271
|
+
(self-contained — no separate read/replace round trip). Required
|
|
272
|
+
inputs: `dashboardIdOrApiName`, `semanticModelIdOrName`, `objectName`,
|
|
273
|
+
`fieldName`, `placement`. Set `filterLabel` explicitly for a
|
|
274
|
+
business-friendly display name (defaults to the raw `fieldName` if
|
|
275
|
+
omitted — exactly the kind of technical-name leak §6 warns against).
|
|
276
|
+
|
|
277
|
+
**Always look up `objectName` — never guess it.** There is no
|
|
278
|
+
`sdm_fields[field]['objectName']` accessor. `objectName` is the field's
|
|
279
|
+
owning SDM data-object apiName, discovered via
|
|
280
|
+
`list_semantic_model_data_objects`; it is a **required** param on
|
|
281
|
+
`add_global_filter_to_dashboard`. Calculated fields have no owning object —
|
|
282
|
+
omit `objectName` for them in `create_visualization` (same rule as §7).
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## 10. Data-Presence Gate — Hard Stop Before Any Viz
|
|
287
|
+
|
|
288
|
+
**Confirm rows exist before building anything.** This is Rule 1 of the
|
|
289
|
+
parent skill (SKILL.md) and the primary defense against empty dashboards.
|
|
290
|
+
|
|
291
|
+
- `run_query` — `SELECT COUNT(*) AS n FROM <table>__dll` (or `__dlm`/`__dlc`)
|
|
292
|
+
for a raw-table presence check.
|
|
293
|
+
- `run_semantic_query` — for a model that traverses relationships, confirm
|
|
294
|
+
the query returns non-empty rows before charting from it (this doubles as
|
|
295
|
+
the Step 7 model-validation check in SKILL.md).
|
|
296
|
+
|
|
297
|
+
**If the result is zero rows or a "table does not exist" error, STOP.** Do
|
|
298
|
+
not call `create_visualization`. Report the empty/unmaterialized source to
|
|
299
|
+
the user and offer an alternative source or metric — see
|
|
300
|
+
`empty-source-handling.md` for exact wording.
|
|
301
|
+
|
|
302
|
+
**`query_data.py --count` and `lib.query.assert_has_rows` do not exist** —
|
|
303
|
+
those are constructs from an external scripting workflow, which has no
|
|
304
|
+
equivalent MCP tool. The gate is real; those helpers are not. Use
|
|
305
|
+
`run_query`/`run_semantic_query` directly.
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## 11. Dashboard Quality Checklist (MCP Reality)
|
|
310
|
+
|
|
311
|
+
**Business clarity**
|
|
312
|
+
- [ ] Every chart title states the business question it answers (≥3 words, no jargon)
|
|
313
|
+
- [ ] Field labels come from SDM `label` (via `list_semantic_model_*`), not raw apiNames
|
|
314
|
+
- [ ] No `_Clc`/`_mtc`/`_MTC`/`_CLC` suffixes or raw apiNames visible to the end user
|
|
315
|
+
- [ ] KPIs → Trends → Breakdowns → Correlations story order reflected in ascending `placement.row`
|
|
316
|
+
|
|
317
|
+
**Visual design**
|
|
318
|
+
- [ ] Metrics placed top/left (row 0) per the F-pattern or Z-pattern grid coordinates in §4
|
|
319
|
+
- [ ] Same dimension used for `Color` encoding across every chart that breaks down by that category
|
|
320
|
+
- [ ] Grid not overcrowded — deliberate empty rows/`cellSpacingX/Y` between widget groups
|
|
321
|
+
- [ ] Donut used only for dimension cardinality < 5; Bar used at ≥ 5
|
|
322
|
+
|
|
323
|
+
**UX**
|
|
324
|
+
- [ ] Every `add_global_filter_to_dashboard` call has an explicit business-friendly `filterLabel`
|
|
325
|
+
- [ ] Filters target dimensions, never measures; avoid ID fields
|
|
326
|
+
- [ ] Filter fields also appear as an encoding in at least one on-dashboard viz where practical
|
|
327
|
+
|
|
328
|
+
**Technical**
|
|
329
|
+
- [ ] `run_query`/`run_semantic_query` confirmed non-empty rows before any `create_visualization` call (§10)
|
|
330
|
+
- [ ] CLC/calculated measures use `function: "UserAgg"`, never re-aggregated with `Sum`/`Avg`
|
|
331
|
+
- [ ] `objectName` omitted for calculated measures/dimensions; looked up (never guessed) for raw fields and global filters
|
|
332
|
+
- [ ] Bar charts left to auto-sort descending, or `sortIntent` set deliberately
|
|
333
|
+
- [ ] YoY comparisons use `DatePartMonth` + `DatePartYear` period overlay, not a continuous timeline
|
|
334
|
+
- [ ] Viz created before the dashboard widget references it by `source.{id,name}` (creation order matters)
|
|
335
|
+
- [ ] Text/label widgets added via `edit_dashboard`'s `upsert_text_widget` + `place_widget_on_page` — the only supported path
|
|
336
|
+
- [ ] A `401`/auth-failure on any `create_*`/`update_*`/`run_*` call is treated as an expired org auth token or MCP connection — refresh org auth and reconnect the MCP server, then retry the same call; do not misdiagnose it as an empty-source or malformed-payload error
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## Not supported by the tableau-next-pilot MCP (do not attempt)
|
|
341
|
+
|
|
342
|
+
| Best-practices item | Why unsupported | Nearest achievable alternative |
|
|
343
|
+
|---|---|---|
|
|
344
|
+
| Map / geomap (point map, lat+lon+measure) | No map/geo mark type; lat/lon not routed | `Bar` chart by Region/Territory dimension |
|
|
345
|
+
| Flow / Sankey (`flow_sankey`, `flow_package_*`, `flow_simple_*`) | No flow/sankey mark type | Two `Bar` charts showing source→destination volumes separately |
|
|
346
|
+
| Conversion funnel | No funnel mark type | Sorted `Bar` by stage order; communicate each stage's count in the title/description |
|
|
347
|
+
| Dot matrix (2 dims + 2 measures) | No dot-matrix mark | `Circle` scatter (2 measures) or ranked `Bar` |
|
|
348
|
+
| Nightingale rose (measure-driven radius) | Radial layout supports `Donut` marks only — no measure-driven radius | Horizontal `Bar` |
|
|
349
|
+
| Radial spoke bars | Not available in current tools | `Bar` |
|
|
350
|
+
| Radial heatmap (2 ring dims + slice dim + measure) | Not available | `Square` heatmap (2D grid) |
|
|
351
|
+
| Map/Flow color variants (`geomap_*` encodings, `flow_uniform_fill`, node-size color rules) | No map or flow/sankey mark exists to carry them | N/A — see map/flow fallbacks above |
|
|
352
|
+
| Named layout patterns (`f_layout`, `z_layout`, `performance_overview`) with fixed filter/metric/viz counts | The patterns and their auto-select logic do not exist — only the raw 48-column grid | Hand-place widgets using the F-pattern/Z-pattern grid coordinates in §4; filter/metric/viz counts are an authoring choice, not a pattern constraint |
|