mirror of
https://github.com/grafana/grafana.git
synced 2026-07-29 15:59:50 -05:00
DashboardScene: Add time picker keybindings (#78632)
* grafana/data: Add time range zoom out util
* Add keybindings for time range zoom out
* TimeRangePicker: change the way absolute time range is detected
* Depend on dashboard scene tructure rather
* Revert "grafana/data: Add time range zoom out util"
This reverts commit bc1602db57.
* Lint
* Lint
* dashboardSceneGraph tests
This commit is contained in:
@@ -214,7 +214,7 @@ export const convertRawToRange = (
|
||||
return { from, to, raw: { from, to } };
|
||||
};
|
||||
|
||||
function isRelativeTime(v: DateTime | string) {
|
||||
export function isRelativeTime(v: DateTime | string) {
|
||||
if (typeof v === 'string') {
|
||||
return v.indexOf('now') >= 0;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import { useOverlay } from '@react-aria/overlays';
|
||||
import React, { memo, createRef, useState, useEffect } from 'react';
|
||||
|
||||
import {
|
||||
isDateTime,
|
||||
rangeUtil,
|
||||
GrafanaTheme2,
|
||||
dateTimeFormat,
|
||||
@@ -108,7 +107,8 @@ export function TimeRangePicker(props: TimeRangePickerProps) {
|
||||
|
||||
const styles = useStyles2(getStyles);
|
||||
const { modalBackdrop } = useStyles2(getModalStyles);
|
||||
const hasAbsolute = isDateTime(value.raw.from) || isDateTime(value.raw.to);
|
||||
const hasAbsolute = !rangeUtil.isRelativeTime(value.raw.from) || !rangeUtil.isRelativeTime(value.raw.to);
|
||||
|
||||
const variant = isSynced ? 'active' : isOnCanvas ? 'canvas' : 'default';
|
||||
|
||||
const currentTimeRange = formattedRange(value, timeZone);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { OptionsWithLegend } from '@grafana/schema';
|
||||
import { KeybindingSet } from 'app/core/services/KeybindingSet';
|
||||
|
||||
import { ShareModal } from '../sharing/ShareModal';
|
||||
import { dashboardSceneGraph } from '../utils/dashboardSceneGraph';
|
||||
import { getDashboardUrl, getInspectUrl, getViewPanelUrl, tryGetExploreUrlForPanel } from '../utils/urlBuilders';
|
||||
import { getPanelIdForVizPanel } from '../utils/utils';
|
||||
|
||||
@@ -79,6 +80,34 @@ export function setupKeyboardShortcuts(scene: DashboardScene) {
|
||||
onTrigger: () => sceneGraph.getTimeRange(scene).onRefresh(),
|
||||
});
|
||||
|
||||
// Zoom out
|
||||
keybindings.addBinding({
|
||||
key: 't z',
|
||||
onTrigger: () => {
|
||||
handleZoomOut(scene);
|
||||
},
|
||||
});
|
||||
keybindings.addBinding({
|
||||
key: 'ctrl+z',
|
||||
onTrigger: () => {
|
||||
handleZoomOut(scene);
|
||||
},
|
||||
});
|
||||
|
||||
keybindings.addBinding({
|
||||
key: 't left',
|
||||
onTrigger: () => {
|
||||
handleTimeRangeShift(scene, 'left');
|
||||
},
|
||||
});
|
||||
|
||||
keybindings.addBinding({
|
||||
key: 't right',
|
||||
onTrigger: () => {
|
||||
handleTimeRangeShift(scene, 'right');
|
||||
},
|
||||
});
|
||||
|
||||
// Dashboard settings
|
||||
keybindings.addBinding({
|
||||
key: 'd s',
|
||||
@@ -128,3 +157,23 @@ export function toggleVizPanelLegend(vizPanel: VizPanel) {
|
||||
function hasLegendOptions(optionsWithLegend: unknown): optionsWithLegend is OptionsWithLegend {
|
||||
return optionsWithLegend != null && typeof optionsWithLegend === 'object' && 'legend' in optionsWithLegend;
|
||||
}
|
||||
|
||||
function handleZoomOut(scene: DashboardScene) {
|
||||
const timePicker = dashboardSceneGraph.getTimePicker(scene);
|
||||
timePicker?.onZoom();
|
||||
}
|
||||
|
||||
function handleTimeRangeShift(scene: DashboardScene, direction: 'left' | 'right') {
|
||||
const timePicker = dashboardSceneGraph.getTimePicker(scene);
|
||||
|
||||
if (!timePicker) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (direction === 'left') {
|
||||
timePicker.onMoveBackward();
|
||||
}
|
||||
if (direction === 'right') {
|
||||
timePicker.onMoveForward();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { DashboardDataDTO } from 'app/types';
|
||||
|
||||
import dashboard_to_load from '../serialization/testfiles/dashboard_to_load1.json';
|
||||
import { transformSaveModelToScene } from '../serialization/transformSaveModelToScene';
|
||||
|
||||
import { dashboardSceneGraph } from './dashboardSceneGraph';
|
||||
|
||||
describe('dashboardSceneGraph', () => {
|
||||
describe('getTimePicker', () => {
|
||||
it('should return null if no time picker', () => {
|
||||
const dashboard: DashboardDataDTO = {
|
||||
...(dashboard_to_load as unknown as DashboardDataDTO),
|
||||
timepicker: {
|
||||
hidden: true,
|
||||
collapse: false,
|
||||
refresh_intervals: [],
|
||||
time_options: [],
|
||||
},
|
||||
};
|
||||
|
||||
const scene = transformSaveModelToScene({
|
||||
dashboard: dashboard as unknown as DashboardDataDTO,
|
||||
meta: {},
|
||||
});
|
||||
|
||||
const timePicker = dashboardSceneGraph.getTimePicker(scene);
|
||||
expect(timePicker).toBeNull();
|
||||
});
|
||||
|
||||
it('should return time picker', () => {
|
||||
const scene = transformSaveModelToScene({
|
||||
dashboard: dashboard_to_load as unknown as DashboardDataDTO,
|
||||
meta: {},
|
||||
});
|
||||
const timePicker = dashboardSceneGraph.getTimePicker(scene);
|
||||
expect(timePicker).not.toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import { SceneTimePicker } from '@grafana/scenes';
|
||||
|
||||
import { DashboardControls } from '../scene/DashboardControls';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
|
||||
function getTimePicker(scene: DashboardScene) {
|
||||
const controls = scene.state.controls;
|
||||
|
||||
if (controls && controls[0] instanceof DashboardControls) {
|
||||
const dashboardControls = controls[0];
|
||||
const timePicker = dashboardControls.state.timeControls.find((c) => c instanceof SceneTimePicker);
|
||||
if (timePicker && timePicker instanceof SceneTimePicker) {
|
||||
return timePicker;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export const dashboardSceneGraph = {
|
||||
getTimePicker,
|
||||
};
|
||||
Reference in New Issue
Block a user