mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-24 21:24:05 -08:00
Feat UI metrics search (#9629)
* feat: add search to metrics explorer Signed-off-by: mtfoley <mtfoley.mae@gmail.com> * fix: ui-lint and ui-build errors Signed-off-by: mtfoley <mtfoley.mae@gmail.com> * feat: use @nexucis/fuzzy Signed-off-by: mtfoley <mtfoley.mae@gmail.com> * chore: code style and delete commented test Signed-off-by: mtfoley <mtfoley.mae@gmail.com> * rename Props to MetricsExplorerProps Signed-off-by: mtfoley <mtfoley.mae@gmail.com>
This commit is contained in:
parent
4caae4e4a6
commit
628211c25a
46
web/ui/react-app/src/pages/graph/MetricsExplorer.test.tsx
Normal file
46
web/ui/react-app/src/pages/graph/MetricsExplorer.test.tsx
Normal file
|
@ -0,0 +1,46 @@
|
|||
import * as React from 'react';
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import MetricsExplorer from './MetricsExplorer';
|
||||
import { Input } from 'reactstrap';
|
||||
|
||||
describe('MetricsExplorer', () => {
|
||||
const spyInsertAtCursor = jest.fn().mockImplementation((value: string) => {
|
||||
value = value;
|
||||
});
|
||||
const metricsExplorerProps = {
|
||||
show: true,
|
||||
updateShow: (show: boolean): void => {
|
||||
show = show;
|
||||
},
|
||||
metrics: ['go_test_1', 'prometheus_test_1'],
|
||||
insertAtCursor: spyInsertAtCursor,
|
||||
};
|
||||
|
||||
let metricsExplorer: ReactWrapper;
|
||||
beforeEach(() => {
|
||||
metricsExplorer = mount(<MetricsExplorer {...metricsExplorerProps} />);
|
||||
});
|
||||
|
||||
it('renders an Input[type=text]', () => {
|
||||
const input = metricsExplorer.find(Input);
|
||||
expect(input.prop('type')).toEqual('text');
|
||||
});
|
||||
|
||||
it('lists all metrics in props', () => {
|
||||
const metrics = metricsExplorer.find('.metric');
|
||||
expect(metrics).toHaveLength(metricsExplorerProps.metrics.length);
|
||||
});
|
||||
|
||||
it('filters metrics with search', () => {
|
||||
const input = metricsExplorer.find(Input);
|
||||
input.simulate('change', { target: { value: 'go' } });
|
||||
const metrics = metricsExplorer.find('.metric');
|
||||
expect(metrics).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('handles click on metric', () => {
|
||||
const metric = metricsExplorer.find('.metric').at(0);
|
||||
metric.simulate('click');
|
||||
expect(metricsExplorerProps.insertAtCursor).toHaveBeenCalled();
|
||||
});
|
||||
});
|
|
@ -1,33 +1,60 @@
|
|||
import React, { Component } from 'react';
|
||||
import { Modal, ModalBody, ModalHeader } from 'reactstrap';
|
||||
import React, { Component, ChangeEvent } from 'react';
|
||||
import { Modal, ModalBody, ModalHeader, Input } from 'reactstrap';
|
||||
import { Fuzzy, FuzzyResult } from '@nexucis/fuzzy';
|
||||
|
||||
interface Props {
|
||||
const fuz = new Fuzzy({ pre: '<strong>', post: '</strong>', shouldSort: true });
|
||||
|
||||
interface MetricsExplorerProps {
|
||||
show: boolean;
|
||||
updateShow(show: boolean): void;
|
||||
metrics: string[];
|
||||
insertAtCursor(value: string): void;
|
||||
}
|
||||
|
||||
class MetricsExplorer extends Component<Props> {
|
||||
type MetricsExplorerState = {
|
||||
searchTerm: string;
|
||||
};
|
||||
|
||||
class MetricsExplorer extends Component<MetricsExplorerProps, MetricsExplorerState> {
|
||||
constructor(props: MetricsExplorerProps) {
|
||||
super(props);
|
||||
this.state = { searchTerm: '' };
|
||||
}
|
||||
handleSearchTerm = (event: ChangeEvent<HTMLInputElement>): void => {
|
||||
this.setState({ searchTerm: event.target.value });
|
||||
};
|
||||
handleMetricClick = (query: string): void => {
|
||||
this.props.insertAtCursor(query);
|
||||
this.props.updateShow(false);
|
||||
this.setState({ searchTerm: '' });
|
||||
};
|
||||
|
||||
toggle = (): void => {
|
||||
this.props.updateShow(!this.props.show);
|
||||
};
|
||||
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<Modal isOpen={this.props.show} toggle={this.toggle} className="metrics-explorer">
|
||||
<Modal isOpen={this.props.show} toggle={this.toggle} className="metrics-explorer" scrollable>
|
||||
<ModalHeader toggle={this.toggle}>Metrics Explorer</ModalHeader>
|
||||
<ModalBody>
|
||||
{this.props.metrics.map((metric) => (
|
||||
<p key={metric} className="metric" onClick={this.handleMetricClick.bind(this, metric)}>
|
||||
{metric}
|
||||
</p>
|
||||
))}
|
||||
<Input placeholder="Search" value={this.state.searchTerm} type="text" onChange={this.handleSearchTerm} />
|
||||
{this.state.searchTerm.length > 0 &&
|
||||
fuz
|
||||
.filter(this.state.searchTerm, this.props.metrics)
|
||||
.map((result: FuzzyResult) => (
|
||||
<p
|
||||
key={result.original}
|
||||
className="metric"
|
||||
onClick={this.handleMetricClick.bind(this, result.original)}
|
||||
dangerouslySetInnerHTML={{ __html: result.rendered }}
|
||||
></p>
|
||||
))}
|
||||
{this.state.searchTerm.length === 0 &&
|
||||
this.props.metrics.map((metric) => (
|
||||
<p key={metric} className="metric" onClick={this.handleMetricClick.bind(this, metric)}>
|
||||
{metric}
|
||||
</p>
|
||||
))}
|
||||
</ModalBody>
|
||||
</Modal>
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue