Explore: Moves PromContext from query level to DataQueryRequest level (#21260)

Closes #19598

Fixes bug introduced recently where the new PromQueryEditor did not preserve
the PromContext.Explore set on the query model by PromQueryField which caused
the table to be empty for Prometheus in explore.
This commit is contained in:
Torkel Ödegaard 2019-12-27 09:11:16 +01:00 committed by GitHub
parent 545b72da33
commit 45b7de1910
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 40 additions and 38 deletions

View File

@ -3,6 +3,11 @@ import { KeyValue } from './data';
import { NavModel } from './navModel'; import { NavModel } from './navModel';
import { PluginMeta, GrafanaPlugin, PluginIncludeType } from './plugin'; import { PluginMeta, GrafanaPlugin, PluginIncludeType } from './plugin';
export enum CoreApp {
Dashboard = 'dashboard',
Explore = 'explore',
}
export interface AppRootProps<T = KeyValue> { export interface AppRootProps<T = KeyValue> {
meta: AppPluginMeta<T>; meta: AppPluginMeta<T>;

View File

@ -7,6 +7,7 @@ import { AnnotationEvent, KeyValue, LoadingState, TableData, TimeSeries } from '
import { DataFrame, DataFrameDTO } from './dataFrame'; import { DataFrame, DataFrameDTO } from './dataFrame';
import { RawTimeRange, TimeRange, AbsoluteTimeRange } from './time'; import { RawTimeRange, TimeRange, AbsoluteTimeRange } from './time';
import { ScopedVars } from './ScopedVars'; import { ScopedVars } from './ScopedVars';
import { CoreApp } from './app';
export interface DataSourcePluginOptionsEditorProps<JSONData = DataSourceJsonData, SecureJSONData = {}> { export interface DataSourcePluginOptionsEditorProps<JSONData = DataSourceJsonData, SecureJSONData = {}> {
options: DataSourceSettings<JSONData, SecureJSONData>; options: DataSourceSettings<JSONData, SecureJSONData>;
@ -449,6 +450,7 @@ export interface DataQueryRequest<TQuery extends DataQuery = DataQuery> {
scopedVars: ScopedVars; scopedVars: ScopedVars;
targets: TQuery[]; targets: TQuery[];
timezone: string; timezone: string;
app: CoreApp | string;
cacheTimeout?: string; cacheTimeout?: string;
exploreMode?: 'Logs' | 'Metrics'; exploreMode?: 'Logs' | 'Metrics';

View File

@ -4,6 +4,7 @@ import { Unsubscribable } from 'rxjs';
// Services & Utils // Services & Utils
import { import {
DataQuery, DataQuery,
CoreApp,
DataQueryError, DataQueryError,
DataQueryRequest, DataQueryRequest,
DataSourceApi, DataSourceApi,
@ -130,6 +131,7 @@ export function buildQueryTransaction(
const panelId = `${key}`; const panelId = `${key}`;
const request: DataQueryRequest = { const request: DataQueryRequest = {
app: CoreApp.Explore,
dashboardId: 0, dashboardId: 0,
// TODO probably should be taken from preferences but does not seem to be used anyway. // TODO probably should be taken from preferences but does not seem to be used anyway.
timezone: DefaultTimeZone, timezone: DefaultTimeZone,

View File

@ -15,6 +15,7 @@ import { runSharedRequest, isSharedDashboardQuery } from '../../../plugins/datas
import { import {
PanelData, PanelData,
DataQuery, DataQuery,
CoreApp,
DataQueryRequest, DataQueryRequest,
DataSourceApi, DataSourceApi,
DataSourceJsonData, DataSourceJsonData,
@ -106,6 +107,7 @@ export class PanelQueryRunner {
} }
const request: DataQueryRequest = { const request: DataQueryRequest = {
app: CoreApp.Dashboard,
requestId: getNextRequestId(), requestId: getNextRequestId(),
timezone, timezone,
panelId, panelId,

View File

@ -6,6 +6,8 @@ import { Table, Collapse } from '@grafana/ui';
import { ExploreId, ExploreItemState } from 'app/types/explore'; import { ExploreId, ExploreItemState } from 'app/types/explore';
import { StoreState } from 'app/types'; import { StoreState } from 'app/types';
import { toggleTable } from './state/actions'; import { toggleTable } from './state/actions';
import { config } from 'app/core/config';
import { PANEL_BORDER } from 'app/core/constants';
interface TableContainerProps { interface TableContainerProps {
exploreId: ExploreId; exploreId: ExploreId;
@ -37,8 +39,7 @@ export class TableContainer extends PureComponent<TableContainerProps> {
const { loading, onClickCell, showingTable, tableResult, width } = this.props; const { loading, onClickCell, showingTable, tableResult, width } = this.props;
const height = this.getTableHeight(); const height = this.getTableHeight();
const paddingWidth = 16; const tableWidth = width - config.theme.panelPadding * 2 - PANEL_BORDER;
const tableWidth = width - paddingWidth;
return ( return (
<Collapse label="Table" loading={loading} collapsible isOpen={showingTable} onToggle={this.onClickTableButton}> <Collapse label="Table" loading={loading} collapsible isOpen={showingTable} onToggle={this.onClickTableButton}>

View File

@ -262,7 +262,7 @@ export default class LokiLanguageProvider extends LanguageProvider {
return Promise.all( return Promise.all(
queries.map(async query => { queries.map(async query => {
const expr = await this.importPrometheusQuery(query.expr); const expr = await this.importPrometheusQuery(query.expr);
const { context, ...rest } = query as PromQuery; const { ...rest } = query as PromQuery;
return { return {
...rest, ...rest,
expr, expr,

View File

@ -15,7 +15,7 @@ import {
import Prism from 'prismjs'; import Prism from 'prismjs';
// dom also includes Element polyfills // dom also includes Element polyfills
import { PromQuery, PromContext, PromOptions, PromMetricsMetadata } from '../types'; import { PromQuery, PromOptions, PromMetricsMetadata } from '../types';
import { CancelablePromise, makePromiseCancelable } from 'app/core/utils/CancelablePromise'; import { CancelablePromise, makePromiseCancelable } from 'app/core/utils/CancelablePromise';
import { ExploreQueryFieldProps, QueryHint, isDataFrame, toLegacyResponseData, HistoryItem } from '@grafana/data'; import { ExploreQueryFieldProps, QueryHint, isDataFrame, toLegacyResponseData, HistoryItem } from '@grafana/data';
import { DOMUtil, SuggestionsState } from '@grafana/ui'; import { DOMUtil, SuggestionsState } from '@grafana/ui';
@ -220,7 +220,7 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
// Send text change to parent // Send text change to parent
const { query, onChange, onRunQuery } = this.props; const { query, onChange, onRunQuery } = this.props;
if (onChange) { if (onChange) {
const nextQuery: PromQuery = { ...query, expr: value, context: PromContext.Explore }; const nextQuery: PromQuery = { ...query, expr: value };
onChange(nextQuery); onChange(nextQuery);
if (override && onRunQuery) { if (override && onRunQuery) {

View File

@ -11,9 +11,10 @@ import {
DataQueryResponseData, DataQueryResponseData,
DataQueryRequest, DataQueryRequest,
dateTime, dateTime,
CoreApp,
LoadingState, LoadingState,
} from '@grafana/data'; } from '@grafana/data';
import { PromOptions, PromQuery, PromContext } from './types'; import { PromOptions, PromQuery } from './types';
import templateSrv from 'app/features/templating/template_srv'; import templateSrv from 'app/features/templating/template_srv';
import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { CustomVariable } from 'app/features/templating/custom_variable'; import { CustomVariable } from 'app/features/templating/custom_variable';
@ -70,7 +71,7 @@ describe('PrometheusDatasource', () => {
it('returns empty array when no queries', done => { it('returns empty array when no queries', done => {
expect.assertions(2); expect.assertions(2);
ds.query(makeQuery([])).subscribe({ ds.query(createDataRequest([])).subscribe({
next(next) { next(next) {
expect(next.data).toEqual([]); expect(next.data).toEqual([]);
expect(next.state).toBe(LoadingState.Done); expect(next.state).toBe(LoadingState.Done);
@ -84,7 +85,7 @@ describe('PrometheusDatasource', () => {
it('performs time series queries', done => { it('performs time series queries', done => {
expect.assertions(2); expect.assertions(2);
ds.query(makeQuery([{}])).subscribe({ ds.query(createDataRequest([{}])).subscribe({
next(next) { next(next) {
expect(next.data.length).not.toBe(0); expect(next.data.length).not.toBe(0);
expect(next.state).toBe(LoadingState.Done); expect(next.state).toBe(LoadingState.Done);
@ -99,7 +100,7 @@ describe('PrometheusDatasource', () => {
expect.assertions(4); expect.assertions(4);
const responseStatus = [LoadingState.Loading, LoadingState.Done]; const responseStatus = [LoadingState.Loading, LoadingState.Done];
ds.query(makeQuery([{ context: PromContext.Explore }, { context: PromContext.Explore }])).subscribe({ ds.query(createDataRequest([{}, {}], { app: CoreApp.Explore })).subscribe({
next(next) { next(next) {
expect(next.data.length).not.toBe(0); expect(next.data.length).not.toBe(0);
expect(next.state).toBe(responseStatus.shift()); expect(next.state).toBe(responseStatus.shift());
@ -112,7 +113,7 @@ describe('PrometheusDatasource', () => {
it('with 2 queries and used from Panel, waits for all to finish until sending Done status', done => { it('with 2 queries and used from Panel, waits for all to finish until sending Done status', done => {
expect.assertions(2); expect.assertions(2);
ds.query(makeQuery([{ context: PromContext.Panel }, { context: PromContext.Panel }])).subscribe({ ds.query(createDataRequest([{}, {}], { app: CoreApp.Dashboard })).subscribe({
next(next) { next(next) {
expect(next.data.length).not.toBe(0); expect(next.data.length).not.toBe(0);
expect(next.state).toBe(LoadingState.Done); expect(next.state).toBe(LoadingState.Done);
@ -1552,7 +1553,7 @@ describe('PrometheusDatasource for POST', () => {
}); });
}); });
const getPrepareTargetsContext = (target: PromQuery) => { const getPrepareTargetsContext = (target: PromQuery, app?: CoreApp) => {
const instanceSettings = ({ const instanceSettings = ({
url: 'proxied', url: 'proxied',
directUrl: 'direct', directUrl: 'direct',
@ -1563,7 +1564,7 @@ const getPrepareTargetsContext = (target: PromQuery) => {
const start = 0; const start = 0;
const end = 1; const end = 1;
const panelId = '2'; const panelId = '2';
const options = ({ targets: [target], interval: '1s', panelId } as any) as DataQueryRequest<PromQuery>; const options = ({ targets: [target], interval: '1s', panelId, app } as any) as DataQueryRequest<PromQuery>;
const ds = new PrometheusDatasource(instanceSettings); const ds = new PrometheusDatasource(instanceSettings);
const { queries, activeTargets } = ds.prepareTargets(options, start, end); const { queries, activeTargets } = ds.prepareTargets(options, start, end);
@ -1583,7 +1584,6 @@ describe('prepareTargets', () => {
const target: PromQuery = { const target: PromQuery = {
refId: 'A', refId: 'A',
expr: 'up', expr: 'up',
context: PromContext.Panel,
}; };
const { queries, activeTargets, panelId, end, start } = getPrepareTargetsContext(target); const { queries, activeTargets, panelId, end, start } = getPrepareTargetsContext(target);
@ -1614,12 +1614,11 @@ describe('prepareTargets', () => {
const target: PromQuery = { const target: PromQuery = {
refId: 'A', refId: 'A',
expr: 'up', expr: 'up',
context: PromContext.Explore,
showingGraph: true, showingGraph: true,
showingTable: true, showingTable: true,
}; };
const { queries, activeTargets, panelId, end, start } = getPrepareTargetsContext(target); const { queries, activeTargets, panelId, end, start } = getPrepareTargetsContext(target, CoreApp.Explore);
expect(queries.length).toBe(2); expect(queries.length).toBe(2);
expect(activeTargets.length).toBe(2); expect(activeTargets.length).toBe(2);
@ -1672,12 +1671,11 @@ describe('prepareTargets', () => {
const target: PromQuery = { const target: PromQuery = {
refId: 'A', refId: 'A',
expr: 'up', expr: 'up',
context: PromContext.Explore,
showingGraph: false, showingGraph: false,
showingTable: false, showingTable: false,
}; };
const { queries, activeTargets } = getPrepareTargetsContext(target); const { queries, activeTargets } = getPrepareTargetsContext(target, CoreApp.Explore);
expect(queries.length).toBe(0); expect(queries.length).toBe(0);
expect(activeTargets.length).toBe(0); expect(activeTargets.length).toBe(0);
@ -1689,12 +1687,11 @@ describe('prepareTargets', () => {
const target: PromQuery = { const target: PromQuery = {
refId: 'A', refId: 'A',
expr: 'up', expr: 'up',
context: PromContext.Explore,
showingGraph: false, showingGraph: false,
showingTable: true, showingTable: true,
}; };
const { queries, activeTargets, panelId, end, start } = getPrepareTargetsContext(target); const { queries, activeTargets, panelId, end, start } = getPrepareTargetsContext(target, CoreApp.Explore);
expect(queries.length).toBe(1); expect(queries.length).toBe(1);
expect(activeTargets.length).toBe(1); expect(activeTargets.length).toBe(1);
@ -1727,12 +1724,11 @@ describe('prepareTargets', () => {
const target: PromQuery = { const target: PromQuery = {
refId: 'A', refId: 'A',
expr: 'up', expr: 'up',
context: PromContext.Explore,
showingGraph: true, showingGraph: true,
showingTable: false, showingTable: false,
}; };
const { queries, activeTargets, panelId, end, start } = getPrepareTargetsContext(target); const { queries, activeTargets, panelId, end, start } = getPrepareTargetsContext(target, CoreApp.Explore);
expect(queries.length).toBe(1); expect(queries.length).toBe(1);
expect(activeTargets.length).toBe(1); expect(activeTargets.length).toBe(1);
@ -1761,8 +1757,9 @@ describe('prepareTargets', () => {
}); });
}); });
function makeQuery(targets: any[]): any { function createDataRequest(targets: any[], overrides?: Partial<DataQueryRequest>): DataQueryRequest<PromQuery> {
return { const defaults = {
app: CoreApp.Dashboard,
targets: targets.map(t => { targets: targets.map(t => {
return { return {
instant: false, instant: false,
@ -1779,4 +1776,6 @@ function makeQuery(targets: any[]): any {
}, },
interval: '15s', interval: '15s',
}; };
return Object.assign(defaults, overrides || {}) as DataQueryRequest<PromQuery>;
} }

View File

@ -11,6 +11,7 @@ import {
LoadingState, LoadingState,
TimeRange, TimeRange,
TimeSeries, TimeSeries,
CoreApp,
DataQueryError, DataQueryError,
DataQueryRequest, DataQueryRequest,
DataQueryResponse, DataQueryResponse,
@ -29,7 +30,7 @@ import addLabelToQuery from './add_label_to_query';
import { getQueryHints } from './query_hints'; import { getQueryHints } from './query_hints';
import { expandRecordingRules } from './language_utils'; import { expandRecordingRules } from './language_utils';
// Types // Types
import { PromContext, PromOptions, PromQuery, PromQueryRequest } from './types'; import { PromOptions, PromQuery, PromQueryRequest } from './types';
import { safeStringifyValue } from 'app/core/utils/explore'; import { safeStringifyValue } from 'app/core/utils/explore';
import templateSrv from 'app/features/templating/template_srv'; import templateSrv from 'app/features/templating/template_srv';
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
@ -202,7 +203,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
target.requestId = options.panelId + target.refId; target.requestId = options.panelId + target.refId;
if (target.context !== PromContext.Explore) { if (options.app !== CoreApp.Explore) {
activeTargets.push(target); activeTargets.push(target);
queries.push(this.createQuery(target, options, start, end)); queries.push(this.createQuery(target, options, start, end));
continue; continue;
@ -237,11 +238,6 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
}; };
}; };
calledFromExplore = (options: DataQueryRequest<PromQuery>): boolean => {
const exploreTargets = options.targets.filter(target => target.context === PromContext.Explore).length;
return exploreTargets === options.targets.length;
};
query(options: DataQueryRequest<PromQuery>): Observable<DataQueryResponse> { query(options: DataQueryRequest<PromQuery>): Observable<DataQueryResponse> {
const start = this.getPrometheusTime(options.range.from, false); const start = this.getPrometheusTime(options.range.from, false);
const end = this.getPrometheusTime(options.range.to, true); const end = this.getPrometheusTime(options.range.to, true);
@ -255,7 +251,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
}); });
} }
if (this.calledFromExplore(options)) { if (options.app === CoreApp.Explore) {
return this.exploreQuery(queries, activeTargets, end); return this.exploreQuery(queries, activeTargets, end);
} }

View File

@ -1,13 +1,7 @@
import { DataQuery, DataSourceJsonData } from '@grafana/data'; import { DataQuery, DataSourceJsonData } from '@grafana/data';
export enum PromContext {
Explore = 'explore',
Panel = 'panel',
}
export interface PromQuery extends DataQuery { export interface PromQuery extends DataQuery {
expr: string; expr: string;
context?: PromContext;
format?: string; format?: string;
instant?: boolean; instant?: boolean;
hinting?: boolean; hinting?: boolean;

View File

@ -1,4 +1,4 @@
import { DataQueryRequest, DataQuery } from '@grafana/data'; import { DataQueryRequest, DataQuery, CoreApp } from '@grafana/data';
import { dateTime } from '@grafana/data'; import { dateTime } from '@grafana/data';
export function getQueryOptions<TQuery extends DataQuery>( export function getQueryOptions<TQuery extends DataQuery>(
@ -9,6 +9,7 @@ export function getQueryOptions<TQuery extends DataQuery>(
const defaults: DataQueryRequest<TQuery> = { const defaults: DataQueryRequest<TQuery> = {
requestId: 'TEST', requestId: 'TEST',
app: CoreApp.Dashboard,
range: range, range: range,
targets: [], targets: [],
scopedVars: {}, scopedVars: {},