Skip to content

Commit 1ac54f4

Browse files
committed
fix(dashboard): reject deprecated datasets at CLI level before API call
Split WIDGET_TYPES into active types and DEPRECATED_WIDGET_TYPES (discover, transaction-like). The CLI now rejects deprecated datasets immediately with actionable migration hints instead of letting the API return a cryptic error. - WIDGET_TYPES: only active datasets the API accepts for creation - DEPRECATED_WIDGET_TYPES: discover, transaction-like - ALL_WIDGET_TYPES: union of both, used for parsing server responses - validateWidgetEnums: checks deprecated types first with specific hints - --dataset flag brief now lists valid values inline from WIDGET_TYPES - DashboardWidgetInputSchema uses WIDGET_TYPES (rejects deprecated) - DashboardWidgetSchema still accepts ALL_WIDGET_TYPES (server compat)
1 parent 2e159c1 commit 1ac54f4

File tree

6 files changed

+63
-19
lines changed

6 files changed

+63
-19
lines changed

plugins/sentry-cli/skills/sentry-cli/references/dashboards.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Add a widget to a dashboard
7676

7777
**Flags:**
7878
- `-d, --display <value> - Display type (big_number, line, area, bar, table, stacked_area, top_n, text, categorical_bar, details, wheel, rage_and_dead_clicks, server_tree, agents_traces_table)`
79-
- `--dataset <value> - Widget dataset (default: spans). Do NOT use "discover" or "transaction-like" — both are deprecated. Use "spans" with --where "is_transaction:true" to query transactions`
79+
- `--dataset <value> - Widget dataset: issue, metrics, error-events, spans, logs, tracemetrics, preprod-app-size (default: spans)`
8080
- `-q, --query <value>... - Aggregate expression (e.g. count, p95:span.duration)`
8181
- `-w, --where <value> - Search conditions filter (e.g. is:unresolved)`
8282
- `-g, --group-by <value>... - Group-by column (repeatable). Requires --limit`
@@ -121,7 +121,7 @@ Edit a widget in a dashboard
121121
- `-t, --title <value> - Widget title to match`
122122
- `--new-title <value> - New widget title`
123123
- `-d, --display <value> - Display type (big_number, line, area, bar, table, stacked_area, top_n, text, categorical_bar, details, wheel, rage_and_dead_clicks, server_tree, agents_traces_table)`
124-
- `--dataset <value> - Widget dataset (default: spans)`
124+
- `--dataset <value> - Widget dataset: issue, metrics, error-events, spans, logs, tracemetrics, preprod-app-size (default: spans)`
125125
- `-q, --query <value>... - Aggregate expression (e.g. count, p95:span.duration)`
126126
- `-w, --where <value> - Search conditions filter (e.g. is:unresolved)`
127127
- `-g, --group-by <value>... - Group-by column (repeatable)`

src/commands/dashboard/resolve.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -477,9 +477,20 @@ export function enrichDashboardError(
477477
throw error;
478478
}
479479

