import { css } from '@emotion/css'; import { saveAs } from 'file-saver'; import React, { useState, useMemo } from 'react'; import { useAsync, useCopyToClipboard } from 'react-use'; import AutoSizer from 'react-virtualized-auto-sizer'; import { PanelPlugin, GrafanaTheme2, AppEvents, SelectableValue, dateTimeFormat, getValueFormat, FeatureState, formattedValueToString, } from '@grafana/data'; import { config, getTemplateSrv } from '@grafana/runtime'; import { Drawer, Tab, TabsBar, CodeEditor, useStyles2, Field, HorizontalGroup, InlineSwitch, Button, Spinner, Alert, FeatureBadge, Select, } from '@grafana/ui'; import appEvents from 'app/core/app_events'; import { contextSrv } from 'app/core/core'; import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { PanelModel } from 'app/features/dashboard/state'; import { setDashboardToFetchFromLocalStorage } from 'app/features/dashboard/state/initDashboard'; import { InspectTab } from 'app/features/inspector/types'; import { Randomize } from './randomizer'; import { getGithubMarkdown, getDebugDashboard } from './utils'; interface Props { panel: PanelModel; plugin?: PanelPlugin | null; onClose: () => void; } enum ShowMessge { PanelSnapshot = 'snap', GithubComment = 'github', } const options: Array> = [ { label: 'Github comment', description: 'Copy and paste this message into a github issue or comment', value: ShowMessge.GithubComment, }, { label: 'Panel support snapshot', description: 'Dashboard JSON used to help troubleshoot visualization issues', value: ShowMessge.PanelSnapshot, }, ]; export function SupportSnapshot({ panel, plugin, onClose }: Props) { const styles = useStyles2(getStyles); const [currentTab, setCurrentTab] = useState(InspectTab.Support); const [showMessage, setShowMessge] = useState(ShowMessge.GithubComment); const [snapshotText, setDashboardText] = useState('...'); const [rand, setRand] = useState({}); const [_, copyToClipboard] = useCopyToClipboard(); const info = useAsync(async () => { const dashboard = await getDebugDashboard(panel, rand, getTimeSrv().timeRange()); setDashboardToFetchFromLocalStorage({ meta: {}, dashboard }); setDashboardText(JSON.stringify(dashboard, null, 2)); }, [rand, panel, plugin, setDashboardText, currentTab]); const snapshotSize = useMemo(() => { return formattedValueToString(getValueFormat('bytes')(snapshotText?.length ?? 0)); }, [snapshotText]); const markdownText = useMemo(() => { return getGithubMarkdown(panel, snapshotText); }, [snapshotText, panel]); if (!plugin) { return null; } const panelTitle = getTemplateSrv().replace(panel.title, panel.scopedVars, 'text') || 'Panel'; const toggleRandomize = (k: keyof Randomize) => { setRand({ ...rand, [k]: !rand[k] }); }; const doImportDashboard = () => { setDashboardToFetchFromLocalStorage({ meta: {}, dashboard: JSON.parse(snapshotText) }); global.open(config.appUrl + 'dashboard/new', '_blank'); }; const doDownloadDashboard = () => { const blob = new Blob([snapshotText], { type: 'text/plain', }); const fileName = `debug-${panelTitle}-${dateTimeFormat(new Date())}.json.txt`; saveAs(blob, fileName); }; const doCopyMarkdown = () => { const maxLen = Math.pow(1024, 2) * 1.5; // 1.5MB if (markdownText.length > maxLen) { appEvents.emit(AppEvents.alertError, [ `Snapshot is too large`, 'Consider downloading and attaching the file instead', ]); return; } copyToClipboard(markdownText); appEvents.emit(AppEvents.alertSuccess, [`Message copied`]); }; const tabs = [ { label: 'Support', value: InspectTab.Support }, { label: 'Data', value: InspectTab.JSON }, ]; let activeTab = currentTab; if (!tabs.find((item) => item.value === currentTab)) { activeTab = InspectTab.JSON; } const renderError = () => { console.error('Error', info.error); return {`${info.error}`}; }; return (

} tabs={ {tabs.map((t, index) => { return ( setCurrentTab(t.value || InspectTab.Support)} /> ); })} } > {info.loading && } {info.error && renderError()} {activeTab === InspectTab.JSON ? (