diff --git a/public/app/core/services/backend_srv.ts b/public/app/core/services/backend_srv.ts index 331f0b00ab2..be9a2c01cbf 100644 --- a/public/app/core/services/backend_srv.ts +++ b/public/app/core/services/backend_srv.ts @@ -55,11 +55,16 @@ export interface FolderRequestOptions { const GRAFANA_TRACEID_HEADER = 'grafana-trace-id'; +export interface InspectorStream { + response: FetchResponse | FetchError; + requestId?: string; +} + export class BackendSrv implements BackendService { private inFlightRequests: Subject = new Subject(); private HTTP_REQUEST_CANCELED = -1; private noBackendCache: boolean; - private inspectorStream: Subject = new Subject(); + private inspectorStream: Subject = new Subject(); private readonly fetchQueue: FetchQueue; private readonly responseQueue: ResponseQueue; private _tokenRotationInProgress?: Observable | null = null; @@ -333,7 +338,7 @@ export class BackendSrv implements BackendService { }, 50); } - this.inspectorStream.next(err); + this.inspectorStream.next({ response: err, requestId: options.requestId }); return err; } @@ -356,7 +361,7 @@ export class BackendSrv implements BackendService { }), tap((response) => { this.showSuccessAlert(response); - this.inspectorStream.next(response); + this.inspectorStream.next({ response: response, requestId: options.requestId }); }) ); } @@ -446,7 +451,7 @@ export class BackendSrv implements BackendService { ); } - getInspectorStream(): Observable { + getInspectorStream(): Observable { return this.inspectorStream; } diff --git a/public/app/core/specs/backend_srv.test.ts b/public/app/core/specs/backend_srv.test.ts index 25dd30124f8..54118ce553f 100644 --- a/public/app/core/specs/backend_srv.test.ts +++ b/public/app/core/specs/backend_srv.test.ts @@ -664,7 +664,7 @@ describe('backendSrv', () => { let inspectorPacket: FetchResponse | FetchError; backendSrv.getInspectorStream().subscribe({ - next: (rsp) => (inspectorPacket = rsp), + next: (rsp) => (inspectorPacket = rsp.response), }); await backendSrv.datasourceRequest(options).catch((error) => { diff --git a/public/app/core/utils/explore.ts b/public/app/core/utils/explore.ts index 49fff84b18b..7852a73a263 100644 --- a/public/app/core/utils/explore.ts +++ b/public/app/core/utils/explore.ts @@ -101,6 +101,10 @@ export async function getExploreUrl(args: GetExploreUrlArguments): Promise { width={width} onClose={this.toggleShowQueryInspector} timeZone={timeZone} + isMixed={datasourceInstance.meta.mixed || false} /> )} diff --git a/public/app/features/explore/ExploreQueryInspector.test.tsx b/public/app/features/explore/ExploreQueryInspector.test.tsx index 3210ba6e782..c52d0533a88 100644 --- a/public/app/features/explore/ExploreQueryInspector.test.tsx +++ b/public/app/features/explore/ExploreQueryInspector.test.tsx @@ -4,6 +4,7 @@ import AutoSizer from 'react-virtualized-auto-sizer'; import { Observable } from 'rxjs'; import { LoadingState, InternalTimeZones, getDefaultTimeRange } from '@grafana/data'; +import { InspectorStream } from 'app/core/services/backend_srv'; import { ExploreQueryInspector } from './ExploreQueryInspector'; @@ -50,6 +51,7 @@ const setup = (propOverrides = {}) => { exploreId: 'left', onClose: jest.fn(), timeZone: InternalTimeZones.utc, + isMixed: false, queryResponse: { state: LoadingState.Done, series: [], @@ -143,22 +145,26 @@ describe('ExploreQueryInspector', () => { }); }); -const response = (hideFromInspector = false) => ({ - status: 1, - statusText: '', - ok: true, - headers: {}, - redirected: false, - type: 'basic', - url: '', - request: {}, - data: { - test: { - testKey: 'Very unique test value', +const response = (hideFromInspector = false): InspectorStream => { + return { + response: { + status: 1, + statusText: '', + ok: true, + headers: new Headers(), + redirected: false, + type: 'basic', + url: '', + data: { + test: { + testKey: 'Very unique test value', + }, + }, + config: { + url: '', + hideFromInspector, + }, }, - }, - config: { - url: '', - hideFromInspector, - }, -}); + requestId: 'explore_left', + }; +}; diff --git a/public/app/features/explore/ExploreQueryInspector.tsx b/public/app/features/explore/ExploreQueryInspector.tsx index 1d6204c5fce..4b611fae705 100644 --- a/public/app/features/explore/ExploreQueryInspector.tsx +++ b/public/app/features/explore/ExploreQueryInspector.tsx @@ -5,12 +5,14 @@ import { CoreApp, LoadingState } from '@grafana/data'; import { reportInteraction } from '@grafana/runtime/src'; import { defaultTimeZone, TimeZone } from '@grafana/schema'; import { TabbedContainer, TabConfig } from '@grafana/ui'; +import { requestIdGenerator } from 'app/core/utils/explore'; import { ExploreDrawer } from 'app/features/explore/ExploreDrawer'; import { InspectDataTab } from 'app/features/inspector/InspectDataTab'; import { InspectErrorTab } from 'app/features/inspector/InspectErrorTab'; import { InspectJSONTab } from 'app/features/inspector/InspectJSONTab'; import { InspectStatsTab } from 'app/features/inspector/InspectStatsTab'; import { QueryInspector } from 'app/features/inspector/QueryInspector'; +import { mixedRequestId } from 'app/plugins/datasource/mixed/MixedDataSource'; import { StoreState, ExploreItemState } from 'app/types'; import { GetDataOptions } from '../query/state/PanelQueryRunner'; @@ -22,12 +24,13 @@ interface DispatchProps { exploreId: string; timeZone: TimeZone; onClose: () => void; + isMixed: boolean; } type Props = DispatchProps & ConnectedProps; export function ExploreQueryInspector(props: Props) { - const { width, onClose, queryResponse, timeZone } = props; + const { width, onClose, queryResponse, timeZone, isMixed, exploreId } = props; const [dataOptions, setDataOptions] = useState({ withTransforms: false, withFieldConfig: true, @@ -79,7 +82,11 @@ export function ExploreQueryInspector(props: Props) { value: 'query', icon: 'info-circle', content: ( - props.runQueries({ exploreId: props.exploreId })} /> + props.runQueries({ exploreId })} + /> ), }; diff --git a/public/app/features/inspector/QueryInspector.tsx b/public/app/features/inspector/QueryInspector.tsx index 23e1fac5290..fb1e0cd8238 100644 --- a/public/app/features/inspector/QueryInspector.tsx +++ b/public/app/features/inspector/QueryInspector.tsx @@ -19,6 +19,7 @@ interface ExecutedQueryInfo { } interface Props { + instanceId?: string; // Must match the prefix of the requestId of the query being inspected. For updating only one instance of the inspector in case of multiple instances, ie Explore split view data: PanelData; onRefreshQuery: () => void; } @@ -49,7 +50,15 @@ export class QueryInspector extends PureComponent { componentDidMount() { this.subs.add( backendSrv.getInspectorStream().subscribe({ - next: (response) => this.onDataSourceResponse(response), + next: (response) => { + let update = true; + if (this.props.instanceId && response?.requestId) { + update = response.requestId.startsWith(this.props.instanceId); + } + if (update) { + return this.onDataSourceResponse(response.response); + } + }, }) ); } diff --git a/public/app/plugins/datasource/mixed/MixedDataSource.ts b/public/app/plugins/datasource/mixed/MixedDataSource.ts index d0296261f99..2466cdcbda9 100644 --- a/public/app/plugins/datasource/mixed/MixedDataSource.ts +++ b/public/app/plugins/datasource/mixed/MixedDataSource.ts @@ -15,6 +15,8 @@ import { getDataSourceSrv, toDataQueryError } from '@grafana/runtime'; export const MIXED_DATASOURCE_NAME = '-- Mixed --'; +export const mixedRequestId = (queryIdx: number, requestId?: string) => `mixed-${queryIdx}-${requestId || ''}`; + export interface BatchedQueries { datasource: Promise; targets: DataQuery[]; @@ -61,7 +63,7 @@ export class MixedDatasource extends DataSourceApi { from(query.datasource).pipe( mergeMap((api: DataSourceApi) => { const dsRequest = cloneDeep(request); - dsRequest.requestId = `mixed-${i}-${dsRequest.requestId || ''}`; + dsRequest.requestId = mixedRequestId(i, dsRequest.requestId); dsRequest.targets = query.targets; return from(api.query(dsRequest)).pipe( @@ -70,7 +72,7 @@ export class MixedDatasource extends DataSourceApi { ...response, data: response.data || [], state: LoadingState.Loading, - key: `mixed-${i}-${response.key || ''}`, + key: mixedRequestId(i, response.key), }; }), toArray(), @@ -83,7 +85,7 @@ export class MixedDatasource extends DataSourceApi { data: [], state: LoadingState.Error, error: err, - key: `mixed-${i}-${dsRequest.requestId || ''}`, + key: mixedRequestId(i, dsRequest.requestId), }, ]); })