480+
/** Migration hints for deprecated dataset names */
481+
const DEPRECATED_DATASET_HINTS: Record<string, string> = {
482+
discover:
483+
'The "discover" dataset is deprecated. Use "error-events" for errors or "spans" for transactions/spans.',
484+
"transaction-like":
485+
'The "transaction-like" dataset is deprecated. Use "spans" with --where "is_transaction:true" instead.',
486+
};
487+
480488
/**
481489
* Validate --display and --dataset flag values against known enums.
482490
*
491+
* Rejects deprecated datasets (`discover`, `transaction-like`) with
492+
* actionable migration hints before making any API calls.
493+
*
483494
* @param display - Display type flag value
484495
* @param dataset - Dataset flag value
485496
*/
@@ -493,14 +504,18 @@ export function validateWidgetEnums(display?: string, dataset?: string): void {
493504
"display"
494505
);
495506
}
496-
if (
497-
dataset &&
498-
!WIDGET_TYPES.includes(dataset as (typeof WIDGET_TYPES)[number])
499-
) {
500-
throw new ValidationError(
501-
`Invalid --dataset value "${dataset}".\nValid datasets: ${WIDGET_TYPES.join(", ")}`,
502-
"dataset"
503-
);
507+
if (dataset) {
508+
// Check for deprecated datasets first — give a specific migration hint
509+
const deprecationHint = DEPRECATED_DATASET_HINTS[dataset];
510+
if (deprecationHint) {
511+
throw new ValidationError(deprecationHint, "dataset");
512+
}
513+
if (!WIDGET_TYPES.includes(dataset as (typeof WIDGET_TYPES)[number])) {
514+
throw new ValidationError(
515+
`Invalid --dataset value "${dataset}".\nValid datasets: ${WIDGET_TYPES.join(", ")}`,
516+
"dataset"
517+
);
518+
}
504519
}
505520
if (display && dataset) {
506521
// Untracked display types (text, wheel, rage_and_dead_clicks, agents_traces_table)

src/commands/dashboard/widget/add.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
FALLBACK_LAYOUT,
2020
prepareDashboardForUpdate,
2121
validateWidgetLayout,
22+
WIDGET_TYPES,
2223
type WidgetLayoutFlags,
2324
} from "../../../types/dashboard.js";
2425
import {
@@ -119,8 +120,7 @@ export const addCommand = buildCommand({
119120
dataset: {
120121
kind: "parsed",
121122
parse: String,
122-
brief:
123-
'Widget dataset (default: spans). Do NOT use "discover" or "transaction-like" — both are deprecated. Use "spans" with --where "is_transaction:true" to query transactions',
123+
brief: `Widget dataset: ${WIDGET_TYPES.join(", ")} (default: spans)`,
124124
optional: true,
125125
},
126126
query: {

src/commands/dashboard/widget/edit.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
prepareWidgetQueries,
2525
validateAggregateNames,
2626
validateWidgetLayout,
27+
WIDGET_TYPES,
2728
type WidgetLayoutFlags,
2829
} from "../../../types/dashboard.js";
2930
import {
@@ -207,7 +208,7 @@ export const editCommand = buildCommand({
207208
dataset: {
208209
kind: "parsed",
209210
parse: String,
210-
brief: "Widget dataset (default: spans)",
211+
brief: `Widget dataset: ${WIDGET_TYPES.join(", ")} (default: spans)`,
211212
optional: true,
212213
},
213214
query: {

src/types/dashboard.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,43 @@ import { logger } from "../lib/logger.js";
1919
// ---------------------------------------------------------------------------
2020

2121
/**
22-
* Valid widget types (dataset selectors).
22+
* Widget types (dataset selectors) the API still accepts for creation.
2323
*
2424
* Source: sentry/src/sentry/models/dashboard_widget.py DashboardWidgetTypes.TYPES
2525
*/
2626
export const WIDGET_TYPES = [
27-
"discover",
2827
"issue",
2928
"metrics",
3029
"error-events",
31-
"transaction-like",
3230
"spans",
3331
"logs",
3432
"tracemetrics",
3533
"preprod-app-size",
3634
] as const;
3735

38-
export type WidgetType = (typeof WIDGET_TYPES)[number];
36+
/**
37+
* Deprecated widget types rejected by the Sentry Dashboard API.
38+
*
39+
* - `discover` → use `error-events` for errors or `spans` for everything else
40+
* - `transaction-like` → use `spans` with `is_transaction:true` filter
41+
*/
42+
export const DEPRECATED_WIDGET_TYPES = [
43+
"discover",
44+
"transaction-like",
45+
] as const;
46+
47+
export type DeprecatedWidgetType = (typeof DEPRECATED_WIDGET_TYPES)[number];
48+
49+
/**
50+
* All widget types including deprecated — used for parsing server responses
51+
* where existing dashboards may still reference old types.
52+
*/
53+
export const ALL_WIDGET_TYPES = [
54+
...WIDGET_TYPES,
55+
...DEPRECATED_WIDGET_TYPES,
56+
] as const;
57+
58+
export type WidgetType = (typeof ALL_WIDGET_TYPES)[number];
3959

4060
/** Default widgetType — the modern spans dataset covers most use cases */
4161
export const DEFAULT_WIDGET_TYPE: WidgetType = "spans";

test/types/dashboard.test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88
import { describe, expect, test } from "bun:test";
99
import { ValidationError } from "../../src/lib/errors.js";
1010
import {
11+
ALL_WIDGET_TYPES,
1112
assignDefaultLayout,
1213
type DashboardWidget,
1314
DashboardWidgetInputSchema,
1415
DEFAULT_WIDGET_TYPE,
16+
DEPRECATED_WIDGET_TYPES,
1517
DISCOVER_AGGREGATE_FUNCTIONS,
1618
DISPLAY_TYPES,
1719
DiscoverAggregateFunctionSchema,
@@ -49,7 +51,13 @@ describe("WIDGET_TYPES", () => {
4951
expect(DEFAULT_WIDGET_TYPE).toBe("spans");
5052
});
5153

52-
test("contains all expected dataset types", () => {
54+
test("excludes deprecated types", () => {
55+
for (const t of DEPRECATED_WIDGET_TYPES) {
56+
expect(WIDGET_TYPES).not.toContain(t);
57+
}
58+
});
59+
60+
test("ALL_WIDGET_TYPES includes both active and deprecated", () => {
5361
const expected: WidgetType[] = [
5462
"discover",
5563
"issue",
@@ -62,7 +70,7 @@ describe("WIDGET_TYPES", () => {
6270
"preprod-app-size",
6371
];
6472
for (const t of expected) {
65-
expect(WIDGET_TYPES).toContain(t);
73+
expect(ALL_WIDGET_TYPES).toContain(t);
6674
}
6775
});
6876
});

0 commit comments

Comments
 (0)