diff --git a/kinds/dashboard/dashboard_kind.cue b/kinds/dashboard/dashboard_kind.cue
index 04e9d4f1322..58ae9457718 100644
--- a/kinds/dashboard/dashboard_kind.cue
+++ b/kinds/dashboard/dashboard_kind.cue
@@ -99,6 +99,9 @@ lineage: schemas: [{
// Snapshot options. They are present only if the dashboard is a snapshot.
snapshot?: #Snapshot @grafanamaturity(NeedsExpertReview)
+
+ // When set to true, the dashboard will load all panels in the dashboard when it's loaded.
+ preload?: bool
} @cuetsy(kind="interface") @grafana(TSVeneer="type")
///////////////////////////////////////
diff --git a/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts b/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts
index 46e58446be2..784b96494f4 100644
--- a/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts
+++ b/packages/grafana-schema/src/raw/dashboard/x/dashboard_types.gen.ts
@@ -1062,6 +1062,10 @@ export interface Dashboard {
* List of dashboard panels
*/
panels?: Array<(Panel | RowPanel)>;
+ /**
+ * When set to true, the dashboard will load all panels in the dashboard when it's loaded.
+ */
+ preload?: boolean;
/**
* Refresh rate of dashboard. Represented via interval string, e.g. "5s", "1m", "1h", "1d".
*/
diff --git a/pkg/kinds/dashboard/dashboard_spec_gen.go b/pkg/kinds/dashboard/dashboard_spec_gen.go
index ab33a177135..889dd767c9b 100644
--- a/pkg/kinds/dashboard/dashboard_spec_gen.go
+++ b/pkg/kinds/dashboard/dashboard_spec_gen.go
@@ -753,6 +753,9 @@ type Spec struct {
// List of dashboard panels
Panels []any `json:"panels,omitempty"`
+ // When set to true, the dashboard will load all panels in the dashboard when it's loaded.
+ Preload *bool `json:"preload,omitempty"`
+
// Refresh rate of dashboard. Represented via interval string, e.g. "5s", "1m", "1h", "1d".
Refresh *string `json:"refresh,omitempty"`
diff --git a/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts b/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts
index b55f281e4a8..201773bd2f6 100644
--- a/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts
+++ b/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts
@@ -322,40 +322,57 @@ export function getDashboardScenePageStateManager(): DashboardScenePageStateMana
}
function getErrorScene(msg: string) {
- return createDashboardSceneFromDashboardModel(
- new DashboardModel(
- {
- ...defaultDashboard,
- title: msg,
- panels: [
+ const dto: DashboardDTO = {
+ dashboard: {
+ ...defaultDashboard,
+ uid: 'error-dash',
+ title: msg,
+ annotations: {
+ list: [
{
- fieldConfig: {
- defaults: {},
- overrides: [],
+ builtIn: 1,
+ datasource: {
+ type: 'grafana',
+ uid: '-- Grafana --',
},
- gridPos: {
- h: 6,
- w: 12,
- x: 7,
- y: 0,
- },
- id: 1,
- options: {
- code: {
- language: 'plaintext',
- showLineNumbers: false,
- showMiniMap: false,
- },
- content: `
${msg}
`,
- mode: 'html',
- },
- title: '',
- transparent: true,
- type: 'text',
+ enable: false,
+ hide: true,
+ iconColor: 'rgba(0, 211, 255, 1)',
+ name: 'Annotations & Alerts',
+ type: 'dashboard',
},
],
},
- { canSave: false, canEdit: false }
- )
- );
+
+ panels: [
+ {
+ fieldConfig: {
+ defaults: {},
+ overrides: [],
+ },
+ gridPos: {
+ h: 6,
+ w: 12,
+ x: 7,
+ y: 0,
+ },
+ id: 1,
+ options: {
+ code: {
+ language: 'plaintext',
+ showLineNumbers: false,
+ showMiniMap: false,
+ },
+ content: `
${msg}
`,
+ mode: 'html',
+ },
+ title: '',
+ transparent: true,
+ type: 'text',
+ },
+ ],
+ },
+ meta: { canSave: false, canEdit: false },
+ };
+ return createDashboardSceneFromDashboardModel(new DashboardModel(dto.dashboard, dto.meta), dto.dashboard);
}
diff --git a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx
index e5fabb7f09d..1726c669031 100644
--- a/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx
+++ b/public/app/features/dashboard-scene/panel-edit/PanelDataPane/PanelDataAlertingTab.test.tsx
@@ -28,7 +28,7 @@ import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import { configureStore } from 'app/store/configureStore';
-import { AccessControlAction } from 'app/types';
+import { AccessControlAction, DashboardDataDTO } from 'app/types';
import { AlertQuery, PromRulesResponse } from 'app/types/unified-alerting-dto';
import { createDashboardSceneFromDashboardModel } from '../../serialization/transformSaveModelToScene';
@@ -359,7 +359,7 @@ async function clickNewButton() {
}
function createModel(dashboard: DashboardModel) {
- const scene = createDashboardSceneFromDashboardModel(dashboard);
+ const scene = createDashboardSceneFromDashboardModel(dashboard, {} as DashboardDataDTO);
const vizPanel = findVizPanelByKey(scene, getVizPanelKeyForPanelId(34))!;
const model = new PanelDataAlertingTab(VizPanelManager.createFor(vizPanel));
jest.spyOn(utils, 'getDashboardSceneFor').mockReturnValue(scene);
diff --git a/public/app/features/dashboard-scene/scene/DashboardScene.tsx b/public/app/features/dashboard-scene/scene/DashboardScene.tsx
index 2b04bec57de..8c84394c5eb 100644
--- a/public/app/features/dashboard-scene/scene/DashboardScene.tsx
+++ b/public/app/features/dashboard-scene/scene/DashboardScene.tsx
@@ -78,7 +78,7 @@ import { ScopesScene } from './Scopes/ScopesScene';
import { ViewPanelScene } from './ViewPanelScene';
import { setupKeyboardShortcuts } from './keyboardShortcuts';
-export const PERSISTED_PROPS = ['title', 'description', 'tags', 'editable', 'graphTooltip', 'links', 'meta'];
+export const PERSISTED_PROPS = ['title', 'description', 'tags', 'editable', 'graphTooltip', 'links', 'meta', 'preload'];
export interface DashboardSceneState extends SceneObjectState {
/** The title */
@@ -91,6 +91,8 @@ export interface DashboardSceneState extends SceneObjectState {
links: DashboardLink[];
/** Is editable */
editable?: boolean;
+ /** Allows disabling grid lazy loading */
+ preload?: boolean;
/** A uid when saved */
uid?: string;
/** @deprecated */
diff --git a/public/app/features/dashboard-scene/serialization/__snapshots__/transformSceneToSaveModel.test.ts.snap b/public/app/features/dashboard-scene/serialization/__snapshots__/transformSceneToSaveModel.test.ts.snap
index 48a27c18ea2..9b5c0a119ae 100644
--- a/public/app/features/dashboard-scene/serialization/__snapshots__/transformSceneToSaveModel.test.ts.snap
+++ b/public/app/features/dashboard-scene/serialization/__snapshots__/transformSceneToSaveModel.test.ts.snap
@@ -278,6 +278,7 @@ exports[`transformSceneToSaveModel Given a scene with rows Should transform back
"type": "row",
},
],
+ "preload": false,
"refresh": "",
"schemaVersion": 39,
"tags": [
@@ -545,6 +546,7 @@ exports[`transformSceneToSaveModel Given a simple scene with custom settings Sho
"type": "text",
},
],
+ "preload": false,
"refresh": "5m",
"schemaVersion": 39,
"tags": [
@@ -902,6 +904,7 @@ exports[`transformSceneToSaveModel Given a simple scene with variables Should tr
"type": "text",
},
],
+ "preload": false,
"refresh": "",
"schemaVersion": 39,
"tags": [
diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts
index 444676ca936..ea3e0c936f5 100644
--- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts
+++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.test.ts
@@ -111,7 +111,7 @@ describe('transformSaveModelToScene', () => {
};
const oldModel = new DashboardModel(dash);
- const scene = createDashboardSceneFromDashboardModel(oldModel);
+ const scene = createDashboardSceneFromDashboardModel(oldModel, dash);
const dashboardControls = scene.state.controls!;
expect(scene.state.title).toBe('test');
@@ -138,11 +138,13 @@ describe('transformSaveModelToScene', () => {
it('should apply cursor sync behavior', () => {
const dash = {
...defaultDashboard,
+ title: 'Test dashboard',
+ uid: 'test-uid',
graphTooltip: DashboardCursorSync.Crosshair,
};
const oldModel = new DashboardModel(dash);
- const scene = createDashboardSceneFromDashboardModel(oldModel);
+ const scene = createDashboardSceneFromDashboardModel(oldModel, dash);
const cursorSync = scene.state.$behaviors?.find((b) => b instanceof behaviors.CursorSync);
expect(cursorSync).toBeInstanceOf(behaviors.CursorSync);
@@ -150,8 +152,13 @@ describe('transformSaveModelToScene', () => {
});
it('should apply live now timer behavior', () => {
- const oldModel = new DashboardModel(defaultDashboard);
- const scene = createDashboardSceneFromDashboardModel(oldModel);
+ const dash = {
+ ...defaultDashboard,
+ title: 'Test dashboard',
+ uid: 'test-uid',
+ };
+ const oldModel = new DashboardModel(dash);
+ const scene = createDashboardSceneFromDashboardModel(oldModel, dash);
const liveNowTimer = scene.state.$behaviors?.find((b) => b instanceof behaviors.LiveNowTimer);
expect(liveNowTimer).toBeInstanceOf(behaviors.LiveNowTimer);
@@ -172,7 +179,7 @@ describe('transformSaveModelToScene', () => {
};
const oldModel = new DashboardModel(dash);
- const scene = createDashboardSceneFromDashboardModel(oldModel);
+ const scene = createDashboardSceneFromDashboardModel(oldModel, dash);
expect(scene.state.$variables?.state.variables).toBeDefined();
});
});
@@ -212,12 +219,14 @@ describe('transformSaveModelToScene', () => {
const dashboard = {
...defaultDashboard,
+ title: 'Test dashboard',
+ uid: 'test-uid',
panels: [row],
};
const oldModel = new DashboardModel(dashboard);
- const scene = createDashboardSceneFromDashboardModel(oldModel);
+ const scene = createDashboardSceneFromDashboardModel(oldModel, dashboard);
const body = scene.state.body as SceneGridLayout;
expect(body.state.children).toHaveLength(1);
@@ -304,12 +313,14 @@ describe('transformSaveModelToScene', () => {
const dashboard = {
...defaultDashboard,
+ title: 'Test dashboard',
+ uid: 'test-uid',
panels: [panelOutOfRow, libPanelOutOfRow, rowWithPanel, panelInRow, libPanelInRow, emptyRow],
};
const oldModel = new DashboardModel(dashboard);
- const scene = createDashboardSceneFromDashboardModel(oldModel);
+ const scene = createDashboardSceneFromDashboardModel(oldModel, dashboard);
const body = scene.state.body as SceneGridLayout;
expect(body.state.children).toHaveLength(4);
diff --git a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
index 2d76314a1cb..1e11bc51bde 100644
--- a/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
+++ b/public/app/features/dashboard-scene/serialization/transformSaveModelToScene.ts
@@ -30,7 +30,7 @@ import {
AdHocFiltersVariable,
} from '@grafana/scenes';
import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
-import { DashboardDTO } from 'app/types';
+import { DashboardDTO, DashboardDataDTO } from 'app/types';
import { AlertStatesDataLayer } from '../scene/AlertStatesDataLayer';
import { DashboardAnnotationsDataLayer } from '../scene/DashboardAnnotationsDataLayer';
@@ -74,7 +74,7 @@ export function transformSaveModelToScene(rsp: DashboardDTO): DashboardScene {
// Just to have migrations run
const oldModel = new DashboardModel(rsp.dashboard, rsp.meta);
- const scene = createDashboardSceneFromDashboardModel(oldModel);
+ const scene = createDashboardSceneFromDashboardModel(oldModel, rsp.dashboard);
// TODO: refactor createDashboardSceneFromDashboardModel to work on Dashboard schema model
scene.setInitialSaveModel(rsp.dashboard);
@@ -190,7 +190,7 @@ function createRowFromPanelModel(row: PanelModel, content: SceneGridItemLike[]):
});
}
-export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel) {
+export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel, dto: DashboardDataDTO) {
let variables: SceneVariableSet | undefined;
let annotationLayers: SceneDataLayerProvider[] = [];
let alertStatesLayer: AlertStatesDataLayer | undefined;
@@ -249,6 +249,7 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel)
const dashboardScene = new DashboardScene({
description: oldModel.description,
editable: oldModel.editable,
+ preload: dto.preload ?? false,
id: oldModel.id,
isDirty: false,
links: oldModel.links || [],
@@ -258,7 +259,7 @@ export function createDashboardSceneFromDashboardModel(oldModel: DashboardModel)
uid: oldModel.uid,
version: oldModel.version,
body: new SceneGridLayout({
- isLazy: true,
+ isLazy: dto.preload ? false : true,
children: createSceneObjectsForPanels(oldModel.panels),
$behaviors: [trackIfEmpty],
}),
diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts
index e633b7fb0ce..d6bba6aa82f 100644
--- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts
+++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts
@@ -112,6 +112,7 @@ export function transformSceneToSaveModel(scene: DashboardScene, isSnapshot = fa
uid: state.uid,
id: state.id,
editable: state.editable,
+ preload: state.preload,
time: {
from: timeRange.from,
to: timeRange.to,
diff --git a/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx b/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx
index fafe32472c7..73b1d8cdceb 100644
--- a/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx
+++ b/public/app/features/dashboard-scene/settings/GeneralSettingsEditView.tsx
@@ -12,6 +12,7 @@ import {
Label,
RadioButtonGroup,
Stack,
+ Switch,
TagsInput,
TextArea,
} from '@grafana/ui';
@@ -161,6 +162,10 @@ export class GeneralSettingsEditView
this.getCursorSync()?.setState({ sync: value });
};
+ public onPreloadChange = (preload: boolean) => {
+ this._dashboard.setState({ preload });
+ };
+
public onDeleteDashboard = () => {};
static Component = ({ model }: SceneComponentProps) => {
@@ -271,6 +276,20 @@ export class GeneralSettingsEditView
>
+
+
+ model.onPreloadChange(e.currentTarget.checked)}
+ />
+
{meta.canDelete && }
diff --git a/public/app/features/dashboard/components/HelpWizard/SupportSnapshotService.ts b/public/app/features/dashboard/components/HelpWizard/SupportSnapshotService.ts
index 0a1f9b39f2c..e9f68ad556d 100644
--- a/public/app/features/dashboard/components/HelpWizard/SupportSnapshotService.ts
+++ b/public/app/features/dashboard/components/HelpWizard/SupportSnapshotService.ts
@@ -83,7 +83,7 @@ export class SupportSnapshotService extends StateManagerBase