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:
Dominik Prokop
2023-11-27 00:32:23 -08:00
committed by GitHub
parent 0f25f18739
commit 703deeff0b
5 changed files with 113 additions and 3 deletions
@@ -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,
};