Panels: Add panel debug support helper (#54678)

pull/55009/head
Ryan McKinley 3 years ago committed by GitHub
parent c49c238974
commit 4125dd57ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      .betterer.results
  2. 6
      public/app/features/dashboard/components/Inspector/PanelInspector.tsx
  3. 37
      public/app/features/dashboard/components/SupportSnapshot/SupportSnapshot.tsx
  4. 0
      public/app/features/dashboard/components/SupportSnapshot/randomizer.test.ts
  5. 0
      public/app/features/dashboard/components/SupportSnapshot/randomizer.ts
  6. 0
      public/app/features/dashboard/components/SupportSnapshot/utils.ts
  7. 21
      public/app/features/dashboard/utils/getPanelMenu.ts
  8. 6
      public/app/features/inspector/InspectJSONTab.tsx
  9. 2
      public/app/features/inspector/types.ts

@ -3705,9 +3705,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"] [0, 0, 0, "Unexpected any. Specify a different type.", "1"]
], ],
"public/app/features/dashboard/components/DebugWizard/randomizer.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/dashboard/components/Inspector/PanelInspectActions.tsx:5381": [ "public/app/features/dashboard/components/Inspector/PanelInspectActions.tsx:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Do not use any type assertions.", "0"],
[0, 0, 0, "Do not use any type assertions.", "1"], [0, 0, 0, "Do not use any type assertions.", "1"],
@ -3859,6 +3856,9 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"] [0, 0, 0, "Unexpected any. Specify a different type.", "1"]
], ],
"public/app/features/dashboard/components/SupportSnapshot/randomizer.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx:5381": [ "public/app/features/dashboard/components/TransformationsEditor/TransformationEditor.tsx:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"] [0, 0, 0, "Unexpected any. Specify a different type.", "1"]

