Dashboard Controls: Make it possible to hide dashboard controls from the URL (#111001)
* feat: make it possible to hide dashboard-controls from the URL * tests: update tests with the new url query param
This commit is contained in:
@@ -14,17 +14,56 @@ describe('DashboardControls', () => {
|
||||
expect(scene.state.refreshPicker).toBeDefined();
|
||||
});
|
||||
|
||||
it('should return if time controls are hidden', () => {
|
||||
const scene = buildTestScene({
|
||||
hideTimeControls: false,
|
||||
hideVariableControls: false,
|
||||
hideLinksControls: false,
|
||||
describe('.hasControls()', () => {
|
||||
it('should return TRUE if any of the controls are available', () => {
|
||||
const scene = buildTestScene({
|
||||
hideTimeControls: false,
|
||||
hideVariableControls: false,
|
||||
hideLinksControls: false,
|
||||
hideDashboardControls: false,
|
||||
});
|
||||
|
||||
// All controls visible
|
||||
expect(scene.hasControls()).toBeTruthy();
|
||||
|
||||
// Hiding time controls
|
||||
scene.setState({
|
||||
hideTimeControls: true,
|
||||
hideVariableControls: false,
|
||||
hideLinksControls: false,
|
||||
hideDashboardControls: false,
|
||||
});
|
||||
expect(scene.hasControls()).toBeTruthy();
|
||||
|
||||
// Hide variable controls as well
|
||||
scene.setState({
|
||||
hideTimeControls: true,
|
||||
hideVariableControls: true,
|
||||
hideLinksControls: false,
|
||||
hideDashboardControls: false,
|
||||
});
|
||||
expect(scene.hasControls()).toBeTruthy();
|
||||
|
||||
// Hide link controls as well
|
||||
scene.setState({
|
||||
hideTimeControls: true,
|
||||
hideVariableControls: true,
|
||||
hideLinksControls: true,
|
||||
hideDashboardControls: false,
|
||||
});
|
||||
expect(scene.hasControls()).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return FALSE if no controls are available', () => {
|
||||
const scene = buildTestScene({
|
||||
hideTimeControls: true,
|
||||
hideVariableControls: true,
|
||||
hideLinksControls: true,
|
||||
hideDashboardControls: true,
|
||||
});
|
||||
|
||||
expect(scene.hasControls()).toBeFalsy();
|
||||
});
|
||||
expect(scene.hasControls()).toBeTruthy();
|
||||
scene.setState({ hideTimeControls: true });
|
||||
expect(scene.hasControls()).toBeTruthy();
|
||||
scene.setState({ hideVariableControls: true, hideLinksControls: true });
|
||||
expect(scene.hasControls()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -52,10 +91,11 @@ describe('DashboardControls', () => {
|
||||
hideTimeControls: true,
|
||||
hideVariableControls: true,
|
||||
hideLinksControls: true,
|
||||
hideDashboardControls: true,
|
||||
});
|
||||
const renderer = render(<scene.Component model={scene} />);
|
||||
|
||||
expect(await renderer.queryByTestId(selectors.pages.Dashboard.Controls)).not.toBeInTheDocument();
|
||||
expect(renderer.queryByTestId(selectors.pages.Dashboard.Controls)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -63,7 +103,12 @@ describe('DashboardControls', () => {
|
||||
it('should return keys', () => {
|
||||
const scene = buildTestScene();
|
||||
// @ts-expect-error
|
||||
expect(scene._urlSync.getKeys()).toEqual(['_dash.hideTimePicker', '_dash.hideVariables', '_dash.hideLinks']);
|
||||
expect(scene._urlSync.getKeys()).toEqual([
|
||||
'_dash.hideTimePicker',
|
||||
'_dash.hideVariables',
|
||||
'_dash.hideLinks',
|
||||
'_dash.hideDashboardControls',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not return url state for hide flags', () => {
|
||||
@@ -73,6 +118,7 @@ describe('DashboardControls', () => {
|
||||
hideTimeControls: true,
|
||||
hideVariableControls: true,
|
||||
hideLinksControls: true,
|
||||
hideDashboardControls: true,
|
||||
});
|
||||
expect(scene.getUrlState()).toEqual({});
|
||||
});
|
||||
@@ -83,18 +129,22 @@ describe('DashboardControls', () => {
|
||||
'_dash.hideTimePicker': 'true',
|
||||
'_dash.hideVariables': 'true',
|
||||
'_dash.hideLinks': 'true',
|
||||
'_dash.hideDashboardControls': 'true',
|
||||
});
|
||||
expect(scene.state.hideTimeControls).toBeTruthy();
|
||||
expect(scene.state.hideVariableControls).toBeTruthy();
|
||||
expect(scene.state.hideLinksControls).toBeTruthy();
|
||||
expect(scene.state.hideDashboardControls).toBeTruthy();
|
||||
scene.updateFromUrl({
|
||||
'_dash.hideTimePicker': '',
|
||||
'_dash.hideVariables': '',
|
||||
'_dash.hideLinks': '',
|
||||
'_dash.hideDashboardControls': '',
|
||||
});
|
||||
expect(scene.state.hideTimeControls).toBeTruthy();
|
||||
expect(scene.state.hideVariableControls).toBeTruthy();
|
||||
expect(scene.state.hideLinksControls).toBeTruthy();
|
||||
expect(scene.state.hideDashboardControls).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not override state if no new state comes from url', () => {
|
||||
@@ -102,11 +152,13 @@ describe('DashboardControls', () => {
|
||||
hideTimeControls: true,
|
||||
hideVariableControls: true,
|
||||
hideLinksControls: true,
|
||||
hideDashboardControls: true,
|
||||
});
|
||||
scene.updateFromUrl({});
|
||||
expect(scene.state.hideTimeControls).toBeTruthy();
|
||||
expect(scene.state.hideVariableControls).toBeTruthy();
|
||||
expect(scene.state.hideLinksControls).toBeTruthy();
|
||||
expect(scene.state.hideDashboardControls).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should not call setState if no changes', () => {
|
||||
@@ -114,6 +166,7 @@ describe('DashboardControls', () => {
|
||||
hideTimeControls: true,
|
||||
hideVariableControls: true,
|
||||
hideLinksControls: true,
|
||||
hideDashboardControls: true,
|
||||
});
|
||||
const setState = jest.spyOn(scene, 'setState');
|
||||
|
||||
@@ -121,6 +174,7 @@ describe('DashboardControls', () => {
|
||||
'_dash.hideTimePicker': 'true',
|
||||
'_dash.hideVariables': 'true',
|
||||
'_dash.hideLinks': 'true',
|
||||
'_dash.hideDashboardControls': 'true',
|
||||
});
|
||||
|
||||
expect(setState).toHaveBeenCalledTimes(0);
|
||||
@@ -151,6 +205,19 @@ function buildTestScene(state?: Partial<DashboardControlsState>): DashboardContr
|
||||
targetBlank: false,
|
||||
tooltip: 'Link',
|
||||
},
|
||||
{
|
||||
title: 'Link (dashboard controls)',
|
||||
url: 'http://localhost:3000/$A',
|
||||
type: 'link',
|
||||
asDropdown: false,
|
||||
icon: '',
|
||||
includeVars: true,
|
||||
keepTime: true,
|
||||
tags: [],
|
||||
targetBlank: false,
|
||||
tooltip: 'Link',
|
||||
placement: 'inControlsMenu',
|
||||
},
|
||||
],
|
||||
$variables: new SceneVariableSet({
|
||||
variables: [variable],
|
||||
|
||||
@@ -31,6 +31,8 @@ export interface DashboardControlsState extends SceneObjectState {
|
||||
hideTimeControls?: boolean;
|
||||
hideVariableControls?: boolean;
|
||||
hideLinksControls?: boolean;
|
||||
// Hides the dashbaord-controls dropdown menu
|
||||
hideDashboardControls?: boolean;
|
||||
}
|
||||
|
||||
export class DashboardControls extends SceneObjectBase<DashboardControlsState> {
|
||||
@@ -41,7 +43,7 @@ export class DashboardControls extends SceneObjectBase<DashboardControlsState> {
|
||||
});
|
||||
|
||||
protected _urlSync = new SceneObjectUrlSyncConfig(this, {
|
||||
keys: ['_dash.hideTimePicker', '_dash.hideVariables', '_dash.hideLinks'],
|
||||
keys: ['_dash.hideTimePicker', '_dash.hideVariables', '_dash.hideLinks', '_dash.hideDashboardControls'],
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -53,7 +55,7 @@ export class DashboardControls extends SceneObjectBase<DashboardControlsState> {
|
||||
}
|
||||
|
||||
updateFromUrl(values: SceneObjectUrlValues) {
|
||||
const { hideTimeControls, hideVariableControls, hideLinksControls } = this.state;
|
||||
const { hideTimeControls, hideVariableControls, hideLinksControls, hideDashboardControls } = this.state;
|
||||
const isEnabledViaUrl = (key: string) => values[key] === 'true' || values[key] === '';
|
||||
|
||||
// Only allow hiding, never "unhiding" from url
|
||||
@@ -70,6 +72,10 @@ export class DashboardControls extends SceneObjectBase<DashboardControlsState> {
|
||||
if (!hideLinksControls && isEnabledViaUrl('_dash.hideLinks')) {
|
||||
this.setState({ hideLinksControls: true });
|
||||
}
|
||||
|
||||
if (!hideDashboardControls && isEnabledViaUrl('_dash.hideDashboardControls')) {
|
||||
this.setState({ hideDashboardControls: true });
|
||||
}
|
||||
}
|
||||
|
||||
public constructor(state: Partial<DashboardControlsState>) {
|
||||
@@ -104,6 +110,18 @@ export class DashboardControls extends SceneObjectBase<DashboardControlsState> {
|
||||
}
|
||||
}
|
||||
|
||||
// Dashboard controls is a separate dropdown menu at the top-right of the controls
|
||||
public hasDashboardControls(): boolean {
|
||||
const dashboard = getDashboardSceneFor(this);
|
||||
const { links } = dashboard.state;
|
||||
const hasControlMenuVariables = sceneGraph
|
||||
.getVariables(dashboard)
|
||||
?.state.variables.some((v) => v.state.showInControlsMenu === true);
|
||||
const hasControlMenuLinks = links.some((link) => link.placement === 'inControlsMenu');
|
||||
|
||||
return hasControlMenuVariables || hasControlMenuLinks;
|
||||
}
|
||||
|
||||
public hasControls(): boolean {
|
||||
const hasVariables = sceneGraph
|
||||
.getVariables(this)
|
||||
@@ -113,22 +131,25 @@ export class DashboardControls extends SceneObjectBase<DashboardControlsState> {
|
||||
const hideLinks = this.state.hideLinksControls || !hasLinks;
|
||||
const hideVariables = this.state.hideVariableControls || (!hasAnnotations && !hasVariables);
|
||||
const hideTimePicker = this.state.hideTimeControls;
|
||||
const hideDashboardControls = this.state.hideDashboardControls || !this.hasDashboardControls();
|
||||
|
||||
return !(hideVariables && hideLinks && hideTimePicker);
|
||||
return !(hideVariables && hideLinks && hideTimePicker && hideDashboardControls);
|
||||
}
|
||||
}
|
||||
|
||||
function DashboardControlsRenderer({ model }: SceneComponentProps<DashboardControls>) {
|
||||
const { refreshPicker, timePicker, hideTimeControls, hideVariableControls, hideLinksControls } = model.useState();
|
||||
const {
|
||||
refreshPicker,
|
||||
timePicker,
|
||||
hideTimeControls,
|
||||
hideVariableControls,
|
||||
hideLinksControls,
|
||||
hideDashboardControls,
|
||||
} = model.useState();
|
||||
const dashboard = getDashboardSceneFor(model);
|
||||
const { links, editPanel } = dashboard.useState();
|
||||
const styles = useStyles2(getStyles);
|
||||
const showDebugger = window.location.search.includes('scene-debugger');
|
||||
const hasControlMenuVariables = sceneGraph
|
||||
.getVariables(dashboard)
|
||||
.useState()
|
||||
.variables.some((v) => v.state.showInControlsMenu === true);
|
||||
const hasControlMenuLinks = links.some((link) => link.placement === 'inControlsMenu');
|
||||
|
||||
if (!model.hasControls()) {
|
||||
// To still have spacing when no controls are rendered
|
||||
@@ -157,7 +178,7 @@ function DashboardControlsRenderer({ model }: SceneComponentProps<DashboardContr
|
||||
<refreshPicker.Component model={refreshPicker} />
|
||||
</div>
|
||||
)}
|
||||
{(hasControlMenuVariables || hasControlMenuLinks) && (
|
||||
{!hideDashboardControls && model.hasDashboardControls() && (
|
||||
<Stack>
|
||||
<DashboardControlsButton dashboard={dashboard} />
|
||||
</Stack>
|
||||
|
||||
Reference in New Issue
Block a user