From 00aa876e467e8873b319ea0aef3bedab813cf444 Mon Sep 17 00:00:00 2001 From: Haris Rozajac <58232930+harisrozajac@users.noreply.github.com> Date: Wed, 7 Feb 2024 06:32:08 -0700 Subject: [PATCH] Dashboard Scene: All panel menu items available (#81678) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WIP: removing panel functionality * wip * Deleting works with old model and with unified alerting * Add shortcut for removing panel * Add duplicate panel functionality; improve remove panel logic * Copy and new alert rule * Hide legend * WIP: Help wizard * Fix PanelMenuBehavior tests * Got help wizard to work in scenes * Fix HelpWizard and SupportSnapshotService tests * Use object for writing styles * betterer * Fix create lib panel * PanelRepeaterItem should be duplicated * Share randomizer from dashboard-scenes * share randomizer * Fix import * Update error message * Fix test * When duplicating PanelRepeaterGridItem's child use PanelRepeaterGridItem.state.source * Don't use getResultsStream --------- Co-authored-by: Torkel Ödegaard Co-authored-by: Dominik Prokop --- .betterer.results | 8 +- .../inspect/HelpWizard/HelpWizard.test.tsx | 94 ++++++ .../inspect/HelpWizard/HelpWizard.tsx | 229 +++++++++++++ .../HelpWizard/SupportSnapshotService.test.ts | 140 ++++++++ .../HelpWizard/SupportSnapshotService.ts | 132 ++++++++ .../inspect}/HelpWizard/randomizer.test.ts | 0 .../inspect}/HelpWizard/randomizer.ts | 0 .../inspect/HelpWizard/utils.ts | 307 ++++++++++++++++++ .../inspect/PanelInspectDrawer.tsx | 10 +- .../panel-edit/VizPanelManager.tsx | 2 +- .../dashboard-scene/scene/DashboardScene.tsx | 71 +++- .../scene/PanelMenuBehavior.test.tsx | 16 +- .../scene/PanelMenuBehavior.tsx | 176 +++++++++- .../scene/keyboardShortcuts.ts | 34 +- .../HelpWizard/SupportSnapshotService.ts | 2 +- .../dashboard/components/HelpWizard/utils.ts | 3 +- 16 files changed, 1187 insertions(+), 37 deletions(-) create mode 100644 public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.test.tsx create mode 100644 public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.tsx create mode 100644 public/app/features/dashboard-scene/inspect/HelpWizard/SupportSnapshotService.test.ts create mode 100644 public/app/features/dashboard-scene/inspect/HelpWizard/SupportSnapshotService.ts rename public/app/features/{dashboard/components => dashboard-scene/inspect}/HelpWizard/randomizer.test.ts (100%) rename public/app/features/{dashboard/components => dashboard-scene/inspect}/HelpWizard/randomizer.ts (100%) create mode 100644 public/app/features/dashboard-scene/inspect/HelpWizard/utils.ts diff --git a/.betterer.results b/.betterer.results index 0d2c5197690..b044889ad27 100644 --- a/.betterer.results +++ b/.betterer.results @@ -2571,6 +2571,9 @@ exports[`better eslint`] = { [0, 0, 0, "Styles should be written using objects.", "0"], [0, 0, 0, "Styles should be written using objects.", "1"] ], + "public/app/features/dashboard-scene/inspect/HelpWizard/utils.ts:5381": [ + [0, 0, 0, "Do not use any type assertions.", "0"] + ], "public/app/features/dashboard-scene/inspect/InspectJsonTab.tsx:5381": [ [0, 0, 0, "Use data-testid for E2E selectors instead of aria-label", "0"] ], @@ -2600,9 +2603,10 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "0"] ], "public/app/features/dashboard-scene/scene/PanelMenuBehavior.tsx:5381": [ - [0, 0, 0, "Unexpected any. Specify a different type.", "0"], + [0, 0, 0, "Do not use any type assertions.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"], - [0, 0, 0, "Do not use any type assertions.", "2"] + [0, 0, 0, "Unexpected any. Specify a different type.", "2"], + [0, 0, 0, "Do not use any type assertions.", "3"] ], "public/app/features/dashboard-scene/scene/setDashboardPanelContext.test.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] diff --git a/public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.test.tsx b/public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.test.tsx new file mode 100644 index 00000000000..1b42b2dad66 --- /dev/null +++ b/public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.test.tsx @@ -0,0 +1,94 @@ +import { render, screen } from '@testing-library/react'; +import React from 'react'; + +import { FieldType, getDefaultTimeRange, LoadingState, toDataFrame } from '@grafana/data'; +import { getPanelPlugin } from '@grafana/data/test/__mocks__/pluginMocks'; +import { + SceneGridItem, + SceneGridLayout, + SceneQueryRunner, + SceneTimeRange, + VizPanel, + VizPanelMenu, +} from '@grafana/scenes'; + +import { DashboardScene } from '../../scene/DashboardScene'; +import { VizPanelLinks, VizPanelLinksMenu } from '../../scene/PanelLinks'; +import { panelMenuBehavior } from '../../scene/PanelMenuBehavior'; + +import { HelpWizard } from './HelpWizard'; + +async function setup() { + const { panel } = await buildTestScene(); + panel.getPlugin = () => getPanelPlugin({ skipDataQuery: false }); + + return render( {}} />); +} +describe('SupportSnapshot', () => { + it('Can render', async () => { + setup(); + expect(await screen.findByRole('button', { name: 'Dashboard (3.50 KiB)' })).toBeInTheDocument(); + }); +}); + +async function buildTestScene() { + const menu = new VizPanelMenu({ + $behaviors: [panelMenuBehavior], + }); + + const panel = new VizPanel({ + title: 'Panel A', + pluginId: 'timeseries', + key: 'panel-12', + menu, + titleItems: [new VizPanelLinks({ menu: new VizPanelLinksMenu({}) })], + $data: new SceneQueryRunner({ + data: { + state: LoadingState.Done, + series: [ + toDataFrame({ + name: 'http_requests_total', + fields: [ + { name: 'Time', type: FieldType.time, values: [1, 2, 3] }, + { name: 'Value', type: FieldType.number, values: [11, 22, 33] }, + ], + }), + ], + timeRange: getDefaultTimeRange(), + }, + datasource: { uid: 'my-uid' }, + queries: [{ query: 'QueryA', refId: 'A' }], + }), + }); + + const scene = new DashboardScene({ + title: 'My dashboard', + uid: 'dash-1', + tags: ['database', 'panel'], + $timeRange: new SceneTimeRange({ + from: 'now-5m', + to: 'now', + timeZone: 'Africa/Abidjan', + }), + meta: { + canEdit: true, + isEmbedded: false, + }, + body: new SceneGridLayout({ + children: [ + new SceneGridItem({ + key: 'griditem-1', + x: 0, + y: 0, + width: 10, + height: 12, + body: panel, + }), + ], + }), + }); + + await new Promise((r) => setTimeout(r, 1)); + + return { scene, panel, menu }; +} diff --git a/public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.tsx b/public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.tsx new file mode 100644 index 00000000000..ca08356354a --- /dev/null +++ b/public/app/features/dashboard-scene/inspect/HelpWizard/HelpWizard.tsx @@ -0,0 +1,229 @@ +import { css } from '@emotion/css'; +import React, { useMemo, useEffect } from 'react'; +import AutoSizer from 'react-virtualized-auto-sizer'; + +import { GrafanaTheme2, FeatureState } from '@grafana/data'; +import { config } from '@grafana/runtime'; +import { VizPanel } from '@grafana/scenes'; +import { + Drawer, + Tab, + TabsBar, + CodeEditor, + useStyles2, + Field, + HorizontalGroup, + InlineSwitch, + Button, + Spinner, + Alert, + FeatureBadge, + Select, + ClipboardButton, + Icon, + Stack, +} from '@grafana/ui'; +import { contextSrv } from 'app/core/services/context_srv'; +import { AccessControlAction } from 'app/types'; + +import { ShowMessage, SnapshotTab, SupportSnapshotService } from './SupportSnapshotService'; + +interface Props { + panel: VizPanel; + onClose: () => void; +} + +export function HelpWizard({ panel, onClose }: Props) { + const styles = useStyles2(getStyles); + const service = useMemo(() => new SupportSnapshotService(panel), [panel]); + const plugin = panel.getPlugin(); + + const { + currentTab, + loading, + error, + options, + showMessage, + snapshotSize, + markdownText, + snapshotText, + randomize, + panelTitle, + scene, + } = service.useState(); + + useEffect(() => { + service.buildDebugDashboard(); + }, [service, plugin, randomize]); + + if (!plugin) { + return null; + } + + const tabs = [ + { label: 'Snapshot', value: SnapshotTab.Support }, + { label: 'Data', value: SnapshotTab.Data }, + ]; + + const hasSupportBundleAccess = + config.supportBundlesEnabled && contextSrv.hasPermission(AccessControlAction.ActionSupportBundlesCreate); + + return ( + + + + + Troubleshooting docs + + + + To request troubleshooting help, send a snapshot of this panel to Grafana Labs Technical Support. The + snapshot contains query response data and panel settings. + + {hasSupportBundleAccess && ( + + You can also retrieve a support bundle containing information concerning your Grafana instance and + configured datasources in the support bundles section. + + )} + + } + tabs={ + + {tabs.map((t, index) => ( + service.onCurrentTabChange(t.value!)} + /> + ))} + + } + > + {loading && } + {error && {error.message}} + + {currentTab === SnapshotTab.Data && ( +
+
+ +