@ -10,8 +10,8 @@ import { getPanelStateForModel } from 'app/features/panel/state/selectors';
import { StoreState } from 'app/types'; import { StoreState } from 'app/types';
import { GetDataOptions } from '../../../query/state/PanelQueryRunner'; import { GetDataOptions } from '../../../query/state/PanelQueryRunner';
import { DebugWizard } from '../DebugWizard/DebugWizard';
import { usePanelLatestData } from '../PanelEditor/usePanelLatestData'; import { usePanelLatestData } from '../PanelEditor/usePanelLatestData';
import { SupportSnapshot } from '../SupportSnapshot/SupportSnapshot';
import { InspectContent } from './InspectContent'; import { InspectContent } from './InspectContent';
import { useDatasourceMetadata, useInspectTabs } from './hooks'; import { useDatasourceMetadata, useInspectTabs } from './hooks';
@ -50,8 +50,8 @@ const PanelInspectorUnconnected = ({ panel, dashboard, plugin }: Props) => {
return null; return null;
} }
if (defaultTab === InspectTab.Debug) { if (defaultTab === InspectTab.Support) {
return <DebugWizard panel={panel} plugin={plugin} onClose={onClose} />; return <SupportSnapshot panel={panel} plugin={plugin} onClose={onClose} />;
} }
return ( return (

@ -58,15 +58,15 @@ const options: Array<SelectableValue<ShowMessge>> = [
value: ShowMessge.GithubComment, value: ShowMessge.GithubComment,
}, },
{ {
label: 'Panel debug snapshot', label: 'Panel support snapshot',
description: 'Dashboard to help debug any visualization issues', description: 'Dashboard JSON used to help troubleshoot visualization issues',
value: ShowMessge.PanelSnapshot, value: ShowMessge.PanelSnapshot,
}, },
]; ];
export const DebugWizard = ({ panel, plugin, onClose }: Props) => { export function SupportSnapshot({ panel, plugin, onClose }: Props) {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
const [currentTab, setCurrentTab] = useState(InspectTab.Debug); const [currentTab, setCurrentTab] = useState(InspectTab.Support);
const [showMessage, setShowMessge] = useState(ShowMessge.GithubComment); const [showMessage, setShowMessge] = useState(ShowMessge.GithubComment);
const [snapshotText, setDashboardText] = useState('...'); const [snapshotText, setDashboardText] = useState('...');
const [rand, setRand] = useState<Randomize>({}); const [rand, setRand] = useState<Randomize>({});
@ -109,13 +109,22 @@ export const DebugWizard = ({ panel, plugin, onClose }: Props) => {
}; };
const doCopyMarkdown = () => { 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); copyToClipboard(markdownText);
appEvents.emit(AppEvents.alertSuccess, [`Message copied`]); appEvents.emit(AppEvents.alertSuccess, [`Message copied`]);
}; };
const tabs = [ const tabs = [
{ label: 'Snapshot', value: InspectTab.Debug }, { label: 'Support', value: InspectTab.Support },
{ label: 'Code', value: InspectTab.JSON }, { label: 'Data', value: InspectTab.JSON },
]; ];
let activeTab = currentTab; let activeTab = currentTab;
if (!tabs.find((item) => item.value === currentTab)) { if (!tabs.find((item) => item.value === currentTab)) {
@ -129,7 +138,7 @@ export const DebugWizard = ({ panel, plugin, onClose }: Props) => {
return ( return (
<Drawer <Drawer
title={`Debug: ${panelTitle}`} title={`Panel: ${panelTitle}`}
width="90%" width="90%"
onClose={onClose} onClose={onClose}
expandable expandable
@ -137,7 +146,7 @@ export const DebugWizard = ({ panel, plugin, onClose }: Props) => {
subtitle={ subtitle={
<div> <div>
<p> <p>
<FeatureBadge featureState={FeatureState.alpha} /> <FeatureBadge featureState={FeatureState.beta} />
</p> </p>
</div> </div>
} }
@ -149,7 +158,7 @@ export const DebugWizard = ({ panel, plugin, onClose }: Props) => {
key={`${t.value}-${index}`} key={`${t.value}-${index}`}
label={t.label} label={t.label}
active={t.value === activeTab} active={t.value === activeTab}
onChangeTab={() => setCurrentTab(t.value || InspectTab.Debug)} onChangeTab={() => setCurrentTab(t.value || InspectTab.Support)}
/> />
); );
})} })}
@ -226,15 +235,15 @@ export const DebugWizard = ({ panel, plugin, onClose }: Props) => {
)} )}
<Field <Field
label="Debug snapshot" label="Support snapshot"
description="A panel debug snapshot creates a dashboard that can reproduce visualization issues while disconnected from the original data sources." description="This snapshot contains the query response data and raw panel settings. Including this snapshot in support requests can help identify issues faster."
> >
<> <>
<HorizontalGroup> <HorizontalGroup>
<Button icon="download-alt" onClick={doDownloadDashboard}> <Button icon="download-alt" onClick={doDownloadDashboard}>
Download ({snapshotSize}) Dashboard ({snapshotSize})
</Button> </Button>
<Button icon="github" onClick={doCopyMarkdown}> <Button icon="github" onClick={doCopyMarkdown} title="Paste this into a github issue">
Copy for github Copy for github
</Button> </Button>
<Button onClick={doImportDashboard} variant="secondary"> <Button onClick={doImportDashboard} variant="secondary">
@ -258,7 +267,7 @@ export const DebugWizard = ({ panel, plugin, onClose }: Props) => {
)} )}
</Drawer> </Drawer>
); );
}; }
const getStyles = (theme: GrafanaTheme2) => ({ const getStyles = (theme: GrafanaTheme2) => ({
code: css` code: css`

@ -4,6 +4,8 @@ import { PanelMenuItem } from '@grafana/data';
import { AngularComponent, getDataSourceSrv, locationService } from '@grafana/runtime'; import { AngularComponent, getDataSourceSrv, locationService } from '@grafana/runtime';
import { PanelCtrl } from 'app/angular/panel/panel_ctrl'; import { PanelCtrl } from 'app/angular/panel/panel_ctrl';
import config from 'app/core/config'; import config from 'app/core/config';
import { contextSrv } from 'app/core/services/context_srv';
import { getExploreUrl } from 'app/core/utils/explore';
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel'; import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
import { PanelModel } from 'app/features/dashboard/state/PanelModel'; import { PanelModel } from 'app/features/dashboard/state/PanelModel';
import { import {
@ -15,11 +17,10 @@ import {
toggleLegend, toggleLegend,
unlinkLibraryPanel, unlinkLibraryPanel,
} from 'app/features/dashboard/utils/panel'; } from 'app/features/dashboard/utils/panel';
import { InspectTab } from 'app/features/inspector/types';
import { isPanelModelLibraryPanel } from 'app/features/library-panels/guard'; import { isPanelModelLibraryPanel } from 'app/features/library-panels/guard';
import { store } from 'app/store/store'; import { store } from 'app/store/store';
import { contextSrv } from '../../../core/services/context_srv';
import { getExploreUrl } from '../../../core/utils/explore';
import { navigateToExplore } from '../../explore/state/main'; import { navigateToExplore } from '../../explore/state/main';
import { getTimeSrv } from '../services/TimeSrv'; import { getTimeSrv } from '../services/TimeSrv';
@ -62,7 +63,7 @@ export function getPanelMenu(
unlinkLibraryPanel(panel); unlinkLibraryPanel(panel);
}; };
const onInspectPanel = (tab?: string) => { const onInspectPanel = (tab?: InspectTab) => {
locationService.partial({ locationService.partial({
inspect: panel.id, inspect: panel.id,
inspectTab: tab, inspectTab: tab,
@ -158,13 +159,13 @@ export function getPanelMenu(
inspectMenu.push({ inspectMenu.push({
text: dataTextTranslation, text: dataTextTranslation,
onClick: (e: React.MouseEvent<any>) => onInspectPanel('data'), onClick: (e: React.MouseEvent<any>) => onInspectPanel(InspectTab.Data),
}); });
if (dashboard.meta.canEdit) { if (dashboard.meta.canEdit) {
inspectMenu.push({ inspectMenu.push({
text: 'Query', text: 'Query',
onClick: (e: React.MouseEvent<any>) => onInspectPanel('query'), onClick: (e: React.MouseEvent<any>) => onInspectPanel(InspectTab.Query),
}); });
} }
} }
@ -176,9 +177,17 @@ export function getPanelMenu(
inspectMenu.push({ inspectMenu.push({
text: jsonTextTranslation, text: jsonTextTranslation,
onClick: (e: React.MouseEvent<any>) => onInspectPanel('json'), onClick: (e: React.MouseEvent<any>) => onInspectPanel(InspectTab.JSON),
}); });
// Only show for editors
if (panel.plugin && dashboard.meta.canEdit && !panel.plugin.meta.skipDataQuery) {
inspectMenu.push({
text: 'Support snapshot',
onClick: (e: React.MouseEvent) => onInspectPanel(InspectTab.Support),
});
}
const inspectTextTranslation = t({ const inspectTextTranslation = t({
id: 'panel.header-menu.inspect', id: 'panel.header-menu.inspect',
message: `Inspect`, message: `Inspect`,

@ -10,7 +10,7 @@ import { Button, CodeEditor, Field, Select } from '@grafana/ui';
import { appEvents } from 'app/core/core'; import { appEvents } from 'app/core/core';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { getPanelDataFrames } from '../dashboard/components/DebugWizard/utils'; import { getPanelDataFrames } from '../dashboard/components/SupportSnapshot/utils';
import { getPanelInspectorStyles } from '../inspector/styles'; import { getPanelInspectorStyles } from '../inspector/styles';
import { InspectTab } from './types'; import { InspectTab } from './types';
@ -136,7 +136,7 @@ export class InspectJSONTab extends PureComponent<Props, State> {
onShowSupportWizard = () => { onShowSupportWizard = () => {
const queryParms = locationService.getSearch(); const queryParms = locationService.getSearch();
queryParms.set('inspectTab', InspectTab.Debug.toString()); queryParms.set('inspectTab', InspectTab.Support.toString());
locationService.push('?' + queryParms.toString()); locationService.push('?' + queryParms.toString());
}; };
@ -170,7 +170,7 @@ export class InspectJSONTab extends PureComponent<Props, State> {
)} )}
{show === ShowContent.DataFrames && ( {show === ShowContent.DataFrames && (
<Button className={styles.toolbarItem} onClick={this.onShowSupportWizard}> <Button className={styles.toolbarItem} onClick={this.onShowSupportWizard}>
Debug Support
</Button> </Button>
)} )}
</div> </div>

@ -6,5 +6,5 @@ export enum InspectTab {
JSON = 'json', JSON = 'json',
Query = 'query', Query = 'query',
Actions = 'actions', // ALPHA! Actions = 'actions', // ALPHA!
Debug = 'debug', // get info required for support+debugging Support = 'support', // get info required for support+debugging
} }

Loading…
Cancel
Save