diff --git a/e2e-playwright/dashboard-new-layouts/dashboards-edit-variables.spec.ts b/e2e-playwright/dashboard-new-layouts/dashboards-edit-variables.spec.ts index 4b5ea9574f8..15a41047fe6 100644 --- a/e2e-playwright/dashboard-new-layouts/dashboards-edit-variables.spec.ts +++ b/e2e-playwright/dashboard-new-layouts/dashboards-edit-variables.spec.ts @@ -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(); + }); } ); diff --git a/e2e-playwright/dashboard-new-layouts/utils.ts b/e2e-playwright/dashboard-new-layouts/utils.ts index 69851994812..ade6825b7c1 100644 --- a/e2e-playwright/dashboard-new-layouts/utils.ts +++ b/e2e-playwright/dashboard-new-layouts/utils.ts @@ -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(); } diff --git a/packages/grafana-e2e-selectors/src/selectors/pages.ts b/packages/grafana-e2e-selectors/src/selectors/pages.ts index b88dac9099c..35bc4f7c975 100644 --- a/packages/grafana-e2e-selectors/src/selectors/pages.ts +++ b/packages/grafana-e2e-selectors/src/selectors/pages.ts @@ -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', diff --git a/public/app/features/dashboard-scene/scene/VariableControls.tsx b/public/app/features/dashboard-scene/scene/VariableControls.tsx index 73dd2614472..a2e6f3daf88 100644 --- a/public/app/features/dashboard-scene/scene/VariableControls.tsx +++ b/public/app/features/dashboard-scene/scene/VariableControls.tsx @@ -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) => ( - + ))} {config.featureToggles.dashboardNewLayouts ? : 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(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 ; } @@ -97,6 +111,7 @@ export function VariableValueSelectWrapper({ variable, inMenu }: VariableSelectP
({ display: 'flex', alignItems: 'center', }), + hidden: css({ + opacity: 0.6, + '&:hover': css({ + opacity: 1, + }), + label: css({ + textDecoration: 'line-through', + }), + }), }); diff --git a/public/app/features/dashboard-scene/scene/dashboard-controls-menu/DashboardControlsMenuButton.tsx b/public/app/features/dashboard-scene/scene/dashboard-controls-menu/DashboardControlsMenuButton.tsx index f3a98f2e9b0..399cd8f13f6 100644 --- a/public/app/features/dashboard-scene/scene/dashboard-controls-menu/DashboardControlsMenuButton.tsx +++ b/public/app/features/dashboard-scene/scene/dashboard-controls-menu/DashboardControlsMenuButton.tsx @@ -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