From 3018c6a1b1b2a4280c680979650b711c5d7a7abe Mon Sep 17 00:00:00 2001 From: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> Date: Fri, 4 Dec 2020 17:01:43 +0100 Subject: [PATCH] Prometheus: Fix link to Prometheus graph in dashboard (#29543) * Fix Promlink to have href after componentDidMount * Refactor to hooks and react testing library * Update * Update snapshot test --- .../prometheus/components/PromLink.test.tsx | 105 ++++++++++-------- .../prometheus/components/PromLink.tsx | 99 ++++++++--------- .../PromQueryEditor.test.tsx.snap | 2 +- 3 files changed, 103 insertions(+), 103 deletions(-) diff --git a/public/app/plugins/datasource/prometheus/components/PromLink.test.tsx b/public/app/plugins/datasource/prometheus/components/PromLink.test.tsx index 0206173211d..7087b7d79de 100644 --- a/public/app/plugins/datasource/prometheus/components/PromLink.test.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromLink.test.tsx @@ -1,58 +1,67 @@ import React from 'react'; -import { mount } from 'enzyme'; +import { render, screen } from '@testing-library/react'; +import { PanelData } from '@grafana/data'; +import { PromQuery } from '../types'; +import { PrometheusDatasource } from '../datasource'; import PromLink from './PromLink'; -const getPanelData = () => ({ - request: { - targets: [ - { refId: 'A', datasource: 'prom1' }, - { refId: 'B', datasource: 'prom2' }, - ], - range: { - to: { - utc: () => ({ - format: jest.fn(), - }), +const getPanelData = (panelDataOverrides?: Partial) => { + const panelData = { + request: { + targets: [ + { refId: 'A', datasource: 'prom1' }, + { refId: 'B', datasource: 'prom2' }, + ], + range: { + to: { + utc: () => ({ + format: jest.fn(), + }), + }, }, }, - }, -}); -describe('PromLink component', () => { - it('should show different link when there are 2 components with the same panel data', async () => { - const Comp = () => ( + }; + + return Object.assign(panelData, panelDataOverrides) as PanelData; +}; + +const getDataSource = (datasourceOverrides?: Partial) => { + const datasource = { + getPrometheusTime: () => 123, + createQuery: () => ({ expr: 'up', step: 15 }), + directUrl: 'prom1', + }; + + return (Object.assign(datasource, datasourceOverrides) as unknown) as PrometheusDatasource; +}; + +describe('PromLink', () => { + it('should show correct link for 1 component', async () => { + render(
- 123, createQuery: () => ({ expr: 'up', step: 15 }), directUrl: 'prom1' } as any - } - panelData={getPanelData() as any} - query={{} as any} - /> - 123, createQuery: () => ({ expr: 'up', step: 15 }), directUrl: 'prom2' } as any - } - panelData={getPanelData() as any} - query={{} as any} - /> +
); - const wrapper = mount(); - // Trigger componentDidUpdate - wrapper.setProps('s'); - await Promise.resolve(); - - expect( - wrapper - .find('a') - .first() - .getDOMNode().href - ).toMatch('prom1'); - expect( - wrapper - .find('a') - .last() - .getDOMNode().href - ).toMatch('prom2'); + expect(screen.getByText('Prometheus')).toHaveAttribute( + 'href', + 'prom1/graph?g0.expr=up&g0.range_input=0s&g0.end_input=undefined&g0.step_input=15&g0.tab=0' + ); + }); + it('should show different link when there are 2 components with the same panel data', () => { + render( +
+ + +
+ ); + const promLinkButtons = screen.getAllByText('Prometheus'); + expect(promLinkButtons[0]).toHaveAttribute( + 'href', + 'prom1/graph?g0.expr=up&g0.range_input=0s&g0.end_input=undefined&g0.step_input=15&g0.tab=0' + ); + expect(promLinkButtons[1]).toHaveAttribute( + 'href', + 'prom2/graph?g0.expr=up&g0.range_input=0s&g0.end_input=undefined&g0.step_input=15&g0.tab=0' + ); }); }); diff --git a/public/app/plugins/datasource/prometheus/components/PromLink.tsx b/public/app/plugins/datasource/prometheus/components/PromLink.tsx index 18cc7e9c81c..b88c2072909 100644 --- a/public/app/plugins/datasource/prometheus/components/PromLink.tsx +++ b/public/app/plugins/datasource/prometheus/components/PromLink.tsx @@ -1,5 +1,5 @@ import _ from 'lodash'; -import React, { Component } from 'react'; +import React, { FC, useEffect, useState, memo } from 'react'; import { PrometheusDatasource } from '../datasource'; import { PromQuery } from '../types'; @@ -11,62 +11,53 @@ interface Props { panelData?: PanelData; } -interface State { - href: string; -} +const PromLink: FC = ({ panelData, query, datasource }) => { + const [href, setHref] = useState(''); -export default class PromLink extends Component { - state: State = { href: '' }; + useEffect(() => { + if (panelData) { + const getExternalLink = () => { + if (!panelData.request) { + return ''; + } - async componentDidUpdate(prevProps: Props) { - const { panelData } = this.props; + const { + request: { range, interval }, + } = panelData; - if (panelData && panelData.request && prevProps.panelData !== panelData) { - const href = await this.getExternalLink(panelData); - this.setState({ href }); + const start = datasource.getPrometheusTime(range.from, false); + const end = datasource.getPrometheusTime(range.to, true); + const rangeDiff = Math.ceil(end - start); + const endTime = range.to.utc().format('YYYY-MM-DD HH:mm'); + + const options = { + interval, + } as DataQueryRequest; + + const queryOptions = datasource.createQuery(query, options, start, end); + const expr = { + 'g0.expr': queryOptions.expr, + 'g0.range_input': rangeDiff + 's', + 'g0.end_input': endTime, + 'g0.step_input': queryOptions.step, + 'g0.tab': 0, + }; + + const args = _.map(expr, (v: string, k: string) => { + return k + '=' + encodeURIComponent(v); + }).join('&'); + return `${datasource.directUrl}/graph?${args}`; + }; + + setHref(getExternalLink()); } - } + }, [panelData]); - async getExternalLink(panelData: PanelData): Promise { - const { query, datasource } = this.props; - const { request } = panelData; + return ( + + Prometheus + + ); +}; - if (!request) { - return ''; - } - - const range = request.range; - const start = datasource.getPrometheusTime(range.from, false); - const end = datasource.getPrometheusTime(range.to, true); - const rangeDiff = Math.ceil(end - start); - const endTime = range.to.utc().format('YYYY-MM-DD HH:mm'); - - const options = { - interval: request.interval, - } as DataQueryRequest; - - const queryOptions = datasource.createQuery(query, options, start, end); - const expr = { - 'g0.expr': queryOptions.expr, - 'g0.range_input': rangeDiff + 's', - 'g0.end_input': endTime, - 'g0.step_input': queryOptions.step, - 'g0.tab': 0, - }; - - const args = _.map(expr, (v: string, k: string) => { - return k + '=' + encodeURIComponent(v); - }).join('&'); - return `${datasource.directUrl}/graph?${args}`; - } - - render() { - const { href } = this.state; - - return ( - - Prometheus - - ); - } -} +export default memo(PromLink); diff --git a/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap b/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap index 7d2f4ee1866..e1647b3fcc6 100644 --- a/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap +++ b/public/app/plugins/datasource/prometheus/components/__snapshots__/PromQueryEditor.test.tsx.snap @@ -164,7 +164,7 @@ exports[`Render PromQueryEditor with basic options should render 1`] = ` tooltip="Link to Graph in Prometheus" width={10} > -