feat: render IPv6 links (#9853)

* feat: render IPv6 links

Signed-off-by: mtfoley <mtfoley.mae@gmail.com>
This commit is contained in:
Matthew 2021-11-29 10:33:47 -05:00 committed by GitHub
parent d677aa4b29
commit 8e9b8d499d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 15 deletions

View File

@ -1,6 +1,6 @@
import React from 'react';
import { shallow, mount } from 'enzyme';
import { Badge, Alert } from 'reactstrap';
import { Badge } from 'reactstrap';
import EndpointLink from './EndpointLink';
describe('EndpointLink', () => {
@ -29,11 +29,24 @@ describe('EndpointLink', () => {
const targetLabel = badges.filterWhere((badge) => badge.children().text() === 'target="http://some-service"');
expect(targetLabel.length).toEqual(1);
});
it('renders an alert if url is invalid', () => {
const endpointLink = shallow(<EndpointLink endpoint={'afdsacas'} globalUrl={'afdsacas'} />);
const err = endpointLink.find(Alert);
expect(err.render().text()).toEqual('Error: Invalid URL: afdsacas');
// In cases of IPv6 addresses with a Zone ID, URL may not be parseable.
// See https://github.com/prometheus/prometheus/issues/9760
it('renders an anchor for IPv6 link with zone ID including labels for query params', () => {
const endpoint =
'http://[fe80::f1ee:adeb:371d:983%eth1]:9100/stats/prometheus?module=http_2xx&target=http://some-service';
const globalURL =
'http://[fe80::f1ee:adeb:371d:983%eth1]:9100/stats/prometheus?module=http_2xx&target=http://some-service';
const endpointLink = shallow(<EndpointLink endpoint={endpoint} globalUrl={globalURL} />);
const anchor = endpointLink.find('a');
const badges = endpointLink.find(Badge);
expect(anchor.prop('href')).toEqual(globalURL);
expect(anchor.children().text()).toEqual('http://[fe80::f1ee:adeb:371d:983%eth1]:9100/stats/prometheus');
expect(endpointLink.find('br')).toHaveLength(1);
expect(badges).toHaveLength(2);
const moduleLabel = badges.filterWhere((badge) => badge.children().text() === 'module="http_2xx"');
expect(moduleLabel.length).toEqual(1);
const targetLabel = badges.filterWhere((badge) => badge.children().text() === 'target="http://some-service"');
expect(targetLabel.length).toEqual(1);
});
it('handles params with multiple values correctly', () => {

View File

@ -1,5 +1,5 @@
import React, { FC } from 'react';
import { Badge, Alert } from 'reactstrap';
import { Badge } from 'reactstrap';
export interface EndpointLinkProps {
endpoint: string;
@ -8,23 +8,28 @@ export interface EndpointLinkProps {
const EndpointLink: FC<EndpointLinkProps> = ({ endpoint, globalUrl }) => {
let url: URL;
let search = '';
let invalidURL = false;
try {
url = new URL(endpoint);
} catch (err: unknown) {
const error = err as Error;
return (
<Alert color="danger">
<strong>Error:</strong> {error.message}
</Alert>
);
// In cases of IPv6 addresses with a Zone ID, URL may not be parseable.
// See https://github.com/prometheus/prometheus/issues/9760
// In this case, we attempt to prepare a synthetic URL with the
// same query parameters, for rendering purposes.
invalidURL = true;
if (endpoint.indexOf('?') > -1) {
search = endpoint.substring(endpoint.indexOf('?'));
}
url = new URL('http://0.0.0.0' + search);
}
const { host, pathname, protocol, searchParams }: URL = url;
const params = Array.from(searchParams.entries());
const displayLink = invalidURL ? endpoint.replace(search, '') : `${protocol}//${host}${pathname}`;
return (
<>
<a href={globalUrl}>{`${protocol}//${host}${pathname}`}</a>
<a href={globalUrl}>{displayLink}</a>
{params.length > 0 ? <br /> : null}
{params.map(([labelName, labelValue]: [string, string]) => {
return (