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
This commit is contained in:
Ivana Huckova 2020-12-04 17:01:43 +01:00 committed by GitHub
parent c2e81ab166
commit 3018c6a1b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 103 additions and 103 deletions

View File

@ -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<PanelData>) => {
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<PrometheusDatasource>) => {
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(
<div>
<PromLink
datasource={
{ getPrometheusTime: () => 123, createQuery: () => ({ expr: 'up', step: 15 }), directUrl: 'prom1' } as any
}
panelData={getPanelData() as any}
query={{} as any}
/>
<PromLink
datasource={
{ getPrometheusTime: () => 123, createQuery: () => ({ expr: 'up', step: 15 }), directUrl: 'prom2' } as any
}
panelData={getPanelData() as any}
query={{} as any}
/>
<PromLink datasource={getDataSource()} panelData={getPanelData()} query={{} as PromQuery} />
</div>
);
const wrapper = mount(<Comp />);
// Trigger componentDidUpdate
wrapper.setProps('s');
await Promise.resolve();
expect(
wrapper
.find('a')
.first()
.getDOMNode<HTMLAnchorElement>().href
).toMatch('prom1');
expect(
wrapper
.find('a')
.last()
.getDOMNode<HTMLAnchorElement>().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(
<div>
<PromLink datasource={getDataSource()} panelData={getPanelData()} query={{} as PromQuery} />
<PromLink datasource={getDataSource({ directUrl: 'prom2' })} panelData={getPanelData()} query={{} as any} />
</div>
);
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'
);
});
});

View File

@ -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<Props> = ({ panelData, query, datasource }) => {
const [href, setHref] = useState('');
export default class PromLink extends Component<Props, State> {
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<PromQuery>;
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<string> {
const { query, datasource } = this.props;
const { request } = panelData;
return (
<a href={href} target="_blank" rel="noopener noreferrer">
Prometheus
</a>
);
};
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<PromQuery>;
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 (
<a href={href} target="_blank" rel="noopener noreferrer">
Prometheus
</a>
);
}
}
export default memo(PromLink);

View File

@ -164,7 +164,7 @@ exports[`Render PromQueryEditor with basic options should render 1`] = `
tooltip="Link to Graph in Prometheus"
width={10}
>
<PromLink
<Memo(PromLink)
datasource={
Object {
"createQuery": [MockFunction],