Dynamic Dashboards: Show hidden variables greyed out (#115723)
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { test, expect } from '@grafana/plugin-e2e';
|
import { test, expect } from '@grafana/plugin-e2e';
|
||||||
|
|
||||||
import { flows, type Variable } from './utils';
|
import { flows, saveDashboard, type Variable } from './utils';
|
||||||
|
|
||||||
test.use({
|
test.use({
|
||||||
featureToggles: {
|
featureToggles: {
|
||||||
@@ -64,20 +64,7 @@ test.describe(
|
|||||||
label: 'VariableUnderTest',
|
label: 'VariableUnderTest',
|
||||||
};
|
};
|
||||||
|
|
||||||
// common steps to add a new variable
|
await flows.addNewTextBoxVariable(dashboardPage, variable);
|
||||||
await flows.newEditPaneVariableClick(dashboardPage, selectors);
|
|
||||||
await flows.newEditPanelCommonVariableInputs(dashboardPage, selectors, variable);
|
|
||||||
|
|
||||||
// set the textbox variable value
|
|
||||||
const type = 'variable-type Value';
|
|
||||||
const fieldLabel = dashboardPage.getByGrafanaSelector(
|
|
||||||
selectors.components.PanelEditor.OptionsPane.fieldLabel(type)
|
|
||||||
);
|
|
||||||
await expect(fieldLabel).toBeVisible();
|
|
||||||
const inputField = fieldLabel.locator('input');
|
|
||||||
await expect(inputField).toBeVisible();
|
|
||||||
await inputField.fill(variable.value);
|
|
||||||
await inputField.blur();
|
|
||||||
|
|
||||||
// select the variable in the dashboard and confirm the variable value is set
|
// select the variable in the dashboard and confirm the variable value is set
|
||||||
await dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItem).click();
|
await dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItem).click();
|
||||||
@@ -140,5 +127,94 @@ test.describe(
|
|||||||
await expect(panelContent).toBeVisible();
|
await expect(panelContent).toBeVisible();
|
||||||
await expect(markdownContent).toContainText('VariableUnderTest: 10m');
|
await expect(markdownContent).toContainText('VariableUnderTest: 10m');
|
||||||
});
|
});
|
||||||
|
test('can hide a variable', async ({ dashboardPage, selectors, page }) => {
|
||||||
|
const variable: Variable = {
|
||||||
|
type: 'textbox',
|
||||||
|
name: 'VariableUnderTest',
|
||||||
|
value: 'foo',
|
||||||
|
label: 'VariableUnderTest',
|
||||||
|
};
|
||||||
|
|
||||||
|
await saveDashboard(dashboardPage, page, selectors, 'can hide a variable');
|
||||||
|
await flows.addNewTextBoxVariable(dashboardPage, variable);
|
||||||
|
|
||||||
|
// check the variable is visible in the dashboard
|
||||||
|
const variableLabel = dashboardPage.getByGrafanaSelector(
|
||||||
|
selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label)
|
||||||
|
);
|
||||||
|
await expect(variableLabel).toBeVisible();
|
||||||
|
// hide the variable
|
||||||
|
await dashboardPage
|
||||||
|
.getByGrafanaSelector(selectors.pages.Dashboard.Settings.Variables.Edit.General.generalDisplaySelect)
|
||||||
|
.click();
|
||||||
|
await page.getByText('Hidden', { exact: true }).click();
|
||||||
|
|
||||||
|
// check that the variable is still visible
|
||||||
|
await expect(
|
||||||
|
dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!))
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
// save dashboard and exit edit mode and check variable is not visible
|
||||||
|
await saveDashboard(dashboardPage, page, selectors);
|
||||||
|
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.editButton).click();
|
||||||
|
await expect(
|
||||||
|
dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!))
|
||||||
|
).toBeHidden();
|
||||||
|
// refresh and check that variable isn't visible
|
||||||
|
await page.reload();
|
||||||
|
await expect(
|
||||||
|
dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!))
|
||||||
|
).toBeHidden();
|
||||||
|
// check that the variable is visible in edit mode
|
||||||
|
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.editButton).click();
|
||||||
|
await expect(
|
||||||
|
dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!))
|
||||||
|
).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('can hide variable under the controls menu', async ({ dashboardPage, selectors, page }) => {
|
||||||
|
const variable: Variable = {
|
||||||
|
type: 'textbox',
|
||||||
|
name: 'VariableUnderTest',
|
||||||
|
value: 'foo',
|
||||||
|
label: 'VariableUnderTest',
|
||||||
|
};
|
||||||
|
await saveDashboard(dashboardPage, page, selectors, 'can hide a variable in controls menu');
|
||||||
|
|
||||||
|
await flows.addNewTextBoxVariable(dashboardPage, variable);
|
||||||
|
|
||||||
|
// check the variable is visible in the dashboard
|
||||||
|
const variableLabel = dashboardPage.getByGrafanaSelector(
|
||||||
|
selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label)
|
||||||
|
);
|
||||||
|
await expect(variableLabel).toBeVisible();
|
||||||
|
// hide the variable
|
||||||
|
await dashboardPage
|
||||||
|
.getByGrafanaSelector(selectors.pages.Dashboard.Settings.Variables.Edit.General.generalDisplaySelect)
|
||||||
|
.click();
|
||||||
|
await page.getByText('Controls menu', { exact: true }).click();
|
||||||
|
|
||||||
|
// check that the variable is hidden under the controls menu
|
||||||
|
await expect(
|
||||||
|
dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!))
|
||||||
|
).toBeHidden();
|
||||||
|
await dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.ControlsButton).click();
|
||||||
|
await expect(
|
||||||
|
dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!))
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
// save dashboard and refresh
|
||||||
|
await saveDashboard(dashboardPage, page, selectors);
|
||||||
|
await page.reload();
|
||||||
|
|
||||||
|
//check that the variable is hidden under the controls menu
|
||||||
|
await expect(
|
||||||
|
dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!))
|
||||||
|
).toBeHidden();
|
||||||
|
await dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.ControlsButton).click();
|
||||||
|
await expect(
|
||||||
|
dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItemLabels(variable.label!))
|
||||||
|
).toBeVisible();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -79,6 +79,20 @@ export const flows = {
|
|||||||
await variableLabelInput.blur();
|
await variableLabelInput.blur();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async addNewTextBoxVariable(dashboardPage: DashboardPage, variable: Variable) {
|
||||||
|
await flows.newEditPaneVariableClick(dashboardPage, selectors);
|
||||||
|
await flows.newEditPanelCommonVariableInputs(dashboardPage, selectors, variable);
|
||||||
|
// set the textbox variable value
|
||||||
|
const type = 'variable-type Value';
|
||||||
|
const fieldLabel = dashboardPage.getByGrafanaSelector(
|
||||||
|
selectors.components.PanelEditor.OptionsPane.fieldLabel(type)
|
||||||
|
);
|
||||||
|
await expect(fieldLabel).toBeVisible();
|
||||||
|
const inputField = fieldLabel.locator('input');
|
||||||
|
await expect(inputField).toBeVisible();
|
||||||
|
await inputField.fill(variable.value);
|
||||||
|
await inputField.blur();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Variable = {
|
export type Variable = {
|
||||||
@@ -89,8 +103,16 @@ export type Variable = {
|
|||||||
value: string;
|
value: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function saveDashboard(dashboardPage: DashboardPage, page: Page, selectors: E2ESelectorGroups) {
|
export async function saveDashboard(
|
||||||
|
dashboardPage: DashboardPage,
|
||||||
|
page: Page,
|
||||||
|
selectors: E2ESelectorGroups,
|
||||||
|
title?: string
|
||||||
|
) {
|
||||||
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.saveButton).click();
|
await dashboardPage.getByGrafanaSelector(selectors.components.NavToolbar.editDashboard.saveButton).click();
|
||||||
|
if (title) {
|
||||||
|
await page.getByTestId(selectors.components.Drawer.DashboardSaveDrawer.saveAsTitleInput).fill(title);
|
||||||
|
}
|
||||||
await dashboardPage.getByGrafanaSelector(selectors.components.Drawer.DashboardSaveDrawer.saveButton).click();
|
await dashboardPage.getByGrafanaSelector(selectors.components.Drawer.DashboardSaveDrawer.saveButton).click();
|
||||||
await expect(page.getByText('Dashboard saved')).toBeVisible();
|
await expect(page.getByText('Dashboard saved')).toBeVisible();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -266,6 +266,9 @@ export const versionedPages = {
|
|||||||
Controls: {
|
Controls: {
|
||||||
'11.1.0': 'data-testid dashboard controls',
|
'11.1.0': 'data-testid dashboard controls',
|
||||||
},
|
},
|
||||||
|
ControlsButton: {
|
||||||
|
'12.3.0': 'data-testid dashboard controls button',
|
||||||
|
},
|
||||||
SubMenu: {
|
SubMenu: {
|
||||||
submenu: {
|
submenu: {
|
||||||
[MIN_GRAFANA_VERSION]: 'Dashboard submenu',
|
[MIN_GRAFANA_VERSION]: 'Dashboard submenu',
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ import { AddVariableButton } from './VariableControlsAddButton';
|
|||||||
|
|
||||||
export function VariableControls({ dashboard }: { dashboard: DashboardScene }) {
|
export function VariableControls({ dashboard }: { dashboard: DashboardScene }) {
|
||||||
const { variables } = sceneGraph.getVariables(dashboard)!.useState();
|
const { variables } = sceneGraph.getVariables(dashboard)!.useState();
|
||||||
|
const { isEditing } = dashboard.useState();
|
||||||
|
const isEditingNewLayouts = isEditing && config.featureToggles.dashboardNewLayouts;
|
||||||
|
|
||||||
// Get visible variables for drilldown layout
|
// Get visible variables for drilldown layout
|
||||||
const visibleVariables = variables.filter((v) => v.state.hide !== VariableHide.inControlsMenu);
|
const visibleVariables = variables.filter((v) => v.state.hide !== VariableHide.inControlsMenu);
|
||||||
@@ -35,13 +37,22 @@ export function VariableControls({ dashboard }: { dashboard: DashboardScene }) {
|
|||||||
// Variables to render (exclude adhoc/groupby when drilldown controls are shown in top row)
|
// Variables to render (exclude adhoc/groupby when drilldown controls are shown in top row)
|
||||||
const variablesToRender = hasDrilldownControls
|
const variablesToRender = hasDrilldownControls
|
||||||
? restVariables.filter((v) => v.state.hide !== VariableHide.inControlsMenu)
|
? restVariables.filter((v) => v.state.hide !== VariableHide.inControlsMenu)
|
||||||
: variables.filter((v) => v.state.hide !== VariableHide.inControlsMenu);
|
: variables.filter(
|
||||||
|
(v) =>
|
||||||
|
// if we're editing in dynamic dashboards, still shows hidden variable but greyed out
|
||||||
|
(isEditingNewLayouts && v.state.hide === VariableHide.hideVariable) ||
|
||||||
|
v.state.hide !== VariableHide.inControlsMenu
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{variablesToRender.length > 0 &&
|
{variablesToRender.length > 0 &&
|
||||||
variablesToRender.map((variable) => (
|
variablesToRender.map((variable) => (
|
||||||
<VariableValueSelectWrapper key={variable.state.key} variable={variable} />
|
<VariableValueSelectWrapper
|
||||||
|
key={variable.state.key}
|
||||||
|
variable={variable}
|
||||||
|
isEditingNewLayouts={isEditingNewLayouts}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{config.featureToggles.dashboardNewLayouts ? <AddVariableButton dashboard={dashboard} /> : null}
|
{config.featureToggles.dashboardNewLayouts ? <AddVariableButton dashboard={dashboard} /> : null}
|
||||||
@@ -52,14 +63,17 @@ export function VariableControls({ dashboard }: { dashboard: DashboardScene }) {
|
|||||||
interface VariableSelectProps {
|
interface VariableSelectProps {
|
||||||
variable: SceneVariable;
|
variable: SceneVariable;
|
||||||
inMenu?: boolean;
|
inMenu?: boolean;
|
||||||
|
isEditingNewLayouts?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function VariableValueSelectWrapper({ variable, inMenu }: VariableSelectProps) {
|
export function VariableValueSelectWrapper({ variable, inMenu, isEditingNewLayouts }: VariableSelectProps) {
|
||||||
const state = useSceneObjectState<SceneVariableState>(variable, { shouldActivateOrKeepAlive: true });
|
const state = useSceneObjectState<SceneVariableState>(variable, { shouldActivateOrKeepAlive: true });
|
||||||
const { isSelected, onSelect, isSelectable } = useElementSelection(variable.state.key);
|
const { isSelected, onSelect, isSelectable } = useElementSelection(variable.state.key);
|
||||||
|
const isHidden = state.hide === VariableHide.hideVariable;
|
||||||
|
const shouldShowHiddenVariables = isEditingNewLayouts && isHidden;
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
|
|
||||||
if (state.hide === VariableHide.hideVariable) {
|
if (isHidden && !isEditingNewLayouts) {
|
||||||
if (variable.UNSAFE_renderAsHidden) {
|
if (variable.UNSAFE_renderAsHidden) {
|
||||||
return <variable.Component model={variable} />;
|
return <variable.Component model={variable} />;
|
||||||
}
|
}
|
||||||
@@ -97,6 +111,7 @@ export function VariableValueSelectWrapper({ variable, inMenu }: VariableSelectP
|
|||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
styles.switchMenuContainer,
|
styles.switchMenuContainer,
|
||||||
|
shouldShowHiddenVariables && styles.hidden,
|
||||||
isSelected && 'dashboard-selected-element',
|
isSelected && 'dashboard-selected-element',
|
||||||
isSelectable && !isSelected && 'dashboard-selectable-element'
|
isSelectable && !isSelected && 'dashboard-selectable-element'
|
||||||
)}
|
)}
|
||||||
@@ -120,6 +135,7 @@ export function VariableValueSelectWrapper({ variable, inMenu }: VariableSelectP
|
|||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
styles.verticalContainer,
|
styles.verticalContainer,
|
||||||
|
shouldShowHiddenVariables && styles.hidden,
|
||||||
isSelected && 'dashboard-selected-element',
|
isSelected && 'dashboard-selected-element',
|
||||||
isSelectable && !isSelected && 'dashboard-selectable-element'
|
isSelectable && !isSelected && 'dashboard-selectable-element'
|
||||||
)}
|
)}
|
||||||
@@ -136,6 +152,7 @@ export function VariableValueSelectWrapper({ variable, inMenu }: VariableSelectP
|
|||||||
<div
|
<div
|
||||||
className={cx(
|
className={cx(
|
||||||
styles.container,
|
styles.container,
|
||||||
|
shouldShowHiddenVariables && styles.hidden,
|
||||||
isSelected && 'dashboard-selected-element',
|
isSelected && 'dashboard-selected-element',
|
||||||
isSelectable && !isSelected && 'dashboard-selectable-element'
|
isSelectable && !isSelected && 'dashboard-selectable-element'
|
||||||
)}
|
)}
|
||||||
@@ -223,4 +240,13 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
|||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
}),
|
}),
|
||||||
|
hidden: css({
|
||||||
|
opacity: 0.6,
|
||||||
|
'&:hover': css({
|
||||||
|
opacity: 1,
|
||||||
|
}),
|
||||||
|
label: css({
|
||||||
|
textDecoration: 'line-through',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|||||||
+2
@@ -1,6 +1,7 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css } from '@emotion/css';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
import { t } from '@grafana/i18n';
|
import { t } from '@grafana/i18n';
|
||||||
import { Dropdown, ToolbarButton, useStyles2 } from '@grafana/ui';
|
import { Dropdown, ToolbarButton, useStyles2 } from '@grafana/ui';
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ export function DashboardControlsButton({ dashboard }: { dashboard: DashboardSce
|
|||||||
<ToolbarButton
|
<ToolbarButton
|
||||||
aria-label={t('dashboard.controls.menu.aria-label', DASHBOARD_CONTROLS_MENU_ARIA_LABEL)}
|
aria-label={t('dashboard.controls.menu.aria-label', DASHBOARD_CONTROLS_MENU_ARIA_LABEL)}
|
||||||
title={t('dashboard.controls.menu.title', DASHBOARD_CONTROLS_MENU_TITLE)}
|
title={t('dashboard.controls.menu.title', DASHBOARD_CONTROLS_MENU_TITLE)}
|
||||||
|
data-testid={selectors.pages.Dashboard.ControlsButton}
|
||||||
icon="sliders-v-alt"
|
icon="sliders-v-alt"
|
||||||
iconSize="md"
|
iconSize="md"
|
||||||
variant="canvas"
|
variant="canvas"
|
||||||
|
|||||||
+4
@@ -38,6 +38,10 @@ export function VariableDisplaySelect({ onChange, display, type, minWidth = 52 }
|
|||||||
{
|
{
|
||||||
value: VariableHide.hideVariable,
|
value: VariableHide.hideVariable,
|
||||||
label: t('dashboard-scene.variable-display-select.options.hidden.label', 'Hidden'),
|
label: t('dashboard-scene.variable-display-select.options.hidden.label', 'Hidden'),
|
||||||
|
description: t(
|
||||||
|
'dashboard-scene.variable-display-select.options.hidden.description',
|
||||||
|
'Only visible in edit mode'
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[]
|
[]
|
||||||
|
|||||||
@@ -6578,6 +6578,7 @@
|
|||||||
"label": "Controls menu"
|
"label": "Controls menu"
|
||||||
},
|
},
|
||||||
"hidden": {
|
"hidden": {
|
||||||
|
"description": "Only visible in edit mode",
|
||||||
"label": "Hidden"
|
"label": "Hidden"
|
||||||
},
|
},
|
||||||
"hidden-label": {
|
"hidden-label": {
|
||||||
|
|||||||
Reference in New Issue
Block a user