import { css } from '@emotion/css'; import saveAs from 'file-saver'; import { useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { useAsyncFn } from 'react-use'; import { lastValueFrom } from 'rxjs'; import { GrafanaTheme2, UrlQueryMap } from '@grafana/data'; import { selectors as e2eSelectors } from '@grafana/e2e-selectors'; import { config, getBackendSrv, isFetchError } from '@grafana/runtime'; import { Alert, Button, Field, FieldSet, Icon, Input, LoadingBar, Stack, Text, Tooltip, useStyles2 } from '@grafana/ui'; import { t, Trans } from 'app/core/internationalization'; import { DashboardInteractions } from '../../utils/interactions'; type ImageSettingsForm = { width: number; height: number; scaleFactor: number; }; type Props = { title: string; buildUrl: (urlParams: UrlQueryMap) => void; imageUrl: string; disabled: boolean; theme: string; }; const selector = e2eSelectors.pages.ShareDashboardDrawer.ShareInternally.SharePanel; export function SharePanelPreview({ title, imageUrl, buildUrl, disabled, theme }: Props) { const styles = useStyles2(getStyles); const { handleSubmit, register, watch, formState: { errors, isValid }, } = useForm({ mode: 'onChange', defaultValues: { width: 1000, height: 500, scaleFactor: 1, }, }); useEffect(() => { buildUrl({ width: watch('width'), height: watch('height'), scale: watch('scaleFactor') }); }, [buildUrl, watch]); const [{ loading, value: image, error }, renderImage] = useAsyncFn(async (imageUrl) => { const response = await lastValueFrom(getBackendSrv().fetch({ url: imageUrl, responseType: 'blob' })); return new Blob([response.data], { type: 'image/png' }); }, []); const onRenderImageClick = async (data: ImageSettingsForm) => { const { width, height, scaleFactor } = data; DashboardInteractions.generatePanelImageClicked({ width, height, scaleFactor, theme, shareResource: 'panel', }); await renderImage(imageUrl); }; const onDownloadImageClick = () => { DashboardInteractions.downloadPanelImageClicked({ shareResource: 'panel' }); saveAs(image!, `${title}.png`); }; const onChange = () => { buildUrl({ width: watch('width'), height: watch('height'), scale: watch('scaleFactor') }); }; return (
Panel preview
Image settings } >
{loading && (
{title || ''}
)} {image && !loading && panel-preview-img} {error && !loading && ( {isFetchError(error) ? error.statusText : t('link.share-panel.render-image-error-description', 'An error occurred when generating the image')} )}
); } const getStyles = (theme: GrafanaTheme2) => ({ imageConfigurationField: css({ flex: 1, }), image: css({ maxWidth: '100%', width: 'max-content', }), imageLoadingContainer: css({ maxWidth: '100%', height: 362, border: `1px solid ${theme.components.input.borderColor}`, padding: theme.spacing(1), }), });