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 { flows, type Variable } from './utils';
|
||||
import { flows, saveDashboard, type Variable } from './utils';
|
||||
|
||||
test.use({
|
||||
featureToggles: {
|
||||
@@ -64,20 +64,7 @@ test.describe(
|
||||
label: 'VariableUnderTest',
|
||||
};
|
||||
|
||||
// common steps to add a new 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();
|
||||
await flows.addNewTextBoxVariable(dashboardPage, variable);
|
||||
|
||||
// select the variable in the dashboard and confirm the variable value is set
|
||||
await dashboardPage.getByGrafanaSelector(selectors.pages.Dashboard.SubMenu.submenuItem).click();
|
||||
@@ -140,5 +127,94 @@ test.describe(
|
||||
await expect(panelContent).toBeVisible();
|
||||
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();
|
||||
}
|
||||
},
|
||||
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 = {
|
||||
@@ -89,8 +103,16 @@ export type Variable = {
|
||||
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();
|
||||
if (title) {
|
||||
await page.getByTestId(selectors.components.Drawer.DashboardSaveDrawer.saveAsTitleInput).fill(title);
|
||||
}
|
||||
await dashboardPage.getByGrafanaSelector(selectors.components.Drawer.DashboardSaveDrawer.saveButton).click();
|
||||
await expect(page.getByText('Dashboard saved')).toBeVisible();
|
||||
}
|
||||
|
||||
@@ -266,6 +266,9 @@ export const versionedPages = {
|
||||
Controls: {
|
||||
'11.1.0': 'data-testid dashboard controls',
|
||||
},
|
||||
ControlsButton: {
|
||||
'12.3.0': 'data-testid dashboard controls button',
|
||||
},
|
||||
SubMenu: {
|
||||
submenu: {
|
||||
[MIN_GRAFANA_VERSION]: 'Dashboard submenu',
|
||||
|
||||
@@ -19,6 +19,8 @@ import { AddVariableButton } from './VariableControlsAddButton';
|
||||
|
||||
export function VariableControls({ dashboard }: { dashboard: DashboardScene }) {
|
||||
const { variables } = sceneGraph.getVariables(dashboard)!.useState();
|
||||
const { isEditing } = dashboard.useState();
|
||||
const isEditingNewLayouts = isEditing && config.featureToggles.dashboardNewLayouts;
|
||||
|
||||
// Get visible variables for drilldown layout
|
||||
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)
|
||||
const variablesToRender = hasDrilldownControls
|
||||
? 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 (
|
||||
<>
|
||||
{variablesToRender.length > 0 &&
|
||||
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}
|
||||
@@ -52,14 +63,17 @@ export function VariableControls({ dashboard }: { dashboard: DashboardScene }) {
|
||||
interface VariableSelectProps {
|
||||
variable: SceneVariable;
|
||||
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 { isSelected, onSelect, isSelectable } = useElementSelection(variable.state.key);
|
||||
const isHidden = state.hide === VariableHide.hideVariable;
|
||||
const shouldShowHiddenVariables = isEditingNewLayouts && isHidden;
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
if (state.hide === VariableHide.hideVariable) {
|
||||
if (isHidden && !isEditingNewLayouts) {
|
||||
if (variable.UNSAFE_renderAsHidden) {
|
||||
return <variable.Component model={variable} />;
|
||||
}
|
||||
@@ -97,6 +111,7 @@ export function VariableValueSelectWrapper({ variable, inMenu }: VariableSelectP
|
||||
<div
|
||||
className={cx(
|
||||
styles.switchMenuContainer,
|
||||
shouldShowHiddenVariables && styles.hidden,
|
||||
isSelected && 'dashboard-selected-element',
|
||||
isSelectable && !isSelected && 'dashboard-selectable-element'
|
||||
)}
|
||||
@@ -120,6 +135,7 @@ export function VariableValueSelectWrapper({ variable, inMenu }: VariableSelectP
|
||||
<div
|
||||
className={cx(
|
||||
styles.verticalContainer,
|
||||
shouldShowHiddenVariables && styles.hidden,
|
||||
isSelected && 'dashboard-selected-element',
|
||||
isSelectable && !isSelected && 'dashboard-selectable-element'
|
||||
)}
|
||||
@@ -136,6 +152,7 @@ export function VariableValueSelectWrapper({ variable, inMenu }: VariableSelectP
|
||||
<div
|
||||
className={cx(
|
||||
styles.container,
|
||||
shouldShowHiddenVariables && styles.hidden,
|
||||
isSelected && 'dashboard-selected-element',
|
||||
isSelectable && !isSelected && 'dashboard-selectable-element'
|
||||
)}
|
||||
@@ -223,4 +240,13 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
||||
display: 'flex',
|
||||
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 { GrafanaTheme2 } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { t } from '@grafana/i18n';
|
||||
import { Dropdown, ToolbarButton, useStyles2 } from '@grafana/ui';
|
||||
|
||||
@@ -33,6 +34,7 @@ export function DashboardControlsButton({ dashboard }: { dashboard: DashboardSce
|
||||
<ToolbarButton
|
||||
aria-label={t('dashboard.controls.menu.aria-label', DASHBOARD_CONTROLS_MENU_ARIA_LABEL)}
|
||||
title={t('dashboard.controls.menu.title', DASHBOARD_CONTROLS_MENU_TITLE)}
|
||||
data-testid={selectors.pages.Dashboard.ControlsButton}
|
||||
icon="sliders-v-alt"
|
||||
iconSize="md"
|
||||
variant="canvas"
|
||||
|
||||
+4
@@ -38,6 +38,10 @@ export function VariableDisplaySelect({ onChange, display, type, minWidth = 52 }
|
||||
{
|
||||
value: VariableHide.hideVariable,
|
||||
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"
|
||||
},
|
||||
"hidden": {
|
||||
"description": "Only visible in edit mode",
|
||||
"label": "Hidden"
|
||||
},
|
||||
"hidden-label": {
|
||||
|
||||
Reference in New Issue
Block a user