diff --git a/e2e/dashboard-new-layouts/dashboard-group-panels.spec.ts b/e2e/dashboard-new-layouts/dashboard-group-panels.spec.ts index f5ea94bc735..c74d43fbd8d 100644 --- a/e2e/dashboard-new-layouts/dashboard-group-panels.spec.ts +++ b/e2e/dashboard-new-layouts/dashboard-group-panels.spec.ts @@ -9,17 +9,14 @@ describe('Grouping panels', () => { e2e.flows.revertAllChanges(); }); + /* + * Rows + */ + it('can group and ungroup new panels into row', () => { - e2e.flows.addDashboard({ title: 'Group new panels into row' }); - cy.contains('Group new panels into row').should('be.visible'); + e2e.flows.scenes.importV2Dashboard({ title: 'Group new panels into row' }); - // Toggle edit mode - e2e.components.NavToolbar.editDashboard.editButton().should('be.visible').click(); - - // Add 3 panels - e2e.flows.scenes.addFirstPanel(); - e2e.flows.scenes.addPanel(); - e2e.flows.scenes.addPanel(); + e2e.components.NavToolbar.editDashboard.editButton().click(); // Group into row e2e.flows.scenes.groupIntoRow(); @@ -36,7 +33,7 @@ describe('Grouping panels', () => { e2e.components.DashboardRow.title('New row').should('be.visible'); e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - e2e.components.NavToolbar.editDashboard.editButton().should('be.visible').click(); + e2e.components.NavToolbar.editDashboard.editButton().click(); // Ungroup e2e.flows.scenes.ungroupPanels(); @@ -54,17 +51,239 @@ describe('Grouping panels', () => { e2e.components.Panels.Panel.title('New panel').should('have.length', 3); }); + it('can add and remove several rows', () => { + e2e.flows.scenes.importV2Dashboard({ title: 'Add and remove rows' }); + + e2e.components.NavToolbar.editDashboard.editButton().click(); + + e2e.flows.scenes.groupIntoRow(); + + e2e.components.CanvasGridAddActions.addRow().click({ scrollBehavior: 'bottom' }); + e2e.flows.scenes.addPanel(); + + e2e.components.CanvasGridAddActions.addRow().click({ scrollBehavior: 'bottom' }); + e2e.components.DashboardEditPaneSplitter.primaryBody().scrollTo('bottom', { ensureScrollable: false }); + e2e.components.CanvasGridAddActions.addPanel().should('have.length', 3).last().click(); + + e2e.components.DashboardRow.title('New row').should('exist'); + e2e.components.DashboardRow.title('New row 1').should('exist'); + e2e.components.DashboardRow.title('New row 2').should('exist'); + + e2e.components.Panels.Panel.title('New panel').should('have.length', 5); + + //Save dashboards and reload + e2e.flows.scenes.saveDashboard(); + cy.reload(); + + e2e.components.DashboardRow.title('New row').should('exist'); + e2e.components.DashboardRow.title('New row 1').should('exist'); + e2e.components.DashboardRow.title('New row 2').should('exist'); + + e2e.components.Panels.Panel.title('New panel').should('have.length', 5); + + e2e.components.NavToolbar.editDashboard.editButton().click(); + + e2e.components.DashboardRow.title('New row 1').parent().click(); + e2e.components.EditPaneHeader.deleteButton().click(); + e2e.pages.ConfirmModal.delete().click(); + + e2e.components.DashboardRow.title('New row 2').parent().click(); + e2e.components.EditPaneHeader.deleteButton().click(); + e2e.pages.ConfirmModal.delete().click(); + + e2e.components.DashboardRow.title('New row').should('exist'); + e2e.components.DashboardRow.title('New row 1').should('not.exist'); + e2e.components.DashboardRow.title('New row 2').should('not.exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + + e2e.flows.scenes.saveDashboard(); + cy.reload(); + + e2e.components.DashboardRow.title('New row').should('exist'); + e2e.components.DashboardRow.title('New row 1').should('not.exist'); + e2e.components.DashboardRow.title('New row 2').should('not.exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + }); + + it('can paste a copied row', () => { + e2e.flows.scenes.importV2Dashboard({ title: 'Paste row' }); + + e2e.components.NavToolbar.editDashboard.editButton().click(); + + e2e.flows.scenes.groupIntoRow(); + + e2e.components.DashboardRow.title('New row').should('exist'); + + e2e.flows.scenes.editPaneCopy(); + + e2e.components.CanvasGridAddActions.pasteRow().click({ scrollBehavior: 'bottom' }); + + e2e.components.DashboardEditPaneSplitter.primaryBody().scrollTo('bottom', { ensureScrollable: false }); + + e2e.components.DashboardRow.title('New row').should('exist'); + e2e.components.DashboardRow.title('New row 1').should('exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 6); + + e2e.flows.scenes.saveDashboard(); + cy.reload(); + + cy.scrollTo('bottom'); + + e2e.components.DashboardRow.title('New row').should('exist'); + e2e.components.DashboardRow.title('New row 1').should('exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 6); + }); + + it('can duplicate a row', () => { + e2e.flows.scenes.importV2Dashboard({ title: 'Duplicate row' }); + + e2e.components.NavToolbar.editDashboard.editButton().click(); + + e2e.flows.scenes.groupIntoRow(); + + e2e.components.DashboardRow.title('New row').should('exist'); + + e2e.flows.scenes.editPaneDuplicate(); + + e2e.components.DashboardEditPaneSplitter.primaryBody().scrollTo('bottom', { ensureScrollable: false }); + + e2e.components.DashboardRow.title('New row').should('exist'); + e2e.components.DashboardRow.title('New row 1').should('exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 6); + + e2e.flows.scenes.saveDashboard(); + cy.reload(); + + cy.scrollTo('bottom'); + + e2e.components.DashboardRow.title('New row').should('exist'); + e2e.components.DashboardRow.title('New row 1').should('exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 6); + }); + + it('can collapse rows', () => { + e2e.flows.scenes.importV2Dashboard({ title: 'Collapse rows' }); + + e2e.components.NavToolbar.editDashboard.editButton().click(); + + e2e.flows.scenes.groupIntoRow(); + + e2e.components.DashboardRow.title('New row').should('exist'); + + e2e.flows.scenes.editPaneDuplicate(); + + e2e.components.DashboardEditPaneSplitter.primaryBody().scrollTo('bottom', { ensureScrollable: false }); + + e2e.components.DashboardRow.title('New row').should('exist'); + e2e.components.DashboardRow.title('New row 1').should('exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 6); + + e2e.components.DashboardRow.title('New row').click(); + e2e.components.DashboardRow.title('New row 1').click(); + + e2e.components.DashboardRow.title('New row').should('exist'); + e2e.components.DashboardRow.title('New row 1').should('exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 0); + + e2e.flows.scenes.saveDashboard(); + cy.reload(); + + e2e.components.DashboardRow.title('New row').should('exist'); + e2e.components.DashboardRow.title('New row 1').should('exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 0); + }); + + it('can convert rows into tabs when changing layout', () => { + e2e.flows.scenes.importV2Dashboard({ title: 'Rows to tabs' }); + + e2e.components.NavToolbar.editDashboard.editButton().click(); + + e2e.flows.scenes.groupIntoRow(); + + e2e.components.DashboardRow.title('New row').should('exist'); + + e2e.flows.scenes.editPaneDuplicate(); + + e2e.components.DashboardRow.title('New row').should('exist'); + e2e.components.DashboardRow.title('New row 1').should('exist'); + + e2e.components.EditPaneHeader.backButton().click({ force: true }); + + // expand collapsed layouts section + e2e.components.OptionsGroup.toggle('group-layout-category').click(); + + e2e.flows.scenes.selectTabsLayout(); + + e2e.components.Tab.title('New row').should('be.visible'); + e2e.components.Tab.title('New row 1').should('be.visible'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + + e2e.components.Tab.title('New row 1').click(); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + + e2e.flows.scenes.saveDashboard(); + cy.reload(); + + e2e.components.Tab.title('New row').should('be.visible'); + e2e.components.Tab.title('New row 1').should('be.visible'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + + e2e.components.Tab.title('New row').click(); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + }); + + it('can group and ungroup new panels into row with tab', () => { + e2e.flows.scenes.importV2Dashboard({ title: 'Group new panels into tab with row' }); + + e2e.components.NavToolbar.editDashboard.editButton().click(); + + // Group into row with tab + e2e.flows.scenes.groupIntoRow(); + e2e.flows.scenes.groupIntoTab(); + + // Verify tab and panel titles + e2e.components.DashboardRow.title('New row').should('be.visible'); + e2e.components.Tab.title('New tab').should('be.visible'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + + // Save dashboards and reload + e2e.flows.scenes.saveDashboard(); + cy.reload(); + + // Verify tab, row and panel titles after reload + e2e.components.DashboardRow.title('New row').should('be.visible'); + e2e.components.Tab.title('New tab').should('be.visible'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + + e2e.components.NavToolbar.editDashboard.editButton().click(); + + // Ungroup + e2e.flows.scenes.ungroupPanels(); // ungroup tabs + e2e.flows.scenes.ungroupPanels(); // ungroup rows + + // Verify tab and row titles is gone + e2e.components.DashboardRow.title('New row').should('not.exist'); + e2e.components.Tab.title('New tab').should('not.exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + + // Save dashboards and reload + e2e.flows.scenes.saveDashboard(); + cy.reload(); + + // Verify Row title is gone + e2e.components.DashboardRow.title('New row').should('not.exist'); + e2e.components.Tab.title('New tab').should('not.exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + }); + + /* + * Tabs + */ + it('can group and ungroup new panels into tab', () => { - e2e.flows.addDashboard({ title: 'Group new panels into tab' }); - cy.contains('Group new panels into tab').should('be.visible'); + e2e.flows.scenes.importV2Dashboard({ title: 'Group new panels into tab' }); - // Toggle edit mode - e2e.components.NavToolbar.editDashboard.editButton().should('be.visible').click(); - - // Add 3 panels - e2e.flows.scenes.addFirstPanel(); - e2e.flows.scenes.addPanel(); - e2e.flows.scenes.addPanel(); + e2e.components.NavToolbar.editDashboard.editButton().click(); // Group into tab e2e.flows.scenes.groupIntoTab(); @@ -81,7 +300,7 @@ describe('Grouping panels', () => { e2e.components.Tab.title('New tab').should('be.visible'); e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - e2e.components.NavToolbar.editDashboard.editButton().should('be.visible').click(); + e2e.components.NavToolbar.editDashboard.editButton().click(); // Ungroup e2e.flows.scenes.ungroupPanels(); @@ -99,17 +318,156 @@ describe('Grouping panels', () => { e2e.components.Panels.Panel.title('New panel').should('have.length', 3); }); + it('can add and remove several tabs', () => { + e2e.flows.scenes.importV2Dashboard({ title: 'Add and remove tabs' }); + + e2e.components.NavToolbar.editDashboard.editButton().click(); + + e2e.flows.scenes.groupIntoTab(); + + e2e.components.CanvasGridAddActions.addTab().click(); + e2e.flows.scenes.addPanel(); + + e2e.components.CanvasGridAddActions.addTab().click(); + e2e.flows.scenes.addPanel(); + + e2e.components.Tab.title('New tab').should('exist'); + e2e.components.Tab.title('New tab 1').should('exist'); + e2e.components.Tab.title('New tab 2').should('exist'); + e2e.components.Tab.title('New tab 2').should('have.attr', 'aria-selected', 'true'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 1); + + //Save dashboards and reload + e2e.flows.scenes.saveDashboard(); + cy.reload(); + + e2e.components.Tab.title('New tab').should('exist'); + e2e.components.Tab.title('New tab 1').should('exist'); + e2e.components.Tab.title('New tab 2').should('exist'); + e2e.components.Tab.title('New tab 2').should('have.attr', 'aria-selected', 'true'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 1); + + e2e.components.NavToolbar.editDashboard.editButton().click(); + + e2e.components.Tab.title('New tab 2').click(); + e2e.components.EditPaneHeader.deleteButton().click(); + e2e.pages.ConfirmModal.delete().click(); + + e2e.components.Tab.title('New tab 1').click(); + e2e.components.EditPaneHeader.deleteButton().click(); + e2e.pages.ConfirmModal.delete().click(); + + e2e.components.Tab.title('New tab').should('exist'); + e2e.components.Tab.title('New tab 1').should('not.exist'); + e2e.components.Tab.title('New tab 2').should('not.exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + + e2e.flows.scenes.saveDashboard(); + cy.reload(); + + e2e.components.Tab.title('New tab').should('exist'); + e2e.components.Tab.title('New tab 1').should('not.exist'); + e2e.components.Tab.title('New tab 2').should('not.exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + }); + + it('can paste a copied tab', () => { + e2e.flows.scenes.importV2Dashboard({ title: 'Paste tab' }); + + e2e.components.NavToolbar.editDashboard.editButton().click(); + + e2e.flows.scenes.groupIntoTab(); + + e2e.components.Tab.title('New tab').should('exist'); + + e2e.flows.scenes.editPaneCopy(); + + e2e.components.CanvasGridAddActions.pasteTab().click(); + + e2e.components.Tab.title('New tab').should('exist'); + e2e.components.Tab.title('New tab 1').should('exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + + e2e.flows.scenes.saveDashboard(); + cy.reload(); + + e2e.components.Tab.title('New tab').should('exist'); + e2e.components.Tab.title('New tab 1').should('exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + }); + + it('can duplicate a tab', () => { + e2e.flows.scenes.importV2Dashboard({ title: 'Duplicate tab' }); + + e2e.components.NavToolbar.editDashboard.editButton().click(); + + e2e.flows.scenes.groupIntoTab(); + + e2e.components.Tab.title('New tab').should('exist'); + + e2e.flows.scenes.editPaneDuplicate(); + + e2e.components.Tab.title('New tab').should('exist'); + e2e.components.Tab.title('New tab 1').should('exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + + e2e.flows.scenes.saveDashboard(); + cy.reload(); + + e2e.components.Tab.title('New tab').should('exist'); + e2e.components.Tab.title('New tab 1').should('exist'); + e2e.components.Panels.Panel.title('New panel').should('have.length', 3); + }); + + it('can convert tabs into rows when changing layout', () => { + e2e.flows.scenes.importV2Dashboard({ title: 'Tabs to rows' }); + + e2e.components.NavToolbar.editDashboard.editButton().click(); + + e2e.flows.scenes.groupIntoTab(); + + e2e.components.Tab.title('New tab').should('exist'); + + e2e.flows.scenes.editPaneDuplicate(); + e2e.flows.scenes.editPaneDuplicate(); + + e2e.components.Tab.title('New tab').should('exist'); + e2e.components.Tab.title('New tab 1').should('exist'); + e2e.components.Tab.title('New tab 2').should('exist'); + + e2e.components.EditPaneHeader.backButton().click({ force: true }); + + // expand collapsed layouts section + e2e.components.OptionsGroup.toggle('group-layout-category').click(); + + e2e.flows.scenes.selectRowsLayout(); + + e2e.components.DashboardRow.title('New tab').should('exist'); + e2e.components.Panels.Panel.title('New panel').first().should('be.visible'); // wait for panels to load + e2e.components.DashboardRow.title('New tab 1').should('exist'); + e2e.components.DashboardRow.title('New tab 2').should('exist'); + + e2e.components.DashboardEditPaneSplitter.primaryBody().scrollTo('bottom', { ensureScrollable: false }); + + e2e.components.Panels.Panel.title('New panel').should('have.length', 9); + + e2e.flows.scenes.saveDashboard(); + cy.reload(); + + e2e.components.DashboardRow.title('New tab').should('exist'); + e2e.components.Panels.Panel.title('New panel').first().should('be.visible'); // wait for panels to load + e2e.components.DashboardRow.title('New tab 1').should('exist'); + e2e.components.DashboardRow.title('New tab 2').should('exist'); + + cy.scrollTo('bottom'); + + e2e.components.Panels.Panel.title('New panel').should('have.length', 9); + }); + it('can group and ungroup new panels into tab with row', () => { - e2e.flows.addDashboard({ title: 'Group new panels into tab with row' }); - cy.contains('Group new panels into tab with row').should('be.visible'); + e2e.flows.scenes.importV2Dashboard({ title: 'Group new panels into tab with row' }); - // Toggle edit mode - e2e.components.NavToolbar.editDashboard.editButton().should('be.visible').click(); - - // Add 3 panels - e2e.flows.scenes.addFirstPanel(); - e2e.flows.scenes.addPanel(); - e2e.flows.scenes.addPanel(); + e2e.components.NavToolbar.editDashboard.editButton().click(); // Group into tab e2e.flows.scenes.groupIntoTab(); @@ -129,7 +487,7 @@ describe('Grouping panels', () => { e2e.components.DashboardRow.title('New row').should('be.visible'); e2e.components.Panels.Panel.title('New panel').should('have.length', 3); - e2e.components.NavToolbar.editDashboard.editButton().should('be.visible').click(); + e2e.components.NavToolbar.editDashboard.editButton().click(); // Ungroup e2e.flows.scenes.ungroupPanels(); // ungroup rows diff --git a/e2e/dashboards/TestV2Dashboard.json b/e2e/dashboards/TestV2Dashboard.json new file mode 100644 index 00000000000..da89762c3a6 --- /dev/null +++ b/e2e/dashboards/TestV2Dashboard.json @@ -0,0 +1,424 @@ +{ + "apiVersion": "dashboard.grafana.app/v2alpha1", + "kind": "Dashboard", + "metadata": { + "name": "admjzp8", + "namespace": "default", + "uid": "hrbekBWXeM7nC7GtouIbcngFyuqt8Xx7KlE4AnTwV7AX", + "resourceVersion": "1", + "generation": 1, + "creationTimestamp": "2025-05-16T09:41:56Z", + "labels": { + "grafana.app/deprecatedInternalID": "182" + }, + "annotations": { + "grafana.app/createdBy": "user:cejvsh18uudxcf", + "grafana.app/updatedBy": "user:cejvsh18uudxcf", + "grafana.app/updatedTimestamp": "2025-05-16T09:41:56Z", + "grafana.app/folder": "" + } + }, + "spec": { + "annotations": [ + { + "kind": "AnnotationQuery", + "spec": { + "builtIn": true, + "datasource": { + "type": "grafana", + "uid": "-- Grafana --" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts" + } + } + ], + "cursorSync": "Off", + "description": "", + "editable": true, + "elements": { + "panel-1": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "PD8C576611E62080A" + }, + "hidden": false, + "query": { + "kind": "grafana-testdata-datasource", + "spec": {} + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "", + "id": 1, + "links": [], + "title": "New panel", + "vizConfig": { + "kind": "timeseries", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.0-pre" + } + } + } + }, + "panel-2": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "PD8C576611E62080A" + }, + "hidden": false, + "query": { + "kind": "grafana-testdata-datasource", + "spec": {} + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "", + "id": 2, + "links": [], + "title": "New panel", + "vizConfig": { + "kind": "timeseries", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.0-pre" + } + } + } + }, + "panel-3": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "datasource": { + "type": "grafana-testdata-datasource", + "uid": "PD8C576611E62080A" + }, + "hidden": false, + "query": { + "kind": "grafana-testdata-datasource", + "spec": {} + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "", + "id": 3, + "links": [], + "title": "New panel", + "vizConfig": { + "kind": "timeseries", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.1.0-pre" + } + } + } + } + }, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-1" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-2" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-3" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 8 + } + } + ] + } + }, + "links": [], + "liveNow": false, + "preload": false, + "tags": [], + "timeSettings": { + "autoRefresh": "", + "autoRefreshIntervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"], + "fiscalYearStartMonth": 0, + "from": "now-6h", + "hideTimepicker": false, + "timezone": "browser", + "to": "now" + }, + "title": "New Test V2 Dashboard", + "variables": [] + }, + "status": {} +} diff --git a/e2e/utils/flows/scenes/addPanel.ts b/e2e/utils/flows/scenes/addPanel.ts index 1e7f31d0fe1..d911542afd2 100644 --- a/e2e/utils/flows/scenes/addPanel.ts +++ b/e2e/utils/flows/scenes/addPanel.ts @@ -2,7 +2,7 @@ import { e2e } from '../..'; export const addPanel = () => { e2e.components.DashboardEditPaneSplitter.primaryBody().scrollTo('bottom', { ensureScrollable: false }); - e2e.components.CanvasGridAddActions.addPanel().should('be.visible').click(); + e2e.components.CanvasGridAddActions.addPanel().last().should('be.visible').click(); }; export const addFirstPanel = () => { diff --git a/e2e/utils/flows/scenes/editPaneActions.ts b/e2e/utils/flows/scenes/editPaneActions.ts new file mode 100644 index 00000000000..bba3f40578e --- /dev/null +++ b/e2e/utils/flows/scenes/editPaneActions.ts @@ -0,0 +1,23 @@ +import { e2e } from '../..'; + +export const clickGroupLayoutButton = (buttonLabel: string) => { + cy.get(`[aria-label='layout-selection-option-${buttonLabel}']`).click(); +}; + +export const selectTabsLayout = () => { + clickGroupLayoutButton('Tabs'); +}; + +export const selectRowsLayout = () => { + clickGroupLayoutButton('Rows'); +}; + +const editPaneCopyOrDuplicate = (buttonLabel: string) => { + e2e.components.EditPaneHeader.copyDropdown().click(); + cy.get('[role="menu"]').within(() => { + cy.contains(buttonLabel).click(); + }); +}; + +export const editPaneCopy = () => editPaneCopyOrDuplicate('Copy'); +export const editPaneDuplicate = () => editPaneCopyOrDuplicate('Duplicate'); diff --git a/e2e/utils/flows/scenes/importDashboard.ts b/e2e/utils/flows/scenes/importDashboard.ts new file mode 100644 index 00000000000..e0b0a8ae929 --- /dev/null +++ b/e2e/utils/flows/scenes/importDashboard.ts @@ -0,0 +1,21 @@ +import { e2e } from '../..'; +import testV2Dashboard from '../../../dashboards/TestV2Dashboard.json'; + +export interface ImportDashboardConfig { + title?: string; +} + +export const importV2Dashboard = ({ title }: ImportDashboardConfig) => { + e2e.pages.ImportDashboard.visit(); + e2e.components.DashboardImportPage.textarea().type(JSON.stringify(testV2Dashboard), { + delay: 0, + parseSpecialCharSequences: false, + }); + + e2e.components.DashboardImportPage.submit().click(); + + if (title) { + e2e.components.ImportDashboardForm.name().clear().type(title); + } + e2e.components.ImportDashboardForm.submit().click(); +}; diff --git a/e2e/utils/flows/scenes/index.ts b/e2e/utils/flows/scenes/index.ts index c18a4151ab0..9a5562237dc 100644 --- a/e2e/utils/flows/scenes/index.ts +++ b/e2e/utils/flows/scenes/index.ts @@ -5,4 +5,6 @@ export * from './toggleEditMode'; export * from './movePanel'; export * from './groupPanels'; export * from './saveDashboard'; +export * from './importDashboard'; +export * from './editPaneActions'; export * from './selectPanel'; diff --git a/packages/grafana-e2e-selectors/src/selectors/components.ts b/packages/grafana-e2e-selectors/src/selectors/components.ts index 084acb8b561..2ed224e222d 100644 --- a/packages/grafana-e2e-selectors/src/selectors/components.ts +++ b/packages/grafana-e2e-selectors/src/selectors/components.ts @@ -33,6 +33,18 @@ export const versionedComponents = { ungroup: { '12.1.0': 'data-testid CanvasGridAddActions ungroup', }, + addRow: { + '12.1.0': 'data-testid CanvasGridAddActions add-row', + }, + pasteRow: { + '12.1.0': 'data-testid CanvasGridAddActions paste-row', + }, + addTab: { + '12.1.0': 'data-testid CanvasGridAddActions add-tab', + }, + pasteTab: { + '12.1.0': 'data-testid CanvasGridAddActions paste-tab', + }, }, DashboardEditPaneSplitter: { primaryBody: { @@ -43,6 +55,18 @@ export const versionedComponents = { deleteButton: { '12.1.0': 'data-testid EditPaneHeader delete panel', }, + copyDropdown: { + '12.1.0': 'data-testid EditPaneHeader copy dropdown', + }, + copy: { + '12.1.0': 'data-testid EditPaneHeader copy', + }, + duplicate: { + '12.1.0': 'data-testid EditPaneHeader duplicate', + }, + backButton: { + '12.1.0': 'data-testid EditPaneHeader back', + }, }, TimePicker: { openButton: { diff --git a/packages/grafana-e2e-selectors/src/selectors/pages.ts b/packages/grafana-e2e-selectors/src/selectors/pages.ts index 7ac2413298e..3a82ba6efe0 100644 --- a/packages/grafana-e2e-selectors/src/selectors/pages.ts +++ b/packages/grafana-e2e-selectors/src/selectors/pages.ts @@ -163,6 +163,11 @@ export const versionedPages = { }, }, }, + ImportDashboard: { + url: { + [MIN_GRAFANA_VERSION]: '/dashboard/import', + }, + }, Dashboard: { url: { [MIN_GRAFANA_VERSION]: (uid: string) => `/d/${uid}`, diff --git a/public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx b/public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx index 4c753cda529..3e1601062af 100644 --- a/public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx +++ b/public/app/features/dashboard-scene/edit-pane/EditPaneHeader.tsx @@ -36,6 +36,7 @@ export function EditPaneHeader({ element, editPane }: EditPaneHeaderProps) { onClick={onGoBack} tooltip={t('grafana.dashboard.edit-pane.go-back', 'Go back')} aria-label={t('grafana.dashboard.edit-pane.go-back', 'Go back')} + data-testid={selectors.components.EditPaneHeader.backButton} /> )} {elementInfo.typeName} @@ -65,6 +66,7 @@ export function EditPaneHeader({ element, editPane }: EditPaneHeaderProps) { variant="secondary" size="sm" icon="copy" + data-testid={selectors.components.EditPaneHeader.copyDropdown} > diff --git a/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx index a86c76ef184..ea2c0ac27f1 100644 --- a/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/layout-rows/RowsLayoutManagerRenderer.tsx @@ -2,6 +2,7 @@ import { css } from '@emotion/css'; import { DragDropContext, Droppable } from '@hello-pangea/dnd'; import { GrafanaTheme2 } from '@grafana/data'; +import { selectors } from '@grafana/e2e-selectors'; import { Trans } from '@grafana/i18n'; import { SceneComponentProps } from '@grafana/scenes'; import { Button, useStyles2 } from '@grafana/ui'; @@ -41,11 +42,23 @@ export function RowLayoutManagerRenderer({ model }: SceneComponentProps - model.addNewRow()}> + model.addNewRow()} + data-testid={selectors.components.CanvasGridAddActions.addRow} + > New row {hasCopiedRow && ( - model.pasteRow()}> + model.pasteRow()} + data-testid={selectors.components.CanvasGridAddActions.pasteRow} + > Paste row )} diff --git a/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManagerRenderer.tsx b/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManagerRenderer.tsx index 64f495a4734..fe592b171ab 100644 --- a/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManagerRenderer.tsx +++ b/public/app/features/dashboard-scene/scene/layout-tabs/TabsLayoutManagerRenderer.tsx @@ -2,6 +2,7 @@ import { css, cx } from '@emotion/css'; import { DragDropContext, Droppable } from '@hello-pangea/dnd'; import { GrafanaTheme2 } from '@grafana/data'; +import { selectors } from '@grafana/e2e-selectors'; import { Trans } from '@grafana/i18n'; import { SceneComponentProps } from '@grafana/scenes'; import { Button, TabContent, TabsBar, useStyles2 } from '@grafana/ui'; @@ -53,11 +54,23 @@ export function TabsLayoutManagerRenderer({ model }: SceneComponentProps {isEditing && ( - model.addNewTab()}> + model.addNewTab()} + data-testid={selectors.components.CanvasGridAddActions.addTab} + > New tab {hasCopiedTab && ( - model.pasteTab()}> + model.pasteTab()} + data-testid={selectors.components.CanvasGridAddActions.pasteTab} + > Paste tab )} diff --git a/public/app/features/dashboard-scene/scene/layouts-shared/DashboardLayoutSelector.tsx b/public/app/features/dashboard-scene/scene/layouts-shared/DashboardLayoutSelector.tsx index 75754db3c9a..ddac70cea1b 100644 --- a/public/app/features/dashboard-scene/scene/layouts-shared/DashboardLayoutSelector.tsx +++ b/public/app/features/dashboard-scene/scene/layouts-shared/DashboardLayoutSelector.tsx @@ -35,6 +35,7 @@ export function DashboardLayoutSelector({ layoutManager }: Props) { label: opt.name, icon: opt.icon, description: opt.description, + ariaLabel: `layout-selection-option-${opt.name}`, })); return (