diff --git a/public/app/features/dashboard/components/DebugWizard/DebugWizard.tsx b/public/app/features/dashboard/components/DebugWizard/DebugWizard.tsx new file mode 100644 index 00000000000..920610bc2fc --- /dev/null +++ b/public/app/features/dashboard/components/DebugWizard/DebugWizard.tsx @@ -0,0 +1,280 @@ +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 { getTemplateSrv, locationService } 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 { pendingNewDashboard } 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 debug snapshot', + description: 'Dashboard to help debug any visualization issues', + value: ShowMessge.PanelSnapshot, + }, +]; + +export const DebugWizard = ({ panel, plugin, onClose }: Props) => { + const styles = useStyles2(getStyles); + const [currentTab, setCurrentTab] = useState(InspectTab.Debug); + const [showMessage, setShowMessge] = useState(ShowMessge.GithubComment); + const [snapshotText, setDashboardText] = useState('...'); + const [rand, setRand] = useState({}); + const [_, copyToClipboard] = useCopyToClipboard(); + const info = useAsync(async () => { + const dash = await getDebugDashboard(panel, rand, getTimeSrv().timeRange()); + setDashboardText(JSON.stringify(dash, null, 2)); + }, [rand, panel, plugin, setDashboardText]); + + 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 = () => { + pendingNewDashboard.dashboard = JSON.parse(snapshotText); + locationService.push('/dashboard/new'); // will load the above body + appEvents.emit(AppEvents.alertSuccess, ['Panel snapshot dashboard']); + }; + + const doDownloadDashboard = () => { + const blob = new Blob([snapshotText], { + type: 'text/plain', + }); + const fileName = `debug-${panelTitle}-${dateTimeFormat(new Date())}.json.txt`; + saveAs(blob, fileName); + }; + + const doCopyMarkdown = () => { + copyToClipboard(markdownText); + appEvents.emit(AppEvents.alertSuccess, [`Message copied`]); + }; + + const tabs = [ + { label: 'Snapshot', value: InspectTab.Debug }, + { label: 'Code', 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.Debug)} + /> + ); + })} + + } + > + {info.loading && } + {info.error && renderError()} + + {activeTab === InspectTab.JSON ? ( +
+
+ +