Explore: Remove not running query for collapsed elements (#27026)

* Make graph and table collapsing just a UI thing

* Remove showingGraph and showingTable, set them defaultly to true

* Remove collaapsing for panels in Explore

* UI toggle WiP

* WIP, add query type

* Refactor, clean up

* Update tests

* Clean uo

* Update rangeAll to range and instant

* Remove console logs

* Update packages/grafana-data/src/types/datasource.ts

Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com>

* Update public/app/core/utils/explore.ts

Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com>

* Fix prettier error

Co-authored-by: Zoltán Bedi <zoltan.bedi@gmail.com>
pull/27711/head
Ivana Huckova 5 years ago committed by GitHub
parent 32deddbf0b
commit f6c91d1318
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      packages/grafana-data/src/types/datasource.ts
  2. 7
      public/app/core/utils/explore.ts
  3. 4
      public/app/features/explore/Explore.test.tsx
  4. 19
      public/app/features/explore/Explore.tsx
  5. 25
      public/app/features/explore/ExploreGraphPanel.tsx
  6. 2
      public/app/features/explore/Logs.tsx
  7. 26
      public/app/features/explore/LogsContainer.tsx
  8. 5
      public/app/features/explore/TableContainer.test.tsx
  9. 17
      public/app/features/explore/TableContainer.tsx
  10. 2
      public/app/features/explore/__snapshots__/TableContainer.test.tsx.snap
  11. 18
      public/app/features/explore/state/actionTypes.ts
  12. 58
      public/app/features/explore/state/actions.ts
  13. 38
      public/app/features/explore/state/reducers.test.ts
  14. 22
      public/app/features/explore/state/reducers.ts
  15. 92
      public/app/plugins/datasource/prometheus/components/PromExploreQueryEditor.tsx
  16. 2
      public/app/plugins/datasource/prometheus/components/PromQueryField.tsx
  17. 104
      public/app/plugins/datasource/prometheus/components/__snapshots__/PromExploreQueryEditor.test.tsx.snap
  18. 104
      public/app/plugins/datasource/prometheus/datasource.test.ts
  19. 49
      public/app/plugins/datasource/prometheus/datasource.ts
  20. 1
      public/app/plugins/datasource/prometheus/types.ts
  21. 10
      public/app/types/explore.ts

@ -453,6 +453,9 @@ export interface DataQueryRequest<TQuery extends DataQuery = DataQuery> {
// Explore state used by various datasources
liveStreaming?: boolean;
/**
* @deprecated showingGraph and showingTable are always set to true and set to true
*/
showingGraph?: boolean;
showingTable?: boolean;
}

@ -160,8 +160,11 @@ export function buildQueryTransaction(
maxDataPoints: queryOptions.maxDataPoints,
exploreMode: queryOptions.mode,
liveStreaming: queryOptions.liveStreaming,
showingGraph: queryOptions.showingGraph,
showingTable: queryOptions.showingTable,
/**
* @deprecated (external API) showingGraph and showingTable are always set to true and set to true
*/
showingGraph: true,
showingTable: true,
};
return {

@ -5,7 +5,6 @@ import { ExploreId } from 'app/types/explore';
import { shallow } from 'enzyme';
import { Explore, ExploreProps } from './Explore';
import { scanStopAction } from './state/actionTypes';
import { toggleGraph } from './state/actions';
import { SecondaryActions } from './SecondaryActions';
import { getTheme } from '@grafana/ui';
@ -67,11 +66,8 @@ const dummyProps: ExploreProps = {
from: 0,
to: 0,
},
showingGraph: false,
showingTable: false,
timeZone: 'UTC',
onHiddenSeriesChanged: jest.fn(),
toggleGraph: toggleGraph,
queryResponse: {
state: LoadingState.NotStarted,
series: [],

@ -37,7 +37,6 @@ import {
refreshExplore,
scanStart,
setQueries,
toggleGraph,
updateTimeRange,
} from './state/actions';
@ -114,11 +113,8 @@ export interface ExploreProps {
logsResult?: LogsModel;
loading?: boolean;
absoluteRange: AbsoluteTimeRange;
showingGraph?: boolean;
showingTable?: boolean;
timeZone?: TimeZone;
onHiddenSeriesChanged?: (hiddenSeries: string[]) => void;
toggleGraph: typeof toggleGraph;
queryResponse: PanelData;
originPanelId: number;
addQueryRow: typeof addQueryRow;
@ -269,11 +265,6 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
this.props.scanStopAction({ exploreId: this.props.exploreId });
};
onToggleGraph = (showingGraph: boolean) => {
const { toggleGraph, exploreId } = this.props;
toggleGraph(exploreId, showingGraph);
};
onUpdateTimeRange = (absoluteRange: AbsoluteTimeRange) => {
const { exploreId, updateTimeRange } = this.props;
updateTimeRange({ exploreId, absoluteRange });
@ -321,8 +312,6 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
graphResult,
loading,
absoluteRange,
showingGraph,
showingTable,
timeZone,
queryResponse,
syncedTimes,
@ -396,10 +385,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
absoluteRange={absoluteRange}
isStacked={false}
showPanel={true}
showingGraph={showingGraph}
showingTable={showingTable}
timeZone={timeZone}
onToggleGraph={this.onToggleGraph}
onUpdateTimeRange={this.onUpdateTimeRange}
showBars={false}
showLines={true}
@ -484,8 +470,6 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps): Partia
showTable,
showTrace,
loading,
showingGraph,
showingTable,
absoluteRange,
queryResponse,
} = item;
@ -514,8 +498,6 @@ function mapStateToProps(state: StoreState, { exploreId }: ExploreProps): Partia
graphResult: graphResult ?? undefined,
logsResult: logsResult ?? undefined,
loading,
showingGraph,
showingTable,
absoluteRange,
queryResponse,
originPanelId,
@ -537,7 +519,6 @@ const mapDispatchToProps: Partial<ExploreProps> = {
scanStopAction,
setQueries,
updateTimeRange,
toggleGraph,
addQueryRow,
};

@ -49,11 +49,8 @@ interface Props extends Themeable {
showBars: boolean;
showLines: boolean;
isStacked: boolean;
showingGraph?: boolean;
showingTable?: boolean;
timeZone?: TimeZone;
onUpdateTimeRange: (absoluteRange: AbsoluteTimeRange) => void;
onToggleGraph?: (showingGraph: boolean) => void;
onHiddenSeriesChanged?: (hiddenSeries: string[]) => void;
}
@ -74,13 +71,6 @@ class UnThemedExploreGraphPanel extends PureComponent<Props, State> {
});
};
onClickGraphButton = () => {
const { onToggleGraph, showingGraph } = this.props;
if (onToggleGraph) {
onToggleGraph(showingGraph ?? false);
}
};
onChangeTime = (from: number, to: number) => {
const { onUpdateTimeRange } = this.props;
onUpdateTimeRange({ from, to });
@ -95,8 +85,6 @@ class UnThemedExploreGraphPanel extends PureComponent<Props, State> {
timeZone,
absoluteRange,
showPanel,
showingGraph,
showingTable,
showBars,
showLines,
isStacked,
@ -116,10 +104,9 @@ class UnThemedExploreGraphPanel extends PureComponent<Props, State> {
},
};
const height = showPanel === false ? 100 : showingGraph && showingTable ? 200 : 400;
const height = showPanel ? 200 : 100;
const lineWidth = showLines ? 1 : 5;
const seriesToShow = showAllTimeSeries ? series : series.slice(0, MAX_NUMBER_OF_TIME_SERIES);
return (
<GraphSeriesToggler series={seriesToShow} onHiddenSeriesChanged={onHiddenSeriesChanged}>
{({ onSeriesToggle, toggledSeries }: GraphSeriesTogglerAPI) => {
@ -153,7 +140,7 @@ class UnThemedExploreGraphPanel extends PureComponent<Props, State> {
};
render() {
const { series, showPanel, showingGraph, loading, theme } = this.props;
const { series, showPanel, loading, theme } = this.props;
const { showAllTimeSeries } = this.state;
const style = getStyles(theme);
@ -171,13 +158,7 @@ class UnThemedExploreGraphPanel extends PureComponent<Props, State> {
)}
{showPanel && (
<Collapse
label="Graph"
collapsible
isOpen={showingGraph}
loading={loading}
onToggle={this.onClickGraphButton}
>
<Collapse label="Graph" loading={loading} isOpen>
{this.renderGraph()}
</Collapse>
)}

@ -266,8 +266,6 @@ export class Logs extends PureComponent<Props, State> {
absoluteRange={visibleRange || absoluteRange}
isStacked={true}
showPanel={false}
showingGraph={true}
showingTable={true}
timeZone={timeZone}
showBars={true}
showLines={false}

@ -62,15 +62,7 @@ interface LogsContainerProps {
splitOpen: typeof splitOpen;
}
interface LogsContainerState {
logsContainerOpen: boolean;
}
export class LogsContainer extends PureComponent<LogsContainerProps, LogsContainerState> {
state: LogsContainerState = {
logsContainerOpen: true,
};
export class LogsContainer extends PureComponent<LogsContainerProps> {
onChangeTime = (absoluteRange: AbsoluteTimeRange) => {
const { exploreId, updateTimeRange } = this.props;
updateTimeRange({ exploreId, absoluteRange });
@ -102,12 +94,6 @@ export class LogsContainer extends PureComponent<LogsContainerProps, LogsContain
return getFieldLinksForExplore(field, rowIndex, this.props.splitOpen, this.props.range);
};
onToggleCollapse = () => {
this.setState(state => ({
logsContainerOpen: !state.logsContainerOpen,
}));
};
render() {
const {
loading,
@ -130,8 +116,6 @@ export class LogsContainer extends PureComponent<LogsContainerProps, LogsContain
exploreId,
} = this.props;
const { logsContainerOpen } = this.state;
return (
<>
<LogsCrossFadeTransition visible={isLive}>
@ -151,13 +135,7 @@ export class LogsContainer extends PureComponent<LogsContainerProps, LogsContain
</Collapse>
</LogsCrossFadeTransition>
<LogsCrossFadeTransition visible={!isLive}>
<Collapse
label="Logs"
loading={loading}
isOpen={logsContainerOpen}
onToggle={this.onToggleCollapse}
collapsible
>
<Collapse label="Logs" loading={loading} isOpen>
<Logs
dedupStrategy={this.props.dedupStrategy || LogsDedupStrategy.none}
logRows={logRows}

@ -2,7 +2,6 @@ import React from 'react';
import { render, shallow } from 'enzyme';
import { TableContainer } from './TableContainer';
import { DataFrame } from '@grafana/data';
import { toggleTable } from './state/actions';
import { ExploreId } from 'app/types/explore';
describe('TableContainer', () => {
@ -12,9 +11,7 @@ describe('TableContainer', () => {
loading: false,
width: 800,
onCellFilterAdded: jest.fn(),
showingTable: true,
tableResult: {} as DataFrame,
toggleTable: {} as typeof toggleTable,
splitOpen: (() => {}) as any,
range: {} as any,
};
@ -29,13 +26,11 @@ describe('TableContainer', () => {
loading: false,
width: 800,
onCellFilterAdded: jest.fn(),
showingTable: true,
tableResult: {
name: 'TableResultName',
fields: [],
length: 0,
} as DataFrame,
toggleTable: {} as typeof toggleTable,
splitOpen: (() => {}) as any,
range: {} as any,
};

@ -5,7 +5,7 @@ import { DataFrame, TimeRange, ValueLinkConfig } from '@grafana/data';
import { Collapse, Table } from '@grafana/ui';
import { ExploreId, ExploreItemState } from 'app/types/explore';
import { StoreState } from 'app/types';
import { splitOpen, toggleTable } from './state/actions';
import { splitOpen } from './state/actions';
import { config } from 'app/core/config';
import { PANEL_BORDER } from 'app/core/constants';
import { MetaInfoText } from './MetaInfoText';
@ -18,18 +18,12 @@ interface TableContainerProps {
loading: boolean;
width: number;
onCellFilterAdded?: (filter: FilterItem) => void;
showingTable: boolean;
tableResult?: DataFrame;
toggleTable: typeof toggleTable;
splitOpen: typeof splitOpen;
range: TimeRange;
}
export class TableContainer extends PureComponent<TableContainerProps> {
onClickTableButton = () => {
this.props.toggleTable(this.props.exploreId, this.props.showingTable);
};
getTableHeight() {
const { tableResult } = this.props;
@ -42,7 +36,7 @@ export class TableContainer extends PureComponent<TableContainerProps> {
}
render() {
const { loading, onCellFilterAdded, showingTable, tableResult, width, splitOpen, range, ariaLabel } = this.props;
const { loading, onCellFilterAdded, tableResult, width, splitOpen, range, ariaLabel } = this.props;
const height = this.getTableHeight();
const tableWidth = width - config.theme.panelPadding * 2 - PANEL_BORDER;
@ -60,7 +54,7 @@ export class TableContainer extends PureComponent<TableContainerProps> {
}
return (
<Collapse label="Table" loading={loading} collapsible isOpen={showingTable} onToggle={this.onClickTableButton}>
<Collapse label="Table" loading={loading} isOpen>
{hasTableResult ? (
<Table
ariaLabel={ariaLabel}
@ -81,13 +75,12 @@ function mapStateToProps(state: StoreState, { exploreId }: { exploreId: string }
const explore = state.explore;
// @ts-ignore
const item: ExploreItemState = explore[exploreId];
const { loading: loadingInState, showingTable, tableResult, range } = item;
const { loading: loadingInState, tableResult, range } = item;
const loading = tableResult && tableResult.length > 0 ? false : loadingInState;
return { loading, showingTable, tableResult, range };
return { loading, tableResult, range };
}
const mapDispatchToProps = {
toggleTable,
splitOpen,
};

@ -2,11 +2,9 @@
exports[`TableContainer should render component 1`] = `
<Collapse
collapsible={true}
isOpen={true}
label="Table"
loading={false}
onToggle={[Function]}
>
<Memo(MetaInfoText)
metaItems={

@ -126,14 +126,6 @@ export interface SyncTimesPayload {
syncedTimes: boolean;
}
export interface ToggleTablePayload {
exploreId: ExploreId;
}
export interface ToggleGraphPayload {
exploreId: ExploreId;
}
export interface UpdateUIStatePayload extends Partial<ExploreUIState> {
exploreId: ExploreId;
}
@ -296,16 +288,6 @@ export const richHistoryUpdatedAction = createAction<any>('explore/richHistoryUp
*/
export const updateUIStateAction = createAction<UpdateUIStatePayload>('explore/updateUIState');
/**
* Expand/collapse the table result viewer. When collapsed, table queries won't be run.
*/
export const toggleTableAction = createAction<ToggleTablePayload>('explore/toggleTable');
/**
* Expand/collapse the graph result viewer. When collapsed, graph queries won't be run.
*/
export const toggleGraphAction = createAction<ToggleGraphPayload>('explore/toggleGraph');
/**
* Updates datasource instance before datasouce loading has started
*/

@ -1,7 +1,7 @@
// Libraries
import { map, throttleTime } from 'rxjs/operators';
import { identity } from 'rxjs';
import { ActionCreatorWithPayload, PayloadAction } from '@reduxjs/toolkit';
import { PayloadAction } from '@reduxjs/toolkit';
import { DataSourceSrv } from '@grafana/runtime';
import { RefreshPicker } from '@grafana/ui';
import {
@ -77,10 +77,6 @@ import {
splitCloseAction,
splitOpenAction,
syncTimesAction,
toggleGraphAction,
ToggleGraphPayload,
toggleTableAction,
ToggleTablePayload,
updateDatasourceInstanceAction,
updateUIStateAction,
changeLoadingStateAction,
@ -429,8 +425,6 @@ export const runQueries = (exploreId: ExploreId): ThunkResult<void> => {
queryResponse,
querySubscription,
history,
showingGraph,
showingTable,
} = exploreItemState;
if (!hasNonEmptyQuery(queries)) {
@ -461,8 +455,6 @@ export const runQueries = (exploreId: ExploreId): ThunkResult<void> => {
// maxDataPoints: mode === ExploreMode.Logs && datasourceId === 'loki' ? undefined : containerWidth,
maxDataPoints: containerWidth,
liveStreaming: live,
showingGraph,
showingTable,
};
const datasourceName = exploreItemState.requestedDatasourceName;
@ -577,9 +569,9 @@ export const stateSave = (): ThunkResult<void> => {
queries: left.queries.map(clearQueryKeys),
range: toRawTimeRange(left.range),
ui: {
showingGraph: left.showingGraph,
showingGraph: true,
showingLogs: true,
showingTable: left.showingTable,
showingTable: true,
dedupStrategy: left.dedupStrategy,
},
};
@ -590,9 +582,9 @@ export const stateSave = (): ThunkResult<void> => {
queries: right.queries.map(clearQueryKeys),
range: toRawTimeRange(right.range),
ui: {
showingGraph: right.showingGraph,
showingGraph: true,
showingLogs: true,
showingTable: right.showingTable,
showingTable: true,
dedupStrategy: right.dedupStrategy,
},
};
@ -753,46 +745,6 @@ export function syncTimes(exploreId: ExploreId): ThunkResult<void> {
};
}
/**
* Creates action to collapse graph/logs/table panel. When panel is collapsed,
* queries won't be run
*/
const togglePanelActionCreator = (
actionCreator: ActionCreatorWithPayload<ToggleGraphPayload> | ActionCreatorWithPayload<ToggleTablePayload>
) => (exploreId: ExploreId, isPanelVisible: boolean): ThunkResult<void> => {
return dispatch => {
let uiFragmentStateUpdate: Partial<ExploreUIState>;
const shouldRunQueries = !isPanelVisible;
switch (actionCreator.type) {
case toggleGraphAction.type:
uiFragmentStateUpdate = { showingGraph: !isPanelVisible };
break;
case toggleTableAction.type:
uiFragmentStateUpdate = { showingTable: !isPanelVisible };
break;
}
dispatch(actionCreator({ exploreId }));
// The switch further up is exhaustive so uiFragmentStateUpdate should definitely be initialized
dispatch(updateExploreUIState(exploreId, uiFragmentStateUpdate!));
if (shouldRunQueries) {
dispatch(runQueries(exploreId));
}
};
};
/**
* Expand/collapse the graph result viewer. When collapsed, graph queries won't be run.
*/
export const toggleGraph = togglePanelActionCreator(toggleGraphAction);
/**
* Expand/collapse the table result viewer. When collapsed, table queries won't be run.
*/
export const toggleTable = togglePanelActionCreator(toggleTableAction);
/**
* Change logs deduplication strategy and update URL.
*/

@ -6,7 +6,6 @@ import {
LoadingState,
LogsDedupStrategy,
RawTimeRange,
toDataFrame,
UrlQueryMap,
ExploreUrlState,
} from '@grafana/data';
@ -28,8 +27,6 @@ import {
scanStopAction,
splitCloseAction,
splitOpenAction,
toggleGraphAction,
toggleTableAction,
updateDatasourceInstanceAction,
addQueryRowAction,
removeQueryRowAction,
@ -160,41 +157,6 @@ describe('Explore item reducer', () => {
});
});
describe('toggling panels', () => {
describe('when toggleGraphAction is dispatched', () => {
it('then it should set correct state', () => {
reducerTester<ExploreItemState>()
.givenReducer(itemReducer, ({ graphResult: [] } as unknown) as ExploreItemState)
.whenActionIsDispatched(toggleGraphAction({ exploreId: ExploreId.left }))
.thenStateShouldEqual(({ showingGraph: true, graphResult: [] } as unknown) as ExploreItemState)
.whenActionIsDispatched(toggleGraphAction({ exploreId: ExploreId.left }))
.thenStateShouldEqual(({ showingGraph: false, graphResult: [] } as unknown) as ExploreItemState);
});
});
describe('when toggleTableAction is dispatched', () => {
it('then it should set correct state', () => {
const table = toDataFrame({
name: 'logs',
fields: [
{
name: 'time',
type: 'number',
values: [1, 2],
},
],
});
reducerTester<ExploreItemState>()
.givenReducer(itemReducer, ({ tableResult: table } as unknown) as ExploreItemState)
.whenActionIsDispatched(toggleTableAction({ exploreId: ExploreId.left }))
.thenStateShouldEqual(({ showingTable: true, tableResult: table } as unknown) as ExploreItemState)
.whenActionIsDispatched(toggleTableAction({ exploreId: ExploreId.left }))
.thenStateShouldEqual(({ showingTable: false, tableResult: table } as unknown) as ExploreItemState);
});
});
});
describe('changing range', () => {
describe('when changeRangeAction is dispatched', () => {
it('then it should set correct state', () => {

@ -60,9 +60,7 @@ import {
SplitCloseActionPayload,
splitOpenAction,
syncTimesAction,
toggleGraphAction,
toggleLogLevelAction,
toggleTableAction,
updateDatasourceInstanceAction,
updateUIStateAction,
cancelQueriesAction,
@ -106,8 +104,6 @@ export const makeExploreItemState = (): ExploreItemState => ({
to: null,
} as any,
scanning: false,
showingGraph: true,
showingTable: true,
loading: false,
queryKeys: [],
urlState: null,
@ -409,24 +405,6 @@ export const itemReducer = (state: ExploreItemState = makeExploreItemState(), ac
return { ...state, ...action.payload };
}
if (toggleGraphAction.match(action)) {
const showingGraph = !state.showingGraph;
if (showingGraph) {
return { ...state, showingGraph };
}
return { ...state, showingGraph };
}
if (toggleTableAction.match(action)) {
const showingTable = !state.showingTable;
if (showingTable) {
return { ...state, showingTable };
}
return { ...state, showingTable };
}
if (queriesImportedAction.match(action)) {
const { queries } = action.payload;
return {

@ -1,7 +1,9 @@
import React, { memo, FC } from 'react';
import { css } from 'emotion';
// Types
import { ExploreQueryFieldProps } from '@grafana/data';
import { RadioButtonGroup } from '@grafana/ui';
import { PrometheusDatasource } from '../datasource';
import { PromQuery, PromOptions } from '../types';
@ -26,6 +28,19 @@ export const PromExploreQueryEditor: FC<Props> = (props: Props) => {
}
}
function onQueryTypeChange(value: string) {
const { query, onChange } = props;
let nextQuery;
if (value === 'instant') {
nextQuery = { ...query, instant: true, range: false };
} else if (value === 'range') {
nextQuery = { ...query, instant: false, range: true };
} else {
nextQuery = { ...query, instant: true, range: true };
}
onChange(nextQuery);
}
function onReturnKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
if (e.key === 'Enter') {
onRunQuery();
@ -33,27 +48,62 @@ export const PromExploreQueryEditor: FC<Props> = (props: Props) => {
}
return (
<PromQueryField
datasource={datasource}
query={query}
onRunQuery={onRunQuery}
onChange={onChange}
onBlur={() => {}}
history={history}
data={data}
ExtraFieldElement={
<PromExploreExtraField
label={'Step'}
onChangeFunc={onStepChange}
onKeyDownFunc={onReturnKeyDown}
value={query.interval || ''}
hasTooltip={true}
tooltipContent={
'Time units can be used here, for example: 5s, 1m, 3h, 1d, 1y (Default if no unit is specified: s)'
}
/>
}
/>
<>
<PromQueryField
datasource={datasource}
query={query}
onRunQuery={onRunQuery}
onChange={onChange}
onBlur={() => {}}
history={history}
data={data}
ExtraFieldElement={
<PromExploreExtraField
label={'Step'}
onChangeFunc={onStepChange}
onKeyDownFunc={onReturnKeyDown}
value={query.interval || ''}
hasTooltip={true}
tooltipContent={
'Time units can be used here, for example: 5s, 1m, 3h, 1d, 1y (Default if no unit is specified: s)'
}
/>
}
/>
<PromExploreRadioButton
selected={query.range && query.instant ? 'both' : query.instant ? 'instant' : 'range'}
onQueryTypeChange={onQueryTypeChange}
/>
</>
);
};
type PromExploreRadioButtonProps = {
selected: string;
onQueryTypeChange: (value: string) => void;
};
const PromExploreRadioButton: React.FunctionComponent<PromExploreRadioButtonProps> = ({
selected,
onQueryTypeChange,
}) => {
const rangeOptions = [
{ value: 'range', label: 'Range' },
{ value: 'instant', label: 'Instant' },
{ value: 'both', label: 'Both' },
];
return (
<div
className={css`
display: flex;
`}
>
<button className={`gf-form-label gf-form-label--btn width-5`}>
<span className="btn-title">Query type</span>
</button>
<RadioButtonGroup options={rangeOptions} value={selected} onChange={onQueryTypeChange} />
</div>
);
};

@ -326,7 +326,7 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
return (
<>
<div className="gf-form-inline gf-form-inline--xs-view-flex-column flex-grow-1">
<div className="gf-form flex-shrink-0">
<div className="gf-form flex-shrink-0 min-width-5">
<ButtonCascader options={metricsOptions} disabled={buttonDisabled} onChange={this.onChangeMetrics}>
{chooserText}
</ButtonCascader>

@ -1,62 +1,68 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`PromExploreQueryEditor should render component 1`] = `
<PromQueryField
ExtraFieldElement={
<PromExploreExtraField
hasTooltip={true}
label="Step"
onChangeFunc={[Function]}
onKeyDownFunc={[Function]}
tooltipContent="Time units can be used here, for example: 5s, 1m, 3h, 1d, 1y (Default if no unit is specified: s)"
value="1s"
/>
}
data={
Object {
"request": Object {
"app": "Grafana",
"dashboardId": 1,
"interval": "1s",
"intervalMs": 1000,
"panelId": 1,
"range": Object {
"from": "2020-01-01T00:00:00.000Z",
"raw": Object {
<Fragment>
<PromQueryField
ExtraFieldElement={
<PromExploreExtraField
hasTooltip={true}
label="Step"
onChangeFunc={[Function]}
onKeyDownFunc={[Function]}
tooltipContent="Time units can be used here, for example: 5s, 1m, 3h, 1d, 1y (Default if no unit is specified: s)"
value="1s"
/>
}
data={
Object {
"request": Object {
"app": "Grafana",
"dashboardId": 1,
"interval": "1s",
"intervalMs": 1000,
"panelId": 1,
"range": Object {
"from": "2020-01-01T00:00:00.000Z",
"raw": Object {
"from": "2020-01-01T00:00:00.000Z",
"to": "2020-01-02T00:00:00.000Z",
},
"to": "2020-01-02T00:00:00.000Z",
},
"to": "2020-01-02T00:00:00.000Z",
"requestId": "1",
"scopedVars": Object {},
"startTime": 0,
"targets": Array [],
"timezone": "GMT",
},
"requestId": "1",
"scopedVars": Object {},
"startTime": 0,
"targets": Array [],
"timezone": "GMT",
},
"series": Array [],
"state": "NotStarted",
"timeRange": Object {
"from": "2020-01-01T00:00:00.000Z",
"raw": Object {
"series": Array [],
"state": "NotStarted",
"timeRange": Object {
"from": "2020-01-01T00:00:00.000Z",
"raw": Object {
"from": "2020-01-01T00:00:00.000Z",
"to": "2020-01-02T00:00:00.000Z",
},
"to": "2020-01-02T00:00:00.000Z",
},
"to": "2020-01-02T00:00:00.000Z",
},
}
}
}
datasource={Object {}}
history={Array []}
onBlur={[Function]}
onChange={[MockFunction]}
onRunQuery={[MockFunction]}
query={
Object {
"expr": "",
"interval": "1s",
"refId": "A",
datasource={Object {}}
history={Array []}
onBlur={[Function]}
onChange={[MockFunction]}
onRunQuery={[MockFunction]}
query={
Object {
"expr": "",
"interval": "1s",
"refId": "A",
}
}
}
/>
/>
<PromExploreRadioButton
onQueryTypeChange={[Function]}
selected="range"
/>
</Fragment>
`;

@ -1810,17 +1810,16 @@ describe('prepareTargets', () => {
});
describe('when run from Explore', () => {
describe('and both Graph and Table are shown', () => {
describe('when query type Both is selected', () => {
it('then it should return both instant and time series related objects', () => {
const target: PromQuery = {
refId: 'A',
expr: 'up',
range: true,
instant: true,
};
const { queries, activeTargets, panelId, end, start } = getPrepareTargetsContext(target, CoreApp.Explore, {
showingGraph: true,
showingTable: true,
});
const { queries, activeTargets, panelId, end, start } = getPrepareTargetsContext(target, CoreApp.Explore);
expect(queries.length).toBe(2);
expect(activeTargets.length).toBe(2);
@ -1868,33 +1867,16 @@ describe('prepareTargets', () => {
});
});
describe('and both Graph and Table are hidden', () => {
it('then it should return empty arrays', () => {
const target: PromQuery = {
refId: 'A',
expr: 'up',
showingGraph: false,
showingTable: false,
};
const { queries, activeTargets } = getPrepareTargetsContext(target, CoreApp.Explore);
expect(queries.length).toBe(0);
expect(activeTargets.length).toBe(0);
});
});
describe('and Graph is hidden', () => {
it('then it should return only intant related objects', () => {
describe('when query type Instant is selected', () => {
it('then it should just add targets', () => {
const target: PromQuery = {
refId: 'A',
expr: 'up',
instant: true,
range: false,
};
const { queries, activeTargets, panelId, end, start } = getPrepareTargetsContext(target, CoreApp.Explore, {
showingGraph: false,
showingTable: true,
});
const { queries, activeTargets, panelId, end, start } = getPrepareTargetsContext(target, CoreApp.Explore);
expect(queries.length).toBe(1);
expect(activeTargets.length).toBe(1);
@ -1908,55 +1890,43 @@ describe('prepareTargets', () => {
hinting: undefined,
instant: true,
refId: target.refId,
requestId: panelId + target.refId + '_instant',
requestId: panelId + target.refId,
start,
step: 1,
});
expect(activeTargets[0]).toEqual({
...target,
format: 'table',
instant: true,
requestId: panelId + target.refId + '_instant',
valueWithRefId: true,
});
expect(activeTargets[0]).toEqual(target);
});
});
});
describe('and Table is hidden', () => {
it('then it should return only time series related objects', () => {
const target: PromQuery = {
refId: 'A',
expr: 'up',
};
describe('when query type Range is selected', () => {
it('then it should just add targets', () => {
const target: PromQuery = {
refId: 'A',
expr: 'up',
range: true,
instant: false,
};
const { queries, activeTargets, panelId, end, start } = getPrepareTargetsContext(target, CoreApp.Explore, {
showingGraph: true,
showingTable: false,
});
const { queries, activeTargets, panelId, end, start } = getPrepareTargetsContext(target, CoreApp.Explore);
expect(queries.length).toBe(1);
expect(activeTargets.length).toBe(1);
expect(queries[0]).toEqual({
end,
expr: 'up',
headers: {
'X-Dashboard-Id': undefined,
'X-Panel-Id': panelId,
},
hinting: undefined,
instant: false,
refId: target.refId,
requestId: panelId + target.refId,
start,
step: 1,
});
expect(activeTargets[0]).toEqual({
...target,
format: 'time_series',
instant: false,
requestId: panelId + target.refId,
});
expect(queries.length).toBe(1);
expect(activeTargets.length).toBe(1);
expect(queries[0]).toEqual({
end,
expr: 'up',
headers: {
'X-Dashboard-Id': undefined,
'X-Panel-Id': panelId,
},
hinting: undefined,
instant: false,
refId: target.refId,
requestId: panelId + target.refId,
start,
step: 1,
});
expect(activeTargets[0]).toEqual(target);
});
});
});

@ -176,7 +176,8 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
query: PromQueryRequest,
target: PromQuery,
responseListLength: number,
scopedVars?: ScopedVars
scopedVars?: ScopedVars,
mixedQueries?: boolean
) => {
// Keeping original start/end for transformers
const transformerOptions = {
@ -191,8 +192,10 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
refId: target.refId,
valueWithRefId: target.valueWithRefId,
meta: {
/** Fix for showing of Prometheus results in Explore table. We want to show result of instant query in table and the rest of time series in graph */
preferredVisualisationType: query.instant ? 'table' : 'graph',
/** Fix for showing of Prometheus results in Explore table.
* We want to show result of instant query always in table and result of range query based on target.runAll;
*/
preferredVisualisationType: target.instant ? 'table' : mixedQueries ? 'graph' : undefined,
},
};
const series = this.resultTransformer.transform(response, transformerOptions);
@ -211,32 +214,32 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
target.requestId = options.panelId + target.refId;
if (options.app !== CoreApp.Explore) {
activeTargets.push(target);
queries.push(this.createQuery(target, options, start, end));
continue;
}
if (options.showingTable) {
// create instant target only if Table is showed in Explore
if (target.range && target.instant) {
// If running both (only available in Explore) - instant and range query, prepare both targets
// Create instant target
const instantTarget: any = cloneDeep(target);
instantTarget.format = 'table';
instantTarget.instant = true;
instantTarget.range = false;
instantTarget.valueWithRefId = true;
delete instantTarget.maxDataPoints;
instantTarget.requestId += '_instant';
activeTargets.push(instantTarget);
queries.push(this.createQuery(instantTarget, options, start, end));
}
if (options.showingGraph) {
// create time series target only if Graph is showed in Explore
target.format = 'time_series';
target.instant = false;
activeTargets.push(target);
// Create range target
const rangeTarget: any = cloneDeep(target);
rangeTarget.format = 'time_series';
rangeTarget.instant = false;
instantTarget.range = true;
// Add both targets to activeTargets and queries arrays
activeTargets.push(instantTarget, rangeTarget);
queries.push(
this.createQuery(instantTarget, options, start, end),
this.createQuery(rangeTarget, options, start, end)
);
} else {
queries.push(this.createQuery(target, options, start, end));
activeTargets.push(target);
}
}
@ -268,6 +271,8 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
private exploreQuery(queries: PromQueryRequest[], activeTargets: PromQuery[], end: number) {
let runningQueriesCount = queries.length;
const mixedQueries = activeTargets.some(t => t.range) && activeTargets.some(t => t.instant);
const subQueries = queries.map((query, index) => {
const target = activeTargets[index];
@ -281,7 +286,7 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
tap(() => runningQueriesCount--),
filter((response: any) => (response.cancelled ? false : true)),
map((response: any) => {
const data = this.processResult(response, query, target, queries.length);
const data = this.processResult(response, query, target, queries.length, undefined, mixedQueries);
return {
data,
key: query.requestId,

@ -4,6 +4,7 @@ export interface PromQuery extends DataQuery {
expr: string;
format?: string;
instant?: boolean;
range?: boolean;
hinting?: boolean;
interval?: string;
intervalFactor?: number;

@ -118,14 +118,6 @@ export interface ExploreItemState {
* Current scanning range to be shown to the user while scanning is active.
*/
scanRange?: RawTimeRange;
/**
* True if graph result viewer is expanded. Query runs will contain graph queries.
*/
showingGraph: boolean;
/**
* True if table result viewer is expanded. Query runs will contain table queries.
*/
showingTable: boolean;
loading: boolean;
/**
@ -206,8 +198,6 @@ export interface QueryOptions {
minInterval?: string;
maxDataPoints?: number;
liveStreaming?: boolean;
showingGraph?: boolean;
showingTable?: boolean;
mode?: ExploreMode;
}

Loading…
Cancel
Save