@agent-native/core 0.78.9 → 0.79.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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +11 -0
- package/corpus/core/docs/content/actions.md +4 -2
- package/corpus/core/docs/content/agent-surfaces.md +9 -0
- package/corpus/core/docs/content/extensions.md +10 -0
- package/corpus/core/docs/content/generative-ui.md +217 -0
- package/corpus/core/docs/content/key-concepts.md +2 -2
- package/corpus/core/docs/content/mcp-apps.md +3 -5
- package/corpus/core/docs/content/native-chat-ui.md +9 -5
- package/corpus/core/docs/content/tracking.md +9 -3
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/action-ui.ts +1 -0
- package/corpus/core/src/client/analytics.ts +195 -12
- package/corpus/core/src/client/chat/index.ts +1 -0
- package/corpus/core/src/client/chat/tool-call-display.tsx +5 -2
- package/corpus/core/src/client/chat/widgets/InlineExtensionWidget.tsx +139 -0
- package/corpus/core/src/client/chat/widgets/builtin-tool-renderers.tsx +27 -1
- package/corpus/core/src/client/conversation/AgentConversation.tsx +38 -0
- package/corpus/core/src/client/conversation/code-agent-transcript.ts +9 -0
- package/corpus/core/src/client/conversation/types.ts +4 -0
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +27 -5
- package/corpus/core/src/client/extensions/ExtensionViewer.tsx +26 -5
- package/corpus/core/src/client/extensions/InlineExtensionFrame.tsx +654 -0
- package/corpus/core/src/client/extensions/iframe-bridge.ts +30 -0
- package/corpus/core/src/client/extensions/index.ts +5 -0
- package/corpus/core/src/client/index.ts +1 -0
- package/corpus/core/src/client/session-replay.ts +89 -14
- package/corpus/core/src/code-agents/transcript-normalizer.ts +14 -0
- package/corpus/core/src/extensions/actions.ts +218 -1
- package/corpus/core/src/extensions/html-shell.ts +70 -3
- package/corpus/core/src/extensions/routes.ts +12 -4
- package/corpus/core/src/index.browser.ts +1 -0
- package/corpus/core/src/index.ts +1 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +21 -9
- package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +13 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/references/api.md +2 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/generative-ui/SKILL.md +115 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +198 -59
- package/corpus/templates/analytics/AGENTS.md +12 -0
- package/corpus/templates/analytics/actions/dashboard-mutation-api.ts +1105 -0
- package/corpus/templates/analytics/actions/dashboard-panel-order.ts +169 -0
- package/corpus/templates/analytics/actions/get-sql-dashboard.ts +89 -6
- package/corpus/templates/analytics/actions/mutate-dashboard.ts +333 -0
- package/corpus/templates/analytics/actions/reorder-dashboard-panels.ts +214 -0
- package/corpus/templates/analytics/actions/send-dashboard-report-now.ts +48 -21
- package/corpus/templates/analytics/actions/update-dashboard.ts +193 -100
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +11 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/analytics/app/global.css +81 -10
- package/corpus/templates/analytics/app/i18n-data.ts +249 -4
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/ChartCard.tsx +3 -3
- package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +41 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/EmailReportDialog.tsx +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/PanelEditorDialog.tsx +4 -4
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +48 -18
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/dashboard-layout.ts +32 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +204 -70
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +1101 -227
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +160 -133
- package/corpus/templates/analytics/changelog/2026-06-26-agents-can-now-edit-dashboards-through-a-typed-mutation-scri.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-26-dashboard-bar-chart-hovers-stay-subtle-in-dark-mode.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-26-dashboard-chart-moves-are-now-handled-by-panel-id-making-sim.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-26-dashboard-charts-drag-smoothly-with-stable-cards-inactive-ch.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-26-dashboard-charts-show-a-refresh-spinner-while-keeping-existi.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-26-dashboard-edits-stay-stable-while-chart-order-and-deletions-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-26-dashboard-email-reports-queue-immediate-sends.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-26-explorer-dashboards-now-drag-charts-with-a-stable-preview-an.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-26-session-replay-playback-can-now-be-toggled-by-clicking-the-r.md +6 -0
- package/corpus/templates/analytics/changelog/2026-06-26-session-replays-now-open-from-the-full-row-and-play-with-tim.md +6 -0
- package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +21 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +41 -17
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +5 -0
- package/dist/action-ui.d.ts +1 -0
- package/dist/action-ui.d.ts.map +1 -1
- package/dist/action-ui.js +1 -0
- package/dist/action-ui.js.map +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +173 -12
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/chat/index.d.ts +1 -1
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js +1 -1
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +3 -1
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat/widgets/InlineExtensionWidget.d.ts +17 -0
- package/dist/client/chat/widgets/InlineExtensionWidget.d.ts.map +1 -0
- package/dist/client/chat/widgets/InlineExtensionWidget.js +85 -0
- package/dist/client/chat/widgets/InlineExtensionWidget.js.map +1 -0
- package/dist/client/chat/widgets/builtin-tool-renderers.d.ts.map +1 -1
- package/dist/client/chat/widgets/builtin-tool-renderers.js +15 -2
- package/dist/client/chat/widgets/builtin-tool-renderers.js.map +1 -1
- package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
- package/dist/client/conversation/AgentConversation.js +33 -0
- package/dist/client/conversation/AgentConversation.js.map +1 -1
- package/dist/client/conversation/code-agent-transcript.js +8 -0
- package/dist/client/conversation/code-agent-transcript.js.map +1 -1
- package/dist/client/conversation/types.d.ts +4 -0
- package/dist/client/conversation/types.d.ts.map +1 -1
- package/dist/client/conversation/types.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +29 -1
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/extensions/ExtensionViewer.d.ts.map +1 -1
- package/dist/client/extensions/ExtensionViewer.js +28 -1
- package/dist/client/extensions/ExtensionViewer.js.map +1 -1
- package/dist/client/extensions/InlineExtensionFrame.d.ts +25 -0
- package/dist/client/extensions/InlineExtensionFrame.d.ts.map +1 -0
- package/dist/client/extensions/InlineExtensionFrame.js +488 -0
- package/dist/client/extensions/InlineExtensionFrame.js.map +1 -0
- package/dist/client/extensions/iframe-bridge.d.ts +2 -0
- package/dist/client/extensions/iframe-bridge.d.ts.map +1 -1
- package/dist/client/extensions/iframe-bridge.js +23 -0
- package/dist/client/extensions/iframe-bridge.js.map +1 -1
- package/dist/client/extensions/index.d.ts +1 -0
- package/dist/client/extensions/index.d.ts.map +1 -1
- package/dist/client/extensions/index.js +1 -0
- package/dist/client/extensions/index.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/session-replay.d.ts +11 -1
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +74 -14
- package/dist/client/session-replay.js.map +1 -1
- package/dist/code-agents/transcript-normalizer.d.ts +2 -0
- package/dist/code-agents/transcript-normalizer.d.ts.map +1 -1
- package/dist/code-agents/transcript-normalizer.js +8 -0
- package/dist/code-agents/transcript-normalizer.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/extensions/actions.d.ts.map +1 -1
- package/dist/extensions/actions.js +200 -1
- package/dist/extensions/actions.js.map +1 -1
- package/dist/extensions/html-shell.d.ts.map +1 -1
- package/dist/extensions/html-shell.js +70 -3
- package/dist/extensions/html-shell.js.map +1 -1
- package/dist/extensions/routes.d.ts.map +1 -1
- package/dist/extensions/routes.js +11 -4
- package/dist/extensions/routes.js.map +1 -1
- package/dist/index.browser.d.ts +1 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +21 -9
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +13 -0
- package/dist/templates/workspace-core/.agents/skills/extensions/references/api.md +2 -0
- package/dist/templates/workspace-core/.agents/skills/generative-ui/SKILL.md +115 -0
- package/docs/content/actions.md +4 -2
- package/docs/content/agent-surfaces.md +9 -0
- package/docs/content/extensions.md +10 -0
- package/docs/content/generative-ui.md +217 -0
- package/docs/content/key-concepts.md +2 -2
- package/docs/content/mcp-apps.md +3 -5
- package/docs/content/native-chat-ui.md +9 -5
- package/docs/content/tracking.md +9 -3
- package/package.json +1 -1
- package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +13 -0
- package/src/templates/workspace-core/.agents/skills/extensions/references/api.md +2 -0
- package/src/templates/workspace-core/.agents/skills/generative-ui/SKILL.md +115 -0
|
@@ -16,6 +16,10 @@ import { dryRunQuery } from "../server/lib/bigquery";
|
|
|
16
16
|
import { getDashboard, upsertDashboard } from "../server/lib/dashboards-store";
|
|
17
17
|
import { parseDemoDescriptor } from "../server/lib/demo-source";
|
|
18
18
|
import { validateFirstPartyAnalyticsSql } from "../server/lib/first-party-analytics.js";
|
|
19
|
+
import {
|
|
20
|
+
applyPanelOrder,
|
|
21
|
+
compactDashboardResult,
|
|
22
|
+
} from "./dashboard-panel-order";
|
|
19
23
|
|
|
20
24
|
/**
|
|
21
25
|
* Same validation shape used in the sql-dashboard save path.
|
|
@@ -80,6 +84,62 @@ type JsonOp = {
|
|
|
80
84
|
value?: unknown;
|
|
81
85
|
};
|
|
82
86
|
|
|
87
|
+
const jsonOpSchema = z.object({
|
|
88
|
+
op: z.enum(["set", "replace", "remove", "move", "move-before", "insert"]),
|
|
89
|
+
path: z.string().optional(),
|
|
90
|
+
from: z.string().optional(),
|
|
91
|
+
value: z.unknown().optional(),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
function parseJsonArrayString(value: string, fieldName: string): unknown[] {
|
|
95
|
+
let parsed: unknown;
|
|
96
|
+
try {
|
|
97
|
+
parsed = JSON.parse(value);
|
|
98
|
+
} catch (err: any) {
|
|
99
|
+
throw new Error(`${fieldName} must be a JSON array: ${err.message}`);
|
|
100
|
+
}
|
|
101
|
+
if (!Array.isArray(parsed)) {
|
|
102
|
+
throw new Error(`${fieldName} must be a JSON array`);
|
|
103
|
+
}
|
|
104
|
+
return parsed;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const jsonOpsInputSchema = z
|
|
108
|
+
.union([
|
|
109
|
+
z.array(jsonOpSchema),
|
|
110
|
+
z.string().transform((value) => parseJsonArrayString(value, "ops")),
|
|
111
|
+
])
|
|
112
|
+
.optional();
|
|
113
|
+
|
|
114
|
+
const panelOrderInputSchema = z
|
|
115
|
+
.union([
|
|
116
|
+
z.array(z.string()),
|
|
117
|
+
z
|
|
118
|
+
.string()
|
|
119
|
+
.transform((value) =>
|
|
120
|
+
parseJsonArrayString(value, "panelOrder").map((item) => String(item)),
|
|
121
|
+
),
|
|
122
|
+
])
|
|
123
|
+
.optional();
|
|
124
|
+
|
|
125
|
+
const configInputSchema = z
|
|
126
|
+
.union([
|
|
127
|
+
z.record(z.string(), z.unknown()),
|
|
128
|
+
z.string().transform((value) => {
|
|
129
|
+
let parsed: unknown;
|
|
130
|
+
try {
|
|
131
|
+
parsed = JSON.parse(value);
|
|
132
|
+
} catch (err: any) {
|
|
133
|
+
throw new Error(`config must be a JSON object: ${err.message}`);
|
|
134
|
+
}
|
|
135
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
136
|
+
throw new Error("config must be a JSON object");
|
|
137
|
+
}
|
|
138
|
+
return parsed as Record<string, unknown>;
|
|
139
|
+
}),
|
|
140
|
+
])
|
|
141
|
+
.optional();
|
|
142
|
+
|
|
83
143
|
function parsePointer(pointer: string): string[] {
|
|
84
144
|
if (pointer === "" || pointer === "/") return [];
|
|
85
145
|
if (!pointer.startsWith("/")) {
|
|
@@ -208,7 +268,7 @@ function applyJsonOp(root: any, op: JsonOp): string {
|
|
|
208
268
|
* Returns a human-readable error string, or `null` when the config passes.
|
|
209
269
|
* Mirrors the shape required by `app/pages/adhoc/sql-dashboard/types.ts`.
|
|
210
270
|
*/
|
|
211
|
-
function validateDashboardConfig(
|
|
271
|
+
export function validateDashboardConfig(
|
|
212
272
|
config: Record<string, unknown>,
|
|
213
273
|
): string | null {
|
|
214
274
|
if (!config || typeof config !== "object") {
|
|
@@ -306,7 +366,7 @@ function validateDashboardConfig(
|
|
|
306
366
|
* mismatches fail here, with the full BigQuery error text, rather than
|
|
307
367
|
* silently saving a broken dashboard that crashes on render.
|
|
308
368
|
*/
|
|
309
|
-
async function validatePanelSql(
|
|
369
|
+
export async function validatePanelSql(
|
|
310
370
|
config: Record<string, unknown>,
|
|
311
371
|
): Promise<string | null> {
|
|
312
372
|
const panels = config.panels;
|
|
@@ -383,6 +443,55 @@ function countPanels(config: Record<string, unknown>): number {
|
|
|
383
443
|
return Array.isArray(config.panels) ? config.panels.length : 0;
|
|
384
444
|
}
|
|
385
445
|
|
|
446
|
+
function resolveDashboardId(args: { dashboardId?: string; id?: string }) {
|
|
447
|
+
const dashboardId = args.dashboardId || args.id;
|
|
448
|
+
if (!dashboardId) {
|
|
449
|
+
throw new Error("provide `dashboardId` (or legacy `id`).");
|
|
450
|
+
}
|
|
451
|
+
return dashboardId;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function dashboardResult(
|
|
455
|
+
dashboardId: string,
|
|
456
|
+
config: Record<string, unknown>,
|
|
457
|
+
appliedOps: number,
|
|
458
|
+
summary: string,
|
|
459
|
+
movedPanelIds: string[] = [],
|
|
460
|
+
returnConfig = false,
|
|
461
|
+
) {
|
|
462
|
+
const compact = compactDashboardResult(config, movedPanelIds);
|
|
463
|
+
return {
|
|
464
|
+
id: dashboardId,
|
|
465
|
+
dashboardId,
|
|
466
|
+
name: typeof config.name === "string" ? config.name : dashboardId,
|
|
467
|
+
...compact,
|
|
468
|
+
appliedOps,
|
|
469
|
+
summary,
|
|
470
|
+
...(returnConfig ? { config } : {}),
|
|
471
|
+
urlPath: `/dashboards/${dashboardId}`,
|
|
472
|
+
deepLink: buildDeepLink({
|
|
473
|
+
app: "analytics",
|
|
474
|
+
view: "adhoc",
|
|
475
|
+
params: { dashboardId },
|
|
476
|
+
}),
|
|
477
|
+
message:
|
|
478
|
+
`${summary} First panels: ${compact.firstPanelIds.join(", ")}.` +
|
|
479
|
+
(returnConfig
|
|
480
|
+
? ""
|
|
481
|
+
: " Full config omitted; call get-sql-dashboard with includeConfig=true only if full SQL/config is needed."),
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function opCanChangePanelSql(op: JsonOp): boolean {
|
|
486
|
+
if (op.op === "move" || op.op === "move-before" || op.op === "remove") {
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
if (!op.path) return true;
|
|
490
|
+
return (
|
|
491
|
+
op.path === "/panels" || /^\/panels\/(?:-|[0-9]+)(?:\/|$)/.test(op.path)
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
|
|
386
495
|
/**
|
|
387
496
|
* Push a config update through the collab layer so open dashboard editors
|
|
388
497
|
* receive the change in real time. Seeds the collab state if it doesn't
|
|
@@ -412,61 +521,40 @@ async function syncToCollab(
|
|
|
412
521
|
|
|
413
522
|
export default defineAction({
|
|
414
523
|
description:
|
|
415
|
-
"
|
|
416
|
-
"
|
|
417
|
-
"
|
|
418
|
-
"`ops`
|
|
419
|
-
"When
|
|
420
|
-
"`op` is one of: set | replace | remove | insert | move | move-before. " +
|
|
421
|
-
"`path` is a JSON Pointer into the config (e.g. `/panels/3` is the 4th panel, `/panels/3/title` is its title, `/name` is the dashboard name). The special index `-` means the end of an array: `/panels/-` appends. " +
|
|
422
|
-
"`value` is the panel or object to set/insert. `from` is the source JSON Pointer for move / move-before. " +
|
|
423
|
-
"To ADD N panels in one call, pass N entries of { op: 'insert', path: '/panels/-', value: <panel> }. " +
|
|
424
|
-
"To reorder: [{ op: 'move', from: '/panels/2', path: '/panels/0' }]. " +
|
|
425
|
-
"To edit a field: [{ op: 'replace', path: '/panels/0/title', value: 'Events by Day' }]. " +
|
|
426
|
-
"Use `config` to replace the entire dashboard config in one call. Provide `ops` OR `config`, not both. " +
|
|
524
|
+
"Save or replace a SQL dashboard full config (scope-aware) atomically in ONE call. " +
|
|
525
|
+
"For existing dashboard panel/layout edits, use `mutate-dashboard` instead; it has the typed `dashboard.*` API for moves, inserts, deletes, duplicates, SQL/title/config edits, and bulk edits without JSON-pointer index math. " +
|
|
526
|
+
"Use this action when creating a brand-new dashboard from a complete config, for the UI full-config save path, or for an explicitly requested low-level JSON-pointer compatibility edit. " +
|
|
527
|
+
"Do not use `ops` or `panelOrder` for ordinary agent edits like moving charts, adding panels to an existing dashboard, changing widths, or updating panel config; call `mutate-dashboard` once with the full edit script. " +
|
|
528
|
+
"When this action is appropriate, provide only one of `ops`, `panelOrder`, or `config`; `config` replaces the whole dashboard config. " +
|
|
427
529
|
"To add a shipped catalog template's panels to an existing dashboard, prefer `install-dashboard-template` with `mergePanels: true` — it appends the template's panels in one call without you having to author each panel. " +
|
|
428
|
-
"The result
|
|
530
|
+
"The result is compact by default: `panelCount`, `appliedOps`, `panelOrder`, `firstPanelIds`, and `summary`. Set `returnConfig: true` only when you truly need the full config in the tool result. " +
|
|
429
531
|
"The UI auto-refreshes after this action — do NOT call `refresh-screen`.",
|
|
430
532
|
schema: z.object({
|
|
431
533
|
dashboardId: z
|
|
432
534
|
.string()
|
|
535
|
+
.optional()
|
|
433
536
|
.describe(
|
|
434
537
|
"Dashboard id (without the `sql-dashboard-` prefix). e.g. 'devrel-leaderboard'",
|
|
435
538
|
),
|
|
436
|
-
|
|
437
|
-
.
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
value: z.unknown().optional(),
|
|
452
|
-
}),
|
|
453
|
-
),
|
|
454
|
-
)
|
|
539
|
+
id: z
|
|
540
|
+
.string()
|
|
541
|
+
.optional()
|
|
542
|
+
.describe("Legacy alias for dashboardId. Prefer dashboardId."),
|
|
543
|
+
ops: jsonOpsInputSchema.describe(
|
|
544
|
+
"Legacy low-level JSON-pointer compatibility ops. Agents should use mutate-dashboard for existing dashboard edits; only use this when the user explicitly requests raw JSON-pointer operations.",
|
|
545
|
+
),
|
|
546
|
+
panelOrder: panelOrderInputSchema.describe(
|
|
547
|
+
"Legacy compatibility reorder input. Agents should use mutate-dashboard id-based move methods for ordinary chart/section moves.",
|
|
548
|
+
),
|
|
549
|
+
config: configInputSchema.describe(
|
|
550
|
+
"Replace the whole dashboard config (or a JSON string).",
|
|
551
|
+
),
|
|
552
|
+
returnConfig: z
|
|
553
|
+
.boolean()
|
|
455
554
|
.optional()
|
|
456
555
|
.describe(
|
|
457
|
-
"
|
|
458
|
-
"Each op is { op, path, from?, value? }. op ∈ set|replace|remove|insert|move|move-before. " +
|
|
459
|
-
"path is a JSON Pointer (e.g. '/panels/3', and '/panels/-' appends to the end). " +
|
|
460
|
-
"Add N panels at once with N {op:'insert', path:'/panels/-', value:<panel>} entries. " +
|
|
461
|
-
"Example reorder: [{op:'move', from:'/panels/2', path:'/panels/0'}].",
|
|
556
|
+
"If true, include the full dashboard config in the result. Defaults to false to keep tool output compact.",
|
|
462
557
|
),
|
|
463
|
-
config: z
|
|
464
|
-
.preprocess(
|
|
465
|
-
(v) => (typeof v === "string" ? JSON.parse(v) : v),
|
|
466
|
-
z.record(z.string(), z.unknown()),
|
|
467
|
-
)
|
|
468
|
-
.optional()
|
|
469
|
-
.describe("Replace the whole dashboard config (or a JSON string)."),
|
|
470
558
|
}),
|
|
471
559
|
// The SQL dashboard editor persists user edits through callAction(), which
|
|
472
560
|
// needs this action mounted under /_agent-native/actions/update-dashboard.
|
|
@@ -482,13 +570,18 @@ export default defineAction({
|
|
|
482
570
|
}),
|
|
483
571
|
},
|
|
484
572
|
run: async (args) => {
|
|
485
|
-
|
|
573
|
+
const dashboardId = resolveDashboardId(args);
|
|
574
|
+
const modeCount = [args.ops, args.panelOrder, args.config].filter(
|
|
575
|
+
(value) => value !== undefined,
|
|
576
|
+
).length;
|
|
577
|
+
|
|
578
|
+
if (modeCount === 0) {
|
|
486
579
|
throw new Error(
|
|
487
|
-
"provide
|
|
580
|
+
"provide `ops` (surgical edits), `panelOrder` (id reorder), or `config` (full replace).",
|
|
488
581
|
);
|
|
489
582
|
}
|
|
490
|
-
if (
|
|
491
|
-
throw new Error("provide `ops`
|
|
583
|
+
if (modeCount > 1) {
|
|
584
|
+
throw new Error("provide only one of `ops`, `panelOrder`, or `config`.");
|
|
492
585
|
}
|
|
493
586
|
|
|
494
587
|
const scope = resolveScope();
|
|
@@ -499,40 +592,49 @@ export default defineAction({
|
|
|
499
592
|
if (validation) throw new Error(validation);
|
|
500
593
|
const sqlError = await validatePanelSql(args.config);
|
|
501
594
|
if (sqlError) throw new Error(sqlError);
|
|
502
|
-
await upsertDashboard(
|
|
503
|
-
await syncToCollab(
|
|
595
|
+
await upsertDashboard(dashboardId, "sql", args.config, ctx);
|
|
596
|
+
await syncToCollab(dashboardId, args.config);
|
|
504
597
|
const panelCount = countPanels(args.config);
|
|
505
|
-
return
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
// confirm the new shape cheaply instead of assuming success.
|
|
514
|
-
panelCount,
|
|
515
|
-
appliedOps: 0,
|
|
516
|
-
summary: `Replaced dashboard "${args.dashboardId}"; it now has ${panelCount} panel(s).`,
|
|
517
|
-
config: args.config,
|
|
518
|
-
urlPath: `/dashboards/${args.dashboardId}`,
|
|
519
|
-
deepLink: buildDeepLink({
|
|
520
|
-
app: "analytics",
|
|
521
|
-
view: "adhoc",
|
|
522
|
-
params: { dashboardId: args.dashboardId },
|
|
523
|
-
}),
|
|
524
|
-
message: `Dashboard "${args.dashboardId}" replaced.`,
|
|
525
|
-
};
|
|
598
|
+
return dashboardResult(
|
|
599
|
+
dashboardId,
|
|
600
|
+
args.config,
|
|
601
|
+
0,
|
|
602
|
+
`Replaced dashboard "${dashboardId}"; it now has ${panelCount} panel(s).`,
|
|
603
|
+
[],
|
|
604
|
+
args.returnConfig === true,
|
|
605
|
+
);
|
|
526
606
|
}
|
|
527
607
|
|
|
528
|
-
const existing = await getDashboard(
|
|
608
|
+
const existing = await getDashboard(dashboardId, ctx);
|
|
529
609
|
if (!existing) {
|
|
530
610
|
throw new Error(
|
|
531
|
-
`dashboard "${
|
|
611
|
+
`dashboard "${dashboardId}" not found (or you don't have access).`,
|
|
532
612
|
);
|
|
533
613
|
}
|
|
534
614
|
|
|
535
615
|
const root = existing.config as any;
|
|
616
|
+
|
|
617
|
+
if (args.panelOrder) {
|
|
618
|
+
const orderDetails = applyPanelOrder(root, args.panelOrder);
|
|
619
|
+
const validation = validateDashboardConfig(root);
|
|
620
|
+
if (validation) throw new Error(validation);
|
|
621
|
+
await upsertDashboard(
|
|
622
|
+
dashboardId,
|
|
623
|
+
existing.kind,
|
|
624
|
+
root as Record<string, unknown>,
|
|
625
|
+
ctx,
|
|
626
|
+
);
|
|
627
|
+
await syncToCollab(dashboardId, root as Record<string, unknown>);
|
|
628
|
+
return dashboardResult(
|
|
629
|
+
dashboardId,
|
|
630
|
+
root as Record<string, unknown>,
|
|
631
|
+
1,
|
|
632
|
+
`Moved ${orderDetails.movedPanelIds.length} panel id(s) to the front of dashboard "${dashboardId}"; it now has ${orderDetails.panelCount} panel(s).`,
|
|
633
|
+
orderDetails.movedPanelIds,
|
|
634
|
+
args.returnConfig === true,
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
|
|
536
638
|
const details: string[] = [];
|
|
537
639
|
for (const op of args.ops!) {
|
|
538
640
|
try {
|
|
@@ -542,39 +644,30 @@ export default defineAction({
|
|
|
542
644
|
}
|
|
543
645
|
}
|
|
544
646
|
|
|
545
|
-
const
|
|
546
|
-
if (
|
|
647
|
+
const validation = validateDashboardConfig(root);
|
|
648
|
+
if (validation) throw new Error(validation);
|
|
649
|
+
if (args.ops!.some((op) => opCanChangePanelSql(op as JsonOp))) {
|
|
650
|
+
const sqlError = await validatePanelSql(root);
|
|
651
|
+
if (sqlError) throw new Error(sqlError);
|
|
652
|
+
}
|
|
547
653
|
|
|
548
654
|
await upsertDashboard(
|
|
549
|
-
|
|
655
|
+
dashboardId,
|
|
550
656
|
existing.kind,
|
|
551
657
|
root as Record<string, unknown>,
|
|
552
658
|
ctx,
|
|
553
659
|
);
|
|
554
|
-
await syncToCollab(
|
|
660
|
+
await syncToCollab(dashboardId, root as Record<string, unknown>);
|
|
555
661
|
|
|
556
662
|
const panelCount = countPanels(root as Record<string, unknown>);
|
|
557
|
-
return
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
summary: `Applied ${details.length} op(s); dashboard "${args.dashboardId}" now has ${panelCount} panel(s).`,
|
|
566
|
-
config: root,
|
|
567
|
-
urlPath: `/dashboards/${args.dashboardId}`,
|
|
568
|
-
deepLink: buildDeepLink({
|
|
569
|
-
app: "analytics",
|
|
570
|
-
view: "adhoc",
|
|
571
|
-
params: { dashboardId: args.dashboardId },
|
|
572
|
-
}),
|
|
573
|
-
message:
|
|
574
|
-
`Dashboard "${args.dashboardId}" updated. ` +
|
|
575
|
-
`Applied ${details.length} op(s): ${details.join("; ")}. ` +
|
|
576
|
-
`Now ${panelCount} panel(s).`,
|
|
577
|
-
};
|
|
663
|
+
return dashboardResult(
|
|
664
|
+
dashboardId,
|
|
665
|
+
root as Record<string, unknown>,
|
|
666
|
+
details.length,
|
|
667
|
+
`Applied ${details.length} op(s); dashboard "${dashboardId}" now has ${panelCount} panel(s).`,
|
|
668
|
+
[],
|
|
669
|
+
args.returnConfig === true,
|
|
670
|
+
);
|
|
578
671
|
},
|
|
579
672
|
link: ({ result }) => {
|
|
580
673
|
const dashboardId =
|
|
@@ -89,6 +89,16 @@ const CHART_TOOLTIP_PROPS = {
|
|
|
89
89
|
wrapperStyle: CHART_TOOLTIP_WRAPPER_STYLE,
|
|
90
90
|
} as const;
|
|
91
91
|
|
|
92
|
+
const BAR_TOOLTIP_CURSOR_PROPS = {
|
|
93
|
+
fill: "hsl(var(--muted))",
|
|
94
|
+
fillOpacity: 0.32,
|
|
95
|
+
stroke: "hsl(var(--border))",
|
|
96
|
+
strokeOpacity: 0.5,
|
|
97
|
+
strokeWidth: 1,
|
|
98
|
+
rx: 4,
|
|
99
|
+
ry: 4,
|
|
100
|
+
} as const;
|
|
101
|
+
|
|
92
102
|
const CHART_LEGEND_WRAPPER_STYLE: CSSProperties = {
|
|
93
103
|
fontSize: 11,
|
|
94
104
|
paddingTop: 8,
|
|
@@ -1536,6 +1546,7 @@ function BarRenderer({
|
|
|
1536
1546
|
/>
|
|
1537
1547
|
<Tooltip
|
|
1538
1548
|
{...CHART_TOOLTIP_PROPS}
|
|
1549
|
+
cursor={BAR_TOOLTIP_CURSOR_PROPS}
|
|
1539
1550
|
labelFormatter={xLabelFormatter}
|
|
1540
1551
|
content={
|
|
1541
1552
|
<ChartTooltip
|
|
@@ -1112,7 +1112,7 @@ async function fetchSqlDashboardForPrefetch(
|
|
|
1112
1112
|
try {
|
|
1113
1113
|
const data: any = await callAction(
|
|
1114
1114
|
"get-sql-dashboard",
|
|
1115
|
-
{ id },
|
|
1115
|
+
{ id, includeConfig: true },
|
|
1116
1116
|
{ method: "GET" },
|
|
1117
1117
|
);
|
|
1118
1118
|
if (!data || data.error) return null;
|
|
@@ -193,6 +193,48 @@
|
|
|
193
193
|
box-shadow: none;
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
.an-replay-stage-root iframe {
|
|
197
|
+
display: block;
|
|
198
|
+
border: 0;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.an-replay-stage-root .replayer-wrapper {
|
|
202
|
+
transform-origin: top left;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.an-replay-scrub {
|
|
206
|
+
height: 0.25rem;
|
|
207
|
+
appearance: none;
|
|
208
|
+
border-radius: 9999px;
|
|
209
|
+
outline: none;
|
|
210
|
+
background: hsl(var(--muted));
|
|
211
|
+
cursor: pointer;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
.an-replay-scrub:disabled {
|
|
215
|
+
cursor: not-allowed;
|
|
216
|
+
opacity: 0.55;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.an-replay-scrub::-webkit-slider-thumb {
|
|
220
|
+
width: 0.75rem;
|
|
221
|
+
height: 0.75rem;
|
|
222
|
+
appearance: none;
|
|
223
|
+
border: 2px solid hsl(var(--background));
|
|
224
|
+
border-radius: 9999px;
|
|
225
|
+
background: hsl(var(--primary));
|
|
226
|
+
box-shadow: 0 0 0 1px hsl(var(--border));
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.an-replay-scrub::-moz-range-thumb {
|
|
230
|
+
width: 0.75rem;
|
|
231
|
+
height: 0.75rem;
|
|
232
|
+
border: 2px solid hsl(var(--background));
|
|
233
|
+
border-radius: 9999px;
|
|
234
|
+
background: hsl(var(--primary));
|
|
235
|
+
box-shadow: 0 0 0 1px hsl(var(--border));
|
|
236
|
+
}
|
|
237
|
+
|
|
196
238
|
.dark
|
|
197
239
|
.analytics-chat-panel
|
|
198
240
|
[data-agent-empty-state="centered"]
|
|
@@ -317,12 +359,12 @@
|
|
|
317
359
|
when the agent sidebar is open — not the viewport. Rows are rendered
|
|
318
360
|
explicitly so deleting a card only expands the remaining cards in that row. */
|
|
319
361
|
.dashboard-grid-container {
|
|
362
|
+
--dashboard-drop-line: hsl(217 91% 60%);
|
|
320
363
|
container: dashboard-grid / inline-size;
|
|
321
364
|
}
|
|
322
365
|
|
|
323
366
|
.dashboard-grid {
|
|
324
367
|
--dashboard-grid-gap: 1rem;
|
|
325
|
-
--dashboard-drop-line: hsl(217 91% 60%);
|
|
326
368
|
display: flex;
|
|
327
369
|
flex-direction: column;
|
|
328
370
|
align-items: stretch;
|
|
@@ -338,17 +380,17 @@
|
|
|
338
380
|
.dashboard-column-drop-slot {
|
|
339
381
|
position: relative;
|
|
340
382
|
z-index: 30;
|
|
341
|
-
flex: 0 0
|
|
383
|
+
flex: 0 0 1.5rem;
|
|
342
384
|
}
|
|
343
385
|
|
|
344
386
|
.dashboard-row-drop-slot {
|
|
345
|
-
height:
|
|
346
|
-
margin-block: -0.
|
|
387
|
+
height: 1.5rem;
|
|
388
|
+
margin-block: -0.25rem;
|
|
347
389
|
}
|
|
348
390
|
|
|
349
391
|
.dashboard-column-drop-slot {
|
|
350
|
-
height:
|
|
351
|
-
margin-block: -0.
|
|
392
|
+
height: 1.5rem;
|
|
393
|
+
margin-block: -0.75rem;
|
|
352
394
|
}
|
|
353
395
|
|
|
354
396
|
.dashboard-row-drop-slot::after,
|
|
@@ -367,7 +409,7 @@
|
|
|
367
409
|
left: 0;
|
|
368
410
|
right: 0;
|
|
369
411
|
top: 50%;
|
|
370
|
-
height:
|
|
412
|
+
height: 3px;
|
|
371
413
|
transform: translateY(-50%);
|
|
372
414
|
}
|
|
373
415
|
|
|
@@ -376,6 +418,35 @@
|
|
|
376
418
|
opacity: 1;
|
|
377
419
|
}
|
|
378
420
|
|
|
421
|
+
.dashboard-chart-card[data-dragging="true"],
|
|
422
|
+
.dashboard-section-card[data-dragging="true"] {
|
|
423
|
+
opacity: 0.55;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.dashboard-grid-container[data-dashboard-dragging="true"] .dashboard-grid-cell,
|
|
427
|
+
.dashboard-grid-container[data-dashboard-dragging="true"]
|
|
428
|
+
.dashboard-section-cell,
|
|
429
|
+
.dashboard-grid-container[data-dashboard-dragging="true"]
|
|
430
|
+
.dashboard-chart-content {
|
|
431
|
+
pointer-events: none;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.dashboard-grid-container[data-dashboard-dragging="true"]
|
|
435
|
+
.dashboard-row-drop-slot,
|
|
436
|
+
.dashboard-grid-container[data-dashboard-dragging="true"]
|
|
437
|
+
.dashboard-column-drop-slot {
|
|
438
|
+
pointer-events: auto;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
.explorer-dashboard-grid [data-dragging="true"] {
|
|
442
|
+
opacity: 0.55;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.explorer-dashboard-grid[data-dashboard-dragging="true"]
|
|
446
|
+
.explorer-dashboard-chart-content {
|
|
447
|
+
pointer-events: none;
|
|
448
|
+
}
|
|
449
|
+
|
|
379
450
|
@container dashboard-grid (min-width: 768px) {
|
|
380
451
|
.dashboard-grid {
|
|
381
452
|
flex-direction: row;
|
|
@@ -389,10 +460,10 @@
|
|
|
389
460
|
|
|
390
461
|
.dashboard-column-drop-slot {
|
|
391
462
|
align-self: stretch;
|
|
392
|
-
width:
|
|
463
|
+
width: 1.5rem;
|
|
393
464
|
height: auto;
|
|
394
465
|
margin-block: 0;
|
|
395
|
-
margin-inline: -0.
|
|
466
|
+
margin-inline: -0.75rem;
|
|
396
467
|
}
|
|
397
468
|
|
|
398
469
|
.dashboard-column-drop-slot::after {
|
|
@@ -400,7 +471,7 @@
|
|
|
400
471
|
bottom: 0;
|
|
401
472
|
left: 50%;
|
|
402
473
|
right: auto;
|
|
403
|
-
width:
|
|
474
|
+
width: 3px;
|
|
404
475
|
height: auto;
|
|
405
476
|
transform: translateX(-50%);
|
|
406
477
|
}
|