@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,529 @@
|
|
|
1
|
+
# Editing an Existing Visualization — `edit_visualization` / `update_visualization`
|
|
2
|
+
|
|
3
|
+
Load this when the request mutates a visualization that **already exists** (add/
|
|
4
|
+
remove/replace a shelf field, filter, forecast, sort, mark encoding, mark type, dual
|
|
5
|
+
axis, reference line, quick table calc, axis title, field label, field/axis
|
|
6
|
+
visibility, number/date format, table layout/totals, or fit) — not for building a new
|
|
7
|
+
chart (`viz-authoring.md`/`tasks/create-viz.md` instead).
|
|
8
|
+
|
|
9
|
+
## Contents
|
|
10
|
+
|
|
11
|
+
- 1. Contract
|
|
12
|
+
- 2. Operation-type quick reference
|
|
13
|
+
- 3. Filter-operator rules
|
|
14
|
+
- 4. Filter buckets and `{model:}` vs `{expression:}`
|
|
15
|
+
- 5. Add-then-filter heuristic
|
|
16
|
+
- 6. Sort operations — `targetField` vs `byField`
|
|
17
|
+
- 7. Reference lines: `field.function` vs `line.function`
|
|
18
|
+
- 8. Table-layout shelf operations (Columns/Groups)
|
|
19
|
+
- 9. Table totals and subtotals
|
|
20
|
+
- 10. Layout and fit
|
|
21
|
+
- 11. Field label, field-label visibility, axis visibility, number/date format
|
|
22
|
+
- 12. Measure Values shelf editing
|
|
23
|
+
- 13. Table calcs — `quickTableCalc` types and `computeUsing`
|
|
24
|
+
- 14. Logical views and HLV field naming
|
|
25
|
+
- 15. Persistence handoff — `update_visualization`
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 1. Contract
|
|
30
|
+
|
|
31
|
+
`edit_visualization`'s **required inputs are `visualizationId` and
|
|
32
|
+
`editOperations`** — never pass a raw `visualizationMetadata` blob as input, the
|
|
33
|
+
server resolves the metadata itself from the id:
|
|
34
|
+
|
|
35
|
+
- `visualizationId` — the id from `get_visualization` or a prior edit's response.
|
|
36
|
+
After `create_visualization`, call `get_visualization` first — create returns
|
|
37
|
+
only `{id, label, name}`, no editable metadata to chain from. If a call reports
|
|
38
|
+
the id was **not found**, call `get_visualization` with that id to reload it,
|
|
39
|
+
then retry.
|
|
40
|
+
- `editOperations` is a **JSON string** encoding an array of `{operationType, params}`
|
|
41
|
+
objects — build the array, then `JSON.stringify` it; never pass a raw array.
|
|
42
|
+
- Operations run **in order**, each seeing the previous one's result.
|
|
43
|
+
- The batch is **all-or-nothing** — one failing operation means none are applied.
|
|
44
|
+
- The result **renders inline automatically** — never call `render_visualization`
|
|
45
|
+
afterward.
|
|
46
|
+
- The result is **never persisted**. The response's `outputValues.visualizationMetadata`
|
|
47
|
+
holds the edited definition (for `update_visualization`, see §15) — there is no
|
|
48
|
+
separate top-level id field in the response. The server keeps per-`visualizationId`
|
|
49
|
+
working state: reuse the **same `visualizationId`** you already have (no need to
|
|
50
|
+
re-read it from the response) to chain straight into another `edit_visualization`
|
|
51
|
+
call, and each call's edits accumulate on top of the previous ones for that id.
|
|
52
|
+
|
|
53
|
+
## 2. Operation-type quick reference
|
|
54
|
+
|
|
55
|
+
Every operation targets a field already on a shelf/encoding/axis by
|
|
56
|
+
`{fieldName, objectName?, function?}` (`function` disambiguates same-name copies
|
|
57
|
+
under different aggregations, e.g. Sum vs Avg of the same measure — never a display
|
|
58
|
+
word like "Year", use the canonical values in the Field-functions note below).
|
|
59
|
+
|
|
60
|
+
| Category | Operations | Sharpest constraint |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| Shelf fields | `addFieldToRowsOrColumns`, `removeFieldFromRowsOrColumns`, `replaceFieldFromRowsOrColumns`, `changeFieldOnRowsOrColumns`, `reorderFieldsOnRowsOrColumns` | `changeFieldOnRowsOrColumns` changes an existing field's aggregation, discrete-vs-continuous display, and/or role in place — never adds/removes/swaps. Params `{field, shelfType, occurrence?, function?, displayCategory?, role?}` — supply at least one of `function` (an aggregation), `displayCategory` (`Discrete`/`Continuous`), or `role` (`Dimension`/`Measure`); omitted ones unchanged. Changing to a Measure requires a `function` (`Sum`/`Avg`/`Median`/`Min`/`Max`/`Count`/`CountD`/`Stdev`/`Stdevp`/`Var`/`Varp`); changing to a Dimension drops it. Examples: "average Sales instead of summing it" → `{field: {fieldName: "Sales", objectName: "Orders", function: "Sum"}, shelfType: "columns", function: "Avg"}`; "make Sales on rows discrete" → `{field: {...Sales}, shelfType: "rows", displayCategory: "Discrete"}`; "turn Category into a measure counting distinct values" → `{field: {fieldName: "Category", objectName: "Orders"}, shelfType: "columns", role: "Measure", function: "CountD"}`. Use `occurrence` (1-based) when the same field repeats on a shelf. `addFieldToRowsOrColumns` takes an optional 0-based `insertPosition` (appended when omitted). `reorderFieldsOnRowsOrColumns` moves a field already on the shelf to a new `insertPosition` without adding/removing anything — `insertPosition` is counted over the shelf's fields **after the moved field is taken out first**, so any spot right of its old position shifts left by one; `0` is the front, the shelf's last index the back. |
|
|
63
|
+
| Label | `changeLabel` | Renames the **visualization**, not on-chart title text. For a *field's* displayed caption use `editFieldLabel` (§11), not this. |
|
|
64
|
+
| Filters | `addFilter`, `editFilter`, `removeFilter` | See §3-5. The field reference lives inside a **`fields` array nested under a `filter` object** — `params: {filter: {fields: [...], operator, values}, bucket}` — never a bare `field:` key. |
|
|
65
|
+
| Forecasts | `addForecast`, `editForecast`, `removeForecast` | Timeseries-only (date field + measure). Omitting `forecastInterval` defaults to 4 periods at the date field's own granularity; `forecastInterval` is `{value, timeUnit}` with `timeUnit` ∈ `Minutes`/`Hours`/`Days`/`Weeks`/`Months`/`Quarters`/`Years` to override the period unit explicitly. Other defaults: `forecastModel` → `HoltWinters` (alternative: `RidgeRegression`); `includeBounds` → `true`; `confidenceLevel` → `95` (also `90`/`99`); `fillNullsWithZero` → `false`; `granularity` supports only `InferFromData`. `ignoreLastPeriods` (int) excludes trailing partial/incomplete periods from the fit. Use `occurrence` (1-based) when the target measure repeats on the shelf. `removeForecast` with no `measureField` removes ALL forecasts. Examples: "forecast Sales for 6 months" → `addForecast {measureField: {fieldName: "Sales", objectName: "Orders"}, dateDimensionField: {fieldName: "OrderDate", objectName: "Orders"}, forecastInterval: {value: 6, timeUnit: "Months"}}`; "forecast Revenue 12 months ahead using RidgeRegression" → `addForecast {measureField: {fieldName: "Revenue"}, dateDimensionField: {fieldName: "Date"}, forecastInterval: {value: 12, timeUnit: "Months"}, forecastModel: "RidgeRegression"}`; "change the Sales forecast to 12 months" → `editForecast {measureField: {fieldName: "Sales", objectName: "Orders"}, forecastInterval: {value: 12, timeUnit: "Months"}}`; "remove all forecasts" → `removeForecast {}`. |
|
|
66
|
+
| Sort | `sortAscending`, `sortDescending`, `sortByField`, `clearSort` | Only **discrete** fields can be sorted. Target is keyed **`targetField`**, never `field`. See §6. |
|
|
67
|
+
| Mark encodings | `addFieldToEncoding`, `removeFieldFromEncoding`, `replaceFieldOnEncoding` | `encodingType` ∈ Color(1 field)/Label(≤3, oldest dropped)/Tooltip(measure only, unlimited)/Size(1 field)/Detail(unlimited). On a **Table** layout only Color/Tooltip are valid slots (Label/Size/Detail error); a dimension dropped onto Color/Tooltip on a Table is coerced to a measure via `Attr`. "Measure Names" is named as `{field: {type: "MeasureNames"}}`, Color-only. `removeFieldFromEncoding`/`replaceFieldOnEncoding` must name the field **currently on that slot** — an arbitrary shelf field errors; read the current encoding first if unsure. Optional `targetField` edits/retypes only ONE field's mark on a multi-measure viz — that field must already be a mark on the visualization or the operation errors; omit it to apply to all marks. Examples: "color by Region" → `addFieldToEncoding {encodingType: "Color", field: {fieldName: "Region", objectName: "Orders"}}`; "add Revenue to the tooltip" → `addFieldToEncoding {encodingType: "Tooltip", field: {fieldName: "Revenue", objectName: "Orders"}}`; "size the bubbles by Sales" → `addFieldToEncoding {encodingType: "Size", field: {fieldName: "Sales", objectName: "Orders"}}`; "color by Region instead of by measure" → `replaceFieldOnEncoding {encodingType: "Color", existingField: {type: "MeasureNames"}, newField: {fieldName: "Region", objectName: "Orders"}}`. |
|
|
68
|
+
| Mark type | `changeMarkType` | Only changes shape (`Bar`/`Line`/`Circle`/`Square`/`Donut`/`Text`/`automatic`) — never moves/adds fields, so it cannot alone turn one chart type into another that needs a different shelf layout. Same optional `targetField` single-mark-only mechanism as mark encodings above. On a Table layout only `Text`/`Bar` are valid — any other type (including `automatic`) errors. Examples: "draw the marks as lines" → `{markType: "Line"}`; "let the visualization choose" → `{markType: "automatic"}`; "show the table as text" (Table layout) → `{markType: "Text"}`. |
|
|
69
|
+
| Layout and fit | `changeLayout`, `changeVisualizationFit` | See §10. |
|
|
70
|
+
| Dual axis | `addDualAxis`, `removeDualAxis`, `synchronizeAxis` | Both fields must already be **adjacent continuous fields on the same shelf** — add the second field first if missing. `primaryField` is the LEFT field, `secondaryField` the RIGHT (shelf order matters; the secondary moves onto the shared axis). `synchronization` ∈ `"None"` (default; independent scales) / `"ZeroPosition"` (zero lines align) / `"FullRange"` (shared range) — optional on `addDualAxis`, **required on `synchronizeAxis`**. `"ZeroPosition"` is invalid when both fields are the same kind of date function (use `FullRange`/`None`). `removeDualAxis`/`synchronizeAxis` name the same (primary, secondary) pair. When the same name+object+function pair still repeats on the shelf (can't disambiguate primary/secondary otherwise), add `primaryOccurrence`/`secondaryOccurrence` (1-based) to pick which copy. |
|
|
71
|
+
| Reference lines | `addReferenceLine`, `removeReferenceLine`, `editReferenceLine` | VizQL only. See §7 — the single trickiest disambiguation in this tool. |
|
|
72
|
+
| Table calcs | `applyTableCalc`, `editTableCalc`, `removeTableCalc` | Target must already be a shelf measure. `edit`/`removeTableCalc` error if the field has no existing calc. See §13 for `quickTableCalc.type` enum values and `computeUsing`. |
|
|
73
|
+
| Axis titles | `editAxisTitle`, `resetAxisTitle` | Target by field, not by axis position. |
|
|
74
|
+
| Field label | `editFieldLabel` | Renames a field's displayed caption (axis, row/column header, table header) — distinct from `changeLabel` (renames the viz). See §11. |
|
|
75
|
+
| Field-label visibility | `showFieldLabel` | Shows/hides the field labels on a whole shelf. Discrete fields only. See §11. |
|
|
76
|
+
| Axis visibility | `showAxis` | Shows/hides the axis for one continuous rows/columns field. See §11. |
|
|
77
|
+
| Number/date format | `setFieldFormat` | Currency/percentage/abbreviated/decimal-places number formats, or a date template. See §11. |
|
|
78
|
+
| Table-shelf fields | `addFieldToGroupsOrColumns`, `removeFieldFromGroupsOrColumns`, `replaceFieldFromGroupsOrColumns`, `reorderFieldsOnGroupsOrColumns`, `changeFieldOnGroupsOrColumns` | TABLE layout only — the table equivalent of the rows/columns ops above. See §8. |
|
|
79
|
+
| Table totals | `showGrandTotals`, `showSubtotals`, `editGrandTotalsLabel`, `editSubtotalsLabel` | TABLE layout only. See §9 — includes a reset-semantics gotcha (`{}` vs `{label:""}`). |
|
|
80
|
+
| Measure Values | `addFieldToMeasureValues`, `reorderFieldsOnMeasureValues`, `replaceFieldFromMeasureValues`, `removeFieldFromMeasureValues` | VizQL only, and only once the Measure Names/Measure Values construct already exists on the shelf. See §12. |
|
|
81
|
+
|
|
82
|
+
**Field functions** (the `function` on a field object) — use canonical values, never
|
|
83
|
+
display words: aggregations `Sum/Avg/Median/Count/CountD/Min/Max/Stdev/Stdevp/Var/
|
|
84
|
+
Varp/Attr` (`Count`/`CountD`/`Min`/`Max` also apply to dimensions; the rest are
|
|
85
|
+
measures only); date parts `DatePart{Year,Quarter,Month,Week,Day,Hour,Minute}`; date
|
|
86
|
+
truncations `DateTrunc{Year,Quarter,Month,Week,Day}`; fiscal variants of both exist
|
|
87
|
+
(`FiscalDatePartYear`, `FiscalDateTruncQuarter`, …). A date dropped onto a shelf buckets
|
|
88
|
+
by year by default — use `DatePartYear` explicitly for a "broken out by year" ask; for
|
|
89
|
+
finer/date-part filtering use a `DATEPART`/`DATETRUNC` expression (§4), not a shelf
|
|
90
|
+
function.
|
|
91
|
+
|
|
92
|
+
## 3. Filter-operator rules
|
|
93
|
+
|
|
94
|
+
1. **Never `Equals`/`DoesNotEquals`.** Always `In`/`NotIn` — `In` with one value is
|
|
95
|
+
the equivalent. "Color is Red" → `operator: "In", values: ["Red"]`.
|
|
96
|
+
2. **Always the `IgnoreCase` string variant** — `ContainsIgnoreCase`,
|
|
97
|
+
`StartsWithIgnoreCase`, `EndsWithIgnoreCase`, `DoesNotStartWithIgnoreCase`, etc.
|
|
98
|
+
Users almost never intend case-sensitive matching.
|
|
99
|
+
3. **Never `null`/`undefined` in `values`.** If both bounds of a range can't be
|
|
100
|
+
expressed with concrete values, pick a different operator.
|
|
101
|
+
|
|
102
|
+
Other operator families: comparison (`Between`, `LessThan(OrEqualTo)`,
|
|
103
|
+
`GreaterThan(OrEqualTo)`); null/empty (`IsNull`, `IsNotNull`, `IsEmpty`, `IsNotEmpty`);
|
|
104
|
+
relative-date (no values: `CurrentWeek`/`PreviousMonth`/`NextYear`… · with `values:[N]`:
|
|
105
|
+
`LastNDays`/`NextNWeeks`… — "last/next `<period>`" with no number → singular form,
|
|
106
|
+
with a number → `LastN`/`NextN` form, **except** "last 1 quarter" still uses the `LastN`
|
|
107
|
+
form with `values:[1]`); fiscal-date variants exist but only fire on an explicit
|
|
108
|
+
"fiscal" in the request ("this quarter" ≠ "this fiscal quarter"); date-to-date
|
|
109
|
+
(`CurrentYearToDate`, `PreviousQuarterToDate`, …, plain `{model:}`, no expression);
|
|
110
|
+
Top/Bottom-N (`operator: "AdvancedDimension"`, `bucket: "advancedDimensionFilter"`,
|
|
111
|
+
`topBottomCriteria: {topBottomLimit, isTop, expression}` — always this operator for
|
|
112
|
+
any top/bottom-N ask, never a value filter).
|
|
113
|
+
|
|
114
|
+
## 4. Filter buckets and `{model:}` vs `{expression:}`
|
|
115
|
+
|
|
116
|
+
Execution order / bucket meaning: `filter` (standard) → `contextFilter` (pre-
|
|
117
|
+
aggregation) → `aggregateFilter` (post-aggregation, e.g. `SUM(Sales) > 1000`) →
|
|
118
|
+
`tableCalcFilter` (on a table calc) → `advancedDimensionFilter` (Top/Bottom-N).
|
|
119
|
+
|
|
120
|
+
Decision rule for the filter's field reference:
|
|
121
|
+
|
|
122
|
+
- **`{model: "Object.Field"}`** — plain row-level comparison, no aggregation keyword.
|
|
123
|
+
"sales > 1000" → `{model: "Orders.Sales"}`.
|
|
124
|
+
- **`{expression: "SUM/AVG/…(...)"}`, `bucket: "aggregateFilter"`** — only when the
|
|
125
|
+
request names an aggregate concept explicitly ("total", "sum of", "average", "count
|
|
126
|
+
of"). Without one of those keywords, always use `{model:}`.
|
|
127
|
+
- **`{expression: "DATEPART(...)"}`/`"DATETRUNC(...)"`** — date-part/date-trunc
|
|
128
|
+
phrasing ("orders from 2020 and 2021", "after June 2022"). `DATEPART` returns an
|
|
129
|
+
integer; `DATETRUNC` returns a date (values as ISO strings).
|
|
130
|
+
- **`{expression: "RUNNING_*/RANK/WINDOW_*(...)"}`, `bucket: "tableCalcFilter"`** —
|
|
131
|
+
running total/avg/rank/window/moving/cumulative phrasing. These always wrap an
|
|
132
|
+
aggregate expression as their inner argument (e.g. `RANK(SUM([Orders].[Profit]),
|
|
133
|
+
'ASC')`).
|
|
134
|
+
|
|
135
|
+
**Whole-`params` shape.** The field reference (`{model:}` or `{expression:}`) is never
|
|
136
|
+
passed alone — it sits inside a **`fields` array**, itself nested under a **`filter`**
|
|
137
|
+
object, which is a sibling of `bucket` at the top of `params`:
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{"operationType": "addFilter", "params": {
|
|
141
|
+
"bucket": "filter",
|
|
142
|
+
"filter": {"fields": [{"model": "Orders.Region"}], "operator": "In", "values": ["East", "West"]}
|
|
143
|
+
}}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Full worked examples, each showing the complete `params` object:
|
|
147
|
+
|
|
148
|
+
- "sales greater than 1000" (raw field):
|
|
149
|
+
`{filter: {fields: [{model: "Orders.Sales"}], operator: "GreaterThan", values: [1000]}, bucket: "filter"}`
|
|
150
|
+
- "orders from 2020 and 2021":
|
|
151
|
+
`{filter: {fields: [{expression: "DATEPART('year', [Orders].[Order_Date])"}], operator: "In", values: [2020, 2021]}, bucket: "filter"}`
|
|
152
|
+
- "orders after June 2022" (DATETRUNC, ISO values):
|
|
153
|
+
`{filter: {fields: [{expression: "DATETRUNC('month', [Orders].[Order_Date])"}], operator: "GreaterThan", values: ["2022-06-01"]}, bucket: "filter"}`
|
|
154
|
+
- "where total sales > 10000" (aggregate):
|
|
155
|
+
`{filter: {fields: [{expression: "SUM([Orders].[Sales])"}], operator: "GreaterThan", values: [10000]}, bucket: "aggregateFilter"}`
|
|
156
|
+
- "where profit margin > 15%":
|
|
157
|
+
`{filter: {fields: [{expression: "SUM([Orders].[Profit])/SUM([Orders].[Sales])"}], operator: "GreaterThan", values: [0.15]}, bucket: "aggregateFilter"}`
|
|
158
|
+
- "where running sum of sales > 1000":
|
|
159
|
+
`{filter: {fields: [{expression: "RUNNING_SUM(SUM([Orders].[Sales]))"}], operator: "GreaterThan", values: [1000]}, bucket: "tableCalcFilter"}`
|
|
160
|
+
- "top 10 states by sales":
|
|
161
|
+
`{filter: {fields: [{model: "Orders.State"}], operator: "AdvancedDimension", topBottomCriteria: {topBottomLimit: 10, isTop: true, expression: "SUM([Orders].[Sales])"}}, bucket: "advancedDimensionFilter"}`
|
|
162
|
+
|
|
163
|
+
`editFilter` updates an existing filter's expression (same `params` shape, matched
|
|
164
|
+
against the current filter's field). `removeFilter` removes one by field reference:
|
|
165
|
+
`{filterField: {model: "Object.Field"}}`.
|
|
166
|
+
|
|
167
|
+
## 5. Add-then-filter heuristic
|
|
168
|
+
|
|
169
|
+
Add a field to a shelf **before** filtering it only when the user wants to *display*
|
|
170
|
+
that dimension broken out by value **and** restrict which values show, and it isn't
|
|
171
|
+
already on a shelf. A pure restriction ("filter to top 10 customers", "only show the
|
|
172
|
+
West region", "show orders from this year") is a single `addFilter` — never add a
|
|
173
|
+
field just because a filter names a dimension. If the field is already on a shelf,
|
|
174
|
+
filter/sort it in place.
|
|
175
|
+
|
|
176
|
+
Example (add-then-filter, two chained operations): "I want to see Region in East and
|
|
177
|
+
West" (no Region on a shelf yet) →
|
|
178
|
+
```json
|
|
179
|
+
[
|
|
180
|
+
{"operationType": "addFieldToRowsOrColumns", "params": {"field": {"fieldName": "Region", "objectName": "Orders"}, "shelfType": "rows"}},
|
|
181
|
+
{"operationType": "addFilter", "params": {"filter": {"fields": [{"model": "Orders.Region"}], "operator": "In", "values": ["East", "West"]}, "bucket": "filter"}}
|
|
182
|
+
]
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## 6. Sort operations — `targetField` vs `byField`
|
|
186
|
+
|
|
187
|
+
Sorts apply to a **discrete** field already on a shelf (chart rows/columns, or table
|
|
188
|
+
columns/groups — sort works on both layouts). The field being sorted is keyed
|
|
189
|
+
**`targetField`** — never `field` — `{fieldName, objectName?, function?}`. Every copy
|
|
190
|
+
of the field on the shelf stays in sync.
|
|
191
|
+
|
|
192
|
+
- **`sortAscending`/`sortDescending`** sort by the target field's OWN values (A→Z /
|
|
193
|
+
Z→A). If the field is already sorted by another field, these keep that by-field
|
|
194
|
+
sort and only flip direction; pass `sortType: "Alphabetic"` to force a plain
|
|
195
|
+
alphabetic sort and drop an existing by-field sort.
|
|
196
|
+
- **`sortByField`** sorts `targetField` by the AGGREGATED value of a second field,
|
|
197
|
+
`byField` `{fieldName, objectName?, function?}`. `byField.function` is the
|
|
198
|
+
aggregation — measures keep their default when omitted, dimensions default to
|
|
199
|
+
`Count` (dimensions allow only `Count`/`CountD`/`Min`/`Max`). `sortType`: `"Field"`
|
|
200
|
+
(default) or `"Nested"` (ordered within each group). `descending` (boolean) defaults
|
|
201
|
+
`true` — set `false` for smallest-first.
|
|
202
|
+
- **`clearSort`** removes the current sort — just `{targetField}`.
|
|
203
|
+
|
|
204
|
+
Worked examples:
|
|
205
|
+
|
|
206
|
+
- "Sort Category A to Z": `sortAscending {targetField: {fieldName: "Category", objectName: "Orders"}}`
|
|
207
|
+
- "Sort Category Z to A": `sortDescending {targetField: {fieldName: "Category", objectName: "Orders"}}`
|
|
208
|
+
- "Sort Region to ascending alphabetic" (Region currently sorted by another field):
|
|
209
|
+
`sortAscending {targetField: {fieldName: "Region", objectName: "Orders"}, sortType: "Alphabetic"}`
|
|
210
|
+
- "Sort States by total Sales, largest first":
|
|
211
|
+
`sortByField {targetField: {fieldName: "State", objectName: "Orders"}, byField: {fieldName: "Sales", objectName: "Orders", function: "Sum"}}`
|
|
212
|
+
- "Nest a descending sort on Region by sum of Profit":
|
|
213
|
+
`sortByField {targetField: {fieldName: "Region", objectName: "Orders"}, byField: {fieldName: "Profit", objectName: "Orders", function: "Sum"}, sortType: "Nested"}`
|
|
214
|
+
- "Sort Category by count of Orders, smallest first":
|
|
215
|
+
`sortByField {targetField: {fieldName: "Category", objectName: "Orders"}, byField: {fieldName: "Order_Id", objectName: "Orders", function: "Count"}, descending: false}`
|
|
216
|
+
- "Clear the sort on States": `clearSort {targetField: {fieldName: "State", objectName: "Orders"}}`
|
|
217
|
+
|
|
218
|
+
## 7. Reference lines: `field.function` vs `line.function`
|
|
219
|
+
|
|
220
|
+
The reference-line operations' single trickiest gotcha — two different `function`
|
|
221
|
+
fields that are easy to conflate:
|
|
222
|
+
|
|
223
|
+
- **`field.function`** selects *which shelf pill* the line attaches to (its own
|
|
224
|
+
aggregation) — e.g. when Sum-of-Sales and Avg-of-Sales are both on the shelf.
|
|
225
|
+
A phrase like **"sum of sales"** in a reference-line request names *this* field,
|
|
226
|
+
not the line's statistic.
|
|
227
|
+
- **`line.function`** is the line's *own* computed statistic (an average line, a max
|
|
228
|
+
line) — set it only when the request explicitly names the line's statistic
|
|
229
|
+
("add an **average** line", "a **max** line").
|
|
230
|
+
|
|
231
|
+
So "add a reference line to Sum of Sales" means: attach to the Sum-of-Sales pill and
|
|
232
|
+
use the *default* line (which is an average line when omitted) — it does **not**
|
|
233
|
+
mean a sum line. Two kinds of line: `{valueType: "Computation", function}` (a
|
|
234
|
+
statistic — `function` ∈ `Sum`/`Avg`/`Min`/`Max` for a measure axis or
|
|
235
|
+
`Max`/`Min`/`Today`/`Now` for a date axis; defaults to average for a measure /
|
|
236
|
+
latest-date for a date field when `line` is omitted entirely) or `{valueType:
|
|
237
|
+
"Value", value}` (a constant — a number for a measure axis or ISO date string for a
|
|
238
|
+
date axis). `line.computationField` (`{fieldName, objectName?, function?}`, need not
|
|
239
|
+
be on a shelf) lets the line compute from a *different* field than the one it's drawn
|
|
240
|
+
on. An optional label lives INSIDE `line`: `labelType` ∈ `None`/`Value`/`Computation`/
|
|
241
|
+
`Custom` (with `customLabel`); `scope` ∈ `Table` (default)/`Pane`/`Cell`; `lineColor`
|
|
242
|
+
is a top-level hex (default gray), accepted by both add and edit. Position a specific line among several on the same field
|
|
243
|
+
with `lineOccurrence` (1-based, counts lines); `occurrence` instead picks which
|
|
244
|
+
*shelf pill* when the field repeats — the two are independent and both may be needed
|
|
245
|
+
("2nd reference line on the 2nd Sum of Sales" → `occurrence: 2, lineOccurrence: 2`).
|
|
246
|
+
Beyond position, a line can also be disambiguated by matching its current
|
|
247
|
+
`computationFunction`, `value`, `labelText`, `scope`, or `lineValueType` — useful
|
|
248
|
+
when the request describes the line itself ("the average line", "the line labeled
|
|
249
|
+
Goal") rather than its position.
|
|
250
|
+
`removeReferenceLine` with no scope removes every matching line on the field.
|
|
251
|
+
`editReferenceLine` changes exactly ONE line and **errors if the description
|
|
252
|
+
matches more than one** — narrow with `occurrence`/`lineOccurrence`/`scope`/one of
|
|
253
|
+
the descriptive selectors above until it's unambiguous. Each attribute on
|
|
254
|
+
`editReferenceLine` edits independently: omitting `line` keeps the line's current
|
|
255
|
+
value/function; a `line` change keeps the current label unless you also pass
|
|
256
|
+
`labelType`/`customLabel`; passing only `scope` or `lineColor` changes just that
|
|
257
|
+
attribute and leaves everything else (value, label) untouched. A label passed at
|
|
258
|
+
the top level of `params` wins over one nested inside `line`.
|
|
259
|
+
|
|
260
|
+
Worked examples:
|
|
261
|
+
|
|
262
|
+
- "add an average line to Sales" (default line): `addReferenceLine {field: {fieldName: "Sales", objectName: "Orders"}}`
|
|
263
|
+
- "add a target line at 5000 on Sales" (constant): `addReferenceLine {field: {fieldName: "Sales", objectName: "Orders"}, line: {valueType: "Value", value: 5000}}`
|
|
264
|
+
- "add a line at 100 on avg of Sales labeled 'target' in green": `addReferenceLine {field: {fieldName: "Sales", objectName: "Orders", function: "Avg"}, line: {valueType: "Value", value: 100, labelType: "Custom", customLabel: "target"}, lineColor: "#00FF00"}`
|
|
265
|
+
- "add a sum line for Sales per pane": `addReferenceLine {field: {fieldName: "Sales", objectName: "Orders"}, line: {valueType: "Computation", function: "Sum"}, scope: "Pane"}`
|
|
266
|
+
- "add an average line on Sales computed using sum of Discount": `addReferenceLine {field: {...Sales}, line: {valueType: "Computation", function: "Avg", computationField: {fieldName: "Discount", objectName: "Orders", function: "Sum"}}}`
|
|
267
|
+
- "make the Sales reference line red" (color only, omit `line`): `editReferenceLine {field: {...Sales}, lineColor: "#FF0000"}`
|
|
268
|
+
- "remove the 2nd reference line on avg of Sales": `removeReferenceLine {field: {fieldName: "Sales", objectName: "Orders", function: "Avg"}, lineOccurrence: 2}`
|
|
269
|
+
- "update the 2nd reference line on the 1st Sum of Sales to a max line" (BOTH selectors): `editReferenceLine {field: {fieldName: "Sales", objectName: "Orders", function: "Sum"}, occurrence: 1, lineOccurrence: 2, line: {valueType: "Computation", function: "Max"}}`
|
|
270
|
+
|
|
271
|
+
## 8. Table-layout shelf operations (Columns/Groups)
|
|
272
|
+
|
|
273
|
+
TABLE-layout visualizations use two shelves — **Columns** (fields shown as table
|
|
274
|
+
columns) and **Groups** (fields those columns are grouped by) — instead of
|
|
275
|
+
rows/columns. These operations are the table equivalent of §2's shelf-field row and
|
|
276
|
+
**do not apply to a VizQL chart** — convert to Table first with `changeLayout` (§10),
|
|
277
|
+
or these error. `shelfType` names the shelf: `"columns"` or `"groups"`; the target
|
|
278
|
+
field nests under a `"field"` object exactly like `addFieldToRowsOrColumns`, using
|
|
279
|
+
the same canonical `function` values.
|
|
280
|
+
|
|
281
|
+
- `addFieldToGroupsOrColumns` — `{field, shelfType, insertPosition?}` (0-based;
|
|
282
|
+
appended when omitted).
|
|
283
|
+
- `removeFieldFromGroupsOrColumns` — `{field, shelfType, occurrence?}` (1-based,
|
|
284
|
+
picks the copy).
|
|
285
|
+
- `replaceFieldFromGroupsOrColumns` — `{existingField, newField, shelfType,
|
|
286
|
+
occurrence?}`, keeping the replaced field's position.
|
|
287
|
+
- `reorderFieldsOnGroupsOrColumns` — `{field, shelfType, insertPosition, occurrence?}`
|
|
288
|
+
— moves a field already on the shelf; adds/removes nothing.
|
|
289
|
+
- `changeFieldOnGroupsOrColumns` — changes an EXISTING table-shelf field's
|
|
290
|
+
aggregation and/or role in place: `{field, shelfType, occurrence?, function?,
|
|
291
|
+
role?}` — supply at least one of `function` (an aggregation) or `role`
|
|
292
|
+
(`"Dimension"`/`"Measure"`); the omitted one is unchanged. Changing to a Measure
|
|
293
|
+
requires `function` (`Sum`/`Avg`/`Median`/`Min`/`Max`/`Count`/`CountD`/`Stdev`/
|
|
294
|
+
`Stdevp`/`Var`/`Varp`); changing to a Dimension drops the function. **No
|
|
295
|
+
`displayCategory` param** (unlike `changeFieldOnRowsOrColumns`) — table fields are
|
|
296
|
+
always discrete.
|
|
297
|
+
|
|
298
|
+
Worked examples:
|
|
299
|
+
|
|
300
|
+
- "Add Region to the table columns": `addFieldToGroupsOrColumns {field: {fieldName: "Region", objectName: "Orders"}, shelfType: "columns"}`
|
|
301
|
+
- "Group the table by Category": `addFieldToGroupsOrColumns {field: {fieldName: "Category", objectName: "Orders"}, shelfType: "groups"}`
|
|
302
|
+
- "Add total Sales as the first table column": `addFieldToGroupsOrColumns {field: {fieldName: "Sales", objectName: "Orders", function: "Sum"}, shelfType: "columns", insertPosition: 0}`
|
|
303
|
+
- "Remove Sales from the table columns": `removeFieldFromGroupsOrColumns {field: {fieldName: "Sales", objectName: "Orders", function: "Sum"}, shelfType: "columns"}`
|
|
304
|
+
- "Swap Category for Segment in the table groups": `replaceFieldFromGroupsOrColumns {existingField: {fieldName: "Category", objectName: "Orders"}, newField: {fieldName: "Segment", objectName: "Orders"}, shelfType: "groups"}`
|
|
305
|
+
- "Move Sales to the first table column": `reorderFieldsOnGroupsOrColumns {field: {fieldName: "Sales", objectName: "Orders"}, shelfType: "columns", insertPosition: 0}`
|
|
306
|
+
- "Average Sales in the table instead of summing it" (Sum of Sales on columns): `changeFieldOnGroupsOrColumns {field: {fieldName: "Sales", objectName: "Orders", function: "Sum"}, shelfType: "columns", function: "Avg"}`
|
|
307
|
+
- "Aggregate the Category column as a count of distinct values": `changeFieldOnGroupsOrColumns {field: {fieldName: "Category", objectName: "Orders"}, shelfType: "columns", role: "Measure", function: "CountD"}`
|
|
308
|
+
|
|
309
|
+
## 9. Table totals and subtotals
|
|
310
|
+
|
|
311
|
+
TABLE layout only. Two separate summary rows — **do not confuse them**:
|
|
312
|
+
|
|
313
|
+
- **Grand totals** (`showGrandTotals`, `editGrandTotalsLabel`) — ONE row summarizing
|
|
314
|
+
the whole table. Pick this for "total"/"grand total"/"total row"/"summary row" with
|
|
315
|
+
no mention of groups.
|
|
316
|
+
- **Subtotals** (`showSubtotals`, `editSubtotalsLabel`) — one row PER GROUP boundary.
|
|
317
|
+
Pick this for "subtotal"/"group total"/"total for each group"/"totals per category".
|
|
318
|
+
|
|
319
|
+
Both toggle ROW flags only — there is no `columns` parameter; column subtotals are
|
|
320
|
+
never legal (`showSubtotals` rejects `columns: true`), and `showGrandTotals` preserves
|
|
321
|
+
an existing column-grand-total flag but does not toggle it.
|
|
322
|
+
|
|
323
|
+
- `isVisible` (required) shows (`true`) or hides (`false`) the row.
|
|
324
|
+
- `position` (optional): `"Start"` (above the table, or above each group) or `"End"`
|
|
325
|
+
(below) — map "top"/"above"/"first" → `"Start"`, "bottom"/"below"/"last"/"at the
|
|
326
|
+
end" → `"End"`. Omit when unsaid — grand totals default to `"End"`; subtotals
|
|
327
|
+
follow the grand totals. **`position` is rewritten on EVERY call** — when only
|
|
328
|
+
hiding a row, pass its current position to keep where it sits.
|
|
329
|
+
- `editGrandTotalsLabel`/`editSubtotalsLabel` rename the row (`{label: "text"}`;
|
|
330
|
+
defaults read "Grand Total"/"Subtotal"). **To reset to the default** — "reset it",
|
|
331
|
+
"clear the name", "remove the custom label" — send **EMPTY params `{}`** and leave
|
|
332
|
+
`label` out entirely; **NEVER send `{label: ""}`** (an empty or all-whitespace
|
|
333
|
+
label is rejected). These only rename a row the table already has (shown or
|
|
334
|
+
hidden), so emit the rename ALONE — add a `showGrandTotals`/`showSubtotals` first
|
|
335
|
+
only when the table has no such row yet.
|
|
336
|
+
- **Don't reach for these just because "total" appears** — they add/rename a summary
|
|
337
|
+
ROW only, never a column or a per-row figure: a measure to display/aggregate →
|
|
338
|
+
`addFieldToGroupsOrColumns` (or `addFieldToRowsOrColumns`) with `function: "Sum"`;
|
|
339
|
+
a per-row calc (running total, percent of total, rank, moving average) →
|
|
340
|
+
`applyTableCalc` (§13); a totals COLUMN → `addFieldToGroupsOrColumns`; renaming the
|
|
341
|
+
viz → `changeLabel`.
|
|
342
|
+
|
|
343
|
+
Worked examples:
|
|
344
|
+
|
|
345
|
+
- "Add a grand total row to this table": `showGrandTotals {isVisible: true}`
|
|
346
|
+
- "Show totals at the top of the table": `showGrandTotals {isVisible: true, position: "Start"}`
|
|
347
|
+
- "Turn off the total row": `showGrandTotals {isVisible: false}`
|
|
348
|
+
- "Rename the grand total row to 'Overall Total'": `editGrandTotalsLabel {label: "Overall Total"}`
|
|
349
|
+
- "Reset the grand total label to the default": `editGrandTotalsLabel {}`
|
|
350
|
+
- "Show subtotals for each group": `showSubtotals {isVisible: true}`
|
|
351
|
+
- "Add group totals at the top of each group": `showSubtotals {isVisible: true, position: "Start"}`
|
|
352
|
+
- "Rename the subtotal label to 'Group Total'": `editSubtotalsLabel {label: "Group Total"}`
|
|
353
|
+
- "Clear the subtotal label" (a reset — params stay empty, NOT `{label: ""}`): `editSubtotalsLabel {}`
|
|
354
|
+
|
|
355
|
+
## 10. Layout and fit
|
|
356
|
+
|
|
357
|
+
- **`changeLayout`** switches the WHOLE visualization between the `Vizql` (chart) and
|
|
358
|
+
`Table` layouts, migrating placed fields onto the target layout's shelves. Unlike
|
|
359
|
+
`changeMarkType` (mark shape only), this changes the layout itself. `targetLayout`
|
|
360
|
+
is a canonical value: `"Vizql"` or `"Table"` — nothing else (a donut/pie is the
|
|
361
|
+
Radial layout and a sankey the Flow layout; this operation cannot switch to either).
|
|
362
|
+
Pick by what the user wants to see: a bar/line/area/scatter graph → `"Vizql"`; a
|
|
363
|
+
text table → `"Table"`.
|
|
364
|
+
- "Turn this into a table" → `{targetLayout: "Table"}`
|
|
365
|
+
- "Make this a bar chart again" → `{targetLayout: "Vizql"}`
|
|
366
|
+
- **`changeVisualizationFit`** sets how the viz scales to fit its container: `{fit:
|
|
367
|
+
"Standard"|"Entire"|"RowHeadersWidth"}`. `"Standard"` is default sizing (VizQL and
|
|
368
|
+
Table); `"Entire"` fills the whole view (VizQL only); `"RowHeadersWidth"` fits the
|
|
369
|
+
row-header width (Table only).
|
|
370
|
+
- "Make this chart fit the entire view" → `{fit: "Entire"}`
|
|
371
|
+
- "Fit the table to the row headers" → `{fit: "RowHeadersWidth"}`
|
|
372
|
+
|
|
373
|
+
Chaining example: "Turn this into a table and add a grand total row" →
|
|
374
|
+
`changeLayout {targetLayout: "Table"}`, then `showGrandTotals {isVisible: true}` (fields
|
|
375
|
+
must land on the table's shelves before any table-specific operation references them).
|
|
376
|
+
|
|
377
|
+
## 11. Field label, field-label visibility, axis visibility, number/date format
|
|
378
|
+
|
|
379
|
+
Four distinct single-field cosmetic operations — do not conflate them with
|
|
380
|
+
`changeLabel` (renames the visualization itself, §2) or `editAxisTitle`/
|
|
381
|
+
`resetAxisTitle` (sets a custom axis title text, independent of the field's own
|
|
382
|
+
label).
|
|
383
|
+
|
|
384
|
+
- **`editFieldLabel`** renames a field's displayed CAPTION — wherever the field's
|
|
385
|
+
name appears (axis, row/column header, table header): `{field, label,
|
|
386
|
+
occurrence?}`. Pass `label` to rename; an empty string reverts to the default
|
|
387
|
+
name. Works on any layout.
|
|
388
|
+
- "Rename the Sales axis to Revenue" → `{field: {fieldName: "Sales", objectName: "Orders", function: "Sum"}, label: "Revenue"}`
|
|
389
|
+
- "Reset the Sales label" → `{field: {...Sales}, label: ""}`
|
|
390
|
+
- **`showFieldLabel`** shows/hides the field labels on the WHOLE SHELF a field sits
|
|
391
|
+
on (affects every field on that shelf, not just the one named): `{field,
|
|
392
|
+
isVisible, occurrence?}`. Only supported on Rows, Columns, Groups, and Levels
|
|
393
|
+
shelves (VizQL/Table/Flow), and only for DISCRETE fields (a discrete measure can be
|
|
394
|
+
toggled; a continuous field errors).
|
|
395
|
+
- "Hide the row field labels" → `{field: {fieldName: "Region", objectName: "Orders"}, isVisible: false}`
|
|
396
|
+
- **`showAxis`** shows/hides the axis for one CONTINUOUS field on the Rows or Columns
|
|
397
|
+
shelf: `{field, isVisible, occurrence?}`.
|
|
398
|
+
- "Hide the Sales axis" → `{field: {fieldName: "Sales", objectName: "Orders", function: "Sum"}, isVisible: false}`
|
|
399
|
+
- **`setFieldFormat`** changes how a field's VALUES are displayed — not its
|
|
400
|
+
aggregation/role/position (`changeFieldOnRowsOrColumns`) or its axis title
|
|
401
|
+
(`editAxisTitle`). Target is keyed **`targetField`** (`{fieldName, objectName?,
|
|
402
|
+
function?}`) and must already be on a shelf or mark encoding; every copy of the
|
|
403
|
+
field is reformatted together.
|
|
404
|
+
- Number format: `format: {type: "Number"|"Percentage"|"Currency"|"NumberShort"|
|
|
405
|
+
"PercentageShort"|"CurrencyShort" (the "Short" forms abbreviate to K/M/B),
|
|
406
|
+
decimalPlaces? (0 for whole numbers, 2 for cents), displayUnits? ("Auto"|"None"|
|
|
407
|
+
"K"|"M"|"B"|"G"), prefix?, suffix?, negativeValuesFormat? ("Auto"|"Parenthesis"|
|
|
408
|
+
"Minus"), includeThousandSeparator?}`.
|
|
409
|
+
- Date format: `format: {dateTemplate: "MM/dd/yyyy"|"yyyy-MM-dd"|...}`. A
|
|
410
|
+
date/datetime field takes only a `dateTemplate`; a non-date field only a number
|
|
411
|
+
format (mixing errors); a date MEASURE accepts a `dateTemplate` only when
|
|
412
|
+
aggregated with `Min`, `Max`, or `Attr`.
|
|
413
|
+
- "Show Sales as currency" → `{targetField: {fieldName: "Sales", objectName: "Orders", function: "Sum"}, format: {type: "Currency"}}`
|
|
414
|
+
- "Format Discount as a percent with 1 decimal place" → `{targetField: {fieldName: "Discount", objectName: "Orders"}, format: {type: "Percentage", decimalPlaces: 1}}`
|
|
415
|
+
- "Abbreviate Sales to millions" → `{targetField: {...Sales}, format: {type: "NumberShort", displayUnits: "M"}}`
|
|
416
|
+
- "Show Order Date as MM/DD/YYYY" → `{targetField: {fieldName: "Order_Date", objectName: "Orders"}, format: {dateTemplate: "MM/dd/yyyy"}}`
|
|
417
|
+
|
|
418
|
+
## 12. Measure Values shelf editing
|
|
419
|
+
|
|
420
|
+
The Measure Values shelf holds a list of measures pivoted by a Measure Names field on
|
|
421
|
+
rows or columns so multiple measures share one axis (e.g. "show Sum of Amount and
|
|
422
|
+
Count on the same axis"). VizQL only. **Creating** the construct on a brand-new,
|
|
423
|
+
empty visualization is covered in `viz-authoring.md` (add the special Measure Names/
|
|
424
|
+
Measure Values field via `addFieldToRowsOrColumns` with `{field: {type:
|
|
425
|
+
"MeasureNames"|"MeasureValues"}}` — only valid before any field is placed). Once the
|
|
426
|
+
construct exists, EDIT it with these operations:
|
|
427
|
+
|
|
428
|
+
- `addFieldToMeasureValues` — `{field, insertPosition?}` (appends when omitted; only
|
|
429
|
+
measures — dimensions error).
|
|
430
|
+
- `reorderFieldsOnMeasureValues` — `{field, insertPosition, occurrence?}` (moves a
|
|
431
|
+
measure already on the shelf).
|
|
432
|
+
- `replaceFieldFromMeasureValues` — `{existingField, newField, occurrence?}` — swaps a
|
|
433
|
+
measure already on the shelf for one that is not, keeping the replaced measure's
|
|
434
|
+
slot.
|
|
435
|
+
- `removeFieldFromMeasureValues` — `{field, occurrence?}`.
|
|
436
|
+
- The same measure can sit on the shelf more than once — `occurrence` (1-based)
|
|
437
|
+
picks which copy.
|
|
438
|
+
|
|
439
|
+
Worked examples:
|
|
440
|
+
|
|
441
|
+
- "Show Sum of Sales and Profit on the same axis" (Sum of Sales already on an axis, add Profit): `addFieldToMeasureValues {field: {fieldName: "Profit", objectName: "Orders", function: "Sum"}}`
|
|
442
|
+
- "Add Profit at position 0 on Measure Values": `addFieldToMeasureValues {field: {fieldName: "Profit", objectName: "Orders", function: "Sum"}, insertPosition: 0}`
|
|
443
|
+
- "Move Sales to position 1 on Measure Values": `reorderFieldsOnMeasureValues {field: {fieldName: "Sales", objectName: "Orders", function: "Sum"}, insertPosition: 1}`
|
|
444
|
+
- "Replace Profit with Quantity on Measure Values" (Profit on the shelf, Quantity not): `replaceFieldFromMeasureValues {existingField: {fieldName: "Profit", objectName: "Orders", function: "Sum"}, newField: {fieldName: "Quantity", objectName: "Orders", function: "Sum"}}`
|
|
445
|
+
- "Remove the second Sum of Sales from Measure Values": `removeFieldFromMeasureValues {field: {fieldName: "Sales", objectName: "Orders", function: "Sum"}, occurrence: 2}`
|
|
446
|
+
|
|
447
|
+
## 13. Table calcs — `quickTableCalc` types and `computeUsing`
|
|
448
|
+
|
|
449
|
+
`applyTableCalc`/`editTableCalc`/`removeTableCalc` target a measure already on a
|
|
450
|
+
shelf. `applyTableCalc` adds; `editTableCalc` changes (errors if the field has no
|
|
451
|
+
existing calc); `removeTableCalc` clears (errors if none).
|
|
452
|
+
|
|
453
|
+
`quickTableCalc.type` — canonical values: `RunningSum`, `RunningAvg`, `RunningMin`,
|
|
454
|
+
`RunningMax`, `Difference`, `PercentDifference`, `PercentOfTotal`, `Rank`,
|
|
455
|
+
`RankModified`, `RankDense`, `RankUnique`, `Percentile`, `MovingSum`, `MovingAverage`,
|
|
456
|
+
`MovingMin`, `MovingMax`.
|
|
457
|
+
|
|
458
|
+
- **Moving types** (`MovingSum`/`MovingAverage`/`MovingMin`/`MovingMax`) accept
|
|
459
|
+
`previousValues`, `nextValues`, `useCurrentValue`. `MovingAverage` defaults to
|
|
460
|
+
`previousValues: 2, nextValues: 0, useCurrentValue: true`; the other moving types
|
|
461
|
+
have no defaults — supply them explicitly.
|
|
462
|
+
- **Ranking types** (`Rank`/`RankModified`/`RankDense`/`RankUnique`) accept `order`
|
|
463
|
+
(`"Ascending"`/`"Descending"`). `Rank` defaults to `"Descending"`; the other
|
|
464
|
+
ranking types have no default.
|
|
465
|
+
|
|
466
|
+
`computeUsing` (optional on `applyTableCalc`/`editTableCalc`) — `{type,
|
|
467
|
+
useOrderByForExtraFields?}`. `type` is the calc's addressing direction:
|
|
468
|
+
`TableAcross`, `TableDown`, `TableAcrossThenDown`, `TableDownThenAcross`, `PaneAcross`,
|
|
469
|
+
`PaneDown`, `PaneAcrossThenDown`, `PaneDownThenAcross`, `Cell`. `useOrderByForExtraFields`
|
|
470
|
+
(boolean) orders the extra (non-addressing) fields by whatever sort is applied to
|
|
471
|
+
them.
|
|
472
|
+
|
|
473
|
+
Worked examples:
|
|
474
|
+
|
|
475
|
+
- "show Sales as a running total": `applyTableCalc {field: {fieldName: "Sales", objectName: "Orders"}, quickTableCalc: {type: "RunningSum"}}`
|
|
476
|
+
- "show a 3-period moving average of Sales": `applyTableCalc {field: {...Sales}, quickTableCalc: {type: "MovingAverage", previousValues: 2, nextValues: 0, useCurrentValue: true}}`
|
|
477
|
+
- "compute the running total down the table instead": `editTableCalc {field: {...Sales}, quickTableCalc: {type: "RunningSum"}, computeUsing: {type: "TableDown"}}`
|
|
478
|
+
- "remove the table calculation from Sales": `removeTableCalc {field: {...Sales}}`
|
|
479
|
+
|
|
480
|
+
## 14. Logical views and HLV field naming
|
|
481
|
+
|
|
482
|
+
When a field lives under `semanticLogicalViews[].semanticUnions[].
|
|
483
|
+
semanticMappedFields[]`, use the **logical view's** apiName as `objectName` — never
|
|
484
|
+
the union's; the logical view is the queryable object (e.g. field "Full_Name20" in
|
|
485
|
+
`Manager_Union44` → `objectName: "Manager_oh"`). Hierarchical logical views (HLVs)
|
|
486
|
+
additionally expose:
|
|
487
|
+
|
|
488
|
+
- **Me/My-team filters** via two hardcoded field names: `SemanticManagerUserIdPath`
|
|
489
|
+
(manager hierarchy) / `SemanticRoleUserIdPath` (role hierarchy) — "Me" uses
|
|
490
|
+
`EndsWithIgnoreCase`, "My team" uses `ContainsIgnoreCase`, both against
|
|
491
|
+
`{expression: USERID18()}`. Me example: `{filter: {fields: [{model:
|
|
492
|
+
"Manager_oh.SemanticManagerUserIdPath"}], operator: "EndsWithIgnoreCase", values:
|
|
493
|
+
["{expression: USERID18()}"]}, bucket: "filter"}` (My team: same with
|
|
494
|
+
`ContainsIgnoreCase`).
|
|
495
|
+
- **Level-based display** via `hierarchyLevel` on a field object — e.g.
|
|
496
|
+
`{fieldName: "Full_Name", hierarchyLevel: 1, objectName: "Manager_oh",
|
|
497
|
+
displayCategory: "Discrete", role: "Dimension", type: "Field"}`.
|
|
498
|
+
- **Per-level filters** via `ANCESTOR_AT_LEVEL(n, [Object].[Field])` expressions —
|
|
499
|
+
e.g. `{expression: "ANCESTOR_AT_LEVEL(1, [Manager_oh].[Full_Name])", operator:
|
|
500
|
+
"In", values: ["Sarah Chen (CEO)"]}`.
|
|
501
|
+
|
|
502
|
+
## 15. Persistence handoff — `update_visualization`
|
|
503
|
+
|
|
504
|
+
`edit_visualization` never saves — every edit (or chain of edits) is a preview only.
|
|
505
|
+
**Never call `update_visualization` as an automatic follow-up.** After every
|
|
506
|
+
successful `edit_visualization` call — even small or chained edits — your very next
|
|
507
|
+
reply MUST end by asking, verbatim: **"Do you want to save the visualization?"**
|
|
508
|
+
Call `update_visualization` **only** on confirmation given *after seeing that
|
|
509
|
+
preview* (e.g. "yes", "save it") — this applies even when the
|
|
510
|
+
original request already said "save it" in the same message as the edit; that
|
|
511
|
+
upfront wording does not substitute for a confirmation given after the preview
|
|
512
|
+
renders. See `tasks/edit-viz.md` for the full flow.
|
|
513
|
+
|
|
514
|
+
**`update_visualization` takes only `visualizationId` — never pass a `visualizationMetadata`
|
|
515
|
+
body.** The server tracks the latest working definition for that id server-side (whatever
|
|
516
|
+
`edit_visualization` last produced for it) and persists that; there's nothing else to
|
|
517
|
+
pass. It does not accept or need the workspace/SDM info — those are already fixed on the
|
|
518
|
+
existing visualization record. Its response is just `{updateStatus: "SUCCESS"}` — no
|
|
519
|
+
metadata, no id.
|
|
520
|
+
|
|
521
|
+
**Update is in-place only — it does not relocate the viz.** It writes back over the
|
|
522
|
+
same visualization (by `visualizationId`), so it updates rather than creates a copy,
|
|
523
|
+
and it does NOT move the viz to another workspace or re-point it at a different
|
|
524
|
+
semantic model.
|
|
525
|
+
|
|
526
|
+
**Round-trips back into `edit_visualization` without a re-fetch.** You already have the
|
|
527
|
+
`visualizationId` from before calling `update_visualization` — reuse that same id
|
|
528
|
+
directly in another `edit_visualization` call (§1) without a `get_visualization`
|
|
529
|
+
round trip; the server's working state for that id already reflects the saved edits.
|