Sharing: Export dashboard as image match user's window width (#108827)
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
import { test, expect } from '@grafana/plugin-e2e';
|
||||
|
||||
const DASHBOARD_UID = 'ZqZnVvFZz';
|
||||
|
||||
test.use({
|
||||
featureToggles: {
|
||||
scenes: true,
|
||||
newDashboardSharingComponent: true,
|
||||
sharingDashboardImage: true, // Enable the export image feature
|
||||
},
|
||||
});
|
||||
|
||||
test.describe(
|
||||
'Export as Image',
|
||||
{
|
||||
tag: ['@dashboards'],
|
||||
},
|
||||
() => {
|
||||
test('Show renderer not available message when plugin not installed', async ({
|
||||
gotoDashboardPage,
|
||||
page,
|
||||
selectors,
|
||||
}) => {
|
||||
// Navigate to a dashboard
|
||||
const dashboardPage = await gotoDashboardPage({
|
||||
uid: DASHBOARD_UID,
|
||||
});
|
||||
|
||||
// Open the export dropdown
|
||||
await dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.DashNav.NewExportButton.arrowMenu).click();
|
||||
|
||||
// Click export as image option
|
||||
await dashboardPage
|
||||
.getByGrafanaSelector(selectors.pages.Dashboard.DashNav.NewExportButton.Menu.exportAsImage)
|
||||
.click();
|
||||
|
||||
// Verify we're on the export image view
|
||||
await expect(page).toHaveURL(/.*shareView=image/);
|
||||
|
||||
// Verify the "renderer not available" alert is displayed
|
||||
const rendererAlert = page.getByRole('status');
|
||||
await expect(rendererAlert).toBeVisible();
|
||||
await expect(rendererAlert).toContainText(/Image renderer plugin not installed/i);
|
||||
await expect(rendererAlert).toContainText(
|
||||
/To render an image, you must install the Grafana image renderer plugin/i
|
||||
);
|
||||
|
||||
// Verify the generate button is NOT present when renderer is unavailable
|
||||
await expect(page.getByRole('button', { name: /Generate image/i })).not.toBeVisible();
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -52,6 +52,7 @@ export default function ExportMenu({ dashboard }: { dashboard: DashboardScene })
|
||||
|
||||
menuItems.push({
|
||||
shareId: shareDashboardType.image,
|
||||
testId: newExportButtonSelector.exportAsImage,
|
||||
icon: 'camera',
|
||||
label: t('share-dashboard.menu.export-image-title', 'Export as image'),
|
||||
renderCondition: Boolean(config.featureToggles.sharingDashboardImage),
|
||||
|
||||
@@ -96,6 +96,13 @@ describe('Dashboard Export Image Utils', () => {
|
||||
const fetchMock = jest.fn().mockReturnValue(of({ ok: true, data: mockBlob }));
|
||||
(getBackendSrv as jest.Mock).mockReturnValue({ fetch: fetchMock });
|
||||
|
||||
// Mock window.innerWidth
|
||||
Object.defineProperty(window, 'innerWidth', {
|
||||
writable: true,
|
||||
configurable: true,
|
||||
value: 1280,
|
||||
});
|
||||
|
||||
const dashboard = {
|
||||
state: {
|
||||
uid: 'test-uid',
|
||||
@@ -119,7 +126,7 @@ describe('Dashboard Export Image Utils', () => {
|
||||
absolute: true,
|
||||
updateQuery: {
|
||||
height: -1,
|
||||
width: 1000,
|
||||
width: 1280,
|
||||
scale: 2,
|
||||
kiosk: true,
|
||||
hideNav: true,
|
||||
@@ -128,5 +135,46 @@ describe('Dashboard Export Image Utils', () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should fallback to config width when window.innerWidth is not available', async () => {
|
||||
config.rendererAvailable = true;
|
||||
config.rendererDefaultImageWidth = 1500;
|
||||
const mockBlob = new Blob(['test'], { type: 'image/png' });
|
||||
const fetchMock = jest.fn().mockReturnValue(of({ ok: true, data: mockBlob }));
|
||||
(getBackendSrv as jest.Mock).mockReturnValue({ fetch: fetchMock });
|
||||
|
||||
// Ensure window.innerWidth is undefined
|
||||
Object.defineProperty(window, 'innerWidth', {
|
||||
writable: true,
|
||||
configurable: true,
|
||||
value: undefined,
|
||||
});
|
||||
|
||||
const dashboard = {
|
||||
state: {
|
||||
uid: 'test-uid',
|
||||
},
|
||||
} as DashboardScene;
|
||||
|
||||
const result = await generateDashboardImage({ dashboard, scale: 1 });
|
||||
|
||||
expect(result.error).toBeUndefined();
|
||||
expect(result.blob).toBe(mockBlob);
|
||||
expect(getDashboardUrl).toHaveBeenCalledWith({
|
||||
uid: 'test-uid',
|
||||
currentQueryParams: '',
|
||||
render: true,
|
||||
absolute: true,
|
||||
updateQuery: {
|
||||
height: -1,
|
||||
width: 1500, // Should use config value
|
||||
scale: 1,
|
||||
kiosk: true,
|
||||
hideNav: true,
|
||||
orgId: '1',
|
||||
fullPageImage: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,7 +28,7 @@ export interface ImageGenerationResult {
|
||||
*/
|
||||
export async function generateDashboardImage({
|
||||
dashboard,
|
||||
scale = config.rendererDefaultImageScale || 1,
|
||||
scale = config.rendererDefaultImageScale || 2,
|
||||
}: ImageGenerationOptions): Promise<ImageGenerationResult> {
|
||||
try {
|
||||
// Check if renderer plugin is available
|
||||
@@ -46,7 +46,7 @@ export async function generateDashboardImage({
|
||||
absolute: true,
|
||||
updateQuery: {
|
||||
height: -1, // image renderer will scroll through the dashboard and set the appropriate height
|
||||
width: config.rendererDefaultImageWidth || 1000,
|
||||
width: window.innerWidth || config.rendererDefaultImageWidth || 1000,
|
||||
scale,
|
||||
kiosk: true,
|
||||
hideNav: true,
|
||||
|
||||
Reference in New Issue
Block a user