Suggestions: improve styling for new version (#114381)

* Suggestions: hashes on suggestions, update logic to select first suggestion

* fix types

* Suggestions: New UI style updates

* update some styles

* getting styles just right

* remove grouping when not on flag

* adjust minimum width for sidebar

* CI cleanups

* updates from ad hoc review

* add loading and error states to suggestions

* remove unused import

* update header ui for panel editor

* restore back button to vizpicker

* fix e2e test

* fix e2e

* add i18n update

* use new util for setVisualization operation

* Apply suggestions from code review

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>

* comments from review

* updates from review

---------

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
Paul Marbach
2025-12-02 11:36:46 -08:00
committed by GitHub
co-authored by Torkel Ödegaard
parent 227b596a46
commit 021e0c6da0
16 changed files with 370 additions and 216 deletions
@@ -2,17 +2,18 @@ import { Locator } from '@playwright/test';
import { test, expect } from '@grafana/plugin-e2e';
import { setVisualization } from './vizpicker-utils';
test.use({
featureToggles: {
canvasPanelPanZoom: true,
},
});
test.describe('Canvas Panel - Scene Tests', () => {
test.beforeEach(async ({ page, gotoDashboardPage }) => {
test.beforeEach(async ({ page, gotoDashboardPage, selectors }) => {
const dashboardPage = await gotoDashboardPage({});
const panelEditPage = await dashboardPage.addPanel();
await panelEditPage.setVisualization('Canvas');
await setVisualization(panelEditPage, 'Canvas', selectors);
// Wait for canvas panel to load
await page.waitForSelector('[data-testid="canvas-scene-pan-zoom"]', { timeout: 10000 });
@@ -58,7 +58,7 @@ test.describe(
await dashboardPage.getByGrafanaSelector(selectors.components.Tab.title('Queries')).click();
// Check that Time series is chosen
await expect(dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleVizPicker)).toContainText(
await expect(dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.header)).toHaveText(
'Time series'
);
@@ -71,9 +71,10 @@ test.describe(
// Change to Text panel
await dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleVizPicker).click();
await dashboardPage.getByGrafanaSelector(selectors.components.Tab.title('All visualizations')).click(); // <-- should only need to do this once thanks to the session storage
await dashboardPage.getByGrafanaSelector(selectors.components.PluginVisualization.item('Text')).click();
// Check current visualization shows Text
await expect(dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleVizPicker)).toContainText(
await expect(dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.header)).toHaveText(
'Text'
);
@@ -84,7 +85,7 @@ test.describe(
await dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleVizPicker).click();
await dashboardPage.getByGrafanaSelector(selectors.components.PluginVisualization.item('Table')).click();
// Check current visualization shows Table
await expect(dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleVizPicker)).toContainText(
await expect(dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.header)).toHaveText(
'Table'
);
@@ -0,0 +1,24 @@
import { expect, E2ESelectorGroups, PanelEditPage } from '@grafana/plugin-e2e';
// this replaces the panelEditPage.setVisualization method used previously in tests, since it
// does not know how to use the updated 12.4 viz picker UI to set the visualization
export const setVisualization = async (panelEditPage: PanelEditPage, vizName: string, selectors: E2ESelectorGroups) => {
const vizPicker = panelEditPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleVizPicker);
await expect(vizPicker, '"Change" button should be visible').toBeVisible();
await vizPicker.click();
const allVizTabBtn = panelEditPage.getByGrafanaSelector(selectors.components.Tab.title('All visualizations'));
await expect(allVizTabBtn, '"All visualiations" button should be visible').toBeVisible();
await allVizTabBtn.click();
const vizItem = panelEditPage.getByGrafanaSelector(selectors.components.PluginVisualization.item(vizName));
await expect(vizItem, `"${vizName}" item should be visible`).toBeVisible();
await vizItem.scrollIntoViewIfNeeded();
await vizItem.click();
await expect(vizPicker, '"Change" button should be visible again').toBeVisible();
await expect(
panelEditPage.getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.header),
'Panel header should have the new viz type name'
).toHaveText(vizName);
};
@@ -1,5 +1,6 @@
import { expect, test } from '@grafana/plugin-e2e';
import { setVisualization } from '../../../panels-suite/vizpicker-utils';
import { formatExpectError } from '../errors';
import { successfulDataQuery } from '../mocks/queries';
@@ -24,10 +25,10 @@ test.describe(
).toContainText(['Field', 'Max', 'Mean', 'Last']);
});
test('table panel data assertions', async ({ panelEditPage }) => {
test('table panel data assertions', async ({ panelEditPage, selectors }) => {
await panelEditPage.mockQueryDataResponse(successfulDataQuery, 200);
await panelEditPage.datasource.set('gdev-testdata');
await panelEditPage.setVisualization('Table');
await setVisualization(panelEditPage, 'Table', selectors);
await panelEditPage.refreshPanel();
await expect(
panelEditPage.panel.locator,
@@ -43,10 +44,10 @@ test.describe(
).toContainText(['val1', 'val2', 'val3', 'val4']);
});
test('timeseries panel - table view assertions', async ({ panelEditPage }) => {
test('timeseries panel - table view assertions', async ({ panelEditPage, selectors }) => {
await panelEditPage.mockQueryDataResponse(successfulDataQuery, 200);
await panelEditPage.datasource.set('gdev-testdata');
await panelEditPage.setVisualization('Time series');
await setVisualization(panelEditPage, 'Time series', selectors);
await panelEditPage.refreshPanel();
await panelEditPage.toggleTableView();
await expect(
@@ -1,5 +1,6 @@
import { expect, test } from '@grafana/plugin-e2e';
import { setVisualization } from '../../../panels-suite/vizpicker-utils';
import { formatExpectError } from '../errors';
import { successfulDataQuery } from '../mocks/queries';
import { scenarios } from '../mocks/resources';
@@ -53,10 +54,10 @@ test.describe(
).toHaveText(scenarios.map((s) => s.name));
});
test('mocked query data response', async ({ panelEditPage, page }) => {
test('mocked query data response', async ({ panelEditPage, page, selectors }) => {
await panelEditPage.mockQueryDataResponse(successfulDataQuery, 200);
await panelEditPage.datasource.set('gdev-testdata');
await panelEditPage.setVisualization(TABLE_VIZ_NAME);
await setVisualization(panelEditPage, TABLE_VIZ_NAME, selectors);
await panelEditPage.refreshPanel();
await expect(
panelEditPage.panel.getErrorIcon(),
@@ -75,9 +76,9 @@ test.describe(
selectors,
page,
}) => {
await panelEditPage.setVisualization(TABLE_VIZ_NAME);
await setVisualization(panelEditPage, TABLE_VIZ_NAME, selectors);
await expect(
panelEditPage.getByGrafanaSelector(selectors.components.PanelEditor.toggleVizPicker),
panelEditPage.getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.header),
formatExpectError('Expected panel visualization to be set to table')
).toHaveText(TABLE_VIZ_NAME);
await panelEditPage.setPanelTitle(PANEL_TITLE);
@@ -92,8 +93,8 @@ test.describe(
).toBeVisible();
});
test('Select time zone in timezone picker', async ({ panelEditPage }) => {
await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME);
test('Select time zone in timezone picker', async ({ panelEditPage, selectors }) => {
await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors);
const axisOptions = await panelEditPage.getCustomOptions('Axis');
const timeZonePicker = axisOptions.getSelect('Time zone');
@@ -101,8 +102,8 @@ test.describe(
await expect(timeZonePicker).toHaveSelected('Europe/Stockholm');
});
test('select unit in unit picker', async ({ panelEditPage }) => {
await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME);
test('select unit in unit picker', async ({ panelEditPage, selectors }) => {
await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors);
const standardOptions = panelEditPage.getStandardOptions();
const unitPicker = standardOptions.getUnitPicker('Unit');
@@ -111,8 +112,8 @@ test.describe(
await expect(unitPicker).toHaveSelected('Pixels');
});
test('enter value in number input', async ({ panelEditPage }) => {
await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME);
test('enter value in number input', async ({ panelEditPage, selectors }) => {
await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors);
const axisOptions = panelEditPage.getCustomOptions('Axis');
const lineWith = axisOptions.getNumberInput('Soft min');
@@ -121,8 +122,8 @@ test.describe(
await expect(lineWith).toHaveValue('10');
});
test('enter value in slider', async ({ panelEditPage }) => {
await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME);
test('enter value in slider', async ({ panelEditPage, selectors }) => {
await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors);
const graphOptions = panelEditPage.getCustomOptions('Graph styles');
const lineWidth = graphOptions.getSliderInput('Line width');
@@ -131,8 +132,8 @@ test.describe(
await expect(lineWidth).toHaveValue('10');
});
test('select value in single value select', async ({ panelEditPage }) => {
await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME);
test('select value in single value select', async ({ panelEditPage, selectors }) => {
await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors);
const standardOptions = panelEditPage.getStandardOptions();
const colorSchemeSelect = standardOptions.getSelect('Color scheme');
@@ -140,8 +141,8 @@ test.describe(
await expect(colorSchemeSelect).toHaveSelected('Classic palette');
});
test('clear input', async ({ panelEditPage }) => {
await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME);
test('clear input', async ({ panelEditPage, selectors }) => {
await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors);
const panelOptions = panelEditPage.getPanelOptions();
const title = panelOptions.getTextInput('Title');
@@ -150,8 +151,8 @@ test.describe(
await expect(title).toHaveValue('');
});
test('enter value in input', async ({ panelEditPage }) => {
await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME);
test('enter value in input', async ({ panelEditPage, selectors }) => {
await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors);
const panelOptions = panelEditPage.getPanelOptions();
const description = panelOptions.getTextInput('Description');
@@ -160,8 +161,8 @@ test.describe(
await expect(description).toHaveValue('This is a panel');
});
test('unchecking switch', async ({ panelEditPage }) => {
await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME);
test('unchecking switch', async ({ panelEditPage, selectors }) => {
await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors);
const axisOptions = panelEditPage.getCustomOptions('Axis');
const showBorder = axisOptions.getSwitch('Show border');
@@ -173,8 +174,8 @@ test.describe(
await expect(showBorder).toBeChecked({ checked: false });
});
test('checking switch', async ({ panelEditPage }) => {
await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME);
test('checking switch', async ({ panelEditPage, selectors }) => {
await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors);
const axisOptions = panelEditPage.getCustomOptions('Axis');
const showBorder = axisOptions.getSwitch('Show border');
@@ -183,8 +184,8 @@ test.describe(
await expect(showBorder).toBeChecked();
});
test('re-selecting value in radio button group', async ({ panelEditPage }) => {
await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME);
test('re-selecting value in radio button group', async ({ panelEditPage, selectors }) => {
await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors);
const axisOptions = panelEditPage.getCustomOptions('Axis');
const placement = axisOptions.getRadioGroup('Placement');
@@ -195,8 +196,8 @@ test.describe(
await expect(placement).toHaveChecked('Auto');
});
test('selecting value in radio button group', async ({ panelEditPage }) => {
await panelEditPage.setVisualization(TIME_SERIES_VIZ_NAME);
test('selecting value in radio button group', async ({ panelEditPage, selectors }) => {
await setVisualization(panelEditPage, TIME_SERIES_VIZ_NAME, selectors);
const axisOptions = panelEditPage.getCustomOptions('Axis');
const placement = axisOptions.getRadioGroup('Placement');
@@ -45,7 +45,9 @@ test.describe(
await dashboardPage.getByGrafanaSelector(selectors.components.PluginVisualization.item(panel.name)).click();
// Verify panel type is selected
await expect(vizPicker).toHaveText(panel.name, { timeout: 10000 });
await expect(
dashboardPage.getByGrafanaSelector(selectors.components.PanelEditor.OptionsPane.header)
).toHaveText(panel.name, { timeout: 10000 });
// Wait for panel to finish rendering
await expect(page.getByLabel('Panel loading bar')).toHaveCount(0, { timeout: 10000 });