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.
pull/21247/head
Torkel Ödegaard 6 years ago committed by GitHub
parent 545b72da33
commit 45b7de1910
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      packages/grafana-data/src/types/app.ts
  2. 2
      packages/grafana-data/src/types/datasource.ts
  3. 2
      public/app/core/utils/explore.ts
  4. 2
      public/app/features/dashboard/state/PanelQueryRunner.ts
  5. 5
      public/app/features/explore/TableContainer.tsx
  6. 2
      public/app/plugins/datasource/loki/language_provider.ts
  7. 4
      public/app/plugins/datasource/prometheus/components/PromQueryField.tsx
  8. 35
      public/app/plugins/datasource/prometheus/datasource.test.ts
  9. 12
      public/app/plugins/datasource/prometheus/datasource.ts
  10. 6
      public/app/plugins/datasource/prometheus/types.ts
  11. 3
      public/test/helpers/getQueryOptions.ts

@ -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>;

@ -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';

@ -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,

@ -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,

@ -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}>

@ -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,

@ -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) {

@ -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>;
} }

@ -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);
} }

@ -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;

@ -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: {},

Loading…
Cancel
Save