dashboard screenshots

This commit is contained in:
Nate Kelley 2025-10-02 22:14:59 -06:00
parent c4be6a8c96
commit c3e6bd4164
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
4 changed files with 98 additions and 44 deletions

View File

@ -161,7 +161,7 @@ import { ServerRoute as AuthConfirmServerRouteImport } from './routes/auth.confi
import { ServerRoute as AuthCallbackServerRouteImport } from './routes/auth.callback'
import { ServerRoute as ScreenshotsReportsReportIdServerRouteImport } from './routes/screenshots/reports.$reportId'
import { ServerRoute as ScreenshotsMetricsMetricIdIndexServerRouteImport } from './routes/screenshots/metrics.$metricId.index'
import { ServerRoute as ScreenshotsDashboardDashboardIdIndexServerRouteImport } from './routes/screenshots/dashboard.$dashboardId.index'
import { ServerRoute as ScreenshotsDashboardsDashboardIdIndexServerRouteImport } from './routes/screenshots/dashboards.$dashboardId.index'
import { ServerRoute as ScreenshotsChatsChatIdIndexServerRouteImport } from './routes/screenshots/chats.$chatId.index'
const ScreenshotsRouteImport = createFileRoute('/screenshots')()
@ -1235,10 +1235,10 @@ const ScreenshotsMetricsMetricIdIndexServerRoute =
path: '/screenshots/metrics/$metricId/',
getParentRoute: () => rootServerRouteImport,
} as any)
const ScreenshotsDashboardDashboardIdIndexServerRoute =
ScreenshotsDashboardDashboardIdIndexServerRouteImport.update({
id: '/screenshots/dashboard/$dashboardId/',
path: '/screenshots/dashboard/$dashboardId/',
const ScreenshotsDashboardsDashboardIdIndexServerRoute =
ScreenshotsDashboardsDashboardIdIndexServerRouteImport.update({
id: '/screenshots/dashboards/$dashboardId/',
path: '/screenshots/dashboards/$dashboardId/',
getParentRoute: () => rootServerRouteImport,
} as any)
const ScreenshotsChatsChatIdIndexServerRoute =
@ -2104,7 +2104,7 @@ export interface FileServerRoutesByFullPath {
'/auth/confirm': typeof AuthConfirmServerRoute
'/screenshots/reports/$reportId': typeof ScreenshotsReportsReportIdServerRoute
'/screenshots/chats/$chatId': typeof ScreenshotsChatsChatIdIndexServerRoute
'/screenshots/dashboard/$dashboardId': typeof ScreenshotsDashboardDashboardIdIndexServerRoute
'/screenshots/dashboards/$dashboardId': typeof ScreenshotsDashboardsDashboardIdIndexServerRoute
'/screenshots/metrics/$metricId': typeof ScreenshotsMetricsMetricIdIndexServerRoute
}
export interface FileServerRoutesByTo {
@ -2112,7 +2112,7 @@ export interface FileServerRoutesByTo {
'/auth/confirm': typeof AuthConfirmServerRoute
'/screenshots/reports/$reportId': typeof ScreenshotsReportsReportIdServerRoute
'/screenshots/chats/$chatId': typeof ScreenshotsChatsChatIdIndexServerRoute
'/screenshots/dashboard/$dashboardId': typeof ScreenshotsDashboardDashboardIdIndexServerRoute
'/screenshots/dashboards/$dashboardId': typeof ScreenshotsDashboardsDashboardIdIndexServerRoute
'/screenshots/metrics/$metricId': typeof ScreenshotsMetricsMetricIdIndexServerRoute
}
export interface FileServerRoutesById {
@ -2121,7 +2121,7 @@ export interface FileServerRoutesById {
'/auth/confirm': typeof AuthConfirmServerRoute
'/screenshots/reports/$reportId': typeof ScreenshotsReportsReportIdServerRoute
'/screenshots/chats/$chatId/': typeof ScreenshotsChatsChatIdIndexServerRoute
'/screenshots/dashboard/$dashboardId/': typeof ScreenshotsDashboardDashboardIdIndexServerRoute
'/screenshots/dashboards/$dashboardId/': typeof ScreenshotsDashboardsDashboardIdIndexServerRoute
'/screenshots/metrics/$metricId/': typeof ScreenshotsMetricsMetricIdIndexServerRoute
}
export interface FileServerRouteTypes {
@ -2131,7 +2131,7 @@ export interface FileServerRouteTypes {
| '/auth/confirm'
| '/screenshots/reports/$reportId'
| '/screenshots/chats/$chatId'
| '/screenshots/dashboard/$dashboardId'
| '/screenshots/dashboards/$dashboardId'
| '/screenshots/metrics/$metricId'
fileServerRoutesByTo: FileServerRoutesByTo
to:
@ -2139,7 +2139,7 @@ export interface FileServerRouteTypes {
| '/auth/confirm'
| '/screenshots/reports/$reportId'
| '/screenshots/chats/$chatId'
| '/screenshots/dashboard/$dashboardId'
| '/screenshots/dashboards/$dashboardId'
| '/screenshots/metrics/$metricId'
id:
| '__root__'
@ -2147,7 +2147,7 @@ export interface FileServerRouteTypes {
| '/auth/confirm'
| '/screenshots/reports/$reportId'
| '/screenshots/chats/$chatId/'
| '/screenshots/dashboard/$dashboardId/'
| '/screenshots/dashboards/$dashboardId/'
| '/screenshots/metrics/$metricId/'
fileServerRoutesById: FileServerRoutesById
}
@ -2156,7 +2156,7 @@ export interface RootServerRouteChildren {
AuthConfirmServerRoute: typeof AuthConfirmServerRoute
ScreenshotsReportsReportIdServerRoute: typeof ScreenshotsReportsReportIdServerRoute
ScreenshotsChatsChatIdIndexServerRoute: typeof ScreenshotsChatsChatIdIndexServerRoute
ScreenshotsDashboardDashboardIdIndexServerRoute: typeof ScreenshotsDashboardDashboardIdIndexServerRoute
ScreenshotsDashboardsDashboardIdIndexServerRoute: typeof ScreenshotsDashboardsDashboardIdIndexServerRoute
ScreenshotsMetricsMetricIdIndexServerRoute: typeof ScreenshotsMetricsMetricIdIndexServerRoute
}
@ -3321,11 +3321,11 @@ declare module '@tanstack/react-start/server' {
preLoaderRoute: typeof ScreenshotsMetricsMetricIdIndexServerRouteImport
parentRoute: typeof rootServerRouteImport
}
'/screenshots/dashboard/$dashboardId/': {
id: '/screenshots/dashboard/$dashboardId/'
path: '/screenshots/dashboard/$dashboardId'
fullPath: '/screenshots/dashboard/$dashboardId'
preLoaderRoute: typeof ScreenshotsDashboardDashboardIdIndexServerRouteImport
'/screenshots/dashboards/$dashboardId/': {
id: '/screenshots/dashboards/$dashboardId/'
path: '/screenshots/dashboards/$dashboardId'
fullPath: '/screenshots/dashboards/$dashboardId'
preLoaderRoute: typeof ScreenshotsDashboardsDashboardIdIndexServerRouteImport
parentRoute: typeof rootServerRouteImport
}
'/screenshots/chats/$chatId/': {
@ -4389,8 +4389,8 @@ const rootServerRouteChildren: RootServerRouteChildren = {
ScreenshotsReportsReportIdServerRoute: ScreenshotsReportsReportIdServerRoute,
ScreenshotsChatsChatIdIndexServerRoute:
ScreenshotsChatsChatIdIndexServerRoute,
ScreenshotsDashboardDashboardIdIndexServerRoute:
ScreenshotsDashboardDashboardIdIndexServerRoute,
ScreenshotsDashboardsDashboardIdIndexServerRoute:
ScreenshotsDashboardsDashboardIdIndexServerRoute,
ScreenshotsMetricsMetricIdIndexServerRoute:
ScreenshotsMetricsMetricIdIndexServerRoute,
}

View File

@ -1,6 +1,9 @@
import { createFileRoute } from '@tanstack/react-router';
import { prefetchGetDashboard } from '@/api/buster_rest/dashboards';
import { GetDashboardScreenshotQuerySchema } from '../dashboard.$dashboardId.index';
import { ensureMetricData } from '@/api/buster_rest/metrics';
import { useGetDashboardParams } from '@/context/Dashboards/useGetDashboardParams';
import { DashboardViewDashboardController } from '@/controllers/DashboardController/DashboardViewDashboardController';
import { GetDashboardScreenshotQuerySchema } from '../dashboards.$dashboardId.index';
export const Route = createFileRoute('/screenshots/_content/dashboards/$dashboardId/content')({
component: RouteComponent,
@ -17,10 +20,31 @@ export const Route = createFileRoute('/screenshots/_content/dashboards/$dashboar
throw new Error('Dashboard not found');
}
const allMetrics = Object.entries(dashboard?.metrics || {});
await Promise.all(
allMetrics.map(([metricId, metric]) => {
return ensureMetricData(context.queryClient, {
id: metricId,
version_number: metric.version_number,
});
})
);
return { dashboard };
},
});
function RouteComponent() {
return <div>Hello "/screenshots/_content/dashboards/$dashboardId/content"!</div>;
const { dashboardId, dashboardVersionNumber } = useGetDashboardParams();
return (
<div className="h-full w-full bg-page-background overflow-y-auto">
<DashboardViewDashboardController
dashboardId={dashboardId}
dashboardVersionNumber={dashboardVersionNumber}
readOnly
animate={false}
/>
</div>
);
}

View File

@ -1,23 +0,0 @@
import { createFileRoute } from '@tanstack/react-router';
import { createServerFileRoute } from '@tanstack/react-start/server';
import { z } from 'zod';
export const GetDashboardScreenshotParamsSchema = z.object({
dashboardId: z.string(),
});
export const GetDashboardScreenshotQuerySchema = z.object({
version_number: z.coerce.number().min(1).optional(),
width: z.coerce.number().min(100).max(3840).default(800),
height: z.coerce.number().min(100).max(2160).default(450),
type: z.enum(['png', 'jpeg']).default('png'),
});
export const ServerRoute = createServerFileRoute('/screenshots/dashboard/$dashboardId/').methods({
GET: async ({ request, params }) => {
const { dashboardId } = GetDashboardScreenshotParamsSchema.parse(params);
const { version_number, width, height, type } = GetDashboardScreenshotQuerySchema.parse(
Object.fromEntries(new URL(request.url).searchParams)
);
},
});

View File

@ -0,0 +1,53 @@
import { createFileRoute } from '@tanstack/react-router';
import { createServerFileRoute } from '@tanstack/react-start/server';
import { z } from 'zod';
import { browserLogin } from '@/api/server-functions/browser-login';
import { createScreenshotResponse } from '@/api/server-functions/screenshot-helpers';
import { createHrefFromLink } from '@/lib/routes';
export const GetDashboardScreenshotParamsSchema = z.object({
dashboardId: z.string(),
});
export const GetDashboardScreenshotQuerySchema = z.object({
version_number: z.coerce.number().min(1).optional(),
width: z.coerce.number().min(100).max(3840).default(800),
height: z.coerce.number().min(100).max(4160).default(450),
type: z.enum(['png', 'jpeg']).default('png'),
});
export const ServerRoute = createServerFileRoute('/screenshots/dashboards/$dashboardId/').methods({
GET: async ({ request, params }) => {
const { dashboardId } = GetDashboardScreenshotParamsSchema.parse(params);
const { version_number, width, height, type } = GetDashboardScreenshotQuerySchema.parse(
Object.fromEntries(new URL(request.url).searchParams)
);
try {
const { result: screenshotBuffer } = await browserLogin({
width,
height,
fullPath: createHrefFromLink({
to: '/screenshots/dashboards/$dashboardId/content',
params: { dashboardId },
search: { version_number, type, width, height },
}),
request,
callback: async ({ page }) => {
const screenshotBuffer = await page.screenshot({ type });
return screenshotBuffer;
},
});
return createScreenshotResponse({ screenshotBuffer });
} catch (error) {
console.error('Error capturing dashboard screenshot', error);
return new Response(
JSON.stringify({
message: 'Failed to capture screenshot',
}),
{ status: 500, headers: { 'Content-Type': 'application/json' } }
);
}
},
});