mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Scenes: Be able to show/hide dashboard controls in Kiosk mode (#88920)
This commit is contained in:
parent
7bb883e375
commit
0abe4fc709
@ -2871,6 +2871,9 @@ exports[`better eslint`] = {
|
||||
"public/app/features/dashboard-scene/saving/shared.tsx:5381": [
|
||||
[0, 0, 0, "No untranslated strings. Wrap text with <Trans />", "0"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/scene/DashboardControls.tsx:5381": [
|
||||
[0, 0, 0, "Do not use any type assertions.", "0"]
|
||||
],
|
||||
"public/app/features/dashboard-scene/scene/NavToolbarActions.test.tsx:5381": [
|
||||
[0, 0, 0, "Unexpected any. Specify a different type.", "0"]
|
||||
],
|
||||
|
@ -0,0 +1,159 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { SceneDataLayerControls, SceneVariableSet, TextBoxVariable, VariableValueSelectors } from '@grafana/scenes';
|
||||
|
||||
import { DashboardControls, DashboardControlsState } from './DashboardControls';
|
||||
import { DashboardScene } from './DashboardScene';
|
||||
|
||||
describe('DashboardControls', () => {
|
||||
describe('Given a standard scene', () => {
|
||||
it('should initialize with default values', () => {
|
||||
const scene = buildTestScene();
|
||||
expect(scene.state.variableControls).toEqual([]);
|
||||
expect(scene.state.timePicker).toBeDefined();
|
||||
expect(scene.state.refreshPicker).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return if time controls are hidden', () => {
|
||||
const scene = buildTestScene({ hideTimeControls: false, hideVariableControls: false, hideLinksControls: false });
|
||||
expect(scene.hasControls()).toBeTruthy();
|
||||
scene.setState({ hideTimeControls: true });
|
||||
expect(scene.hasControls()).toBeTruthy();
|
||||
scene.setState({ hideVariableControls: true, hideLinksControls: true });
|
||||
expect(scene.hasControls()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Component', () => {
|
||||
it('should render', () => {
|
||||
const scene = buildTestScene();
|
||||
expect(() => {
|
||||
render(<scene.Component model={scene} />);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should render visible controls', async () => {
|
||||
const scene = buildTestScene({
|
||||
variableControls: [new VariableValueSelectors({}), new SceneDataLayerControls()],
|
||||
});
|
||||
const renderer = render(<scene.Component model={scene} />);
|
||||
|
||||
expect(await renderer.findByTestId(selectors.pages.Dashboard.Controls)).toBeInTheDocument();
|
||||
expect(await renderer.findByTestId(selectors.components.DashboardLinks.container)).toBeInTheDocument();
|
||||
expect(await renderer.findByTestId(selectors.components.TimePicker.openButton)).toBeInTheDocument();
|
||||
expect(await renderer.findByTestId(selectors.components.RefreshPicker.runButtonV2)).toBeInTheDocument();
|
||||
expect(await renderer.findByTestId(selectors.pages.Dashboard.SubMenu.submenuItem)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render with hidden controls', async () => {
|
||||
const scene = buildTestScene({
|
||||
hideTimeControls: true,
|
||||
hideVariableControls: true,
|
||||
hideLinksControls: true,
|
||||
variableControls: [new VariableValueSelectors({}), new SceneDataLayerControls()],
|
||||
});
|
||||
const renderer = render(<scene.Component model={scene} />);
|
||||
|
||||
expect(await renderer.queryByTestId(selectors.pages.Dashboard.Controls)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe('UrlSync', () => {
|
||||
it('should return keys', () => {
|
||||
const scene = buildTestScene();
|
||||
// @ts-expect-error
|
||||
expect(scene._urlSync.getKeys()).toEqual(['_dash.hideTimePicker', '_dash.hideVariables', '_dash.hideLinks']);
|
||||
});
|
||||
|
||||
it('should return url state', () => {
|
||||
const scene = buildTestScene();
|
||||
expect(scene.getUrlState()).toEqual({
|
||||
'_dash.hideTimePicker': undefined,
|
||||
'_dash.hideVariables': undefined,
|
||||
'_dash.hideLinks': undefined,
|
||||
});
|
||||
scene.setState({
|
||||
hideTimeControls: true,
|
||||
hideVariableControls: true,
|
||||
hideLinksControls: true,
|
||||
});
|
||||
expect(scene.getUrlState()).toEqual({
|
||||
'_dash.hideTimePicker': 'true',
|
||||
'_dash.hideVariables': 'true',
|
||||
'_dash.hideLinks': 'true',
|
||||
});
|
||||
});
|
||||
|
||||
it('should update from url', () => {
|
||||
const scene = buildTestScene();
|
||||
scene.updateFromUrl({
|
||||
'_dash.hideTimePicker': 'true',
|
||||
'_dash.hideVariables': 'true',
|
||||
'_dash.hideLinks': 'true',
|
||||
});
|
||||
expect(scene.state.hideTimeControls).toBeTruthy();
|
||||
expect(scene.state.hideVariableControls).toBeTruthy();
|
||||
expect(scene.state.hideLinksControls).toBeTruthy();
|
||||
scene.updateFromUrl({
|
||||
'_dash.hideTimePicker': '',
|
||||
'_dash.hideVariables': '',
|
||||
'_dash.hideLinks': '',
|
||||
});
|
||||
expect(scene.state.hideTimeControls).toBeTruthy();
|
||||
expect(scene.state.hideVariableControls).toBeTruthy();
|
||||
expect(scene.state.hideLinksControls).toBeTruthy();
|
||||
scene.updateFromUrl({});
|
||||
expect(scene.state.hideTimeControls).toBeFalsy();
|
||||
expect(scene.state.hideVariableControls).toBeFalsy();
|
||||
expect(scene.state.hideLinksControls).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should not call setState if no changes', () => {
|
||||
const scene = buildTestScene();
|
||||
const setState = jest.spyOn(scene, 'setState');
|
||||
scene.updateFromUrl({});
|
||||
scene.updateFromUrl({});
|
||||
expect(setState).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function buildTestScene(state?: Partial<DashboardControlsState>): DashboardControls {
|
||||
const variable = new TextBoxVariable({
|
||||
name: 'A',
|
||||
label: 'A',
|
||||
description: 'A',
|
||||
type: 'textbox',
|
||||
value: 'Text',
|
||||
});
|
||||
const dashboard = new DashboardScene({
|
||||
uid: 'A',
|
||||
links: [
|
||||
{
|
||||
title: 'Link',
|
||||
url: 'http://localhost:3000/$A',
|
||||
type: 'link',
|
||||
asDropdown: false,
|
||||
icon: '',
|
||||
includeVars: true,
|
||||
keepTime: true,
|
||||
tags: [],
|
||||
targetBlank: false,
|
||||
tooltip: 'Link',
|
||||
},
|
||||
],
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [variable],
|
||||
}),
|
||||
controls: new DashboardControls({
|
||||
...state,
|
||||
}),
|
||||
});
|
||||
|
||||
dashboard.activate();
|
||||
variable.activate();
|
||||
|
||||
return dashboard.state.controls as DashboardControls;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import React from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { GrafanaTheme2, VariableHide } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import {
|
||||
SceneObjectState,
|
||||
@ -12,6 +12,9 @@ import {
|
||||
SceneRefreshPicker,
|
||||
SceneDebugger,
|
||||
VariableDependencyConfig,
|
||||
sceneGraph,
|
||||
SceneObjectUrlSyncConfig,
|
||||
SceneObjectUrlValues,
|
||||
} from '@grafana/scenes';
|
||||
import { Box, Stack, useStyles2 } from '@grafana/ui';
|
||||
|
||||
@ -20,12 +23,15 @@ import { getDashboardSceneFor } from '../utils/utils';
|
||||
|
||||
import { DashboardLinksControls } from './DashboardLinksControls';
|
||||
|
||||
interface DashboardControlsState extends SceneObjectState {
|
||||
export interface DashboardControlsState extends SceneObjectState {
|
||||
variableControls: SceneObject[];
|
||||
timePicker: SceneTimePicker;
|
||||
refreshPicker: SceneRefreshPicker;
|
||||
hideTimeControls?: boolean;
|
||||
hideVariableControls?: boolean;
|
||||
hideLinksControls?: boolean;
|
||||
}
|
||||
|
||||
export class DashboardControls extends SceneObjectBase<DashboardControlsState> {
|
||||
static Component = DashboardControlsRenderer;
|
||||
|
||||
@ -33,6 +39,30 @@ export class DashboardControls extends SceneObjectBase<DashboardControlsState> {
|
||||
onAnyVariableChanged: this._onAnyVariableChanged.bind(this),
|
||||
});
|
||||
|
||||
protected _urlSync = new SceneObjectUrlSyncConfig(this, {
|
||||
keys: ['_dash.hideTimePicker', '_dash.hideVariables', '_dash.hideLinks'],
|
||||
});
|
||||
|
||||
getUrlState() {
|
||||
return {
|
||||
'_dash.hideTimePicker': this.state.hideTimeControls ? 'true' : undefined,
|
||||
'_dash.hideVariables': this.state.hideVariableControls ? 'true' : undefined,
|
||||
'_dash.hideLinks': this.state.hideLinksControls ? 'true' : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
updateFromUrl(values: SceneObjectUrlValues) {
|
||||
const update: Partial<DashboardControlsState> = {};
|
||||
|
||||
update.hideTimeControls = values['_dash.hideTimePicker'] === 'true' || values['_dash.hideTimePicker'] === '';
|
||||
update.hideVariableControls = values['_dash.hideVariables'] === 'true' || values['_dash.hideVariables'] === '';
|
||||
update.hideLinksControls = values['_dash.hideLinks'] === 'true' || values['_dash.hideLinks'] === '';
|
||||
|
||||
if (Object.entries(update).some(([k, v]) => v !== this.state[k as keyof DashboardControlsState])) {
|
||||
this.setState(update);
|
||||
}
|
||||
}
|
||||
|
||||
public constructor(state: Partial<DashboardControlsState>) {
|
||||
super({
|
||||
variableControls: [],
|
||||
@ -51,26 +81,42 @@ export class DashboardControls extends SceneObjectBase<DashboardControlsState> {
|
||||
this.forceRender();
|
||||
}
|
||||
}
|
||||
|
||||
public hasControls(): boolean {
|
||||
const hasVariables = sceneGraph
|
||||
.getVariables(this)
|
||||
?.state.variables.some((v) => v.state.hide !== VariableHide.hideVariable);
|
||||
const hasAnnotations = sceneGraph.getDataLayers(this).some((d) => d.state.isEnabled && !d.state.isHidden);
|
||||
const hasLinks = getDashboardSceneFor(this).state.links?.length > 0;
|
||||
const hideLinks = this.state.hideLinksControls || !hasLinks;
|
||||
const hideVariables = this.state.hideVariableControls || (!hasAnnotations && !hasVariables);
|
||||
const hideTimePicker = this.state.hideTimeControls;
|
||||
|
||||
return !(hideVariables && hideLinks && hideTimePicker);
|
||||
}
|
||||
}
|
||||
|
||||
function DashboardControlsRenderer({ model }: SceneComponentProps<DashboardControls>) {
|
||||
const { variableControls, refreshPicker, timePicker, hideTimeControls } = model.useState();
|
||||
const { variableControls, refreshPicker, timePicker, hideTimeControls, hideVariableControls, hideLinksControls } =
|
||||
model.useState();
|
||||
const dashboard = getDashboardSceneFor(model);
|
||||
const { links, meta, editPanel } = dashboard.useState();
|
||||
const styles = useStyles2(getStyles);
|
||||
const showDebugger = location.search.includes('scene-debugger');
|
||||
|
||||
if (!model.hasControls()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
data-testid={selectors.pages.Dashboard.Controls}
|
||||
className={cx(styles.controls, meta.isEmbedded && styles.embedded)}
|
||||
>
|
||||
<Stack grow={1} wrap={'wrap'}>
|
||||
{variableControls.map((c) => (
|
||||
<c.Component model={c} key={c.state.key} />
|
||||
))}
|
||||
{!hideVariableControls && variableControls.map((c) => <c.Component model={c} key={c.state.key} />)}
|
||||
<Box grow={1} />
|
||||
{!editPanel && <DashboardLinksControls links={links} uid={dashboard.state.uid} />}
|
||||
{!hideLinksControls && !editPanel && <DashboardLinksControls links={links} uid={dashboard.state.uid} />}
|
||||
{editPanel && <PanelEditControls panelEditor={editPanel} />}
|
||||
</Stack>
|
||||
{!hideTimeControls && (
|
||||
|
@ -35,7 +35,7 @@ import { DashboardModel, PanelModel } from 'app/features/dashboard/state';
|
||||
import { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher';
|
||||
import { deleteDashboard } from 'app/features/manage-dashboards/state/actions';
|
||||
import { VariablesChanged } from 'app/features/variables/types';
|
||||
import { DashboardDTO, DashboardMeta, SaveDashboardResponseDTO } from 'app/types';
|
||||
import { DashboardDTO, DashboardMeta, KioskMode, SaveDashboardResponseDTO } from 'app/types';
|
||||
import { ShowConfirmModalEvent } from 'app/types/events';
|
||||
|
||||
import { PanelEditor } from '../panel-edit/PanelEditor';
|
||||
@ -125,6 +125,8 @@ export interface DashboardSceneState extends SceneObjectState {
|
||||
isEmpty?: boolean;
|
||||
/** Scene object that handles the scopes selector */
|
||||
scopes?: ScopesScene;
|
||||
/** Kiosk mode */
|
||||
kioskMode?: KioskMode;
|
||||
}
|
||||
|
||||
export class DashboardScene extends SceneObjectBase<DashboardSceneState> {
|
||||
|
@ -24,6 +24,7 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
|
||||
const bodyToRender = model.getBodyToRender();
|
||||
const navModel = getNavModel(navIndex, 'dashboards/browse');
|
||||
const isHomePage = !meta.url && !meta.slug && !meta.isNew && !meta.isSnapshot;
|
||||
const hasControls = controls?.hasControls();
|
||||
|
||||
if (editview) {
|
||||
return (
|
||||
@ -37,7 +38,7 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
|
||||
const emptyState = <DashboardEmpty dashboard={model} canCreate={!!model.state.meta.canEdit} />;
|
||||
|
||||
const withPanels = (
|
||||
<div className={cx(styles.body)}>
|
||||
<div className={cx(styles.body, !hasControls && styles.bodyWithoutControls)}>
|
||||
<bodyToRender.Component model={bodyToRender} />
|
||||
</div>
|
||||
);
|
||||
@ -49,14 +50,14 @@ export function DashboardSceneRenderer({ model }: SceneComponentProps<DashboardS
|
||||
<div
|
||||
className={cx(
|
||||
styles.pageContainer,
|
||||
controls && !scopes && styles.pageContainerWithControls,
|
||||
hasControls && !scopes && styles.pageContainerWithControls,
|
||||
scopes && styles.pageContainerWithScopes,
|
||||
scopes && isScopesExpanded && styles.pageContainerWithScopesExpanded
|
||||
)}
|
||||
>
|
||||
{scopes && <scopes.Component model={scopes} />}
|
||||
<NavToolbarActions dashboard={model} />
|
||||
{!isHomePage && controls && (
|
||||
{!isHomePage && controls && hasControls && (
|
||||
<div
|
||||
className={cx(styles.controlsWrapper, scopes && !isScopesExpanded && styles.controlsWrapperWithScopes)}
|
||||
>
|
||||
@ -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),
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
@ -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', () => {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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 {
|
||||
|
@ -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<PlaylistMode>(false);
|
||||
const [autoFit, setAutofit] = useState(false);
|
||||
const [displayTimePicker, setDisplayTimePicker] = useState(true);
|
||||
const [displayVariables, setDisplayVariables] = useState(true);
|
||||
const [displayLinks, setDisplayLinks] = useState(true);
|
||||
|
||||
const modes: Array<SelectableValue<PlaylistMode>> = [
|
||||
{ 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) => {
|
||||
<Field label="Mode">
|
||||
<RadioButtonGroup value={mode} options={modes} onChange={setMode} />
|
||||
</Field>
|
||||
<Checkbox
|
||||
label="Autofit"
|
||||
description="Panel heights will be adjusted to fit screen size"
|
||||
name="autofix"
|
||||
value={autoFit}
|
||||
onChange={(e) => setAutofit(e.currentTarget.checked)}
|
||||
/>
|
||||
<Field>
|
||||
<Checkbox
|
||||
label="Autofit"
|
||||
description="Panel heights will be adjusted to fit screen size"
|
||||
name="autofix"
|
||||
value={autoFit}
|
||||
onChange={(e) => setAutofit(e.currentTarget.checked)}
|
||||
/>
|
||||
</Field>
|
||||
{config.featureToggles.dashboardScene && (
|
||||
<Field label="Display dashboard controls" description="Customize dashboard elements visibility">
|
||||
<Box marginTop={2} marginBottom={2}>
|
||||
<Stack direction="column" alignItems="start" justifyContent="left" gap={2}>
|
||||
<Checkbox
|
||||
label="Time and refresh"
|
||||
name="displayTimePicker"
|
||||
value={displayTimePicker}
|
||||
onChange={(e) => setDisplayTimePicker(e.currentTarget.checked)}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Variables"
|
||||
name="displayVariableControls"
|
||||
value={displayVariables}
|
||||
onChange={(e) => setDisplayVariables(e.currentTarget.checked)}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Dashboard links"
|
||||
name="displayLinks"
|
||||
value={displayLinks}
|
||||
onChange={(e) => setDisplayLinks(e.currentTarget.checked)}
|
||||
/>
|
||||
</Stack>
|
||||
</Box>
|
||||
</Field>
|
||||
)}
|
||||
</FieldSet>
|
||||
<Modal.ButtonRow>
|
||||
<Button variant="primary" onClick={onStart}>
|
||||
|
Loading…
Reference in New Issue
Block a user