mirror of
https://github.com/prometheus/prometheus.git
synced 2025-03-05 20:59:13 -08:00
Escape invalid css selector characters in tooltip ID (#6737)
* Escape invalid css selector characters in tooltip ID Signed-off-by: Dustin Hooten <dhooten@splunk.com> * Use CSS.escape polyfill to escape characters Signed-off-by: Dustin Hooten <dhooten@splunk.com>
This commit is contained in:
parent
0e912faf4f
commit
820d7775eb
|
@ -18,6 +18,7 @@
|
||||||
"@types/react-resize-detector": "^4.0.2",
|
"@types/react-resize-detector": "^4.0.2",
|
||||||
"@types/sanitize-html": "^1.20.2",
|
"@types/sanitize-html": "^1.20.2",
|
||||||
"bootstrap": "^4.2.1",
|
"bootstrap": "^4.2.1",
|
||||||
|
"css.escape": "^1.5.1",
|
||||||
"downshift": "^3.2.2",
|
"downshift": "^3.2.2",
|
||||||
"enzyme-to-json": "^3.4.3",
|
"enzyme-to-json": "^3.4.3",
|
||||||
"fuzzy": "^0.1.3",
|
"fuzzy": "^0.1.3",
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faSpinner } from '@fortawesome/free-solid-svg-icons';
|
import { faSpinner } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { FetchMock } from 'jest-fetch-mock/types';
|
import { FetchMock } from 'jest-fetch-mock/types';
|
||||||
|
|
||||||
describe('Flags', () => {
|
describe('ScrapePoolList', () => {
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
filter: { showHealthy: true, showUnhealthy: true },
|
filter: { showHealthy: true, showUnhealthy: true },
|
||||||
pathPrefix: '..',
|
pathPrefix: '..',
|
||||||
|
@ -39,7 +39,7 @@ describe('Flags', () => {
|
||||||
let mock: FetchMock;
|
let mock: FetchMock;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
//Tooltip requires DOM elements to exist. They do not in enzyme rendering so we must manually create them.
|
//Tooltip requires DOM elements to exist. They do not in enzyme rendering so we must manually create them.
|
||||||
const scrapePools: { [key: string]: number } = { blackbox: 3, node_exporter: 1, prometheus: 1 };
|
const scrapePools: { [key: string]: number } = { blackbox: 3, node_exporter: 1, 'prometheus/test': 1 };
|
||||||
Object.keys(scrapePools).forEach((pool: string): void => {
|
Object.keys(scrapePools).forEach((pool: string): void => {
|
||||||
Array.from(Array(scrapePools[pool]).keys()).forEach((idx: number): void => {
|
Array.from(Array(scrapePools[pool]).keys()).forEach((idx: number): void => {
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
|
|
|
@ -25,7 +25,7 @@ describe('targetLabels', () => {
|
||||||
it('renders a div of series labels', () => {
|
it('renders a div of series labels', () => {
|
||||||
const div = targetLabels.find('div').filterWhere(elem => elem.hasClass('series-labels-container'));
|
const div = targetLabels.find('div').filterWhere(elem => elem.hasClass('series-labels-container'));
|
||||||
expect(div).toHaveLength(1);
|
expect(div).toHaveLength(1);
|
||||||
expect(div.prop('id')).toEqual('series-labels-cortex/node-exporter_group/0-1');
|
expect(div.prop('id')).toEqual('series-labels-cortex\\/node-exporter_group\\/0-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('wraps each label in a label badge', () => {
|
it('wraps each label in a label badge', () => {
|
||||||
|
@ -41,7 +41,7 @@ describe('targetLabels', () => {
|
||||||
const tooltip = targetLabels.find(Tooltip);
|
const tooltip = targetLabels.find(Tooltip);
|
||||||
expect(tooltip).toHaveLength(1);
|
expect(tooltip).toHaveLength(1);
|
||||||
expect(tooltip.prop('isOpen')).toBe(false);
|
expect(tooltip.prop('isOpen')).toBe(false);
|
||||||
expect(tooltip.prop('target')).toEqual('series-labels-cortex/node-exporter_group/0-1');
|
expect(tooltip.prop('target')).toEqual('series-labels-cortex\\/node-exporter_group\\/0-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders discovered labels', () => {
|
it('renders discovered labels', () => {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { FC, Fragment, useState } from 'react';
|
import React, { FC, Fragment, useState } from 'react';
|
||||||
import { Badge, Tooltip } from 'reactstrap';
|
import { Badge, Tooltip } from 'reactstrap';
|
||||||
|
import 'css.escape';
|
||||||
import styles from './TargetLabels.module.css';
|
import styles from './TargetLabels.module.css';
|
||||||
|
|
||||||
interface Labels {
|
interface Labels {
|
||||||
|
@ -19,7 +20,7 @@ const TargetLabels: FC<TargetLabelsProps> = ({ discoveredLabels, labels, idx, sc
|
||||||
const [tooltipOpen, setTooltipOpen] = useState(false);
|
const [tooltipOpen, setTooltipOpen] = useState(false);
|
||||||
|
|
||||||
const toggle = (): void => setTooltipOpen(!tooltipOpen);
|
const toggle = (): void => setTooltipOpen(!tooltipOpen);
|
||||||
const id = `series-labels-${scrapePool}-${idx}`;
|
const id = `series-labels-${CSS.escape(scrapePool)}-${idx}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -4,7 +4,7 @@ exports[`targetLabels renders discovered labels 1`] = `
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<div
|
<div
|
||||||
className="series-labels-container"
|
className="series-labels-container"
|
||||||
id="series-labels-cortex/node-exporter_group/0-1"
|
id="series-labels-cortex\\\\/node-exporter_group\\\\/0-1"
|
||||||
>
|
>
|
||||||
<Badge
|
<Badge
|
||||||
className="mr-1 instance"
|
className="mr-1 instance"
|
||||||
|
@ -45,7 +45,7 @@ exports[`targetLabels renders discovered labels 1`] = `
|
||||||
"textAlign": "left",
|
"textAlign": "left",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
target="series-labels-cortex/node-exporter_group/0-1"
|
target="series-labels-cortex\\\\/node-exporter_group\\\\/0-1"
|
||||||
toggle={[Function]}
|
toggle={[Function]}
|
||||||
trigger="click hover focus"
|
trigger="click hover focus"
|
||||||
>
|
>
|
||||||
|
|
|
@ -197,13 +197,13 @@ export const sampleApiResponse = Object.freeze({
|
||||||
__address__: 'localhost:9090',
|
__address__: 'localhost:9090',
|
||||||
__metrics_path__: '/metrics',
|
__metrics_path__: '/metrics',
|
||||||
__scheme__: 'http',
|
__scheme__: 'http',
|
||||||
job: 'prometheus',
|
job: 'prometheus/test',
|
||||||
},
|
},
|
||||||
labels: {
|
labels: {
|
||||||
instance: 'localhost:9090',
|
instance: 'localhost:9090',
|
||||||
job: 'prometheus',
|
job: 'prometheus/test',
|
||||||
},
|
},
|
||||||
scrapePool: 'prometheus',
|
scrapePool: 'prometheus/test',
|
||||||
scrapeUrl: 'http://localhost:9090/metrics',
|
scrapeUrl: 'http://localhost:9090/metrics',
|
||||||
lastError: '',
|
lastError: '',
|
||||||
lastScrape: '2019-11-04T11:52:18.479731-07:00',
|
lastScrape: '2019-11-04T11:52:18.479731-07:00',
|
||||||
|
|
|
@ -8,7 +8,7 @@ describe('groupTargets', () => {
|
||||||
const targetGroups: ScrapePools = groupTargets(targets);
|
const targetGroups: ScrapePools = groupTargets(targets);
|
||||||
|
|
||||||
it('groups a list of targets by scrape job', () => {
|
it('groups a list of targets by scrape job', () => {
|
||||||
['blackbox', 'prometheus', 'node_exporter'].forEach(scrapePool => {
|
['blackbox', 'prometheus/test', 'node_exporter'].forEach(scrapePool => {
|
||||||
expect(Object.keys(targetGroups)).toContain(scrapePool);
|
expect(Object.keys(targetGroups)).toContain(scrapePool);
|
||||||
});
|
});
|
||||||
Object.keys(targetGroups).forEach((scrapePool: string): void => {
|
Object.keys(targetGroups).forEach((scrapePool: string): void => {
|
||||||
|
@ -20,7 +20,7 @@ describe('groupTargets', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('adds upCount during aggregation', () => {
|
it('adds upCount during aggregation', () => {
|
||||||
const testCases: { [key: string]: number } = { blackbox: 3, prometheus: 1, node_exporter: 1 };
|
const testCases: { [key: string]: number } = { blackbox: 3, 'prometheus/test': 1, node_exporter: 1 };
|
||||||
Object.keys(testCases).forEach((scrapePool: string): void => {
|
Object.keys(testCases).forEach((scrapePool: string): void => {
|
||||||
expect(targetGroups[scrapePool].upCount).toEqual(testCases[scrapePool]);
|
expect(targetGroups[scrapePool].upCount).toEqual(testCases[scrapePool]);
|
||||||
});
|
});
|
||||||
|
|
|
@ -3357,6 +3357,11 @@ css-what@2.1, css-what@^2.1.2:
|
||||||
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
|
resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
|
||||||
integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
|
integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
|
||||||
|
|
||||||
|
css.escape@^1.5.1:
|
||||||
|
version "1.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
|
||||||
|
integrity sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=
|
||||||
|
|
||||||
css@^2.0.0:
|
css@^2.0.0:
|
||||||
version "2.2.4"
|
version "2.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929"
|
resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929"
|
||||||
|
@ -4718,11 +4723,6 @@ flatten@^1.0.2:
|
||||||
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
|
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
|
||||||
integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=
|
integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=
|
||||||
|
|
||||||
flot@^3.2.13:
|
|
||||||
version "3.2.13"
|
|
||||||
resolved "https://registry.yarnpkg.com/flot/-/flot-3.2.13.tgz#f4457fd6042fe4ac4e4e124e7a7c7256e69f5362"
|
|
||||||
integrity sha512-ZJl8zazqgbn79YCdyzt9JV1r38Gk7Dkt+tBb5Kx1sMEDvLVz+ViwF/QTWKcYjyaPO+UW58FP+fFWZFp6dXeMAA==
|
|
||||||
|
|
||||||
flush-write-stream@^1.0.0:
|
flush-write-stream@^1.0.0:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
|
resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
|
||||||
|
|
Loading…
Reference in a new issue