mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DashboardScene: Support panel relative time overrides and timeshift (#62844)
* Things are working * update * Added unit tests * More tests * minor fix * Update * Support hideTimeOverride
This commit is contained in:
parent
8113707dc8
commit
f4c127a1d8
@ -133,10 +133,9 @@ exports[`better eslint`] = {
|
||||
[0, 0, 0, "Do not use any type assertions.", "8"]
|
||||
],
|
||||
"packages/grafana-data/src/datetime/rangeutil.ts:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "1"],
|
||||
[0, 0, 0, "Do not use any type assertions.", "2"],
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "3"]
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "2"]
|
||||
],
|
||||
"packages/grafana-data/src/datetime/timezones.ts:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"],
|
||||
|
@ -447,30 +447,31 @@ Library panels streamline reuse of panels across multiple dashboards.
|
||||
|
||||
Dashboard panels are the basic visualization building blocks.
|
||||
|
||||
| Property | Type | Required | Default | Description |
|
||||
|-------------------|---------------------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `fieldConfig` | [FieldConfigSource](#fieldconfigsource) | **Yes** | | The data model used in Grafana, namely the data frame, is a columnar-oriented table structure that unifies both time series and table query results.<br/>Each column within this structure is called a field. A field can represent a single time series or table column.<br/>Field options allow you to change how the data is displayed in your visualizations. |
|
||||
| `options` | [object](#options) | **Yes** | | It depends on the panel plugin. They are specified by the Options field in panel plugin schemas. |
|
||||
| `transformations` | [DataTransformerConfig](#datatransformerconfig)[] | **Yes** | | List of transformations that are applied to the panel data before rendering.<br/>When there are multiple transformations, Grafana applies them in the order they are listed.<br/>Each transformation creates a result set that then passes on to the next transformation in the processing pipeline. |
|
||||
| `transparent` | boolean | **Yes** | `false` | Whether to display the panel without a background. |
|
||||
| `type` | string | **Yes** | | The panel plugin type id. This is used to find the plugin to display the panel.<br/>Constraint: `length >=1`. |
|
||||
| `datasource` | [DataSourceRef](#datasourceref) | No | | Ref to a DataSource instance |
|
||||
| `description` | string | No | | Panel description. |
|
||||
| `gridPos` | [GridPos](#gridpos) | No | | Position and dimensions of a panel in the grid |
|
||||
| `id` | uint32 | No | | Unique identifier of the panel. Generated by Grafana when creating a new panel. It must be unique within a dashboard, but not globally. |
|
||||
| `interval` | string | No | | The min time interval setting defines a lower limit for the $__interval and $__interval_ms variables.<br/>This value must be formatted as a number followed by a valid time<br/>identifier like: "40s", "3d", etc.<br/>See: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options |
|
||||
| `libraryPanel` | [LibraryPanelRef](#librarypanelref) | No | | A library panel is a reusable panel that you can use in any dashboard.<br/>When you make a change to a library panel, that change propagates to all instances of where the panel is used.<br/>Library panels streamline reuse of panels across multiple dashboards. |
|
||||
| `links` | [DashboardLink](#dashboardlink)[] | No | | Panel links. |
|
||||
| `maxDataPoints` | number | No | | The maximum number of data points that the panel queries are retrieving. |
|
||||
| `pluginVersion` | string | No | | The version of the plugin that is used for this panel. This is used to find the plugin to display the panel and to migrate old panel configs. |
|
||||
| `repeatDirection` | string | No | `h` | Direction to repeat in if 'repeat' is set.<br/>`h` for horizontal, `v` for vertical.<br/>Possible values are: `h`, `v`. |
|
||||
| `repeatPanelId` | integer | No | | Id of the repeating panel. |
|
||||
| `repeat` | string | No | | Name of template variable to repeat for. |
|
||||
| `tags` | string[] | No | | Tags for the panel. |
|
||||
| `targets` | [Target](#target)[] | No | | Depends on the panel plugin. See the plugin documentation for details. |
|
||||
| `timeFrom` | string | No | | Overrides the relative time range for individual panels,<br/>which causes them to be different than what is selected in<br/>the dashboard time picker in the top-right corner of the dashboard. You can use this to show metrics from different<br/>time periods or days on the same dashboard.<br/>The value is formatted as time operation like: `now-5m` (Last 5 minutes), `now/d` (the day so far),<br/>`now-5d/d`(Last 5 days), `now/w` (This week so far), `now-2y/y` (Last 2 years).<br/>Note: Panel time overrides have no effect when the dashboard’s time range is absolute.<br/>See: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options |
|
||||
| `timeShift` | string | No | | Overrides the time range for individual panels by shifting its start and end relative to the time picker.<br/>For example, you can shift the time range for the panel to be two hours earlier than the dashboard time picker setting `2h`.<br/>Note: Panel time overrides have no effect when the dashboard’s time range is absolute.<br/>See: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options |
|
||||
| `title` | string | No | | Panel title. |
|
||||
| Property | Type | Required | Default | Description |
|
||||
|--------------------|---------------------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `fieldConfig` | [FieldConfigSource](#fieldconfigsource) | **Yes** | | The data model used in Grafana, namely the data frame, is a columnar-oriented table structure that unifies both time series and table query results.<br/>Each column within this structure is called a field. A field can represent a single time series or table column.<br/>Field options allow you to change how the data is displayed in your visualizations. |
|
||||
| `options` | [object](#options) | **Yes** | | It depends on the panel plugin. They are specified by the Options field in panel plugin schemas. |
|
||||
| `transformations` | [DataTransformerConfig](#datatransformerconfig)[] | **Yes** | | List of transformations that are applied to the panel data before rendering.<br/>When there are multiple transformations, Grafana applies them in the order they are listed.<br/>Each transformation creates a result set that then passes on to the next transformation in the processing pipeline. |
|
||||
| `transparent` | boolean | **Yes** | `false` | Whether to display the panel without a background. |
|
||||
| `type` | string | **Yes** | | The panel plugin type id. This is used to find the plugin to display the panel.<br/>Constraint: `length >=1`. |
|
||||
| `datasource` | [DataSourceRef](#datasourceref) | No | | Ref to a DataSource instance |
|
||||
| `description` | string | No | | Panel description. |
|
||||
| `gridPos` | [GridPos](#gridpos) | No | | Position and dimensions of a panel in the grid |
|
||||
| `hideTimeOverride` | boolean | No | | Controls if the timeFrom or timeShift overrides are shown in the panel header |
|
||||
| `id` | uint32 | No | | Unique identifier of the panel. Generated by Grafana when creating a new panel. It must be unique within a dashboard, but not globally. |
|
||||
| `interval` | string | No | | The min time interval setting defines a lower limit for the $__interval and $__interval_ms variables.<br/>This value must be formatted as a number followed by a valid time<br/>identifier like: "40s", "3d", etc.<br/>See: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options |
|
||||
| `libraryPanel` | [LibraryPanelRef](#librarypanelref) | No | | A library panel is a reusable panel that you can use in any dashboard.<br/>When you make a change to a library panel, that change propagates to all instances of where the panel is used.<br/>Library panels streamline reuse of panels across multiple dashboards. |
|
||||
| `links` | [DashboardLink](#dashboardlink)[] | No | | Panel links. |
|
||||
| `maxDataPoints` | number | No | | The maximum number of data points that the panel queries are retrieving. |
|
||||
| `pluginVersion` | string | No | | The version of the plugin that is used for this panel. This is used to find the plugin to display the panel and to migrate old panel configs. |
|
||||
| `repeatDirection` | string | No | `h` | Direction to repeat in if 'repeat' is set.<br/>`h` for horizontal, `v` for vertical.<br/>Possible values are: `h`, `v`. |
|
||||
| `repeatPanelId` | integer | No | | Id of the repeating panel. |
|
||||
| `repeat` | string | No | | Name of template variable to repeat for. |
|
||||
| `tags` | string[] | No | | Tags for the panel. |
|
||||
| `targets` | [Target](#target)[] | No | | Depends on the panel plugin. See the plugin documentation for details. |
|
||||
| `timeFrom` | string | No | | Overrides the relative time range for individual panels,<br/>which causes them to be different than what is selected in<br/>the dashboard time picker in the top-right corner of the dashboard. You can use this to show metrics from different<br/>time periods or days on the same dashboard.<br/>The value is formatted as time operation like: `now-5m` (Last 5 minutes), `now/d` (the day so far),<br/>`now-5d/d`(Last 5 days), `now/w` (This week so far), `now-2y/y` (Last 2 years).<br/>Note: Panel time overrides have no effect when the dashboard’s time range is absolute.<br/>See: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options |
|
||||
| `timeShift` | string | No | | Overrides the time range for individual panels by shifting its start and end relative to the time picker.<br/>For example, you can shift the time range for the panel to be two hours earlier than the dashboard time picker setting `2h`.<br/>Note: Panel time overrides have no effect when the dashboard’s time range is absolute.<br/>See: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options |
|
||||
| `title` | string | No | | Panel title. |
|
||||
|
||||
### FieldConfigSource
|
||||
|
||||
@ -594,30 +595,31 @@ Support for legacy graph panel.
|
||||
|
||||
Dashboard panels are the basic visualization building blocks.
|
||||
|
||||
| Property | Type | Required | Default | Description |
|
||||
|-------------------|---------------------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `fieldConfig` | [FieldConfigSource](#fieldconfigsource) | **Yes** | | The data model used in Grafana, namely the data frame, is a columnar-oriented table structure that unifies both time series and table query results.<br/>Each column within this structure is called a field. A field can represent a single time series or table column.<br/>Field options allow you to change how the data is displayed in your visualizations. |
|
||||
| `options` | [options](#options) | **Yes** | | It depends on the panel plugin. They are specified by the Options field in panel plugin schemas. |
|
||||
| `transformations` | [DataTransformerConfig](#datatransformerconfig)[] | **Yes** | | List of transformations that are applied to the panel data before rendering.<br/>When there are multiple transformations, Grafana applies them in the order they are listed.<br/>Each transformation creates a result set that then passes on to the next transformation in the processing pipeline. |
|
||||
| `transparent` | boolean | **Yes** | `false` | Whether to display the panel without a background. |
|
||||
| `type` | string | **Yes** | | The panel plugin type id. This is used to find the plugin to display the panel.<br/>Constraint: `length >=1`. |
|
||||
| `datasource` | [DataSourceRef](#datasourceref) | No | | Ref to a DataSource instance |
|
||||
| `description` | string | No | | Panel description. |
|
||||
| `gridPos` | [GridPos](#gridpos) | No | | Position and dimensions of a panel in the grid |
|
||||
| `id` | uint32 | No | | Unique identifier of the panel. Generated by Grafana when creating a new panel. It must be unique within a dashboard, but not globally. |
|
||||
| `interval` | string | No | | The min time interval setting defines a lower limit for the $__interval and $__interval_ms variables.<br/>This value must be formatted as a number followed by a valid time<br/>identifier like: "40s", "3d", etc.<br/>See: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options |
|
||||
| `libraryPanel` | [LibraryPanelRef](#librarypanelref) | No | | A library panel is a reusable panel that you can use in any dashboard.<br/>When you make a change to a library panel, that change propagates to all instances of where the panel is used.<br/>Library panels streamline reuse of panels across multiple dashboards. |
|
||||
| `links` | [DashboardLink](#dashboardlink)[] | No | | Panel links. |
|
||||
| `maxDataPoints` | number | No | | The maximum number of data points that the panel queries are retrieving. |
|
||||
| `pluginVersion` | string | No | | The version of the plugin that is used for this panel. This is used to find the plugin to display the panel and to migrate old panel configs. |
|
||||
| `repeatDirection` | string | No | `h` | Direction to repeat in if 'repeat' is set.<br/>`h` for horizontal, `v` for vertical.<br/>Possible values are: `h`, `v`. |
|
||||
| `repeatPanelId` | integer | No | | Id of the repeating panel. |
|
||||
| `repeat` | string | No | | Name of template variable to repeat for. |
|
||||
| `tags` | string[] | No | | Tags for the panel. |
|
||||
| `targets` | [Target](#target)[] | No | | Depends on the panel plugin. See the plugin documentation for details. |
|
||||
| `timeFrom` | string | No | | Overrides the relative time range for individual panels,<br/>which causes them to be different than what is selected in<br/>the dashboard time picker in the top-right corner of the dashboard. You can use this to show metrics from different<br/>time periods or days on the same dashboard.<br/>The value is formatted as time operation like: `now-5m` (Last 5 minutes), `now/d` (the day so far),<br/>`now-5d/d`(Last 5 days), `now/w` (This week so far), `now-2y/y` (Last 2 years).<br/>Note: Panel time overrides have no effect when the dashboard’s time range is absolute.<br/>See: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options |
|
||||
| `timeShift` | string | No | | Overrides the time range for individual panels by shifting its start and end relative to the time picker.<br/>For example, you can shift the time range for the panel to be two hours earlier than the dashboard time picker setting `2h`.<br/>Note: Panel time overrides have no effect when the dashboard’s time range is absolute.<br/>See: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options |
|
||||
| `title` | string | No | | Panel title. |
|
||||
| Property | Type | Required | Default | Description |
|
||||
|--------------------|---------------------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `fieldConfig` | [FieldConfigSource](#fieldconfigsource) | **Yes** | | The data model used in Grafana, namely the data frame, is a columnar-oriented table structure that unifies both time series and table query results.<br/>Each column within this structure is called a field. A field can represent a single time series or table column.<br/>Field options allow you to change how the data is displayed in your visualizations. |
|
||||
| `options` | [options](#options) | **Yes** | | It depends on the panel plugin. They are specified by the Options field in panel plugin schemas. |
|
||||
| `transformations` | [DataTransformerConfig](#datatransformerconfig)[] | **Yes** | | List of transformations that are applied to the panel data before rendering.<br/>When there are multiple transformations, Grafana applies them in the order they are listed.<br/>Each transformation creates a result set that then passes on to the next transformation in the processing pipeline. |
|
||||
| `transparent` | boolean | **Yes** | `false` | Whether to display the panel without a background. |
|
||||
| `type` | string | **Yes** | | The panel plugin type id. This is used to find the plugin to display the panel.<br/>Constraint: `length >=1`. |
|
||||
| `datasource` | [DataSourceRef](#datasourceref) | No | | Ref to a DataSource instance |
|
||||
| `description` | string | No | | Panel description. |
|
||||
| `gridPos` | [GridPos](#gridpos) | No | | Position and dimensions of a panel in the grid |
|
||||
| `hideTimeOverride` | boolean | No | | Controls if the timeFrom or timeShift overrides are shown in the panel header |
|
||||
| `id` | uint32 | No | | Unique identifier of the panel. Generated by Grafana when creating a new panel. It must be unique within a dashboard, but not globally. |
|
||||
| `interval` | string | No | | The min time interval setting defines a lower limit for the $__interval and $__interval_ms variables.<br/>This value must be formatted as a number followed by a valid time<br/>identifier like: "40s", "3d", etc.<br/>See: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options |
|
||||
| `libraryPanel` | [LibraryPanelRef](#librarypanelref) | No | | A library panel is a reusable panel that you can use in any dashboard.<br/>When you make a change to a library panel, that change propagates to all instances of where the panel is used.<br/>Library panels streamline reuse of panels across multiple dashboards. |
|
||||
| `links` | [DashboardLink](#dashboardlink)[] | No | | Panel links. |
|
||||
| `maxDataPoints` | number | No | | The maximum number of data points that the panel queries are retrieving. |
|
||||
| `pluginVersion` | string | No | | The version of the plugin that is used for this panel. This is used to find the plugin to display the panel and to migrate old panel configs. |
|
||||
| `repeatDirection` | string | No | `h` | Direction to repeat in if 'repeat' is set.<br/>`h` for horizontal, `v` for vertical.<br/>Possible values are: `h`, `v`. |
|
||||
| `repeatPanelId` | integer | No | | Id of the repeating panel. |
|
||||
| `repeat` | string | No | | Name of template variable to repeat for. |
|
||||
| `tags` | string[] | No | | Tags for the panel. |
|
||||
| `targets` | [Target](#target)[] | No | | Depends on the panel plugin. See the plugin documentation for details. |
|
||||
| `timeFrom` | string | No | | Overrides the relative time range for individual panels,<br/>which causes them to be different than what is selected in<br/>the dashboard time picker in the top-right corner of the dashboard. You can use this to show metrics from different<br/>time periods or days on the same dashboard.<br/>The value is formatted as time operation like: `now-5m` (Last 5 minutes), `now/d` (the day so far),<br/>`now-5d/d`(Last 5 days), `now/w` (This week so far), `now-2y/y` (Last 2 years).<br/>Note: Panel time overrides have no effect when the dashboard’s time range is absolute.<br/>See: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options |
|
||||
| `timeShift` | string | No | | Overrides the time range for individual panels by shifting its start and end relative to the time picker.<br/>For example, you can shift the time range for the panel to be two hours earlier than the dashboard time picker setting `2h`.<br/>Note: Panel time overrides have no effect when the dashboard’s time range is absolute.<br/>See: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options |
|
||||
| `title` | string | No | | Panel title. |
|
||||
|
||||
### Templating
|
||||
|
||||
|
@ -572,6 +572,9 @@ lineage: schemas: [{
|
||||
// See: https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/#query-options
|
||||
timeShift?: string
|
||||
|
||||
// Controls if the timeFrom or timeShift overrides are shown in the panel header
|
||||
hideTimeOverride?: bool
|
||||
|
||||
// Dynamically load the panel
|
||||
libraryPanel?: #LibraryPanelRef
|
||||
|
||||
|
@ -246,7 +246,7 @@
|
||||
"@grafana/lezer-traceql": "0.0.4",
|
||||
"@grafana/monaco-logql": "^0.0.7",
|
||||
"@grafana/runtime": "workspace:*",
|
||||
"@grafana/scenes": "^0.26.0",
|
||||
"@grafana/scenes": "^0.27.0",
|
||||
"@grafana/schema": "workspace:*",
|
||||
"@grafana/ui": "workspace:*",
|
||||
"@kusto/monaco-kusto": "^7.4.0",
|
||||
|
@ -86,7 +86,7 @@ const hiddenRangeOptions: TimeOption[] = [
|
||||
{ from: 'now', to: 'now+5y', display: 'Next 5 years' },
|
||||
];
|
||||
|
||||
const rangeIndex: Record<string, any> = {};
|
||||
const rangeIndex: Record<string, TimeOption> = {};
|
||||
each(rangeOptions, (frame) => {
|
||||
rangeIndex[frame.from + ' to ' + frame.to] = frame;
|
||||
});
|
||||
@ -100,7 +100,7 @@ each(hiddenRangeOptions, (frame) => {
|
||||
// now/d to now
|
||||
// now/d
|
||||
// if no to <expr> then to now is assumed
|
||||
export function describeTextRange(expr: string) {
|
||||
export function describeTextRange(expr: string): TimeOption {
|
||||
const isLast = expr.indexOf('+') !== 0;
|
||||
if (expr.indexOf('now') === -1) {
|
||||
expr = (isLast ? 'now-' : 'now') + expr;
|
||||
@ -112,9 +112,9 @@ export function describeTextRange(expr: string) {
|
||||
}
|
||||
|
||||
if (isLast) {
|
||||
opt = { from: expr, to: 'now' };
|
||||
opt = { from: expr, to: 'now', display: '' };
|
||||
} else {
|
||||
opt = { from: 'now', to: expr };
|
||||
opt = { from: 'now', to: expr, display: '' };
|
||||
}
|
||||
|
||||
const parts = /^now([-+])(\d+)(\w)/.exec(expr);
|
||||
|
@ -41,6 +41,8 @@ export interface TimeOption {
|
||||
from: string;
|
||||
to: string;
|
||||
display: string;
|
||||
invalid?: boolean;
|
||||
section?: number;
|
||||
}
|
||||
|
||||
/** @deprecated use TimeZone from schema */
|
||||
|
@ -666,6 +666,10 @@ export interface Panel {
|
||||
* Grid position.
|
||||
*/
|
||||
gridPos?: GridPos;
|
||||
/**
|
||||
* Controls if the timeFrom or timeShift overrides are shown in the panel header
|
||||
*/
|
||||
hideTimeOverride?: boolean;
|
||||
/**
|
||||
* Unique identifier of the panel. Generated by Grafana when creating a new panel. It must be unique within a dashboard, but not globally.
|
||||
*/
|
||||
|
@ -523,6 +523,9 @@ type Panel struct {
|
||||
// Position and dimensions of a panel in the grid
|
||||
GridPos *GridPos `json:"gridPos,omitempty"`
|
||||
|
||||
// Controls if the timeFrom or timeShift overrides are shown in the panel header
|
||||
HideTimeOverride *bool `json:"hideTimeOverride,omitempty"`
|
||||
|
||||
// Unique identifier of the panel. Generated by Grafana when creating a new panel. It must be unique within a dashboard, but not globally.
|
||||
Id *int `json:"id,omitempty"`
|
||||
|
||||
|
@ -0,0 +1,59 @@
|
||||
import { advanceTo, clear } from 'jest-date-mock';
|
||||
|
||||
import { dateTime } from '@grafana/data';
|
||||
import { SceneCanvasText, SceneFlexItem, SceneFlexLayout, SceneTimeRange } from '@grafana/scenes';
|
||||
|
||||
import { activateFullSceneTree } from '../utils/utils';
|
||||
|
||||
import { PanelTimeRange } from './PanelTimeRange';
|
||||
|
||||
describe('PanelTimeRange', () => {
|
||||
const fakeCurrentDate = dateTime('2019-02-11T19:00:00.000Z').toDate();
|
||||
|
||||
beforeAll(() => {
|
||||
advanceTo(fakeCurrentDate);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
clear();
|
||||
});
|
||||
|
||||
it('should apply relative time override', () => {
|
||||
const panelTime = new PanelTimeRange({ timeFrom: '2h' });
|
||||
|
||||
buildAndActivateSceneFor(panelTime);
|
||||
|
||||
expect(panelTime.state.value.from.toISOString()).toBe('2019-02-11T17:00:00.000Z');
|
||||
expect(panelTime.state.value.to.toISOString()).toBe(fakeCurrentDate.toISOString());
|
||||
expect(panelTime.state.value.raw.from).toBe('now-2h');
|
||||
expect(panelTime.state.timeInfo).toBe('Last 2 hours');
|
||||
});
|
||||
|
||||
it('should apply time shift', () => {
|
||||
const panelTime = new PanelTimeRange({ timeShift: '2h' });
|
||||
|
||||
buildAndActivateSceneFor(panelTime);
|
||||
|
||||
expect(panelTime.state.value.from.toISOString()).toBe('2019-02-11T11:00:00.000Z');
|
||||
expect(panelTime.state.value.to.toISOString()).toBe('2019-02-11T17:00:00.000Z');
|
||||
expect(panelTime.state.timeInfo).toBe(' timeshift -2h');
|
||||
});
|
||||
|
||||
it('should apply both relative time and time shift', () => {
|
||||
const panelTime = new PanelTimeRange({ timeFrom: '2h', timeShift: '2h' });
|
||||
|
||||
buildAndActivateSceneFor(panelTime);
|
||||
|
||||
expect(panelTime.state.value.from.toISOString()).toBe('2019-02-11T15:00:00.000Z');
|
||||
expect(panelTime.state.timeInfo).toBe('Last 2 hours timeshift -2h');
|
||||
});
|
||||
});
|
||||
|
||||
function buildAndActivateSceneFor(panelTime: PanelTimeRange) {
|
||||
const panel = new SceneCanvasText({ text: 'Hello', $timeRange: panelTime });
|
||||
const scene = new SceneFlexLayout({
|
||||
$timeRange: new SceneTimeRange({ from: 'now-6h', to: 'now' }),
|
||||
children: [new SceneFlexItem({ body: panel })],
|
||||
});
|
||||
activateFullSceneTree(scene);
|
||||
}
|
145
public/app/features/dashboard-scene/scene/PanelTimeRange.tsx
Normal file
145
public/app/features/dashboard-scene/scene/PanelTimeRange.tsx
Normal file
@ -0,0 +1,145 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React from 'react';
|
||||
|
||||
import { dateMath, getDefaultTimeRange, GrafanaTheme2, rangeUtil, TimeRange } from '@grafana/data';
|
||||
import {
|
||||
SceneComponentProps,
|
||||
sceneGraph,
|
||||
SceneObjectBase,
|
||||
SceneTimeRangeLike,
|
||||
SceneTimeRangeState,
|
||||
} from '@grafana/scenes';
|
||||
import { Icon, PanelChrome, TimePickerTooltip, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
import { TimeOverrideResult } from 'app/features/dashboard/utils/panel';
|
||||
|
||||
interface PanelTimeRangeState extends SceneTimeRangeState {
|
||||
timeFrom?: string;
|
||||
timeShift?: string;
|
||||
hideTimeOverride?: boolean;
|
||||
timeInfo?: string;
|
||||
}
|
||||
|
||||
export class PanelTimeRange extends SceneObjectBase<PanelTimeRangeState> implements SceneTimeRangeLike {
|
||||
public static Component = PanelTimeRangeRenderer;
|
||||
|
||||
public constructor(state: Partial<PanelTimeRangeState> = {}) {
|
||||
super({
|
||||
...state,
|
||||
// This time range is not valid until activation
|
||||
from: 'now-6h',
|
||||
to: 'now',
|
||||
value: getDefaultTimeRange(),
|
||||
});
|
||||
|
||||
this.addActivationHandler(() => this._activationHandler());
|
||||
}
|
||||
|
||||
private getTimeOverride(parentTimeRange: TimeRange): TimeOverrideResult {
|
||||
const { timeFrom, timeShift } = this.state;
|
||||
const newTimeData = { timeInfo: '', timeRange: parentTimeRange };
|
||||
|
||||
if (timeFrom) {
|
||||
const timeFromInterpolated = sceneGraph.interpolate(this, this.state.timeFrom);
|
||||
const timeFromInfo = rangeUtil.describeTextRange(timeFromInterpolated);
|
||||
|
||||
if (timeFromInfo.invalid) {
|
||||
newTimeData.timeInfo = 'invalid time override';
|
||||
return newTimeData;
|
||||
}
|
||||
|
||||
// Only evaluate if the timeFrom if parent time is relative
|
||||
if (rangeUtil.isRelativeTimeRange(parentTimeRange.raw)) {
|
||||
newTimeData.timeInfo = timeFromInfo.display;
|
||||
newTimeData.timeRange = {
|
||||
from: dateMath.parse(timeFromInfo.from)!,
|
||||
to: dateMath.parse(timeFromInfo.to)!,
|
||||
raw: { from: timeFromInfo.from, to: timeFromInfo.to },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (timeShift) {
|
||||
const timeShiftInterpolated = sceneGraph.interpolate(this, this.state.timeShift);
|
||||
const timeShiftInfo = rangeUtil.describeTextRange(timeShiftInterpolated);
|
||||
|
||||
if (timeShiftInfo.invalid) {
|
||||
newTimeData.timeInfo = 'invalid timeshift';
|
||||
return newTimeData;
|
||||
}
|
||||
|
||||
const timeShift = '-' + timeShiftInterpolated;
|
||||
newTimeData.timeInfo += ' timeshift ' + timeShift;
|
||||
const from = dateMath.parseDateMath(timeShift, newTimeData.timeRange.from, false)!;
|
||||
const to = dateMath.parseDateMath(timeShift, newTimeData.timeRange.to, true)!;
|
||||
|
||||
newTimeData.timeRange = { from, to, raw: { from, to } };
|
||||
}
|
||||
|
||||
return newTimeData;
|
||||
}
|
||||
|
||||
private _activationHandler(): void {
|
||||
const parentTimeRange = this.getParentTimeRange();
|
||||
|
||||
this._subs.add(parentTimeRange.subscribeToState((state) => this.handleParentTimeRangeChanged(state.value)));
|
||||
|
||||
this.handleParentTimeRangeChanged(parentTimeRange.state.value);
|
||||
}
|
||||
|
||||
private handleParentTimeRangeChanged(parentTimeRange: TimeRange) {
|
||||
const overrideResult = this.getTimeOverride(parentTimeRange);
|
||||
this.setState({ value: overrideResult.timeRange, timeInfo: overrideResult.timeInfo });
|
||||
}
|
||||
|
||||
private getParentTimeRange(): SceneTimeRangeLike {
|
||||
if (!this.parent || !this.parent.parent) {
|
||||
throw new Error('Missing parent');
|
||||
}
|
||||
|
||||
// Need to go up two levels otherwise we will get ourselves
|
||||
return sceneGraph.getTimeRange(this.parent.parent);
|
||||
}
|
||||
|
||||
public onTimeRangeChange = (timeRange: TimeRange) => {
|
||||
const parentTimeRange = this.getParentTimeRange();
|
||||
parentTimeRange.onTimeRangeChange(timeRange);
|
||||
};
|
||||
|
||||
public onRefresh(): void {
|
||||
this.getParentTimeRange().onRefresh();
|
||||
}
|
||||
|
||||
public onTimeZoneChange(timeZone: string): void {
|
||||
this.getParentTimeRange().onTimeZoneChange(timeZone);
|
||||
}
|
||||
|
||||
public getTimeZone(): string {
|
||||
return this.getParentTimeRange().getTimeZone();
|
||||
}
|
||||
}
|
||||
|
||||
function PanelTimeRangeRenderer({ model }: SceneComponentProps<PanelTimeRange>) {
|
||||
const { timeInfo, hideTimeOverride } = model.useState();
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
if (!timeInfo || hideTimeOverride) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip content={<TimePickerTooltip timeRange={model.state.value} timeZone={model.getTimeZone()} />}>
|
||||
<PanelChrome.TitleItem className={styles.timeshift}>
|
||||
<Icon name="clock-nine" size="sm" /> {timeInfo}
|
||||
</PanelChrome.TitleItem>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => {
|
||||
return {
|
||||
timeshift: css({
|
||||
color: theme.colors.text.link,
|
||||
gap: theme.spacing(0.5),
|
||||
}),
|
||||
};
|
||||
};
|
@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`transformSceneToSaveModel Given a scene Should transfrom back to peristed model 1`] = `
|
||||
exports[`transformSceneToSaveModel Given a scene Should transform back to peristed model 1`] = `
|
||||
{
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
@ -14,56 +14,17 @@ exports[`transformSceneToSaveModel Given a scene Should transfrom back to perist
|
||||
"mode": "palette-classic",
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false,
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear",
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none",
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off",
|
||||
},
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80,
|
||||
},
|
||||
],
|
||||
"lineWidth": 2,
|
||||
},
|
||||
},
|
||||
"overrides": [],
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 0,
|
||||
},
|
||||
"id": 28,
|
||||
|
@ -33,57 +33,17 @@
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
"lineWidth": 2
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 24,
|
||||
"x": 0,
|
||||
"w": 12,
|
||||
"x": 12,
|
||||
"y": 0
|
||||
},
|
||||
"id": 28,
|
||||
@ -116,10 +76,6 @@
|
||||
},
|
||||
{
|
||||
"collapsed": false,
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 1,
|
||||
"w": 24,
|
||||
@ -128,15 +84,6 @@
|
||||
},
|
||||
"id": 5,
|
||||
"panels": [],
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Row title",
|
||||
"type": "row"
|
||||
},
|
||||
@ -146,56 +93,7 @@
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": {
|
||||
"mode": "palette-classic"
|
||||
},
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"insertNulls": false,
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 5,
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
},
|
||||
"showPoints": "auto",
|
||||
"spanNulls": false,
|
||||
"stacking": {
|
||||
"group": "A",
|
||||
"mode": "none"
|
||||
},
|
||||
"thresholdsStyle": {
|
||||
"mode": "off"
|
||||
}
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{
|
||||
"color": "green",
|
||||
"value": null
|
||||
},
|
||||
{
|
||||
"color": "red",
|
||||
"value": 80
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"defaults": {},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
@ -205,18 +103,7 @@
|
||||
"y": 9
|
||||
},
|
||||
"id": 29,
|
||||
"options": {
|
||||
"legend": {
|
||||
"calcs": [],
|
||||
"displayMode": "list",
|
||||
"placement": "bottom",
|
||||
"showLegend": true
|
||||
},
|
||||
"tooltip": {
|
||||
"mode": "single",
|
||||
"sort": "none"
|
||||
}
|
||||
},
|
||||
"options": {},
|
||||
"targets": [
|
||||
{
|
||||
"alias": "series",
|
||||
@ -233,10 +120,6 @@
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 10,
|
||||
"w": 11,
|
||||
@ -255,18 +138,6 @@
|
||||
"mode": "markdown"
|
||||
},
|
||||
"pluginVersion": "10.2.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"alias": "__server_names",
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"refId": "A",
|
||||
"scenarioId": "random_walk",
|
||||
"seriesCount": 6
|
||||
}
|
||||
],
|
||||
"title": "Transparent text panel",
|
||||
"transparent": true,
|
||||
"type": "text"
|
||||
|
@ -18,11 +18,12 @@ import { createPanelJSONFixture } from 'app/features/dashboard/state/__fixtures_
|
||||
import { SHARED_DASHBOARD_QUERY } from 'app/plugins/datasource/dashboard';
|
||||
import { DASHBOARD_DATASOURCE_PLUGIN_ID } from 'app/plugins/datasource/dashboard/types';
|
||||
|
||||
import { PanelTimeRange } from '../scene/PanelTimeRange';
|
||||
import { ShareQueryDataProvider } from '../scene/ShareQueryDataProvider';
|
||||
|
||||
import {
|
||||
createDashboardSceneFromDashboardModel,
|
||||
createVizPanelFromPanelModel,
|
||||
buildSceneFromPanelModel,
|
||||
createSceneVariableFromVariableModel,
|
||||
} from './transformSaveModelToScene';
|
||||
|
||||
@ -234,7 +235,7 @@ describe('DashboardLoader', () => {
|
||||
},
|
||||
],
|
||||
};
|
||||
const vizPanelSceneObject = createVizPanelFromPanelModel(new PanelModel(panel));
|
||||
const vizPanelSceneObject = buildSceneFromPanelModel(new PanelModel(panel));
|
||||
const vizPanelItelf = vizPanelSceneObject.state.body as VizPanel;
|
||||
expect(vizPanelItelf?.state.title).toBe('test');
|
||||
expect(vizPanelItelf?.state.pluginId).toBe('test-plugin');
|
||||
@ -262,13 +263,29 @@ describe('DashboardLoader', () => {
|
||||
transparent: true,
|
||||
};
|
||||
|
||||
const gridItem = createVizPanelFromPanelModel(new PanelModel(panel));
|
||||
const gridItem = buildSceneFromPanelModel(new PanelModel(panel));
|
||||
const vizPanel = gridItem.state.body as VizPanel;
|
||||
|
||||
expect(vizPanel.state.displayMode).toEqual('transparent');
|
||||
expect(vizPanel.state.hoverHeader).toEqual(true);
|
||||
});
|
||||
|
||||
it('should set PanelTimeRange when timeFrom or timeShift is present', () => {
|
||||
const panel = {
|
||||
type: 'test-plugin',
|
||||
timeFrom: '2h',
|
||||
timeShift: '1d',
|
||||
};
|
||||
|
||||
const gridItem = buildSceneFromPanelModel(new PanelModel(panel));
|
||||
const vizPanel = gridItem.state.body as VizPanel;
|
||||
const timeRange = vizPanel.state.$timeRange as PanelTimeRange;
|
||||
|
||||
expect(timeRange).toBeInstanceOf(PanelTimeRange);
|
||||
expect(timeRange.state.timeFrom).toBe('2h');
|
||||
expect(timeRange.state.timeShift).toBe('1d');
|
||||
});
|
||||
|
||||
it('should handle a dashboard query data source', () => {
|
||||
const panel = {
|
||||
title: '',
|
||||
@ -279,7 +296,7 @@ describe('DashboardLoader', () => {
|
||||
targets: [{ refId: 'A', panelId: 10 }],
|
||||
};
|
||||
|
||||
const vizPanel = createVizPanelFromPanelModel(new PanelModel(panel)).state.body as VizPanel;
|
||||
const vizPanel = buildSceneFromPanelModel(new PanelModel(panel)).state.body as VizPanel;
|
||||
|
||||
expect(vizPanel.state.$data).toBeInstanceOf(ShareQueryDataProvider);
|
||||
});
|
||||
@ -297,7 +314,7 @@ describe('DashboardLoader', () => {
|
||||
skipDataQuery: true,
|
||||
}).meta;
|
||||
|
||||
const gridItem = createVizPanelFromPanelModel(new PanelModel(panel));
|
||||
const gridItem = buildSceneFromPanelModel(new PanelModel(panel));
|
||||
const vizPanel = gridItem.state.body as VizPanel;
|
||||
|
||||
expect(vizPanel.state.$data).toBeUndefined();
|
||||
|
@ -24,6 +24,7 @@ import {
|
||||
SceneControlsSpacer,
|
||||
VizPanelMenu,
|
||||
behaviors,
|
||||
VizPanelState,
|
||||
} from '@grafana/scenes';
|
||||
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||
import { DashboardDTO } from 'app/types';
|
||||
@ -31,6 +32,7 @@ import { DashboardDTO } from 'app/types';
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { LibraryVizPanel } from '../scene/LibraryVizPanel';
|
||||
import { panelMenuBehavior } from '../scene/PanelMenuBehavior';
|
||||
import { PanelTimeRange } from '../scene/PanelTimeRange';
|
||||
import { createPanelDataProvider } from '../utils/createPanelDataProvider';
|
||||
import { getVizPanelKeyForPanelId } from '../utils/utils';
|
||||
|
||||
@ -68,7 +70,7 @@ export function createSceneObjectsForPanels(oldPanels: PanelModel[]): Array<Scen
|
||||
title: panel.title,
|
||||
isCollapsed: true,
|
||||
y: panel.gridPos.y,
|
||||
children: panel.panels ? panel.panels.map(createVizPanelFromPanelModel) : [],
|
||||
children: panel.panels ? panel.panels.map(buildSceneFromPanelModel) : [],
|
||||
})
|
||||
);
|
||||
} else {
|
||||
@ -104,7 +106,7 @@ export function createSceneObjectsForPanels(oldPanels: PanelModel[]): Array<Scen
|
||||
});
|
||||
panels.push(gridItem);
|
||||
} else {
|
||||
const panelObject = createVizPanelFromPanelModel(panel);
|
||||
const panelObject = buildSceneFromPanelModel(panel);
|
||||
|
||||
// when processing an expanded row, collect its panels
|
||||
if (currentRow) {
|
||||
@ -244,28 +246,38 @@ export function createSceneVariableFromVariableModel(variable: VariableModel): S
|
||||
}
|
||||
}
|
||||
|
||||
export function createVizPanelFromPanelModel(panel: PanelModel) {
|
||||
export function buildSceneFromPanelModel(panel: PanelModel): SceneGridItem {
|
||||
const vizPanelState: VizPanelState = {
|
||||
key: getVizPanelKeyForPanelId(panel.id),
|
||||
title: panel.title,
|
||||
pluginId: panel.type,
|
||||
options: panel.options ?? {},
|
||||
fieldConfig: panel.fieldConfig,
|
||||
pluginVersion: panel.pluginVersion,
|
||||
displayMode: panel.transparent ? 'transparent' : undefined,
|
||||
// To be replaced with it's own option persited option instead derived
|
||||
hoverHeader: !panel.title && !panel.timeFrom && !panel.timeShift,
|
||||
$data: createPanelDataProvider(panel),
|
||||
menu: new VizPanelMenu({
|
||||
$behaviors: [panelMenuBehavior],
|
||||
}),
|
||||
};
|
||||
|
||||
if (panel.timeFrom || panel.timeShift) {
|
||||
vizPanelState.$timeRange = new PanelTimeRange({
|
||||
timeFrom: panel.timeFrom,
|
||||
timeShift: panel.timeShift,
|
||||
hideTimeOverride: panel.hideTimeOverride,
|
||||
});
|
||||
}
|
||||
|
||||
return new SceneGridItem({
|
||||
key: `grid-item-${panel.id}`,
|
||||
x: panel.gridPos.x,
|
||||
y: panel.gridPos.y,
|
||||
width: panel.gridPos.w,
|
||||
height: panel.gridPos.h,
|
||||
body: new VizPanel({
|
||||
key: getVizPanelKeyForPanelId(panel.id),
|
||||
title: panel.title,
|
||||
pluginId: panel.type,
|
||||
options: panel.options ?? {},
|
||||
fieldConfig: panel.fieldConfig,
|
||||
pluginVersion: panel.pluginVersion,
|
||||
displayMode: panel.transparent ? 'transparent' : undefined,
|
||||
// To be replaced with it's own option persited option instead derived
|
||||
hoverHeader: !panel.title && !panel.timeFrom && !panel.timeShift,
|
||||
$data: createPanelDataProvider(panel),
|
||||
menu: new VizPanelMenu({
|
||||
$behaviors: [panelMenuBehavior],
|
||||
}),
|
||||
}),
|
||||
body: new VizPanel(vizPanelState),
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,44 @@
|
||||
import { SceneGridItem } from '@grafana/scenes';
|
||||
import { Panel } from '@grafana/schema';
|
||||
import { PanelModel } from 'app/features/dashboard/state';
|
||||
|
||||
import dashboard_to_load1 from './testfiles/dashboard_to_load1.json';
|
||||
import { transformSaveModelToScene } from './transformSaveModelToScene';
|
||||
import { transformSceneToSaveModel } from './transformSceneToSaveModel';
|
||||
import { buildSceneFromPanelModel, transformSaveModelToScene } from './transformSaveModelToScene';
|
||||
import { gridItemToPanel, transformSceneToSaveModel } from './transformSceneToSaveModel';
|
||||
|
||||
describe('transformSceneToSaveModel', () => {
|
||||
describe('Given a scene', () => {
|
||||
it('Should transfrom back to peristed model', () => {
|
||||
it('Should transform back to peristed model', () => {
|
||||
const scene = transformSaveModelToScene({ dashboard: dashboard_to_load1 as any, meta: {} });
|
||||
const saveModel = transformSceneToSaveModel(scene);
|
||||
|
||||
expect(saveModel).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Panel options', () => {
|
||||
it('Given panel with time override', () => {
|
||||
const gridItem = createVizPanelFromPanelSchema({
|
||||
timeFrom: '2h',
|
||||
timeShift: '1d',
|
||||
hideTimeOverride: true,
|
||||
});
|
||||
|
||||
const saveModel = gridItemToPanel(gridItem);
|
||||
expect(saveModel.timeFrom).toBe('2h');
|
||||
expect(saveModel.timeShift).toBe('1d');
|
||||
expect(saveModel.hideTimeOverride).toBe(true);
|
||||
});
|
||||
|
||||
it('transparent panel', () => {
|
||||
const gridItem = createVizPanelFromPanelSchema({ transparent: true });
|
||||
const saveModel = gridItemToPanel(gridItem);
|
||||
|
||||
expect(saveModel.transparent).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
export function createVizPanelFromPanelSchema(panel: Partial<Panel>): SceneGridItem {
|
||||
return buildSceneFromPanelModel(new PanelModel(panel));
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { Dashboard, defaultDashboard, FieldConfigSource, Panel } from '@grafana/
|
||||
import { sortedDeepCloneWithoutNulls } from 'app/core/utils/object';
|
||||
|
||||
import { DashboardScene } from '../scene/DashboardScene';
|
||||
import { PanelTimeRange } from '../scene/PanelTimeRange';
|
||||
import { getPanelIdForVizPanel } from '../utils/utils';
|
||||
|
||||
export function transformSceneToSaveModel(scene: DashboardScene): Dashboard {
|
||||
@ -33,7 +34,7 @@ export function transformSceneToSaveModel(scene: DashboardScene): Dashboard {
|
||||
return sortedDeepCloneWithoutNulls(dashboard);
|
||||
}
|
||||
|
||||
function gridItemToPanel(gridItem: SceneGridItem): Panel {
|
||||
export function gridItemToPanel(gridItem: SceneGridItem): Panel {
|
||||
const vizPanel = gridItem.state.body;
|
||||
if (!(vizPanel instanceof VizPanel)) {
|
||||
throw new Error('SceneGridItem body expected to be VizPanel');
|
||||
@ -55,5 +56,17 @@ function gridItemToPanel(gridItem: SceneGridItem): Panel {
|
||||
transparent: false,
|
||||
};
|
||||
|
||||
const panelTime = vizPanel.state.$timeRange;
|
||||
|
||||
if (panelTime instanceof PanelTimeRange) {
|
||||
panel.timeFrom = panelTime.state.timeFrom;
|
||||
panel.timeShift = panelTime.state.timeShift;
|
||||
panel.hideTimeOverride = panelTime.state.hideTimeOverride;
|
||||
}
|
||||
|
||||
if (vizPanel.state.displayMode === 'transparent') {
|
||||
panel.transparent = true;
|
||||
}
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
10
yarn.lock
10
yarn.lock
@ -3939,9 +3939,9 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@grafana/scenes@npm:^0.26.0":
|
||||
version: 0.26.0
|
||||
resolution: "@grafana/scenes@npm:0.26.0"
|
||||
"@grafana/scenes@npm:^0.27.0":
|
||||
version: 0.27.0
|
||||
resolution: "@grafana/scenes@npm:0.27.0"
|
||||
dependencies:
|
||||
"@grafana/e2e-selectors": 10.0.2
|
||||
react-grid-layout: 1.3.4
|
||||
@ -3953,7 +3953,7 @@ __metadata:
|
||||
"@grafana/runtime": 10.0.3
|
||||
"@grafana/schema": 10.0.3
|
||||
"@grafana/ui": 10.0.3
|
||||
checksum: 041458e463cde07179c75444f245411715ed50f072a5c4d519e258d0e0d57864c55e9cce3fb245943e2bc4245ee48e243701f5f0290c33e0374d4e948820eb14
|
||||
checksum: 71b2ea13c6afca0d8d101e9a7d945ebb181ad2acbeb6fa5ca4018a34332a9b1e09a434feea9080665327d3d30a7e4d2542a7491a2f68a944717d56ba014fba25
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -19259,7 +19259,7 @@ __metadata:
|
||||
"@grafana/lezer-traceql": 0.0.4
|
||||
"@grafana/monaco-logql": ^0.0.7
|
||||
"@grafana/runtime": "workspace:*"
|
||||
"@grafana/scenes": ^0.26.0
|
||||
"@grafana/scenes": ^0.27.0
|
||||
"@grafana/schema": "workspace:*"
|
||||
"@grafana/toolkit": "workspace:*"
|
||||
"@grafana/tsconfig": ^1.3.0-rc1
|
||||
|
Loading…
Reference in New Issue
Block a user