-
Notifications
You must be signed in to change notification settings - Fork 2
feat(trogonstack-datadog): add dashboard tab reference #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
146 changes: 146 additions & 0 deletions
146
plugins/trogonstack-datadog/skills/datadog-design-dashboard/references/tabs.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| # Tabs | ||
|
|
||
| Dashboard tabs organize top-level widget groups into named sections. Tabs reduce scroll fatigue on large dashboards and let viewers navigate directly to the layer they care about during an incident. | ||
|
|
||
| --- | ||
|
|
||
| ## When to Use Tabs | ||
|
|
||
| | Groups | Recommendation | | ||
| |--------|----------------| | ||
| | 1-6 | Tabs add friction without saving scroll. Skip. | | ||
| | 7-12 | Consider tabs if groups span distinct observability layers. | | ||
| | 13+ | Tabs strongly recommended. A 15-group dashboard is unusable without them. | | ||
|
|
||
| --- | ||
|
|
||
| ## Tab Organization Pattern | ||
|
|
||
| Group tabs by observability layer, not by arbitrary concern. Each tab answers a different question during an incident. | ||
|
|
||
| | Tab | Question | Typical groups | | ||
| |-----|----------|---------------| | ||
| | **Business** or **Service Health** | Are customers affected? | Service health, domain groups (by bounded context), domain-specific drill-downs | | ||
| | **Platform** | Is the application pipeline healthy? | CQRS/ES, message queues, job processors, database clients, logging | | ||
| | **Infrastructure** | Are the underlying systems healthy? | HTTP servers, pods, RDS, BEAM, DNS, load balancers | | ||
| | **Testing** | How did the last load test go? | k6, Locust, or other load test groups | | ||
|
|
||
| Adapt the tab names and groupings to the service. A service with no CQRS layer does not need a Platform tab. A service with no load tests does not need a Testing tab. | ||
|
|
||
| --- | ||
|
|
||
| ## JSON Schema | ||
|
|
||
| Tabs are a top-level dashboard field, sibling to `widgets`. Widgets stay in a flat array; tabs reference them by position. | ||
|
|
||
| ```json | ||
| { | ||
| "tabs": [ | ||
| { | ||
| "name": "Business", | ||
| "widget_ids": ["@1", "@2", "@5"] | ||
| }, | ||
| { | ||
| "name": "Platform", | ||
| "widget_ids": ["@3", "@4", "@8"] | ||
| }, | ||
| { | ||
| "name": "Infrastructure", | ||
| "widget_ids": ["@6", "@7"] | ||
| } | ||
| ], | ||
| "widgets": [ ... ] | ||
| } | ||
| ``` | ||
|
|
||
| ### Field reference | ||
|
|
||
| | Field | Type | Required | Notes | | ||
| |-------|------|----------|-------| | ||
| | `name` | string | yes | Display name of the tab. NOT `tab_name`. | | ||
| | `id` | string (UUID) | no | Auto-generated by the Terraform provider using `uuid5(Nil, "tab-{index}")`. Include explicitly for stability across applies. | | ||
| | `widget_ids` | array of strings | yes | References to top-level widgets. NOT `tab_id` for the field name. | | ||
|
|
||
| ### Positional references (`@N`) | ||
|
|
||
| Widget IDs use `@N` notation — **1-indexed strings** referencing position in the `widgets` array. | ||
|
|
||
| - `"@1"` = first widget in the array | ||
| - `"@15"` = fifteenth widget in the array | ||
| - Must be strings (`"@1"`), not integers | ||
| - The Datadog API resolves `@N` to actual widget IDs server-side | ||
| - The Terraform provider converts API-returned integer IDs back to `@N` on read | ||
|
|
||
| **Prefer `@N` over hardcoded integer IDs.** Integer widget IDs are unstable — the API assigns them on creation and they change if widgets are recreated. `@N` references are positional and survive widget ID changes. | ||
|
|
||
| --- | ||
|
|
||
| ## Common Mistakes | ||
|
|
||
| ### Wrong field names | ||
|
|
||
| The Datadog API documentation uses `tab_name` and `tab_id`. The actual API and Terraform provider expect `name` and `id`. Using the documented names returns a 400 error. | ||
|
|
||
| ```json | ||
| // WRONG — returns 400 | ||
| {"tab_name": "Overview", "tab_id": "...", "widget_ids": [...]} | ||
|
|
||
| // CORRECT | ||
| {"name": "Overview", "id": "...", "widget_ids": [...]} | ||
| ``` | ||
|
|
||
| ### Duplicate widget IDs | ||
|
|
||
| Adding tabs triggers strict widget ID uniqueness validation that the API previously ignored. If your dashboard JSON has widgets with duplicate `id` fields (common when widgets were copy-pasted), the API will reject the update with `"Duplicate widget IDs found"`. | ||
|
|
||
| **Before adding tabs**: audit all widget IDs for duplicates. | ||
|
|
||
| ```python | ||
| import json | ||
| from collections import Counter | ||
|
|
||
| with open("dashboard.json") as f: | ||
| d = json.load(f) | ||
|
|
||
| all_ids = [] | ||
| def collect_ids(widgets): | ||
| for w in widgets: | ||
| wid = w.get("id") | ||
| if wid is not None: | ||
| all_ids.append(wid) | ||
| for nested in w.get("definition", {}).get("widgets", []): | ||
| collect_ids([nested]) | ||
|
|
||
| collect_ids(d["widgets"]) | ||
| dupes = {k: v for k, v in Counter(all_ids).items() if v > 1} | ||
| print(f"Duplicates: {dupes}" if dupes else "No duplicates") | ||
| ``` | ||
|
|
||
| ### Every widget must be assigned | ||
|
|
||
| All top-level widgets must appear in exactly one tab. Missing a widget does not hide it — the API may reject the request or behave unpredictably. | ||
|
|
||
| ### Provider version | ||
|
|
||
| Tab support requires Terraform provider `datadog/datadog >= 3.44.0`. Earlier versions silently pass the `tabs` field through but cannot normalize `@N` references on read, causing perpetual diffs. | ||
|
|
||
| --- | ||
|
|
||
| ## Terraform Provider Internals | ||
|
|
||
| Understanding the provider lifecycle prevents debugging dead ends. | ||
|
|
||
| ### On create/update (write path) | ||
|
|
||
| 1. `stripDeprecatedFields()` removes `is_read_only` from the JSON | ||
| 2. Same function injects deterministic UUIDs for any tab missing an `id`: `uuid5(Nil, "tab-{index}")` | ||
| 3. The JSON — including `@N` references — is sent as-is to `PUT /api/v1/dashboard/{id}` | ||
| 4. The API resolves `@N` to actual integer widget IDs server-side | ||
|
|
||
| ### On read (state path) | ||
|
|
||
| 1. `prepResource()` strips computed fields (`id`, `author_handle`, `author_name`, `created_at`, `modified_at`, `url`) for diff comparison | ||
| 2. Same function builds a `widgetID → position` map and converts integer `widget_ids` back to `@N` strings | ||
| 3. Tab `id` fields are stripped from state to prevent diff noise | ||
|
|
||
| This means: the provider handles the `@N` ↔ integer conversion transparently. You write `@N`, the API receives `@N`, the API returns integers, the provider converts back to `@N` for state. | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.