mirror of
https://github.com/grafana/grafana.git
synced 2025-02-14 01:23:32 -06:00
DashboardScene: Inspect / query tab (#74795)
This commit is contained in:
parent
8874a8d398
commit
05f01dee0c
@ -125,7 +125,7 @@ export class InspectJsonTab extends SceneObjectBase<InspectJsonTabState> {
|
||||
panel_type_changed: panel.state.pluginId !== panelModel.type,
|
||||
panel_id_changed: getPanelIdForVizPanel(panel) !== panelModel.id,
|
||||
panel_grid_pos_changed: hasGridPosChanged(panel.parent.state, newState),
|
||||
panel_targets_changed: hasQueriesChanged(getQueryRunnerFor(panel), getQueryRunnerFor(gridItem.state.body)),
|
||||
panel_targets_changed: hasQueriesChanged(getQueryRunnerFor(panel), getQueryRunnerFor(newState.$data)),
|
||||
});
|
||||
};
|
||||
|
||||
@ -218,7 +218,6 @@ function getJsonText(show: ShowContent, panel: VizPanel): string {
|
||||
|
||||
case 'data-frames': {
|
||||
reportPanelInspectInteraction(InspectTab.JSON, 'dataFrame');
|
||||
|
||||
const dataProvider = sceneGraph.getData(panel);
|
||||
|
||||
if (dataProvider.state.data) {
|
||||
|
@ -0,0 +1,47 @@
|
||||
import React from 'react';
|
||||
|
||||
import {
|
||||
SceneComponentProps,
|
||||
sceneGraph,
|
||||
SceneObjectBase,
|
||||
SceneObjectState,
|
||||
SceneObjectRef,
|
||||
VizPanel,
|
||||
} from '@grafana/scenes';
|
||||
import { t } from 'app/core/internationalization';
|
||||
import { QueryInspector } from 'app/features/inspector/QueryInspector';
|
||||
import { InspectTab } from 'app/features/inspector/types';
|
||||
|
||||
import { getQueryRunnerFor } from '../utils/utils';
|
||||
|
||||
export interface InspectQueryTabState extends SceneObjectState {
|
||||
panelRef: SceneObjectRef<VizPanel>;
|
||||
}
|
||||
|
||||
export class InspectQueryTab extends SceneObjectBase<InspectQueryTabState> {
|
||||
public getTabLabel() {
|
||||
return t('dashboard.inspect.query-tab', 'Query');
|
||||
}
|
||||
|
||||
public getTabValue() {
|
||||
return InspectTab.Query;
|
||||
}
|
||||
|
||||
public onRefreshQuery = () => {
|
||||
const queryRunner = getQueryRunnerFor(this.state.panelRef.resolve());
|
||||
|
||||
if (queryRunner) {
|
||||
queryRunner.runQueries();
|
||||
}
|
||||
};
|
||||
|
||||
static Component = ({ model }: SceneComponentProps<InspectQueryTab>) => {
|
||||
const data = sceneGraph.getData(model.state.panelRef.resolve()).useState();
|
||||
|
||||
if (!data.data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <QueryInspector data={data.data} onRefreshQuery={model.onRefreshQuery} />;
|
||||
};
|
||||
}
|
@ -16,6 +16,7 @@ import { supportsDataQuery } from 'app/features/dashboard/components/PanelEditor
|
||||
|
||||
import { InspectDataTab } from './InspectDataTab';
|
||||
import { InspectJsonTab } from './InspectJsonTab';
|
||||
import { InspectQueryTab } from './InspectQueryTab';
|
||||
import { InspectStatsTab } from './InspectStatsTab';
|
||||
import { SceneInspectTab } from './types';
|
||||
|
||||
@ -56,6 +57,7 @@ export class PanelInspectDrawer extends SceneObjectBase<PanelInspectDrawerState>
|
||||
if (supportsDataQuery(plugin)) {
|
||||
tabs.push(new InspectDataTab({ panelRef }));
|
||||
tabs.push(new InspectStatsTab({ panelRef }));
|
||||
tabs.push(new InspectQueryTab({ panelRef }));
|
||||
}
|
||||
|
||||
tabs.push(new InspectJsonTab({ panelRef, onClose: this.onClose }));
|
||||
|
@ -109,9 +109,7 @@ export const InspectContent = ({
|
||||
)}
|
||||
{activeTab === InspectTab.Error && <InspectErrorTab errors={errors} />}
|
||||
{data && activeTab === InspectTab.Stats && <InspectStatsTab data={data} timeZone={dashboard.getTimezone()} />}
|
||||
{data && activeTab === InspectTab.Query && (
|
||||
<QueryInspector panel={panel} data={data.series} onRefreshQuery={() => panel.refresh()} />
|
||||
)}
|
||||
{data && activeTab === InspectTab.Query && <QueryInspector data={data} onRefreshQuery={() => panel.refresh()} />}
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
@ -34,7 +34,7 @@ const PanelInspectorUnconnected = ({ panel, dashboard, plugin }: Props) => {
|
||||
});
|
||||
|
||||
const location = useLocation();
|
||||
const { data, isLoading, error } = usePanelLatestData(panel, dataOptions, true);
|
||||
const { data, isLoading, error } = usePanelLatestData(panel, dataOptions, false);
|
||||
const metaDs = useDatasourceMetadata(data);
|
||||
const tabs = useInspectTabs(panel, dashboard, plugin, error, metaDs);
|
||||
const defaultTab = new URLSearchParams(location.search).get('inspectTab') as InspectTab;
|
||||
|
@ -64,7 +64,7 @@ export const usePanelLatestData = (
|
||||
return {
|
||||
data: latestData,
|
||||
error: latestData && latestData.error,
|
||||
isLoading: latestData ? latestData.state === LoadingState.Loading : true,
|
||||
isLoading: latestData?.state === LoadingState.Loading,
|
||||
hasSeries: latestData ? !!latestData.series : false,
|
||||
};
|
||||
};
|
||||
|
@ -35,7 +35,6 @@ jest.mock('@grafana/runtime', () => ({
|
||||
|
||||
const setup = (propOverrides = {}) => {
|
||||
const props: ExploreQueryInspectorProps = {
|
||||
loading: false,
|
||||
width: 100,
|
||||
exploreId: 'left',
|
||||
onClose: jest.fn(),
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
|
||||
import { CoreApp, TimeZone } from '@grafana/data';
|
||||
import { CoreApp, LoadingState, TimeZone } from '@grafana/data';
|
||||
import { reportInteraction } from '@grafana/runtime/src';
|
||||
import { TabbedContainer, TabConfig } from '@grafana/ui';
|
||||
import { ExploreDrawer } from 'app/features/explore/ExploreDrawer';
|
||||
@ -12,7 +12,7 @@ import { InspectStatsTab } from 'app/features/inspector/InspectStatsTab';
|
||||
import { QueryInspector } from 'app/features/inspector/QueryInspector';
|
||||
import { StoreState, ExploreItemState } from 'app/types';
|
||||
|
||||
import { runQueries, selectIsWaitingForData } from './state/query';
|
||||
import { runQueries } from './state/query';
|
||||
|
||||
interface DispatchProps {
|
||||
width: number;
|
||||
@ -24,7 +24,7 @@ interface DispatchProps {
|
||||
type Props = DispatchProps & ConnectedProps<typeof connector>;
|
||||
|
||||
export function ExploreQueryInspector(props: Props) {
|
||||
const { loading, width, onClose, queryResponse, timeZone } = props;
|
||||
const { width, onClose, queryResponse, timeZone } = props;
|
||||
const dataFrames = queryResponse?.series || [];
|
||||
let errors = queryResponse?.errors;
|
||||
if (!errors?.length && queryResponse?.error) {
|
||||
@ -57,7 +57,7 @@ export function ExploreQueryInspector(props: Props) {
|
||||
<InspectDataTab
|
||||
data={dataFrames}
|
||||
dataName={'Explore'}
|
||||
isLoading={loading}
|
||||
isLoading={queryResponse.state === LoadingState.Loading}
|
||||
options={{ withTransforms: false, withFieldConfig: false }}
|
||||
timeZone={timeZone}
|
||||
app={CoreApp.Explore}
|
||||
@ -70,7 +70,7 @@ export function ExploreQueryInspector(props: Props) {
|
||||
value: 'query',
|
||||
icon: 'info-circle',
|
||||
content: (
|
||||
<QueryInspector data={dataFrames} onRefreshQuery={() => props.runQueries({ exploreId: props.exploreId })} />
|
||||
<QueryInspector data={queryResponse} onRefreshQuery={() => props.runQueries({ exploreId: props.exploreId })} />
|
||||
),
|
||||
};
|
||||
|
||||
@ -97,7 +97,6 @@ function mapStateToProps(state: StoreState, { exploreId }: { exploreId: string }
|
||||
const { queryResponse } = item;
|
||||
|
||||
return {
|
||||
loading: selectIsWaitingForData(exploreId)(state),
|
||||
queryResponse,
|
||||
};
|
||||
}
|
||||
|
@ -2,22 +2,15 @@ import { css } from '@emotion/css';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import { DataFrame } from '@grafana/data';
|
||||
import { LoadingState, PanelData } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { Stack } from '@grafana/experimental';
|
||||
import { config, RefreshEvent } from '@grafana/runtime';
|
||||
import { config } from '@grafana/runtime';
|
||||
import { Button, ClipboardButton, JSONFormatter, LoadingPlaceholder } from '@grafana/ui';
|
||||
import { backendSrv } from 'app/core/services/backend_srv';
|
||||
import { supportsDataQuery } from 'app/features/dashboard/components/PanelEditor/utils';
|
||||
import { PanelModel } from 'app/features/dashboard/state';
|
||||
|
||||
import { getPanelInspectorStyles } from './styles';
|
||||
|
||||
interface DsQuery {
|
||||
isLoading: boolean;
|
||||
response: {};
|
||||
}
|
||||
|
||||
interface ExecutedQueryInfo {
|
||||
refId: string;
|
||||
query: string;
|
||||
@ -26,16 +19,15 @@ interface ExecutedQueryInfo {
|
||||
}
|
||||
|
||||
interface Props {
|
||||
data: DataFrame[];
|
||||
data: PanelData;
|
||||
onRefreshQuery: () => void;
|
||||
panel?: PanelModel;
|
||||
}
|
||||
|
||||
interface State {
|
||||
allNodesExpanded: boolean | null;
|
||||
isMocking: boolean;
|
||||
mockedResponse: string;
|
||||
dsQuery: DsQuery;
|
||||
response: {};
|
||||
executedQueries: ExecutedQueryInfo[];
|
||||
}
|
||||
|
||||
@ -50,26 +42,16 @@ export class QueryInspector extends PureComponent<Props, State> {
|
||||
allNodesExpanded: null,
|
||||
isMocking: false,
|
||||
mockedResponse: '',
|
||||
dsQuery: {
|
||||
isLoading: false,
|
||||
response: {},
|
||||
},
|
||||
response: {},
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { panel } = this.props;
|
||||
|
||||
this.subs.add(
|
||||
backendSrv.getInspectorStream().subscribe({
|
||||
next: (response) => this.onDataSourceResponse(response),
|
||||
})
|
||||
);
|
||||
|
||||
if (panel) {
|
||||
this.subs.add(panel.events.subscribe(RefreshEvent, this.onPanelRefresh));
|
||||
this.updateQueryList();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(oldProps: Props) {
|
||||
@ -83,12 +65,13 @@ export class QueryInspector extends PureComponent<Props, State> {
|
||||
*/
|
||||
updateQueryList() {
|
||||
const { data } = this.props;
|
||||
const frames = data.series;
|
||||
const executedQueries: ExecutedQueryInfo[] = [];
|
||||
|
||||
if (data?.length) {
|
||||
if (frames?.length) {
|
||||
let last: ExecutedQueryInfo | undefined = undefined;
|
||||
|
||||
data.forEach((frame, idx) => {
|
||||
frames.forEach((frame, idx) => {
|
||||
const query = frame.meta?.executedQueryString;
|
||||
|
||||
if (query) {
|
||||
@ -117,16 +100,6 @@ export class QueryInspector extends PureComponent<Props, State> {
|
||||
this.subs.unsubscribe();
|
||||
}
|
||||
|
||||
onPanelRefresh = () => {
|
||||
this.setState((prevState) => ({
|
||||
...prevState,
|
||||
dsQuery: {
|
||||
isLoading: true,
|
||||
response: {},
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
onDataSourceResponse(response: any) {
|
||||
// ignore silent requests
|
||||
if (response.config?.hideFromInspector) {
|
||||
@ -168,13 +141,9 @@ export class QueryInspector extends PureComponent<Props, State> {
|
||||
delete response.$$config;
|
||||
}
|
||||
|
||||
this.setState((prevState) => ({
|
||||
...prevState,
|
||||
dsQuery: {
|
||||
isLoading: false,
|
||||
response: response,
|
||||
},
|
||||
}));
|
||||
this.setState({
|
||||
response: response,
|
||||
});
|
||||
}
|
||||
|
||||
setFormattedJson = (formattedJson: any) => {
|
||||
@ -240,16 +209,12 @@ export class QueryInspector extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { allNodesExpanded, executedQueries } = this.state;
|
||||
const { panel, onRefreshQuery } = this.props;
|
||||
const { response, isLoading } = this.state.dsQuery;
|
||||
const { allNodesExpanded, executedQueries, response } = this.state;
|
||||
const { onRefreshQuery, data } = this.props;
|
||||
const openNodes = this.getNrOfOpenNodes();
|
||||
const styles = getPanelInspectorStyles();
|
||||
const haveData = Object.keys(response).length > 0;
|
||||
|
||||
if (panel && !supportsDataQuery(panel.plugin)) {
|
||||
return null;
|
||||
}
|
||||
const isLoading = data.state === LoadingState.Loading;
|
||||
|
||||
return (
|
||||
<div className={styles.wrap}>
|
||||
|
Loading…
Reference in New Issue
Block a user