diff --git a/packages/grafana-ui/src/components/TabbedContainer/TabbedContainer.tsx b/packages/grafana-ui/src/components/TabbedContainer/TabbedContainer.tsx index daed3779ebe..7106e7b6c8f 100644 --- a/packages/grafana-ui/src/components/TabbedContainer/TabbedContainer.tsx +++ b/packages/grafana-ui/src/components/TabbedContainer/TabbedContainer.tsx @@ -27,6 +27,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => { tabContent: css` padding: ${theme.spacing.md}; background-color: ${theme.colors.bodyBg}; + height: 100%; `, close: css` position: absolute; diff --git a/packages/grafana-ui/src/types/icon.ts b/packages/grafana-ui/src/types/icon.ts index fae4c10076e..6f4f430af9c 100644 --- a/packages/grafana-ui/src/types/icon.ts +++ b/packages/grafana-ui/src/types/icon.ts @@ -24,6 +24,7 @@ export type IconName = | 'bolt' | 'book-open' | 'book' + | 'brackets-curly' | 'bug' | 'calculator-alt' | 'calendar-alt' @@ -157,6 +158,7 @@ export const getAvailableIcons = (): IconName[] => [ 'bolt', 'book-open', 'book', + 'brackets-curly', 'bug', 'calculator-alt', 'calendar-alt', diff --git a/public/app/features/dashboard/components/Inspector/InspectContent.tsx b/public/app/features/dashboard/components/Inspector/InspectContent.tsx index 89a941437c2..31045988324 100644 --- a/public/app/features/dashboard/components/Inspector/InspectContent.tsx +++ b/public/app/features/dashboard/components/Inspector/InspectContent.tsx @@ -2,15 +2,15 @@ import React, { useState } from 'react'; import { DataSourceApi, PanelData, PanelPlugin } from '@grafana/data'; import { getTemplateSrv } from '@grafana/runtime'; import { CustomScrollbar, Drawer, TabContent } from '@grafana/ui'; -import { getPanelInspectorStyles } from './styles'; -import { InspectSubtitle } from './InspectSubtitle'; -import { InspectDataTab } from './InspectDataTab'; -import { InspectMetadataTab } from './InspectMetadataTab'; -import { InspectJSONTab } from './InspectJSONTab'; -import { InspectErrorTab } from './InspectErrorTab'; -import { InspectStatsTab } from './InspectStatsTab'; -import { QueryInspector } from './QueryInspector'; -import { InspectTab } from './types'; +import { getPanelInspectorStyles } from 'app/features/inspector/styles'; +import { InspectMetadataTab } from 'app/features/inspector/InspectMetadataTab'; +import { InspectSubtitle } from 'app/features/inspector/InspectSubtitle'; +import { InspectJSONTab } from 'app/features/inspector/InspectJSONTab'; +import { QueryInspector } from 'app/features/inspector/QueryInspector'; +import { InspectStatsTab } from 'app/features/inspector/InspectStatsTab'; +import { InspectErrorTab } from 'app/features/inspector/InspectErrorTab'; +import { InspectDataTab } from 'app/features/inspector/InspectDataTab'; +import { InspectTab } from 'app/features/inspector/types'; import { DashboardModel, PanelModel } from '../../state'; import { GetDataOptions } from '../../../query/state/PanelQueryRunner'; @@ -94,7 +94,9 @@ export const InspectContent: React.FC = ({ )} {activeTab === InspectTab.Error && } {data && activeTab === InspectTab.Stats && } - {data && activeTab === InspectTab.Query && } + {data && activeTab === InspectTab.Query && ( + panel.refresh()} /> + )} diff --git a/public/app/features/dashboard/components/Inspector/PanelInspector.tsx b/public/app/features/dashboard/components/Inspector/PanelInspector.tsx index e5f63922b35..0e42391801b 100644 --- a/public/app/features/dashboard/components/Inspector/PanelInspector.tsx +++ b/public/app/features/dashboard/components/Inspector/PanelInspector.tsx @@ -9,8 +9,8 @@ import { GetDataOptions } from '../../../query/state/PanelQueryRunner'; import { usePanelLatestData } from '../PanelEditor/usePanelLatestData'; import { InspectContent } from './InspectContent'; import { useDatasourceMetadata, useInspectTabs } from './hooks'; -import { InspectTab } from './types'; import { updateLocation } from 'app/core/actions'; +import { InspectTab } from 'app/features/inspector/types'; interface OwnProps { dashboard: DashboardModel; diff --git a/public/app/features/dashboard/components/Inspector/hooks.ts b/public/app/features/dashboard/components/Inspector/hooks.ts index 72d06588fa9..91dc1179c4d 100644 --- a/public/app/features/dashboard/components/Inspector/hooks.ts +++ b/public/app/features/dashboard/components/Inspector/hooks.ts @@ -4,7 +4,7 @@ import { getDataSourceSrv } from '@grafana/runtime'; import { DashboardModel } from 'app/features/dashboard/state'; import { useMemo } from 'react'; import { supportsDataQuery } from '../PanelEditor/utils'; -import { InspectTab } from './types'; +import { InspectTab } from 'app/features/inspector/types'; /** * Given PanelData return first data source supporting metadata inspector diff --git a/public/app/features/dashboard/containers/DashboardPage.tsx b/public/app/features/dashboard/containers/DashboardPage.tsx index 502bea5ad5c..5d9cfe9bafa 100644 --- a/public/app/features/dashboard/containers/DashboardPage.tsx +++ b/public/app/features/dashboard/containers/DashboardPage.tsx @@ -27,7 +27,7 @@ import { } from 'app/types'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; -import { InspectTab } from '../components/Inspector/types'; +import { InspectTab } from 'app/features/inspector/types'; import { PanelInspector } from '../components/Inspector/PanelInspector'; import { SubMenu } from '../components/SubMenu/SubMenu'; import { cleanUpDashboardAndVariables } from '../state/actions'; diff --git a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx index b71dcf2548f..6e70c6c282c 100644 --- a/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx +++ b/public/app/features/dashboard/dashgrid/PanelHeader/PanelHeaderCorner.tsx @@ -6,7 +6,7 @@ import { getLocationSrv, getTemplateSrv } from '@grafana/runtime'; import { PanelModel } from 'app/features/dashboard/state/PanelModel'; import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; -import { InspectTab } from '../../components/Inspector/types'; +import { InspectTab } from 'app/features/inspector/types'; import { selectors } from '@grafana/e2e-selectors'; enum InfoMode { diff --git a/public/app/features/explore/ExploreQueryInspector.test.tsx b/public/app/features/explore/ExploreQueryInspector.test.tsx index 3f0cda56aee..1ef51b26c08 100644 --- a/public/app/features/explore/ExploreQueryInspector.test.tsx +++ b/public/app/features/explore/ExploreQueryInspector.test.tsx @@ -7,18 +7,18 @@ import { ExploreQueryInspector } from './ExploreQueryInspector'; type ExploreQueryInspectorProps = ComponentProps; -jest.mock('../dashboard/components/Inspector/styles', () => ({ +jest.mock('../inspector/styles', () => ({ getPanelInspectorStyles: () => ({}), })); jest.mock('app/core/services/backend_srv', () => ({ - getBackendSrv: () => ({ + backendSrv: { getInspectorStream: () => new Observable((subscriber) => { subscriber.next(response()); subscriber.next(response(true)); }) as any, - }), + }, })); jest.mock('app/core/services/context_srv', () => ({ @@ -38,6 +38,7 @@ const setup = () => { series: [], timeRange: {} as TimeRange, }, + runQueries: jest.fn(), }; return render(); diff --git a/public/app/features/explore/ExploreQueryInspector.tsx b/public/app/features/explore/ExploreQueryInspector.tsx index 824f8221407..c9412a4f07c 100644 --- a/public/app/features/explore/ExploreQueryInspector.tsx +++ b/public/app/features/explore/ExploreQueryInspector.tsx @@ -1,63 +1,20 @@ -import React, { useState } from 'react'; -import { Button, JSONFormatter, LoadingPlaceholder, TabbedContainer, TabConfig } from '@grafana/ui'; -import { AppEvents, PanelData, TimeZone } from '@grafana/data'; - -import appEvents from 'app/core/app_events'; -import { CopyToClipboard } from 'app/core/components/CopyToClipboard/CopyToClipboard'; +import React from 'react'; +import { TabbedContainer, TabConfig } from '@grafana/ui'; +import { PanelData, TimeZone } from '@grafana/data'; +import { runQueries } from './state/query'; import { StoreState, ExploreItemState, ExploreId } from 'app/types'; import { hot } from 'react-hot-loader'; import { connect } from 'react-redux'; import { ExploreDrawer } from 'app/features/explore/ExploreDrawer'; -import { useEffectOnce } from 'react-use'; -import { getBackendSrv } from 'app/core/services/backend_srv'; -import { InspectStatsTab } from '../dashboard/components/Inspector/InspectStatsTab'; -import { getPanelInspectorStyles } from '../dashboard/components/Inspector/styles'; +import { InspectJSONTab } from 'app/features/inspector/InspectJSONTab'; +import { QueryInspector } from 'app/features/inspector/QueryInspector'; +import { InspectStatsTab } from 'app/features/inspector/InspectStatsTab'; +import { InspectDataTab } from 'app/features/inspector/InspectDataTab'; -function stripPropsFromResponse(response: any) { - // ignore silent requests and return early - if (response.config?.hideFromInspector) { - return; - } - - const clonedResponse = { ...response }; // clone - dont modify the response - - if (clonedResponse.headers) { - delete clonedResponse.headers; - } - - if (clonedResponse.config) { - clonedResponse.request = clonedResponse.config; - - delete clonedResponse.config; - delete clonedResponse.request.transformRequest; - delete clonedResponse.request.transformResponse; - delete clonedResponse.request.paramSerializer; - delete clonedResponse.request.jsonpCallbackParam; - delete clonedResponse.request.headers; - delete clonedResponse.request.requestId; - delete clonedResponse.request.inspect; - delete clonedResponse.request.retry; - delete clonedResponse.request.timeout; - } - - if (clonedResponse.data) { - clonedResponse.response = clonedResponse.data; - - delete clonedResponse.config; - delete clonedResponse.data; - delete clonedResponse.status; - delete clonedResponse.statusText; - delete clonedResponse.ok; - delete clonedResponse.url; - delete clonedResponse.redirected; - delete clonedResponse.type; - delete clonedResponse.$$config; - } - - return clonedResponse; +interface DispatchProps { + runQueries: typeof runQueries; } - -interface Props { +interface Props extends DispatchProps { loading: boolean; width: number; exploreId: ExploreId; @@ -66,50 +23,9 @@ interface Props { } export function ExploreQueryInspector(props: Props) { - const [formattedJSON, setFormattedJSON] = useState({}); - - const getTextForClipboard = () => { - return JSON.stringify(formattedJSON, null, 2); - }; - - const onClipboardSuccess = () => { - appEvents.emit(AppEvents.alertSuccess, ['Content copied to clipboard']); - }; - - const [allNodesExpanded, setAllNodesExpanded] = useState(false); - const getOpenNodeCount = () => { - if (allNodesExpanded === null) { - return 3; // 3 is default, ie when state is null - } else if (allNodesExpanded) { - return 20; - } - return 1; - }; - - const onToggleExpand = () => { - setAllNodesExpanded(!allNodesExpanded); - }; - const { loading, width, onClose, queryResponse } = props; + const dataFrames = queryResponse?.series || []; - const [response, setResponse] = useState({} as PanelData); - useEffectOnce(() => { - const inspectorStreamSub = getBackendSrv() - .getInspectorStream() - .subscribe((resp) => { - const strippedResponse = stripPropsFromResponse(resp); - if (strippedResponse) { - setResponse(strippedResponse); - } - }); - - return () => { - inspectorStreamSub?.unsubscribe(); - }; - }); - - const haveData = response && Object.keys(response).length > 0; - const styles = getPanelInspectorStyles(); const statsTab: TabConfig = { label: 'Stats', value: 'stats', @@ -117,52 +33,34 @@ export function ExploreQueryInspector(props: Props) { content: , }; - const inspectorTab: TabConfig = { - label: 'Query Inspector', - value: 'query_inspector', - icon: 'info-circle', - content: ( - <> -
- {haveData && ( - <> - + const jsonTab: TabConfig = { + label: 'JSON', + value: 'json', + icon: 'brackets-curly', + content: , + }; - - - - - )} -
-
-
- {loading && } - {!loading && haveData && ( - - )} - {!loading && !haveData && ( -

No request & response collected yet. Run query to collect request & response.

- )} -
- + const dataTab: TabConfig = { + label: 'Data', + value: 'data', + icon: 'database', + content: ( + ), }; - const tabs = [statsTab, inspectorTab]; + const queryInspectorTab: TabConfig = { + label: 'Query Inspector', + value: 'query_inspector', + icon: 'info-circle', + content: props.runQueries(props.exploreId)} />, + }; + + const tabs = [statsTab, queryInspectorTab, jsonTab, dataTab]; return ( {}}> @@ -181,4 +79,8 @@ function mapStateToProps(state: StoreState, { exploreId }: { exploreId: ExploreI }; } -export default hot(module)(connect(mapStateToProps)(ExploreQueryInspector)); +const mapDispatchToProps: DispatchProps = { + runQueries, +}; + +export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(ExploreQueryInspector)); diff --git a/public/app/features/explore/SecondaryActions.tsx b/public/app/features/explore/SecondaryActions.tsx index 8b27b12c269..fed4e1793e3 100644 --- a/public/app/features/explore/SecondaryActions.tsx +++ b/public/app/features/explore/SecondaryActions.tsx @@ -54,7 +54,7 @@ export function SecondaryActions(props: Props) { onClick={props.onClickQueryInspectorButton} icon="info-circle" > - Query inspector + Inspector
diff --git a/public/app/features/dashboard/components/Inspector/DetailText.tsx b/public/app/features/inspector/DetailText.tsx similarity index 100% rename from public/app/features/dashboard/components/Inspector/DetailText.tsx rename to public/app/features/inspector/DetailText.tsx diff --git a/public/app/features/dashboard/components/Inspector/InspectDataTab.tsx b/public/app/features/inspector/InspectDataTab.tsx similarity index 94% rename from public/app/features/dashboard/components/Inspector/InspectDataTab.tsx rename to public/app/features/inspector/InspectDataTab.tsx index 6ad0e8b8257..70c5132a2fd 100644 --- a/public/app/features/dashboard/components/Inspector/InspectDataTab.tsx +++ b/public/app/features/inspector/InspectDataTab.tsx @@ -19,17 +19,17 @@ import { getPanelInspectorStyles } from './styles'; import { config } from 'app/core/config'; import { saveAs } from 'file-saver'; import { css } from 'emotion'; -import { GetDataOptions } from '../../../query/state/PanelQueryRunner'; +import { GetDataOptions } from 'app/features/query/state/PanelQueryRunner'; import { QueryOperationRow } from 'app/core/components/QueryOperationRow/QueryOperationRow'; import { PanelModel } from 'app/features/dashboard/state'; -import { DetailText } from './DetailText'; +import { DetailText } from 'app/features/inspector/DetailText'; interface Props { - panel: PanelModel; - data?: DataFrame[]; isLoading: boolean; options: GetDataOptions; - onOptionsChange: (options: GetDataOptions) => void; + data?: DataFrame[]; + panel?: PanelModel; + onOptionsChange?: (options: GetDataOptions) => void; } interface State { @@ -93,8 +93,9 @@ export class InspectDataTab extends PureComponent { const blob = new Blob([String.fromCharCode(0xfeff), dataFrameCsv], { type: 'text/csv;charset=utf-8', }); + const displayTitle = panel ? panel.getDisplayTitle() : 'Explore'; const transformation = transformId !== DataTransformerID.noop ? '-as-' + transformId.toLocaleLowerCase() : ''; - const fileName = `${panel.getDisplayTitle()}-data${transformation}-${dateTimeFormat(new Date())}.csv`; + const fileName = `${displayTitle}-data${transformation}-${dateTimeFormat(new Date())}.csv`; saveAs(blob, fileName); }; @@ -108,10 +109,10 @@ export class InspectDataTab extends PureComponent { }; getProcessedData(): DataFrame[] { - const { options } = this.props; + const { options, panel } = this.props; const data = this.state.transformedData; - if (!options.withFieldConfig) { + if (!options.withFieldConfig || !panel) { return applyRawFieldOverrides(data); } @@ -120,7 +121,7 @@ export class InspectDataTab extends PureComponent { return applyFieldOverrides({ data, theme: config.theme, - fieldConfig: this.props.panel.fieldConfig, + fieldConfig: panel.fieldConfig, replaceVariables: (value: string) => { return value; }, @@ -166,6 +167,9 @@ export class InspectDataTab extends PureComponent { renderDataOptions(dataFrames: DataFrame[]) { const { options, onOptionsChange, panel, data } = this.props; + if (!panel || !onOptionsChange) { + return null; + } const { transformId, transformationOptions, selectedDataFrame } = this.state; const styles = getPanelInspectorStyles(); diff --git a/public/app/features/dashboard/components/Inspector/InspectErrorTab.tsx b/public/app/features/inspector/InspectErrorTab.tsx similarity index 100% rename from public/app/features/dashboard/components/Inspector/InspectErrorTab.tsx rename to public/app/features/inspector/InspectErrorTab.tsx diff --git a/public/app/features/dashboard/components/Inspector/InspectJSONTab.tsx b/public/app/features/inspector/InspectJSONTab.tsx similarity index 65% rename from public/app/features/dashboard/components/Inspector/InspectJSONTab.tsx rename to public/app/features/inspector/InspectJSONTab.tsx index 877432125b6..f0c469dc41f 100644 --- a/public/app/features/dashboard/components/Inspector/InspectJSONTab.tsx +++ b/public/app/features/inspector/InspectJSONTab.tsx @@ -5,12 +5,12 @@ import { Button, CodeEditor, Field, Select } from '@grafana/ui'; import AutoSizer from 'react-virtualized-auto-sizer'; import { selectors } from '@grafana/e2e-selectors'; import { appEvents } from 'app/core/core'; -import { DashboardModel, PanelModel } from '../../state'; -import { getPanelInspectorStyles } from './styles'; +import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; +import { getPanelInspectorStyles } from '../inspector/styles'; enum ShowContent { PanelJSON = 'panel', - PanelData = 'data', + DataJSON = 'data', DataStructure = 'structure', } @@ -21,9 +21,9 @@ const options: Array> = [ value: ShowContent.PanelJSON, }, { - label: 'Panel data', + label: 'Data', description: 'The raw model passed to the panel visualization', - value: ShowContent.PanelData, + value: ShowContent.DataJSON, }, { label: 'DataFrame structure', @@ -33,10 +33,10 @@ const options: Array> = [ ]; interface Props { - dashboard: DashboardModel; - panel: PanelModel; - data?: PanelData; onClose: () => void; + dashboard?: DashboardModel; + panel?: PanelModel; + data?: PanelData; } interface State { @@ -45,11 +45,15 @@ interface State { } export class InspectJSONTab extends PureComponent { + hasPanelJSON: boolean; + constructor(props: Props) { super(props); + this.hasPanelJSON = !!(props.panel && props.dashboard); + // If we are in panel, we want to show PanelJSON, otherwise show DataJSON this.state = { - show: ShowContent.PanelJSON, - text: getPrettyJSON(props.panel.getSaveModel()), + show: this.hasPanelJSON ? ShowContent.PanelJSON : ShowContent.DataJSON, + text: this.hasPanelJSON ? getPrettyJSON(props.panel!.getSaveModel()) : getPrettyJSON(props.data), }; } @@ -65,16 +69,17 @@ export class InspectJSONTab extends PureComponent { }; getJSONObject(show: ShowContent) { - if (show === ShowContent.PanelData) { - return this.props.data; + const { data, panel } = this.props; + if (show === ShowContent.DataJSON) { + return data; } if (show === ShowContent.DataStructure) { - const series = this.props.data?.series; + const series = data?.series; if (!series) { return { note: 'Missing Response Data' }; } - return this.props.data!.series.map((frame) => { + return data!.series.map((frame) => { const { table, fields, ...rest } = frame as any; // remove 'table' from arrow response return { ...rest, @@ -85,8 +90,8 @@ export class InspectJSONTab extends PureComponent { }); } - if (show === ShowContent.PanelJSON) { - return this.props.panel.getSaveModel(); + if (this.hasPanelJSON && show === ShowContent.PanelJSON) { + return panel!.getSaveModel(); } return { note: `Unknown Object: ${show}` }; @@ -94,39 +99,41 @@ export class InspectJSONTab extends PureComponent { onApplyPanelModel = () => { const { panel, dashboard, onClose } = this.props; - - try { - if (!dashboard.meta.canEdit) { - appEvents.emit(AppEvents.alertError, ['Unable to apply']); - } else { - const updates = JSON.parse(this.state.text); - panel.restoreModel(updates); - panel.refresh(); - appEvents.emit(AppEvents.alertSuccess, ['Panel model updated']); + if (this.hasPanelJSON) { + try { + if (!dashboard!.meta.canEdit) { + appEvents.emit(AppEvents.alertError, ['Unable to apply']); + } else { + const updates = JSON.parse(this.state.text); + panel!.restoreModel(updates); + panel!.refresh(); + appEvents.emit(AppEvents.alertSuccess, ['Panel model updated']); + } + } catch (err) { + console.error('Error applying updates', err); + appEvents.emit(AppEvents.alertError, ['Invalid JSON text']); } - } catch (err) { - console.error('Error applying updates', err); - appEvents.emit(AppEvents.alertError, ['Invalid JSON text']); - } - onClose(); + onClose(); + } }; render() { const { dashboard } = this.props; const { show, text } = this.state; + const jsonOptions = this.hasPanelJSON ? options : options.slice(1, options.length); const selected = options.find((v) => v.value === show); const isPanelJSON = show === ShowContent.PanelJSON; - const canEdit = dashboard.meta.canEdit; + const canEdit = dashboard && dashboard.meta.canEdit; const styles = getPanelInspectorStyles(); return ( <>
- - {isPanelJSON && canEdit && ( + {this.hasPanelJSON && isPanelJSON && canEdit && ( diff --git a/public/app/features/dashboard/components/Inspector/InspectMetadataTab.tsx b/public/app/features/inspector/InspectMetadataTab.tsx similarity index 100% rename from public/app/features/dashboard/components/Inspector/InspectMetadataTab.tsx rename to public/app/features/inspector/InspectMetadataTab.tsx diff --git a/public/app/features/dashboard/components/Inspector/InspectStatsTab.tsx b/public/app/features/inspector/InspectStatsTab.tsx similarity index 100% rename from public/app/features/dashboard/components/Inspector/InspectStatsTab.tsx rename to public/app/features/inspector/InspectStatsTab.tsx diff --git a/public/app/features/dashboard/components/Inspector/InspectStatsTable.tsx b/public/app/features/inspector/InspectStatsTable.tsx similarity index 100% rename from public/app/features/dashboard/components/Inspector/InspectStatsTable.tsx rename to public/app/features/inspector/InspectStatsTable.tsx diff --git a/public/app/features/dashboard/components/Inspector/InspectSubtitle.tsx b/public/app/features/inspector/InspectSubtitle.tsx similarity index 93% rename from public/app/features/dashboard/components/Inspector/InspectSubtitle.tsx rename to public/app/features/inspector/InspectSubtitle.tsx index 98b555ac14b..ffd1986c0c6 100644 --- a/public/app/features/dashboard/components/Inspector/InspectSubtitle.tsx +++ b/public/app/features/inspector/InspectSubtitle.tsx @@ -1,8 +1,8 @@ import React, { FC } from 'react'; import { css } from 'emotion'; -import { stylesFactory, Tab, TabsBar, useTheme } from '@grafana/ui'; +import { stylesFactory, useTheme, Tab, TabsBar } from '@grafana/ui'; import { GrafanaTheme, SelectableValue, PanelData, getValueFormat, formattedValueToString } from '@grafana/data'; -import { InspectTab } from './types'; +import { InspectTab } from '../inspector/types'; interface Props { tab: InspectTab; diff --git a/public/app/features/dashboard/components/Inspector/QueryInspector.tsx b/public/app/features/inspector/QueryInspector.tsx similarity index 95% rename from public/app/features/dashboard/components/Inspector/QueryInspector.tsx rename to public/app/features/inspector/QueryInspector.tsx index 822f04aed0d..b51495c5ae6 100644 --- a/public/app/features/dashboard/components/Inspector/QueryInspector.tsx +++ b/public/app/features/inspector/QueryInspector.tsx @@ -7,7 +7,7 @@ import appEvents from 'app/core/app_events'; import { CopyToClipboard } from 'app/core/components/CopyToClipboard/CopyToClipboard'; import { PanelModel } from 'app/features/dashboard/state'; import { getPanelInspectorStyles } from './styles'; -import { supportsDataQuery } from '../PanelEditor/utils'; +import { supportsDataQuery } from 'app/features/dashboard/components/PanelEditor/utils'; import { config } from '@grafana/runtime'; import { css } from 'emotion'; import { Subscription } from 'rxjs'; @@ -27,8 +27,9 @@ interface ExecutedQueryInfo { } interface Props { - panel: PanelModel; data: DataFrame[]; + onRefreshQuery: () => void; + panel?: PanelModel; } interface State { @@ -66,8 +67,10 @@ export class QueryInspector extends PureComponent { }) ); - this.subs.add(panel.events.subscribe(RefreshEvent, this.onPanelRefresh)); - this.updateQueryList(); + if (panel) { + this.subs.add(panel.events.subscribe(RefreshEvent, this.onPanelRefresh)); + this.updateQueryList(); + } } componentDidUpdate(oldProps: Props) { @@ -111,10 +114,6 @@ export class QueryInspector extends PureComponent { this.setState({ executedQueries }); } - onIssueNewQuery = () => { - this.props.panel.refresh(); - }; - componentWillUnmount() { this.subs.unsubscribe(); } @@ -255,12 +254,13 @@ export class QueryInspector extends PureComponent { render() { const { allNodesExpanded, executedQueries } = this.state; + const { panel, onRefreshQuery } = this.props; const { response, isLoading } = this.state.dsQuery; const openNodes = this.getNrOfOpenNodes(); const styles = getPanelInspectorStyles(); const haveData = Object.keys(response).length > 0; - if (!supportsDataQuery(this.props.panel.plugin)) { + if (panel && !supportsDataQuery(panel.plugin)) { return null; } @@ -277,7 +277,7 @@ export class QueryInspector extends PureComponent {