@@ -119,6 +120,9 @@ function getStyles(theme: GrafanaTheme2) {
flexGrow: 0,
gridArea: 'controls',
padding: theme.spacing(2),
+ ':empty': {
+ display: 'none',
+ },
}),
controlsWrapperWithScopes: css({
padding: theme.spacing(2, 2, 2, 0),
@@ -139,7 +143,11 @@ function getStyles(theme: GrafanaTheme2) {
flexGrow: 1,
display: 'flex',
gap: '8px',
- marginBottom: theme.spacing(2),
+ paddingBottom: theme.spacing(2),
+ boxSizing: 'border-box',
+ }),
+ bodyWithoutControls: css({
+ paddingTop: theme.spacing(2),
}),
};
}
diff --git a/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.test.ts b/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.test.ts
index 984b7c488b0..c1a7172044f 100644
--- a/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.test.ts
+++ b/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.test.ts
@@ -1,6 +1,7 @@
import { AppEvents } from '@grafana/data';
import { SceneGridLayout, SceneQueryRunner, VizPanel } from '@grafana/scenes';
import appEvents from 'app/core/app_events';
+import { KioskMode } from 'app/types';
import { DashboardGridItem } from './DashboardGridItem';
import { DashboardScene } from './DashboardScene';
@@ -39,6 +40,29 @@ describe('DashboardSceneUrlSync', () => {
(scene.state.body as SceneGridLayout).setState({ UNSAFE_fitPanels: true });
expect(scene.urlSync?.getUrlState().autofitpanels).toBe('true');
});
+
+ it('Should set kiosk mode when url has kiosk', () => {
+ const scene = buildTestScene();
+
+ scene.urlSync?.updateFromUrl({ kiosk: 'invalid' });
+ expect(scene.state.kioskMode).toBe(undefined);
+ scene.urlSync?.updateFromUrl({ kiosk: '' });
+ expect(scene.state.kioskMode).toBe(KioskMode.Full);
+ scene.urlSync?.updateFromUrl({ kiosk: 'tv' });
+ expect(scene.state.kioskMode).toBe(KioskMode.TV);
+ scene.urlSync?.updateFromUrl({ kiosk: 'true' });
+ expect(scene.state.kioskMode).toBe(KioskMode.Full);
+ });
+
+ it('Should get the kiosk mode from the scene state', () => {
+ const scene = buildTestScene();
+
+ expect(scene.urlSync?.getUrlState().kiosk).toBe(undefined);
+ scene.setState({ kioskMode: KioskMode.TV });
+ expect(scene.urlSync?.getUrlState().kiosk).toBe(KioskMode.TV);
+ scene.setState({ kioskMode: KioskMode.Full });
+ expect(scene.urlSync?.getUrlState().kiosk).toBe('');
+ });
});
describe('entering edit mode', () => {
diff --git a/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts b/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts
index 49fbd51be06..fb891974cfe 100644
--- a/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts
+++ b/public/app/features/dashboard-scene/scene/DashboardSceneUrlSync.ts
@@ -11,6 +11,7 @@ import {
VizPanel,
} from '@grafana/scenes';
import appEvents from 'app/core/app_events';
+import { KioskMode } from 'app/types';
import { PanelInspectDrawer } from '../inspect/PanelInspectDrawer';
import { buildPanelEditScene } from '../panel-edit/PanelEditor';
@@ -28,7 +29,7 @@ export class DashboardSceneUrlSync implements SceneObjectUrlSyncHandler {
constructor(private _scene: DashboardScene) {}
getKeys(): string[] {
- return ['inspect', 'viewPanel', 'editPanel', 'editview', 'autofitpanels'];
+ return ['inspect', 'viewPanel', 'editPanel', 'editview', 'autofitpanels', 'kiosk'];
}
getUrlState(): SceneObjectUrlValues {
@@ -39,6 +40,7 @@ export class DashboardSceneUrlSync implements SceneObjectUrlSyncHandler {
viewPanel: state.viewPanelScene?.getUrlKey(),
editview: state.editview?.getUrlKey(),
editPanel: state.editPanel?.getUrlKey() || undefined,
+ kiosk: state.kioskMode === KioskMode.Full ? '' : state.kioskMode === KioskMode.TV ? 'tv' : undefined,
};
}
@@ -159,6 +161,14 @@ export class DashboardSceneUrlSync implements SceneObjectUrlSyncHandler {
}
}
+ if (typeof values.kiosk === 'string') {
+ if (values.kiosk === 'true' || values.kiosk === '') {
+ update.kioskMode = KioskMode.Full;
+ } else if (values.kiosk === 'tv') {
+ update.kioskMode = KioskMode.TV;
+ }
+ }
+
if (Object.keys(update).length > 0) {
this._scene.setState(update);
}
diff --git a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts
index c6c0b3941a9..e633b7fb0ce 100644
--- a/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts
+++ b/public/app/features/dashboard-scene/serialization/transformSceneToSaveModel.ts
@@ -346,7 +346,6 @@ export function panelRepeaterToPanels(
return [libraryVizPanelToPanel(repeater.state.body, { x, y, w, h })];
}
- // console.log('repeater.state', repeater.state);
if (repeater.state.repeatedPanels) {
const itemHeight = repeater.state.itemHeight ?? 10;
const rowCount = Math.ceil(repeater.state.repeatedPanels!.length / repeater.getMaxPerRow());
diff --git a/public/app/features/playlist/PlaylistSrv.ts b/public/app/features/playlist/PlaylistSrv.ts
index 8fd715dd8f4..c193de2a032 100644
--- a/public/app/features/playlist/PlaylistSrv.ts
+++ b/public/app/features/playlist/PlaylistSrv.ts
@@ -12,6 +12,9 @@ export const queryParamsToPreserve: { [key: string]: boolean } = {
kiosk: true,
autofitpanels: true,
orgId: true,
+ '_dash.hideTimePicker': true,
+ '_dash.hideVariables': true,
+ '_dash.hideLinks': true,
};
export interface PlaylistSrvState {
diff --git a/public/app/features/playlist/StartModal.tsx b/public/app/features/playlist/StartModal.tsx
index 01d63469b58..ba88d771026 100644
--- a/public/app/features/playlist/StartModal.tsx
+++ b/public/app/features/playlist/StartModal.tsx
@@ -1,8 +1,8 @@
import React, { useState } from 'react';
import { SelectableValue, UrlQueryMap, urlUtil } from '@grafana/data';
-import { locationService } from '@grafana/runtime';
-import { Button, Checkbox, Field, FieldSet, Modal, RadioButtonGroup } from '@grafana/ui';
+import { config, locationService } from '@grafana/runtime';
+import { Box, Button, Checkbox, Field, FieldSet, Modal, RadioButtonGroup, Stack } from '@grafana/ui';
import { Playlist, PlaylistMode } from './types';
@@ -14,6 +14,9 @@ export interface Props {
export const StartModal = ({ playlist, onDismiss }: Props) => {
const [mode, setMode] = useState
(false);
const [autoFit, setAutofit] = useState(false);
+ const [displayTimePicker, setDisplayTimePicker] = useState(true);
+ const [displayVariables, setDisplayVariables] = useState(true);
+ const [displayLinks, setDisplayLinks] = useState(true);
const modes: Array> = [
{ label: 'Normal', value: false },
@@ -29,6 +32,17 @@ export const StartModal = ({ playlist, onDismiss }: Props) => {
if (autoFit) {
params.autofitpanels = true;
}
+
+ if (!displayTimePicker) {
+ params['_dash.hideTimePicker'] = true;
+ }
+ if (!displayVariables) {
+ params['_dash.hideVariables'] = true;
+ }
+ if (!displayLinks) {
+ params['_dash.hideLinks'] = true;
+ }
+
locationService.push(urlUtil.renderUrl(`/playlists/play/${playlist.uid}`, params));
};
@@ -38,13 +52,41 @@ export const StartModal = ({ playlist, onDismiss }: Props) => {
- setAutofit(e.currentTarget.checked)}
- />
+
+ setAutofit(e.currentTarget.checked)}
+ />
+
+ {config.featureToggles.dashboardScene && (
+
+
+
+ setDisplayTimePicker(e.currentTarget.checked)}
+ />
+ setDisplayVariables(e.currentTarget.checked)}
+ />
+ setDisplayLinks(e.currentTarget.checked)}
+ />
+
+
+
+ )}