mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
PanelData: Adds timeRange prop to PanelData (#19361)
* Refactor: Adds newTimeRange property to PanelData * Refactor: Handles timeRange prop after requests * Refactor: Makes timeRange mandatory * Refactor: Adds DefaultTimeRange
This commit is contained in:
parent
e35de167f9
commit
889f8e3131
@ -41,3 +41,9 @@ export interface TimeOptions {
|
|||||||
export type TimeFragment = string | DateTime;
|
export type TimeFragment = string | DateTime;
|
||||||
|
|
||||||
export const TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';
|
export const TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';
|
||||||
|
|
||||||
|
export const DefaultTimeRange: TimeRange = {
|
||||||
|
from: {} as DateTime,
|
||||||
|
to: {} as DateTime,
|
||||||
|
raw: { from: '6h', to: 'now' },
|
||||||
|
};
|
||||||
|
@ -16,6 +16,8 @@ export interface PanelData {
|
|||||||
series: DataFrame[];
|
series: DataFrame[];
|
||||||
request?: DataQueryRequest;
|
request?: DataQueryRequest;
|
||||||
error?: DataQueryError;
|
error?: DataQueryError;
|
||||||
|
// Contains the range from the request or a shifted time range if a request uses relative time
|
||||||
|
timeRange: TimeRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PanelProps<T = any> {
|
export interface PanelProps<T = any> {
|
||||||
|
@ -14,7 +14,7 @@ import templateSrv from 'app/features/templating/template_srv';
|
|||||||
import config from 'app/core/config';
|
import config from 'app/core/config';
|
||||||
// Types
|
// Types
|
||||||
import { DashboardModel, PanelModel } from '../state';
|
import { DashboardModel, PanelModel } from '../state';
|
||||||
import { LoadingState, ScopedVars, AbsoluteTimeRange, toUtc, toDataFrameDTO } from '@grafana/data';
|
import { LoadingState, ScopedVars, AbsoluteTimeRange, toUtc, toDataFrameDTO, DefaultTimeRange } from '@grafana/data';
|
||||||
|
|
||||||
const DEFAULT_PLUGIN_ERROR = 'Error in plugin';
|
const DEFAULT_PLUGIN_ERROR = 'Error in plugin';
|
||||||
|
|
||||||
@ -52,6 +52,7 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
data: {
|
data: {
|
||||||
state: LoadingState.NotStarted,
|
state: LoadingState.NotStarted,
|
||||||
series: [],
|
series: [],
|
||||||
|
timeRange: DefaultTimeRange,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -66,6 +67,7 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
if (this.hasPanelSnapshot) {
|
if (this.hasPanelSnapshot) {
|
||||||
this.setState({
|
this.setState({
|
||||||
data: {
|
data: {
|
||||||
|
...this.state.data,
|
||||||
state: LoadingState.Done,
|
state: LoadingState.Done,
|
||||||
series: getProcessedDataFrames(panel.snapshotData),
|
series: getProcessedDataFrames(panel.snapshotData),
|
||||||
},
|
},
|
||||||
@ -241,6 +243,7 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
const PanelComponent = plugin.panel;
|
const PanelComponent = plugin.panel;
|
||||||
const innerPanelHeight = calculateInnerPanelHeight(panel, height);
|
const innerPanelHeight = calculateInnerPanelHeight(panel, height);
|
||||||
|
const timeRange = data.timeRange || this.timeSrv.timeRange();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -249,7 +252,7 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
<PanelComponent
|
<PanelComponent
|
||||||
id={panel.id}
|
id={panel.id}
|
||||||
data={data}
|
data={data}
|
||||||
timeRange={data.request ? data.request.range : this.timeSrv.timeRange()}
|
timeRange={timeRange}
|
||||||
timeZone={this.props.dashboard.getTimezone()}
|
timeZone={this.props.dashboard.getTimezone()}
|
||||||
options={panel.getOptions()}
|
options={panel.getOptions()}
|
||||||
transparent={panel.transparent}
|
transparent={panel.transparent}
|
||||||
|
@ -2,25 +2,29 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { css } from 'emotion';
|
import { css } from 'emotion';
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import { EditorTabBody, EditorToolbarView } from './EditorTabBody';
|
import { EditorTabBody, EditorToolbarView } from './EditorTabBody';
|
||||||
import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
|
import { DataSourcePicker } from 'app/core/components/Select/DataSourcePicker';
|
||||||
import { QueryInspector } from './QueryInspector';
|
import { QueryInspector } from './QueryInspector';
|
||||||
import { QueryOptions } from './QueryOptions';
|
import { QueryOptions } from './QueryOptions';
|
||||||
import { PanelOptionsGroup, TransformationsEditor } from '@grafana/ui';
|
import {
|
||||||
|
PanelOptionsGroup,
|
||||||
|
TransformationsEditor,
|
||||||
|
DataQuery,
|
||||||
|
DataSourceSelectItem,
|
||||||
|
PanelData,
|
||||||
|
AlphaNotice,
|
||||||
|
PluginState,
|
||||||
|
} from '@grafana/ui';
|
||||||
import { QueryEditorRow } from './QueryEditorRow';
|
import { QueryEditorRow } from './QueryEditorRow';
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||||
import { getBackendSrv } from 'app/core/services/backend_srv';
|
import { getBackendSrv } from 'app/core/services/backend_srv';
|
||||||
import config from 'app/core/config';
|
import config from 'app/core/config';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { PanelModel } from '../state/PanelModel';
|
import { PanelModel } from '../state/PanelModel';
|
||||||
import { DashboardModel } from '../state/DashboardModel';
|
import { DashboardModel } from '../state/DashboardModel';
|
||||||
import { DataQuery, DataSourceSelectItem, PanelData, AlphaNotice, PluginState } from '@grafana/ui';
|
import { LoadingState, DataTransformerConfig, DefaultTimeRange } from '@grafana/data';
|
||||||
import { LoadingState, DataTransformerConfig } from '@grafana/data';
|
|
||||||
import { PluginHelp } from 'app/core/components/PluginHelp/PluginHelp';
|
import { PluginHelp } from 'app/core/components/PluginHelp/PluginHelp';
|
||||||
import { Unsubscribable } from 'rxjs';
|
import { Unsubscribable } from 'rxjs';
|
||||||
import { isSharedDashboardQuery, DashboardQueryEditor } from 'app/plugins/datasource/dashboard';
|
import { isSharedDashboardQuery, DashboardQueryEditor } from 'app/plugins/datasource/dashboard';
|
||||||
@ -55,6 +59,7 @@ export class QueriesTab extends PureComponent<Props, State> {
|
|||||||
data: {
|
data: {
|
||||||
state: LoadingState.NotStarted,
|
state: LoadingState.NotStarted,
|
||||||
series: [],
|
series: [],
|
||||||
|
timeRange: DefaultTimeRange,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { LoadingState, toDataFrame } from '@grafana/data';
|
import { LoadingState, toDataFrame, dateTime } from '@grafana/data';
|
||||||
import { PanelData, DataQueryRequest } from '@grafana/ui';
|
import { PanelData, DataQueryRequest } from '@grafana/ui';
|
||||||
import { filterPanelDataToQuery } from './QueryEditorRow';
|
import { filterPanelDataToQuery } from './QueryEditorRow';
|
||||||
|
|
||||||
@ -28,6 +28,7 @@ describe('filterPanelDataToQuery', () => {
|
|||||||
makePretendRequest('sub2'),
|
makePretendRequest('sub2'),
|
||||||
makePretendRequest('sub3'),
|
makePretendRequest('sub3'),
|
||||||
]),
|
]),
|
||||||
|
timeRange: { from: dateTime(), to: dateTime(), raw: { from: 'now-1d', to: 'now' } },
|
||||||
};
|
};
|
||||||
|
|
||||||
it('should not have an error unless the refId matches', () => {
|
it('should not have an error unless the refId matches', () => {
|
||||||
|
@ -2,13 +2,11 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
// Utils & Services
|
// Utils & Services
|
||||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||||
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
|
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
|
||||||
import { Emitter } from 'app/core/utils/emitter';
|
import { Emitter } from 'app/core/utils/emitter';
|
||||||
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { PanelModel } from '../state/PanelModel';
|
import { PanelModel } from '../state/PanelModel';
|
||||||
import { DataQuery, DataSourceApi, PanelData, DataQueryRequest, ErrorBoundaryAlert } from '@grafana/ui';
|
import { DataQuery, DataSourceApi, PanelData, DataQueryRequest, ErrorBoundaryAlert } from '@grafana/ui';
|
||||||
@ -320,10 +318,13 @@ export function filterPanelDataToQuery(data: PanelData, refId: string): PanelDat
|
|||||||
state = LoadingState.Error;
|
state = LoadingState.Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const timeRange = data.timeRange;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
state,
|
state,
|
||||||
series,
|
series,
|
||||||
request,
|
request,
|
||||||
error,
|
error,
|
||||||
|
timeRange,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,23 @@
|
|||||||
// Libraries
|
// Libraries
|
||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
|
|
||||||
// Utils & Services
|
// Utils & Services
|
||||||
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
|
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
|
||||||
import { connectWithStore } from 'app/core/utils/connectWithReduxStore';
|
import { connectWithStore } from 'app/core/utils/connectWithReduxStore';
|
||||||
import { StoreState } from 'app/types';
|
import { StoreState } from 'app/types';
|
||||||
import { updateLocation } from 'app/core/actions';
|
import { updateLocation } from 'app/core/actions';
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import { EditorTabBody, EditorToolbarView } from './EditorTabBody';
|
import { EditorTabBody, EditorToolbarView } from './EditorTabBody';
|
||||||
import { VizTypePicker } from './VizTypePicker';
|
import { VizTypePicker } from './VizTypePicker';
|
||||||
import { PluginHelp } from 'app/core/components/PluginHelp/PluginHelp';
|
import { PluginHelp } from 'app/core/components/PluginHelp/PluginHelp';
|
||||||
import { FadeIn } from 'app/core/components/Animations/FadeIn';
|
import { FadeIn } from 'app/core/components/Animations/FadeIn';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { PanelModel } from '../state';
|
import { PanelModel, DashboardModel } from '../state';
|
||||||
import { DashboardModel } from '../state';
|
|
||||||
import { VizPickerSearch } from './VizPickerSearch';
|
import { VizPickerSearch } from './VizPickerSearch';
|
||||||
import PluginStateinfo from 'app/features/plugins/PluginStateInfo';
|
import PluginStateinfo from 'app/features/plugins/PluginStateInfo';
|
||||||
import { PanelPlugin, PanelPluginMeta, PanelData } from '@grafana/ui';
|
import { PanelPlugin, PanelPluginMeta, PanelData } from '@grafana/ui';
|
||||||
import { PanelCtrl } from 'app/plugins/sdk';
|
import { PanelCtrl } from 'app/plugins/sdk';
|
||||||
import { Unsubscribable } from 'rxjs';
|
import { Unsubscribable } from 'rxjs';
|
||||||
import { LoadingState } from '@grafana/data';
|
import { LoadingState, DefaultTimeRange } from '@grafana/data';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
panel: PanelModel;
|
panel: PanelModel;
|
||||||
@ -57,6 +53,7 @@ export class VisualizationTab extends PureComponent<Props, State> {
|
|||||||
data: {
|
data: {
|
||||||
state: LoadingState.NotStarted,
|
state: LoadingState.NotStarted,
|
||||||
series: [],
|
series: [],
|
||||||
|
timeRange: DefaultTimeRange,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,22 @@
|
|||||||
// Libraries
|
// Libraries
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import kbn from 'app/core/utils/kbn';
|
import kbn from 'app/core/utils/kbn';
|
||||||
import coreModule from 'app/core/core_module';
|
import coreModule from 'app/core/core_module';
|
||||||
import { dateMath } from '@grafana/data';
|
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { TimeRange, RawTimeRange, TimeZone } from '@grafana/data';
|
import {
|
||||||
|
dateMath,
|
||||||
|
DefaultTimeRange,
|
||||||
|
TimeRange,
|
||||||
|
RawTimeRange,
|
||||||
|
TimeZone,
|
||||||
|
toUtc,
|
||||||
|
dateTime,
|
||||||
|
isDateTime,
|
||||||
|
} from '@grafana/data';
|
||||||
import { ITimeoutService, ILocationService } from 'angular';
|
import { ITimeoutService, ILocationService } from 'angular';
|
||||||
import { ContextSrv } from 'app/core/services/context_srv';
|
import { ContextSrv } from 'app/core/services/context_srv';
|
||||||
import { DashboardModel } from '../state/DashboardModel';
|
import { DashboardModel } from '../state/DashboardModel';
|
||||||
import { toUtc, dateTime, isDateTime } from '@grafana/data';
|
|
||||||
import { getZoomedTimeRange, getShiftedTimeRange } from 'app/core/utils/timePicker';
|
import { getZoomedTimeRange, getShiftedTimeRange } from 'app/core/utils/timePicker';
|
||||||
|
|
||||||
export class TimeSrv {
|
export class TimeSrv {
|
||||||
@ -32,7 +37,7 @@ export class TimeSrv {
|
|||||||
private contextSrv: ContextSrv
|
private contextSrv: ContextSrv
|
||||||
) {
|
) {
|
||||||
// default time
|
// default time
|
||||||
this.time = { from: '6h', to: 'now' };
|
this.time = DefaultTimeRange.raw;
|
||||||
|
|
||||||
$rootScope.$on('zoom-out', this.zoomOut.bind(this));
|
$rootScope.$on('zoom-out', this.zoomOut.bind(this));
|
||||||
$rootScope.$on('shift-time', this.shiftTime.bind(this));
|
$rootScope.$on('shift-time', this.shiftTime.bind(this));
|
||||||
|
@ -2,6 +2,7 @@ import { DataFrame, LoadingState, dateTime } from '@grafana/data';
|
|||||||
import { PanelData, DataSourceApi, DataQueryRequest, DataQueryResponse } from '@grafana/ui';
|
import { PanelData, DataSourceApi, DataQueryRequest, DataQueryResponse } from '@grafana/ui';
|
||||||
import { Subscriber, Observable, Subscription } from 'rxjs';
|
import { Subscriber, Observable, Subscription } from 'rxjs';
|
||||||
import { runRequest } from './runRequest';
|
import { runRequest } from './runRequest';
|
||||||
|
import { deepFreeze } from '../../../../test/core/redux/reducerTester';
|
||||||
|
|
||||||
jest.mock('app/core/services/backend_srv');
|
jest.mock('app/core/services/backend_srv');
|
||||||
|
|
||||||
@ -186,19 +187,56 @@ describe('runRequest', () => {
|
|||||||
|
|
||||||
runRequestScenario('If time range is relative', ctx => {
|
runRequestScenario('If time range is relative', ctx => {
|
||||||
ctx.setup(async () => {
|
ctx.setup(async () => {
|
||||||
|
// any changes to ctx.request.range will throw and state would become LoadingState.Error
|
||||||
|
deepFreeze(ctx.request.range);
|
||||||
ctx.start();
|
ctx.start();
|
||||||
|
|
||||||
// wait a bit
|
// wait a bit
|
||||||
await sleep(20);
|
await sleep(20);
|
||||||
|
|
||||||
ctx.emitPacket({ data: [{ name: 'DataB-1' } as DataFrame] });
|
ctx.emitPacket({ data: [{ name: 'DataB-1' } as DataFrame] });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update returned request range', () => {
|
it('should add the correct timeRange property and the request range should not be mutated', () => {
|
||||||
expect(ctx.results[0].request.range.to.valueOf()).not.toBe(ctx.fromStartTime);
|
expect(ctx.results[0].timeRange.to.valueOf()).toBeDefined();
|
||||||
|
expect(ctx.results[0].timeRange.to.valueOf()).not.toBe(ctx.toStartTime.valueOf());
|
||||||
|
expect(ctx.results[0].timeRange.to.valueOf()).not.toBe(ctx.results[0].request.range.to.valueOf());
|
||||||
|
|
||||||
|
expectThatRangeHasNotMutated(ctx);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
runRequestScenario('If time range is not relative', ctx => {
|
||||||
|
ctx.setup(async () => {
|
||||||
|
ctx.request.range.raw.from = ctx.fromStartTime;
|
||||||
|
ctx.request.range.raw.to = ctx.toStartTime;
|
||||||
|
// any changes to ctx.request.range will throw and state would become LoadingState.Error
|
||||||
|
deepFreeze(ctx.request.range);
|
||||||
|
ctx.start();
|
||||||
|
|
||||||
|
// wait a bit
|
||||||
|
await sleep(20);
|
||||||
|
|
||||||
|
ctx.emitPacket({ data: [{ name: 'DataB-1' } as DataFrame] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add the correct timeRange property and the request range should not be mutated', () => {
|
||||||
|
expect(ctx.results[0].timeRange).toBeDefined();
|
||||||
|
expect(ctx.results[0].timeRange.to.valueOf()).toBe(ctx.toStartTime.valueOf());
|
||||||
|
expect(ctx.results[0].timeRange.to.valueOf()).toBe(ctx.results[0].request.range.to.valueOf());
|
||||||
|
|
||||||
|
expectThatRangeHasNotMutated(ctx);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const expectThatRangeHasNotMutated = (ctx: ScenarioCtx) => {
|
||||||
|
// Make sure that the range for request is not changed and that deepfreeze hasn't thrown
|
||||||
|
expect(ctx.results[0].request.range.to.valueOf()).toBe(ctx.toStartTime.valueOf());
|
||||||
|
expect(ctx.results[0].error).not.toBeDefined();
|
||||||
|
expect(ctx.results[0].state).toBe(LoadingState.Done);
|
||||||
|
};
|
||||||
|
|
||||||
async function sleep(ms: number) {
|
async function sleep(ms: number) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
setTimeout(resolve, ms);
|
setTimeout(resolve, ms);
|
||||||
|
@ -34,14 +34,14 @@ export function processResponsePacket(packet: DataQueryResponse, state: RunningQ
|
|||||||
packets[packet.key || 'A'] = packet;
|
packets[packet.key || 'A'] = packet;
|
||||||
|
|
||||||
// Update the time range
|
// Update the time range
|
||||||
let timeRange = request.range;
|
const range = { ...request.range };
|
||||||
if (isString(timeRange.raw.from)) {
|
const timeRange = isString(range.raw.from)
|
||||||
timeRange = {
|
? {
|
||||||
from: dateMath.parse(timeRange.raw.from, false),
|
from: dateMath.parse(range.raw.from, false),
|
||||||
to: dateMath.parse(timeRange.raw.to, true),
|
to: dateMath.parse(range.raw.to, true),
|
||||||
raw: timeRange.raw,
|
raw: range.raw,
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
: range;
|
||||||
|
|
||||||
const combinedData = flatten(
|
const combinedData = flatten(
|
||||||
lodashMap(packets, (packet: DataQueryResponse) => {
|
lodashMap(packets, (packet: DataQueryResponse) => {
|
||||||
@ -52,10 +52,8 @@ export function processResponsePacket(packet: DataQueryResponse, state: RunningQ
|
|||||||
const panelData = {
|
const panelData = {
|
||||||
state: packet.state || LoadingState.Done,
|
state: packet.state || LoadingState.Done,
|
||||||
series: combinedData,
|
series: combinedData,
|
||||||
request: {
|
request,
|
||||||
...request,
|
timeRange,
|
||||||
range: timeRange,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return { packets, panelData };
|
return { packets, panelData };
|
||||||
@ -75,6 +73,7 @@ export function runRequest(datasource: DataSourceApi, request: DataQueryRequest)
|
|||||||
state: LoadingState.Loading,
|
state: LoadingState.Loading,
|
||||||
series: [],
|
series: [],
|
||||||
request: request,
|
request: request,
|
||||||
|
timeRange: request.range,
|
||||||
},
|
},
|
||||||
packets: {},
|
packets: {},
|
||||||
};
|
};
|
||||||
@ -96,6 +95,7 @@ export function runRequest(datasource: DataSourceApi, request: DataQueryRequest)
|
|||||||
request.endTime = Date.now();
|
request.endTime = Date.now();
|
||||||
|
|
||||||
state = processResponsePacket(packet, state);
|
state = processResponsePacket(packet, state);
|
||||||
|
|
||||||
return state.panelData;
|
return state.panelData;
|
||||||
}),
|
}),
|
||||||
// handle errors
|
// handle errors
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
|
|
||||||
import { LoadingState } from '@grafana/data';
|
import { LoadingState, TimeRange } from '@grafana/data';
|
||||||
import { PanelData } from '@grafana/ui';
|
import { PanelData } from '@grafana/ui';
|
||||||
|
|
||||||
import QueryStatus from './QueryStatus';
|
import QueryStatus from './QueryStatus';
|
||||||
|
|
||||||
describe('<QueryStatus />', () => {
|
describe('<QueryStatus />', () => {
|
||||||
it('should render with a latency', () => {
|
it('should render with a latency', () => {
|
||||||
const res: PanelData = { series: [], state: LoadingState.Done };
|
const res: PanelData = { series: [], state: LoadingState.Done, timeRange: {} as TimeRange };
|
||||||
const wrapper = shallow(<QueryStatus latency={0} queryResponse={res} />);
|
const wrapper = shallow(<QueryStatus latency={0} queryResponse={res} />);
|
||||||
expect(wrapper.find('div').exists()).toBeTruthy();
|
expect(wrapper.find('div').exists()).toBeTruthy();
|
||||||
});
|
});
|
||||||
it('should not render when query has not started', () => {
|
it('should not render when query has not started', () => {
|
||||||
const res: PanelData = { series: [], state: LoadingState.NotStarted };
|
const res: PanelData = { series: [], state: LoadingState.NotStarted, timeRange: {} as TimeRange };
|
||||||
const wrapper = shallow(<QueryStatus latency={0} queryResponse={res} />);
|
const wrapper = shallow(<QueryStatus latency={0} queryResponse={res} />);
|
||||||
expect(wrapper.getElement()).toBe(null);
|
expect(wrapper.getElement()).toBe(null);
|
||||||
});
|
});
|
||||||
|
@ -42,7 +42,7 @@ describe('Explore item reducer', () => {
|
|||||||
.givenReducer(itemReducer as Reducer<ExploreItemState, ActionOf<any>>, initalState)
|
.givenReducer(itemReducer as Reducer<ExploreItemState, ActionOf<any>>, initalState)
|
||||||
.whenActionIsDispatched(scanStartAction({ exploreId: ExploreId.left }))
|
.whenActionIsDispatched(scanStartAction({ exploreId: ExploreId.left }))
|
||||||
.thenStateShouldEqual({
|
.thenStateShouldEqual({
|
||||||
...makeExploreItemState(),
|
...initalState,
|
||||||
scanning: true,
|
scanning: true,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -57,7 +57,7 @@ describe('Explore item reducer', () => {
|
|||||||
.givenReducer(itemReducer as Reducer<ExploreItemState, ActionOf<any>>, initalState)
|
.givenReducer(itemReducer as Reducer<ExploreItemState, ActionOf<any>>, initalState)
|
||||||
.whenActionIsDispatched(scanStopAction({ exploreId: ExploreId.left }))
|
.whenActionIsDispatched(scanStopAction({ exploreId: ExploreId.left }))
|
||||||
.thenStateShouldEqual({
|
.thenStateShouldEqual({
|
||||||
...makeExploreItemState(),
|
...initalState,
|
||||||
scanning: false,
|
scanning: false,
|
||||||
scanRange: undefined,
|
scanRange: undefined,
|
||||||
});
|
});
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
refreshIntervalToSortOrder,
|
refreshIntervalToSortOrder,
|
||||||
} from 'app/core/utils/explore';
|
} from 'app/core/utils/explore';
|
||||||
import { ExploreItemState, ExploreState, ExploreId, ExploreUpdateState, ExploreMode } from 'app/types/explore';
|
import { ExploreItemState, ExploreState, ExploreId, ExploreUpdateState, ExploreMode } from 'app/types/explore';
|
||||||
import { LoadingState, toLegacyResponseData } from '@grafana/data';
|
import { LoadingState, toLegacyResponseData, DefaultTimeRange } from '@grafana/data';
|
||||||
import { DataQuery, DataSourceApi, PanelData, DataQueryRequest } from '@grafana/ui';
|
import { DataQuery, DataSourceApi, PanelData, DataQueryRequest } from '@grafana/ui';
|
||||||
import {
|
import {
|
||||||
HigherOrderAction,
|
HigherOrderAction,
|
||||||
@ -121,6 +121,7 @@ export const createEmptyQueryResponse = (): PanelData => ({
|
|||||||
request: {} as DataQueryRequest<DataQuery>,
|
request: {} as DataQueryRequest<DataQuery>,
|
||||||
series: [],
|
series: [],
|
||||||
error: null,
|
error: null,
|
||||||
|
timeRange: DefaultTimeRange,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -131,15 +131,16 @@ class MetricsPanelCtrl extends PanelCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (data.request) {
|
if (data.request) {
|
||||||
const { range, timeInfo } = data.request;
|
const { timeInfo } = data.request;
|
||||||
if (range) {
|
|
||||||
this.range = range;
|
|
||||||
}
|
|
||||||
if (timeInfo) {
|
if (timeInfo) {
|
||||||
this.timeInfo = timeInfo;
|
this.timeInfo = timeInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.timeRange) {
|
||||||
|
this.range = data.timeRange;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.useDataFrames) {
|
if (this.useDataFrames) {
|
||||||
this.handleDataFrames(data.series);
|
this.handleDataFrames(data.series);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { DataQuery, PanelData, DataSourceApi } from '@grafana/ui';
|
import { DataQuery, PanelData, DataSourceApi } from '@grafana/ui';
|
||||||
import { QueryRunnerOptions } from 'app/features/dashboard/state/PanelQueryRunner';
|
import { QueryRunnerOptions } from 'app/features/dashboard/state/PanelQueryRunner';
|
||||||
import { DashboardQuery } from './types';
|
import { DashboardQuery, SHARED_DASHBODARD_QUERY } from './types';
|
||||||
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv';
|
||||||
import { LoadingState } from '@grafana/data';
|
import { LoadingState, DefaultTimeRange } from '@grafana/data';
|
||||||
import { SHARED_DASHBODARD_QUERY } from './types';
|
|
||||||
|
|
||||||
export function isSharedDashboardQuery(datasource: string | DataSourceApi) {
|
export function isSharedDashboardQuery(datasource: string | DataSourceApi) {
|
||||||
if (!datasource) {
|
if (!datasource) {
|
||||||
@ -76,5 +75,6 @@ function getQueryError(msg: string): PanelData {
|
|||||||
state: LoadingState.Error,
|
state: LoadingState.Error,
|
||||||
series: [],
|
series: [],
|
||||||
error: { message: msg },
|
error: { message: msg },
|
||||||
|
timeRange: DefaultTimeRange,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ interface ObjectType extends Object {
|
|||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
const deepFreeze = <T>(obj: T): T => {
|
export const deepFreeze = <T>(obj: T): T => {
|
||||||
Object.freeze(obj);
|
Object.freeze(obj);
|
||||||
|
|
||||||
const isNotException = (object: any, propertyName: any) =>
|
const isNotException = (object: any, propertyName: any) =>
|
||||||
|
Loading…
Reference in New Issue
Block a user