From fa2781391a7f1e684d545957d9186847a2c12ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Thu, 1 Oct 2020 08:44:56 +0200 Subject: [PATCH] DashboardLinks: values in links are updated when variables change (#27926) * DashboardLinks: values in links are updated when variable changes * Tests: adds e2e test that verifies links --- ...plating-dashboard-links-and-variables.json | 132 ++++++++++++++++++ ...emplating-dashboard-links-and-variables.ts | 68 +++++++++ .../src/selectors/components.ts | 5 + .../components/SubMenu/DashboardLinks.tsx | 10 +- .../SubMenu/DashboardLinksDashboard.tsx | 28 +++- 5 files changed, 234 insertions(+), 9 deletions(-) create mode 100644 devenv/dev-dashboards/feature-templating/templating-dashboard-links-and-variables.json create mode 100644 e2e/suite1/specs/templating-dashboard-links-and-variables.ts diff --git a/devenv/dev-dashboards/feature-templating/templating-dashboard-links-and-variables.json b/devenv/dev-dashboards/feature-templating/templating-dashboard-links-and-variables.json new file mode 100644 index 00000000000..f5751ec42f5 --- /dev/null +++ b/devenv/dev-dashboards/feature-templating/templating-dashboard-links-and-variables.json @@ -0,0 +1,132 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": null, + "iteration": 1601526910610, + "links": [ + { + "icon": "external link", + "includeVars": true, + "tags": [], + "title": "Grafana", + "tooltip": "", + "type": "link", + "url": "http://www.grafana.com" + }, + { + "asDropdown": true, + "icon": "external link", + "includeVars": true, + "tags": ["templating"], + "title": "Link as DropDown", + "type": "dashboards" + }, + { + "icon": "external link", + "includeVars": true, + "tags": ["demo"], + "type": "dashboards" + } + ], + "panels": [ + { + "description": "", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 2, + "options": { + "content": "# ${custom.text}\n ", + "mode": "markdown" + }, + "pluginVersion": "7.3.0-pre", + "targets": [ + { + "refId": "A", + "scenarioId": "random_walk" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "${custom.text}", + "type": "text" + } + ], + "schemaVersion": 26, + "style": "dark", + "tags": ["gdev", "templating"], + "templating": { + "list": [ + { + "allValue": null, + "current": { + "selected": false, + "text": "All", + "value": "$__all" + }, + "hide": 0, + "includeAll": true, + "label": null, + "multi": true, + "name": "custom", + "options": [ + { + "selected": true, + "text": "All", + "value": "$__all" + }, + { + "selected": false, + "text": "p1", + "value": "p1" + }, + { + "selected": false, + "text": "p2", + "value": "p2" + }, + { + "selected": false, + "text": "p3", + "value": "p3" + } + ], + "query": "p1,p2,p3", + "skipUrlSync": false, + "type": "custom" + } + ] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Templating - Dashboard Links and Variables", + "uid": "yBCC3aKGk", + "version": 7 +} diff --git a/e2e/suite1/specs/templating-dashboard-links-and-variables.ts b/e2e/suite1/specs/templating-dashboard-links-and-variables.ts new file mode 100644 index 00000000000..336fe11e69e --- /dev/null +++ b/e2e/suite1/specs/templating-dashboard-links-and-variables.ts @@ -0,0 +1,68 @@ +import { e2e } from '@grafana/e2e'; + +e2e.scenario({ + describeName: 'Templating', + itName: 'Tests dashboard links and variables in links', + addScenarioDataSource: false, + addScenarioDashBoard: false, + skipScenario: false, + scenario: () => { + e2e.flows.openDashboard({ uid: 'yBCC3aKGk' }); + e2e().server(); + e2e() + .route({ + method: 'GET', + url: '/api/search?tag=templating&limit=100', + }) + .as('tagsTemplatingSearch'); + e2e() + .route({ + method: 'GET', + url: '/api/search?tag=demo&limit=100', + }) + .as('tagsDemoSearch'); + + // waiting for links to render, couldn't find a better way using routes for instance + e2e().wait(1000); + + const verifyLinks = (variableValue: string) => { + e2e.components.DashboardLinks.link() + .should('be.visible') + .and(links => { + expect(links).to.have.length(13); + + for (let index = 0; index < links.length; index++) { + expect(Cypress.$(links[index]).attr('href')).contains(`var-custom=${variableValue}`); + } + }); + }; + + e2e.components.DashboardLinks.dropDown() + .should('be.visible') + .click() + .wait('@tagsTemplatingSearch') + .wait('@tagsDemoSearch'); + + // verify all links, should have All value + verifyLinks('All'); + + e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownValueLinkTexts('All') + .should('be.visible') + .click(); + + e2e.pages.Dashboard.SubMenu.submenuItemValueDropDownOptionTexts('p2') + .should('be.visible') + .click(); + + e2e.pages.Dashboard.Toolbar.navBar().click(); + + e2e.components.DashboardLinks.dropDown() + .should('be.visible') + .click() + .wait('@tagsTemplatingSearch') + .wait('@tagsDemoSearch'); + + // verify all links, should have p2 value + verifyLinks('p2'); + }, +}); diff --git a/packages/grafana-e2e-selectors/src/selectors/components.ts b/packages/grafana-e2e-selectors/src/selectors/components.ts index e501eadde04..61fa2922ecf 100644 --- a/packages/grafana-e2e-selectors/src/selectors/components.ts +++ b/packages/grafana-e2e-selectors/src/selectors/components.ts @@ -153,4 +153,9 @@ export const Components = { section: 'Search section', items: 'Search items', }, + DashboardLinks: { + container: 'Dashboard link container', + dropDown: 'Dashboard link dropdown', + link: 'Dashboard link', + }, }; diff --git a/public/app/features/dashboard/components/SubMenu/DashboardLinks.tsx b/public/app/features/dashboard/components/SubMenu/DashboardLinks.tsx index 14db266dda3..d733eab69fe 100644 --- a/public/app/features/dashboard/components/SubMenu/DashboardLinks.tsx +++ b/public/app/features/dashboard/components/SubMenu/DashboardLinks.tsx @@ -9,6 +9,7 @@ import { DashboardLink } from '../../state/DashboardModel'; import { iconMap } from '../DashLinks/DashLinksEditorCtrl'; import { useEffectOnce } from 'react-use'; import { CoreEvents } from 'app/types'; +import { selectors } from '@grafana/e2e-selectors'; export interface Props { dashboard: DashboardModel; @@ -42,14 +43,19 @@ export const DashboardLinks: FC = ({ dashboard, links }) => { } const linkElement = ( - + {sanitize(linkInfo.title)} ); return ( -
+
{link.tooltip ? {linkElement} : linkElement}
); diff --git a/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx b/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx index 9d6a4b559a7..bbe445b3122 100644 --- a/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx +++ b/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx @@ -5,6 +5,7 @@ import { getBackendSrv } from 'app/core/services/backend_srv'; import { getLinkSrv } from '../../../panel/panellinks/link_srv'; import { DashboardLink } from '../../state/DashboardModel'; import { DashboardSearchHit } from 'app/features/search/types'; +import { selectors } from '@grafana/e2e-selectors'; interface Props { link: DashboardLink; @@ -24,7 +25,7 @@ export class DashboardLinksDashboard extends PureComponent { } componentDidUpdate(prevProps: Readonly) { - if (this.props.link !== prevProps.link) { + if (this.props.link !== prevProps.link || this.props.linkInfo !== prevProps.linkInfo) { this.searchForDashboards(); } } @@ -38,11 +39,11 @@ export class DashboardLinksDashboard extends PureComponent { this.setState({ resolvedLinks }); }; - renderElement = (linkElement: JSX.Element, key: string) => { + renderElement = (linkElement: JSX.Element, key: string, selector: string) => { const { link } = this.props; return ( -
+
{link.tooltip && {linkElement}} {!link.tooltip && <>{linkElement}}
@@ -58,12 +59,21 @@ export class DashboardLinksDashboard extends PureComponent { {resolvedLinks.length > 0 && resolvedLinks.map((resolvedLink, index) => { const linkElement = ( - + {resolvedLink.title} ); - return this.renderElement(linkElement, `dashlinks-list-item-${resolvedLink.id}-${index}`); + return this.renderElement( + linkElement, + `dashlinks-list-item-${resolvedLink.id}-${index}`, + selectors.components.DashboardLinks.container + ); })} ); @@ -89,7 +99,11 @@ export class DashboardLinksDashboard extends PureComponent { resolvedLinks.map((resolvedLink, index) => { return (
  • - + {resolvedLink.title}
  • @@ -99,7 +113,7 @@ export class DashboardLinksDashboard extends PureComponent { ); - return this.renderElement(linkElement, 'dashlinks-dropdown'); + return this.renderElement(linkElement, 'dashlinks-dropdown', selectors.components.DashboardLinks.dropDown); }; render() {