Skip to content

Commit ef2943c

Browse files
authored
Merge pull request #44 from grafana/matryer/create-dashboards
added create_dashboard tool
2 parents 6ea0128 + ad845cf commit ef2943c

File tree

3 files changed

+119
-0
lines changed

3 files changed

+119
-0
lines changed

public/app/features/dash/agent/tools/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { prometheusRangeQueryTool } from './prometheusRangeQuery';
1717
import { readDashboardPanelsTool } from './tool_read_dashboard_panels';
1818
import { simulateToolError } from './tool_simulate_tool_error';
1919
import { updateDashboardPanelsTool } from './tool_update_dashboard_panels';
20+
import { createDashboardTool } from './tool_create_dashboard';
2021

2122
const grafanaComSearch = new TavilySearchResults({
2223
apiKey: process.env.TAVILY_API_KEY,
@@ -60,6 +61,7 @@ export const tools = [
6061
updateDashboardPanelsTool,
6162
getDrilldownLogToSummarizeTool,
6263
simulateToolError,
64+
createDashboardTool,
6365
];
6466

6567
export const toolsByName = tools.reduce(
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { tool } from '@langchain/core/tools';
2+
import { z } from 'zod';
3+
import { locationService } from '@grafana/runtime';
4+
5+
const dashboardSchema = z.object({
6+
title: z.string().describe('The title of the dashboard'),
7+
uid: z.string().optional().describe('The unique identifier for the dashboard'),
8+
folderUid: z.string().optional().describe('The folder UID to place the dashboard in'),
9+
data: z.any().describe('The dashboard data object containing panels and other configuration'),
10+
});
11+
12+
export const createDashboardTool = tool(
13+
async (input): Promise<string> => {
14+
// Validate input
15+
const validatedInput = dashboardSchema.parse(input);
16+
17+
// Create dashboard data
18+
const dashboardData = {
19+
dashboard: {
20+
...validatedInput.data,
21+
title: validatedInput.title,
22+
uid: validatedInput.uid,
23+
folderUid: validatedInput.folderUid,
24+
},
25+
overwrite: false,
26+
};
27+
28+
// Create dashboard
29+
const response = await fetch('/api/dashboards/db', {
30+
method: 'POST',
31+
headers: {
32+
'Content-Type': 'application/json',
33+
},
34+
body: JSON.stringify(dashboardData),
35+
});
36+
37+
if (!response.ok) {
38+
return JSON.stringify({
39+
error: 'Failed to create dashboard',
40+
details: response.statusText,
41+
});
42+
}
43+
44+
const result = await response.json();
45+
46+
if (!result.uid || !result.url) {
47+
return JSON.stringify({
48+
error: 'Invalid response from Grafana API',
49+
details: 'Response missing required fields',
50+
});
51+
}
52+
53+
// Navigate to the new dashboard
54+
locationService.push({ pathname: result.url });
55+
56+
return JSON.stringify({
57+
success: true,
58+
uid: result.uid,
59+
url: result.url,
60+
message: 'Dashboard created and navigated to successfully',
61+
});
62+
},
63+
{
64+
name: 'create_dashboard',
65+
description:
66+
'Creates a new dashboard with the specified title, optional UID, folder, and dashboard data. Automatically navigates to the new dashboard after creation.',
67+
schema: dashboardSchema,
68+
}
69+
);

tool_create_dashboard.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { z } from 'zod';
2+
import { GrafanaClient } from './grafana-client';
3+
4+
const dashboardSchema = z.object({
5+
title: z.string(),
6+
uid: z.string().optional(),
7+
folderUid: z.string().optional(),
8+
data: z.any(),
9+
});
10+
11+
export type CreateDashboardInput = z.infer<typeof dashboardSchema>;
12+
13+
export async function create_dashboard(
14+
client: GrafanaClient,
15+
input: CreateDashboardInput
16+
): Promise<{ uid: string; url: string }> {
17+
// Validate input
18+
const validatedInput = dashboardSchema.parse(input);
19+
20+
// Create dashboard data
21+
const dashboardData = {
22+
dashboard: {
23+
...validatedInput.data,
24+
title: validatedInput.title,
25+
uid: validatedInput.uid,
26+
folderUid: validatedInput.folderUid,
27+
},
28+
overwrite: false,
29+
};
30+
31+
// Create dashboard
32+
const response = await client.post('/api/dashboards/db', dashboardData);
33+
34+
if (!response.ok) {
35+
throw new Error(`Failed to create dashboard: ${response.statusText}`);
36+
}
37+
38+
const result = await response.json();
39+
40+
if (!result.uid || !result.url) {
41+
throw new Error('Invalid response from Grafana API');
42+
}
43+
44+
return {
45+
uid: result.uid,
46+
url: result.url,
47+
};
48+
}

0 commit comments

Comments
 (0)