mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Explore: Add t * keybindings to change time range (#45020)
* Add keybindings to explore, allow override of dashboard model update for explore update * Remove edits to Dashboard Model, add definition when url params should be updated * Add tests * Add and expose util function instead of bringing in unrelated library do not define explicit path to library file * Use more generic model for TimeSrv * Remove url utility functions, use javascript function instead * Break out TimeModel into new type and bring it in * condense object creation
This commit is contained in:
parent
af1691dbfb
commit
773da0e330
@ -19,6 +19,28 @@ e2e.scenario({
|
|||||||
|
|
||||||
cy.contains('CSV Metric Values').scrollIntoView().should('be.visible').click();
|
cy.contains('CSV Metric Values').scrollIntoView().should('be.visible').click();
|
||||||
|
|
||||||
|
cy.location().then((loc) => {
|
||||||
|
const params = new URLSearchParams(loc.search);
|
||||||
|
const leftJSON = JSON.parse(params.get('left'));
|
||||||
|
expect(leftJSON.range.to).to.equal('now');
|
||||||
|
expect(leftJSON.range.from).to.equal('now-1h');
|
||||||
|
|
||||||
|
cy.get('body').click();
|
||||||
|
cy.get('body').type('t{leftarrow}');
|
||||||
|
|
||||||
|
cy.location().then((locPostKeypress) => {
|
||||||
|
const params = new URLSearchParams(locPostKeypress.search);
|
||||||
|
const leftJSON = JSON.parse(params.get('left'));
|
||||||
|
// be sure the keypress affected the time window
|
||||||
|
expect(leftJSON.range.to).to.not.equal('now');
|
||||||
|
expect(leftJSON.range.from).to.not.equal('now-1h');
|
||||||
|
// be sure the url does not contain dashboard range values
|
||||||
|
// eslint wants this to be a function, so we use this instead of to.be.false
|
||||||
|
expect(params.has('to')).to.equal(false);
|
||||||
|
expect(params.has('from')).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const canvases = e2e().get('canvas');
|
const canvases = e2e().get('canvas');
|
||||||
canvases.should('have.length', 1);
|
canvases.should('have.length', 1);
|
||||||
},
|
},
|
||||||
|
@ -11,7 +11,7 @@ import { exitKioskMode, toggleKioskMode } from '../navigation/kiosk';
|
|||||||
import {
|
import {
|
||||||
RemovePanelEvent,
|
RemovePanelEvent,
|
||||||
ShiftTimeEvent,
|
ShiftTimeEvent,
|
||||||
ShiftTimeEventPayload,
|
ShiftTimeEventDirection,
|
||||||
ShowModalReactEvent,
|
ShowModalReactEvent,
|
||||||
ZoomOutEvent,
|
ZoomOutEvent,
|
||||||
AbsoluteTimeEvent,
|
AbsoluteTimeEvent,
|
||||||
@ -171,6 +171,24 @@ export class KeybindingSrv {
|
|||||||
this.bind(keyArg, withFocusedPanel(fn));
|
this.bind(keyArg, withFocusedPanel(fn));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupTimeRangeBindings(updateUrl = true) {
|
||||||
|
this.bind('t z', () => {
|
||||||
|
appEvents.publish(new ZoomOutEvent({ scale: 2, updateUrl }));
|
||||||
|
});
|
||||||
|
|
||||||
|
this.bind('ctrl+z', () => {
|
||||||
|
appEvents.publish(new ZoomOutEvent({ scale: 2, updateUrl }));
|
||||||
|
});
|
||||||
|
|
||||||
|
this.bind('t left', () => {
|
||||||
|
appEvents.publish(new ShiftTimeEvent({ direction: ShiftTimeEventDirection.Left, updateUrl }));
|
||||||
|
});
|
||||||
|
|
||||||
|
this.bind('t right', () => {
|
||||||
|
appEvents.publish(new ShiftTimeEvent({ direction: ShiftTimeEventDirection.Right, updateUrl }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setupDashboardBindings(dashboard: DashboardModel) {
|
setupDashboardBindings(dashboard: DashboardModel) {
|
||||||
this.bind('mod+o', () => {
|
this.bind('mod+o', () => {
|
||||||
dashboard.graphTooltip = (dashboard.graphTooltip + 1) % 3;
|
dashboard.graphTooltip = (dashboard.graphTooltip + 1) % 3;
|
||||||
@ -191,21 +209,7 @@ export class KeybindingSrv {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.bind('t z', () => {
|
this.setupTimeRangeBindings();
|
||||||
appEvents.publish(new ZoomOutEvent(2));
|
|
||||||
});
|
|
||||||
|
|
||||||
this.bind('ctrl+z', () => {
|
|
||||||
appEvents.publish(new ZoomOutEvent(2));
|
|
||||||
});
|
|
||||||
|
|
||||||
this.bind('t left', () => {
|
|
||||||
appEvents.publish(new ShiftTimeEvent(ShiftTimeEventPayload.Left));
|
|
||||||
});
|
|
||||||
|
|
||||||
this.bind('t right', () => {
|
|
||||||
appEvents.publish(new ShiftTimeEvent(ShiftTimeEventPayload.Right));
|
|
||||||
});
|
|
||||||
|
|
||||||
// edit panel
|
// edit panel
|
||||||
this.bindWithPanelId('e', (panelId) => {
|
this.bindWithPanelId('e', (panelId) => {
|
||||||
|
@ -13,7 +13,7 @@ import { TimePickerWithHistory } from 'app/core/components/TimePicker/TimePicker
|
|||||||
// Utils & Services
|
// Utils & Services
|
||||||
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
import { getTimeSrv } from 'app/features/dashboard/services/TimeSrv';
|
||||||
import { appEvents } from 'app/core/core';
|
import { appEvents } from 'app/core/core';
|
||||||
import { ShiftTimeEvent, ShiftTimeEventPayload, ZoomOutEvent } from '../../../../types/events';
|
import { ShiftTimeEvent, ShiftTimeEventDirection, ZoomOutEvent } from '../../../../types/events';
|
||||||
import { Unsubscribable } from 'rxjs';
|
import { Unsubscribable } from 'rxjs';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
@ -38,16 +38,16 @@ export class DashNavTimeControls extends Component<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onRefresh = () => {
|
onRefresh = () => {
|
||||||
getTimeSrv().refreshDashboard();
|
getTimeSrv().refreshTimeModel();
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
};
|
};
|
||||||
|
|
||||||
onMoveBack = () => {
|
onMoveBack = () => {
|
||||||
appEvents.publish(new ShiftTimeEvent(ShiftTimeEventPayload.Left));
|
appEvents.publish(new ShiftTimeEvent({ direction: ShiftTimeEventDirection.Left }));
|
||||||
};
|
};
|
||||||
|
|
||||||
onMoveForward = () => {
|
onMoveForward = () => {
|
||||||
appEvents.publish(new ShiftTimeEvent(ShiftTimeEventPayload.Right));
|
appEvents.publish(new ShiftTimeEvent({ direction: ShiftTimeEventDirection.Right }));
|
||||||
};
|
};
|
||||||
|
|
||||||
onChangeTimePicker = (timeRange: TimeRange) => {
|
onChangeTimePicker = (timeRange: TimeRange) => {
|
||||||
@ -77,7 +77,7 @@ export class DashNavTimeControls extends Component<Props> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onZoom = () => {
|
onZoom = () => {
|
||||||
appEvents.publish(new ZoomOutEvent(2));
|
appEvents.publish(new ZoomOutEvent({ scale: 2 }));
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -244,6 +244,11 @@ describe('timeSrv', () => {
|
|||||||
|
|
||||||
expect(locationUpdates[1].search).toEqual('?kiosk&from=now-1h&to=now-10s');
|
expect(locationUpdates[1].search).toEqual('?kiosk&from=now-1h&to=now-10s');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not change the URL if the updateUrl param is false', () => {
|
||||||
|
timeSrv.setTime({ from: '1644340584281', to: '1644340584281' }, false);
|
||||||
|
expect(locationUpdates.length).toBe(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('pauseAutoRefresh', () => {
|
describe('pauseAutoRefresh', () => {
|
||||||
|
@ -9,14 +9,14 @@ import {
|
|||||||
TimeRange,
|
TimeRange,
|
||||||
toUtc,
|
toUtc,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { DashboardModel } from '../state/DashboardModel';
|
|
||||||
import { getShiftedTimeRange, getZoomedTimeRange } from 'app/core/utils/timePicker';
|
import { getShiftedTimeRange, getZoomedTimeRange } from 'app/core/utils/timePicker';
|
||||||
import { config } from 'app/core/config';
|
import { config } from 'app/core/config';
|
||||||
import { getRefreshFromUrl } from '../utils/getRefreshFromUrl';
|
import { getRefreshFromUrl } from '../utils/getRefreshFromUrl';
|
||||||
import { locationService } from '@grafana/runtime';
|
import { locationService } from '@grafana/runtime';
|
||||||
import { AbsoluteTimeEvent, ShiftTimeEvent, ShiftTimeEventPayload, ZoomOutEvent } from '../../../types/events';
|
import { AbsoluteTimeEvent, ShiftTimeEvent, ShiftTimeEventDirection, ZoomOutEvent } from '../../../types/events';
|
||||||
import { contextSrv, ContextSrv } from 'app/core/services/context_srv';
|
import { contextSrv, ContextSrv } from 'app/core/services/context_srv';
|
||||||
import appEvents from 'app/core/app_events';
|
import appEvents from 'app/core/app_events';
|
||||||
|
import { TimeModel } from '../state/TimeModel';
|
||||||
|
|
||||||
export class TimeSrv {
|
export class TimeSrv {
|
||||||
time: any;
|
time: any;
|
||||||
@ -24,21 +24,21 @@ export class TimeSrv {
|
|||||||
refresh: any;
|
refresh: any;
|
||||||
previousAutoRefresh: any;
|
previousAutoRefresh: any;
|
||||||
oldRefresh: string | null | undefined;
|
oldRefresh: string | null | undefined;
|
||||||
dashboard?: DashboardModel;
|
timeModel?: TimeModel;
|
||||||
timeAtLoad: any;
|
timeAtLoad: any;
|
||||||
private autoRefreshBlocked?: boolean;
|
private autoRefreshBlocked?: boolean;
|
||||||
|
|
||||||
constructor(private contextSrv: ContextSrv) {
|
constructor(private contextSrv: ContextSrv) {
|
||||||
// default time
|
// default time
|
||||||
this.time = getDefaultTimeRange().raw;
|
this.time = getDefaultTimeRange().raw;
|
||||||
this.refreshDashboard = this.refreshDashboard.bind(this);
|
this.refreshTimeModel = this.refreshTimeModel.bind(this);
|
||||||
|
|
||||||
appEvents.subscribe(ZoomOutEvent, (e) => {
|
appEvents.subscribe(ZoomOutEvent, (e) => {
|
||||||
this.zoomOut(e.payload);
|
this.zoomOut(e.payload.scale, e.payload.updateUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
appEvents.subscribe(ShiftTimeEvent, (e) => {
|
appEvents.subscribe(ShiftTimeEvent, (e) => {
|
||||||
this.shiftTime(e.payload);
|
this.shiftTime(e.payload.direction, e.payload.updateUrl);
|
||||||
});
|
});
|
||||||
|
|
||||||
appEvents.subscribe(AbsoluteTimeEvent, () => {
|
appEvents.subscribe(AbsoluteTimeEvent, () => {
|
||||||
@ -48,15 +48,15 @@ export class TimeSrv {
|
|||||||
document.addEventListener('visibilitychange', () => {
|
document.addEventListener('visibilitychange', () => {
|
||||||
if (this.autoRefreshBlocked && document.visibilityState === 'visible') {
|
if (this.autoRefreshBlocked && document.visibilityState === 'visible') {
|
||||||
this.autoRefreshBlocked = false;
|
this.autoRefreshBlocked = false;
|
||||||
this.refreshDashboard();
|
this.refreshTimeModel();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
init(dashboard: DashboardModel) {
|
init(timeModel: TimeModel) {
|
||||||
this.dashboard = dashboard;
|
this.timeModel = timeModel;
|
||||||
this.time = dashboard.time;
|
this.time = timeModel.time;
|
||||||
this.refresh = dashboard.refresh;
|
this.refresh = timeModel.refresh;
|
||||||
|
|
||||||
this.initTimeFromUrl();
|
this.initTimeFromUrl();
|
||||||
this.parseTime();
|
this.parseTime();
|
||||||
@ -66,8 +66,8 @@ export class TimeSrv {
|
|||||||
|
|
||||||
const range = rangeUtil.convertRawToRange(
|
const range = rangeUtil.convertRawToRange(
|
||||||
this.time,
|
this.time,
|
||||||
this.dashboard?.getTimezone(),
|
this.timeModel?.getTimezone(),
|
||||||
this.dashboard?.fiscalYearStartMonth
|
this.timeModel?.fiscalYearStartMonth
|
||||||
);
|
);
|
||||||
|
|
||||||
if (range.to.isBefore(range.from)) {
|
if (range.to.isBefore(range.from)) {
|
||||||
@ -159,11 +159,11 @@ export class TimeSrv {
|
|||||||
this.time.to = this.parseUrlParam(params.get('to')!) || this.time.to;
|
this.time.to = this.parseUrlParam(params.get('to')!) || this.time.to;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if absolute ignore refresh option saved to dashboard
|
// if absolute ignore refresh option saved to timeModel
|
||||||
if (params.get('to') && params.get('to')!.indexOf('now') === -1) {
|
if (params.get('to') && params.get('to')!.indexOf('now') === -1) {
|
||||||
this.refresh = false;
|
this.refresh = false;
|
||||||
if (this.dashboard) {
|
if (this.timeModel) {
|
||||||
this.dashboard.refresh = false;
|
this.timeModel.refresh = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,8 +176,8 @@ export class TimeSrv {
|
|||||||
this.refresh = getRefreshFromUrl({
|
this.refresh = getRefreshFromUrl({
|
||||||
params: paramsJSON,
|
params: paramsJSON,
|
||||||
currentRefresh: this.refresh,
|
currentRefresh: this.refresh,
|
||||||
refreshIntervals: Array.isArray(this.dashboard?.timepicker?.refresh_intervals)
|
refreshIntervals: Array.isArray(this.timeModel?.timepicker?.refresh_intervals)
|
||||||
? this.dashboard?.timepicker?.refresh_intervals
|
? this.timeModel?.timepicker?.refresh_intervals
|
||||||
: undefined,
|
: undefined,
|
||||||
isAllowedIntervalFn: this.contextSrv.isAllowedInterval,
|
isAllowedIntervalFn: this.contextSrv.isAllowedInterval,
|
||||||
minRefreshInterval: config.minRefreshInterval,
|
minRefreshInterval: config.minRefreshInterval,
|
||||||
@ -213,8 +213,8 @@ export class TimeSrv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setAutoRefresh(interval: any) {
|
setAutoRefresh(interval: any) {
|
||||||
if (this.dashboard) {
|
if (this.timeModel) {
|
||||||
this.dashboard.refresh = interval;
|
this.timeModel.refresh = interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.stopAutoRefresh();
|
this.stopAutoRefresh();
|
||||||
@ -235,7 +235,7 @@ export class TimeSrv {
|
|||||||
|
|
||||||
this.refreshTimer = setTimeout(() => {
|
this.refreshTimer = setTimeout(() => {
|
||||||
this.startNextRefreshTimer(intervalMs);
|
this.startNextRefreshTimer(intervalMs);
|
||||||
this.refreshDashboard();
|
this.refreshTimeModel();
|
||||||
}, intervalMs);
|
}, intervalMs);
|
||||||
|
|
||||||
const refresh = this.contextSrv.getValidInterval(interval);
|
const refresh = this.contextSrv.getValidInterval(interval);
|
||||||
@ -245,15 +245,15 @@ export class TimeSrv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshDashboard() {
|
refreshTimeModel() {
|
||||||
this.dashboard?.timeRangeUpdated(this.timeRange());
|
this.timeModel?.timeRangeUpdated(this.timeRange());
|
||||||
}
|
}
|
||||||
|
|
||||||
private startNextRefreshTimer(afterMs: number) {
|
private startNextRefreshTimer(afterMs: number) {
|
||||||
this.refreshTimer = setTimeout(() => {
|
this.refreshTimer = setTimeout(() => {
|
||||||
this.startNextRefreshTimer(afterMs);
|
this.startNextRefreshTimer(afterMs);
|
||||||
if (this.contextSrv.isGrafanaVisible()) {
|
if (this.contextSrv.isGrafanaVisible()) {
|
||||||
this.refreshDashboard();
|
this.refreshTimeModel();
|
||||||
} else {
|
} else {
|
||||||
this.autoRefreshBlocked = true;
|
this.autoRefreshBlocked = true;
|
||||||
}
|
}
|
||||||
@ -264,10 +264,10 @@ export class TimeSrv {
|
|||||||
clearTimeout(this.refreshTimer);
|
clearTimeout(this.refreshTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// store dashboard refresh value and pause auto-refresh in some places
|
// store timeModel refresh value and pause auto-refresh in some places
|
||||||
// i.e panel edit
|
// i.e panel edit
|
||||||
pauseAutoRefresh() {
|
pauseAutoRefresh() {
|
||||||
this.previousAutoRefresh = this.dashboard?.refresh;
|
this.previousAutoRefresh = this.timeModel?.refresh;
|
||||||
this.setAutoRefresh('');
|
this.setAutoRefresh('');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,20 +276,19 @@ export class TimeSrv {
|
|||||||
this.setAutoRefresh(this.previousAutoRefresh);
|
this.setAutoRefresh(this.previousAutoRefresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTime(time: RawTimeRange, fromRouteUpdate?: boolean) {
|
setTime(time: RawTimeRange, updateUrl = true) {
|
||||||
extend(this.time, time);
|
extend(this.time, time);
|
||||||
|
|
||||||
// disable refresh if zoom in or zoom out
|
// disable refresh if zoom in or zoom out
|
||||||
if (isDateTime(time.to)) {
|
if (isDateTime(time.to)) {
|
||||||
this.oldRefresh = this.dashboard?.refresh || this.oldRefresh;
|
this.oldRefresh = this.timeModel?.refresh || this.oldRefresh;
|
||||||
this.setAutoRefresh(false);
|
this.setAutoRefresh(false);
|
||||||
} else if (this.oldRefresh && this.oldRefresh !== this.dashboard?.refresh) {
|
} else if (this.oldRefresh && this.oldRefresh !== this.timeModel?.refresh) {
|
||||||
this.setAutoRefresh(this.oldRefresh);
|
this.setAutoRefresh(this.oldRefresh);
|
||||||
this.oldRefresh = null;
|
this.oldRefresh = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update url
|
if (updateUrl === true) {
|
||||||
if (fromRouteUpdate !== true) {
|
|
||||||
const urlRange = this.timeRangeForUrl();
|
const urlRange = this.timeRangeForUrl();
|
||||||
const urlParams = locationService.getSearchObject();
|
const urlParams = locationService.getSearchObject();
|
||||||
|
|
||||||
@ -303,7 +302,7 @@ export class TimeSrv {
|
|||||||
locationService.partial(urlParams);
|
locationService.partial(urlParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.refreshDashboard();
|
this.refreshTimeModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
timeRangeForUrl = () => {
|
timeRangeForUrl = () => {
|
||||||
@ -326,30 +325,33 @@ export class TimeSrv {
|
|||||||
to: isDateTime(this.time.to) ? dateTime(this.time.to) : this.time.to,
|
to: isDateTime(this.time.to) ? dateTime(this.time.to) : this.time.to,
|
||||||
};
|
};
|
||||||
|
|
||||||
const timezone = this.dashboard ? this.dashboard.getTimezone() : undefined;
|
const timezone = this.timeModel ? this.timeModel.getTimezone() : undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
from: dateMath.parse(raw.from, false, timezone, this.dashboard?.fiscalYearStartMonth)!,
|
from: dateMath.parse(raw.from, false, timezone, this.timeModel?.fiscalYearStartMonth)!,
|
||||||
to: dateMath.parse(raw.to, true, timezone, this.dashboard?.fiscalYearStartMonth)!,
|
to: dateMath.parse(raw.to, true, timezone, this.timeModel?.fiscalYearStartMonth)!,
|
||||||
raw: raw,
|
raw: raw,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
zoomOut(factor: number) {
|
zoomOut(factor: number, updateUrl = true) {
|
||||||
const range = this.timeRange();
|
const range = this.timeRange();
|
||||||
const { from, to } = getZoomedTimeRange(range, factor);
|
const { from, to } = getZoomedTimeRange(range, factor);
|
||||||
|
|
||||||
this.setTime({ from: toUtc(from), to: toUtc(to) });
|
this.setTime({ from: toUtc(from), to: toUtc(to) }, updateUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
shiftTime(direction: ShiftTimeEventPayload) {
|
shiftTime(direction: ShiftTimeEventDirection, updateUrl = true) {
|
||||||
const range = this.timeRange();
|
const range = this.timeRange();
|
||||||
const { from, to } = getShiftedTimeRange(direction, range);
|
const { from, to } = getShiftedTimeRange(direction, range);
|
||||||
|
|
||||||
this.setTime({
|
this.setTime(
|
||||||
from: toUtc(from),
|
{
|
||||||
to: toUtc(to),
|
from: toUtc(from),
|
||||||
});
|
to: toUtc(to),
|
||||||
|
},
|
||||||
|
updateUrl
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
makeAbsoluteTime() {
|
makeAbsoluteTime() {
|
||||||
@ -359,7 +361,7 @@ export class TimeSrv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { from, to } = this.timeRange();
|
const { from, to } = this.timeRange();
|
||||||
this.setTime({ from, to });
|
this.setTime({ from, to }, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// isRefreshOutsideThreshold function calculates the difference between last refresh and now
|
// isRefreshOutsideThreshold function calculates the difference between last refresh and now
|
||||||
|
@ -20,6 +20,7 @@ import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT, REPEAT_DIR_VERT
|
|||||||
import { contextSrv } from 'app/core/services/context_srv';
|
import { contextSrv } from 'app/core/services/context_srv';
|
||||||
// Types
|
// Types
|
||||||
import { GridPos, PanelModel } from './PanelModel';
|
import { GridPos, PanelModel } from './PanelModel';
|
||||||
|
import { TimeModel } from './TimeModel';
|
||||||
import { DashboardMigrator } from './DashboardMigrator';
|
import { DashboardMigrator } from './DashboardMigrator';
|
||||||
import {
|
import {
|
||||||
AnnotationQuery,
|
AnnotationQuery,
|
||||||
@ -78,7 +79,7 @@ export interface DashboardLink {
|
|||||||
includeVars: boolean;
|
includeVars: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DashboardModel {
|
export class DashboardModel implements TimeModel {
|
||||||
id: any;
|
id: any;
|
||||||
uid: string;
|
uid: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
10
public/app/features/dashboard/state/TimeModel.ts
Normal file
10
public/app/features/dashboard/state/TimeModel.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { TimeRange, TimeZone } from '@grafana/data';
|
||||||
|
|
||||||
|
export interface TimeModel {
|
||||||
|
time: any;
|
||||||
|
fiscalYearStartMonth?: number;
|
||||||
|
refresh: any;
|
||||||
|
timepicker: any;
|
||||||
|
getTimezone(): TimeZone;
|
||||||
|
timeRangeUpdated(timeRange: TimeRange): void;
|
||||||
|
}
|
@ -131,12 +131,12 @@ export const updateTimeZoneDashboard =
|
|||||||
(timeZone: TimeZone): ThunkResult<void> =>
|
(timeZone: TimeZone): ThunkResult<void> =>
|
||||||
(dispatch) => {
|
(dispatch) => {
|
||||||
dispatch(updateTimeZoneForSession(timeZone));
|
dispatch(updateTimeZoneForSession(timeZone));
|
||||||
getTimeSrv().refreshDashboard();
|
getTimeSrv().refreshTimeModel();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateWeekStartDashboard =
|
export const updateWeekStartDashboard =
|
||||||
(weekStart: string): ThunkResult<void> =>
|
(weekStart: string): ThunkResult<void> =>
|
||||||
(dispatch) => {
|
(dispatch) => {
|
||||||
dispatch(updateWeekStartForSession(weekStart));
|
dispatch(updateWeekStartForSession(weekStart));
|
||||||
getTimeSrv().refreshDashboard();
|
getTimeSrv().refreshTimeModel();
|
||||||
};
|
};
|
||||||
|
@ -38,6 +38,7 @@ import { getFiscalYearStartMonth, getTimeZone } from 'app/features/profile/state
|
|||||||
import { getDataSourceSrv } from '@grafana/runtime';
|
import { getDataSourceSrv } from '@grafana/runtime';
|
||||||
import { getRichHistory } from '../../../core/utils/richHistory';
|
import { getRichHistory } from '../../../core/utils/richHistory';
|
||||||
import { richHistoryUpdatedAction, stateSave } from './main';
|
import { richHistoryUpdatedAction, stateSave } from './main';
|
||||||
|
import { keybindingSrv } from 'app/core/services/keybindingSrv';
|
||||||
|
|
||||||
//
|
//
|
||||||
// Actions and Payloads
|
// Actions and Payloads
|
||||||
@ -172,6 +173,8 @@ export function initializeExplore(
|
|||||||
}
|
}
|
||||||
dispatch(updateTime({ exploreId }));
|
dispatch(updateTime({ exploreId }));
|
||||||
|
|
||||||
|
keybindingSrv.setupTimeRangeBindings(false);
|
||||||
|
|
||||||
if (instance) {
|
if (instance) {
|
||||||
// We do not want to add the url to browser history on init because when the pane is initialised it's because
|
// We do not want to add the url to browser history on init because when the pane is initialised it's because
|
||||||
// we already have something in the url. Adding basically the same state as additional history item prevents
|
// we already have something in the url. Adding basically the same state as additional history item prevents
|
||||||
|
@ -14,7 +14,7 @@ import { ExploreItemState, ThunkResult } from 'app/types';
|
|||||||
import { ExploreId } from 'app/types/explore';
|
import { ExploreId } from 'app/types/explore';
|
||||||
import { getFiscalYearStartMonth, getTimeZone } from 'app/features/profile/state/selectors';
|
import { getFiscalYearStartMonth, getTimeZone } from 'app/features/profile/state/selectors';
|
||||||
import { getTimeSrv } from '../../dashboard/services/TimeSrv';
|
import { getTimeSrv } from '../../dashboard/services/TimeSrv';
|
||||||
import { DashboardModel } from 'app/features/dashboard/state';
|
import { TimeModel } from '../../dashboard/state/TimeModel';
|
||||||
import { runQueries } from './query';
|
import { runQueries } from './query';
|
||||||
import { syncTimesAction, stateSave } from './main';
|
import { syncTimesAction, stateSave } from './main';
|
||||||
|
|
||||||
@ -95,14 +95,17 @@ export const updateTime = (config: {
|
|||||||
|
|
||||||
const range = getTimeRange(timeZone, rawRange, fiscalYearStartMonth);
|
const range = getTimeRange(timeZone, rawRange, fiscalYearStartMonth);
|
||||||
const absoluteRange: AbsoluteTimeRange = { from: range.from.valueOf(), to: range.to.valueOf() };
|
const absoluteRange: AbsoluteTimeRange = { from: range.from.valueOf(), to: range.to.valueOf() };
|
||||||
|
const timeModel: TimeModel = {
|
||||||
|
time: range.raw,
|
||||||
|
refresh: false,
|
||||||
|
timepicker: {},
|
||||||
|
getTimezone: () => timeZone,
|
||||||
|
timeRangeUpdated: (rawTimeRange: RawTimeRange) => {
|
||||||
|
dispatch(updateTimeRange({ exploreId: exploreId, rawRange: rawTimeRange }));
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
getTimeSrv().init(
|
getTimeSrv().init(timeModel);
|
||||||
new DashboardModel({
|
|
||||||
time: range.raw,
|
|
||||||
refresh: false,
|
|
||||||
timeZone,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
dispatch(changeRangeAction({ exploreId, range, absoluteRange }));
|
dispatch(changeRangeAction({ exploreId, range, absoluteRange }));
|
||||||
};
|
};
|
||||||
|
@ -187,7 +187,7 @@ export class GraphCtrl extends MetricsPanelCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
zoomOut(evt: any) {
|
zoomOut(evt: any) {
|
||||||
appEvents.publish(new ZoomOutEvent(2));
|
appEvents.publish(new ZoomOutEvent({ scale: 2 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
onDataSnapshotLoad(snapshotData: any) {
|
onDataSnapshotLoad(snapshotData: any) {
|
||||||
|
@ -161,7 +161,7 @@ export class HeatmapCtrl extends MetricsPanelCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
zoomOut(evt: any) {
|
zoomOut(evt: any) {
|
||||||
appEvents.publish(new ZoomOutEvent(2));
|
appEvents.publish(new ZoomOutEvent({ scale: 2 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
onRender() {
|
onRender() {
|
||||||
|
@ -132,14 +132,25 @@ export class RenderEvent extends BusEventBase {
|
|||||||
static type = 'render';
|
static type = 'render';
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ZoomOutEvent extends BusEventWithPayload<number> {
|
interface ZoomOutEventPayload {
|
||||||
|
scale: number;
|
||||||
|
updateUrl?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ZoomOutEvent extends BusEventWithPayload<ZoomOutEventPayload> {
|
||||||
static type = 'zoom-out';
|
static type = 'zoom-out';
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ShiftTimeEventPayload {
|
export enum ShiftTimeEventDirection {
|
||||||
Left = -1,
|
Left = -1,
|
||||||
Right = 1,
|
Right = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ShiftTimeEventPayload {
|
||||||
|
direction: ShiftTimeEventDirection;
|
||||||
|
updateUrl?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export class ShiftTimeEvent extends BusEventWithPayload<ShiftTimeEventPayload> {
|
export class ShiftTimeEvent extends BusEventWithPayload<ShiftTimeEventPayload> {
|
||||||
static type = 'shift-time';
|
static type = 'shift-time';
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user