feat(ui): show progress indicators for silence form matchers

This commit is contained in:
Łukasz Mierzwa
2019-04-02 17:12:46 -07:00
parent 6d5e1532be
commit 549b5c2310
5 changed files with 42 additions and 26 deletions

View File

@@ -4,6 +4,8 @@ import PropTypes from "prop-types";
import { action } from "mobx";
import { observer } from "mobx-react";
import hash from "object-hash";
import { components } from "react-select";
import { SilenceFormStore } from "Stores/SilenceFormStore";
@@ -12,6 +14,16 @@ import { MultiSelect } from "Components/MultiSelect";
import { ValidationError } from "Components/MultiSelect/ValidationError";
import { MatchCounter } from "./MatchCounter";
const GenerateHashFromMatchers = (silenceFormStore, matcher) =>
hash({
alertmanagers: silenceFormStore.data.alertmanagers,
matcher: {
name: matcher.name,
values: matcher.values,
isRegex: matcher.isRegex
}
});
const Placeholder = props => {
return (
<div>
@@ -20,15 +32,19 @@ const Placeholder = props => {
);
};
const ValueContainer = ({ children, ...props }) => (
const ValueContainer = observer(({ children, ...props }) => (
<components.ValueContainer {...props}>
<MatchCounter
key={GenerateHashFromMatchers(
props.selectProps.silenceFormStore,
props.selectProps.matcher
)}
silenceFormStore={props.selectProps.silenceFormStore}
matcher={props.selectProps.matcher}
/>
{children}
</components.ValueContainer>
);
));
const LabelValueInput = observer(
class LabelValueInput extends MultiSelect {

View File

@@ -6,10 +6,9 @@ import { observer } from "mobx-react";
import { throttle } from "lodash";
import hash from "object-hash";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faExclamationCircle } from "@fortawesome/free-solid-svg-icons/faExclamationCircle";
import { faSpinner } from "@fortawesome/free-solid-svg-icons/faSpinner";
import { FormatBackendURI, FormatAlertsQ } from "Stores/AlertStore";
import { SilenceFormStore } from "Stores/SilenceFormStore";
@@ -26,7 +25,7 @@ const MatchCounter = observer(
matchedAlerts = observable(
{
total: 0,
total: null,
error: null,
fetch: null,
setTotal(value) {
@@ -85,13 +84,7 @@ const MatchCounter = observer(
this.onUpdateCounter();
}
componentDidUpdate() {
this.onUpdateCounter();
}
render() {
const { silenceFormStore, matcher } = this.props;
if (this.matchedAlerts.error !== null) {
return (
<TooltipWrapper
@@ -107,23 +100,17 @@ const MatchCounter = observer(
);
}
const matcherHash = hash({
alertmanagers: silenceFormStore.data.alertmanagers,
matcher: {
name: matcher.name,
values: matcher.values,
isRegex: matcher.isRegex
}
});
return (
<TooltipWrapper title="Number of alerts matching this label">
<span
className="badge badge-light badge-pill"
style={{ fontSize: "85%" }}
data-hash={matcherHash}
>
{this.matchedAlerts.total}
{this.matchedAlerts.total === null ? (
<FontAwesomeIcon icon={faSpinner} spin />
) : (
this.matchedAlerts.total
)}
</span>
</TooltipWrapper>
);

View File

@@ -33,6 +33,7 @@ const MountedMatchCounter = () => {
describe("<MatchCounter />", () => {
it("matches snapshot with empty matcher", () => {
fetch.mockResponse(JSON.stringify({ totalAlerts: 0 }));
const tree = MountedMatchCounter();
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
});
@@ -66,6 +67,7 @@ describe("<MatchCounter />", () => {
});
it("totalAlerts is 0 after mount", async () => {
fetch.mockResponse(JSON.stringify({ totalAlerts: 0 }));
const tree = MountedMatchCounter();
expect(tree.text()).toBe("0");
});
@@ -78,7 +80,7 @@ describe("<MatchCounter />", () => {
matcher.values = [MatcherValueToObject("bar")];
const tree = MountedMatchCounter();
expect(tree.text()).toBe("0");
expect(tree.text()).toBe("");
await expect(tree.instance().matchedAlerts.fetch).resolves.toBeUndefined();
expect(tree.text()).toBe("123");
});

View File

@@ -11,9 +11,21 @@ exports[`<LabelValueInput /> matches snapshot 1`] = `
>
<span class=\\"badge badge-light badge-pill\\"
style=\\"font-size:85%\\"
data-hash=\\"76ea01a7b7d0189a690ed2b409ad07a87dbd039c\\"
>
0
<svg aria-hidden=\\"true\\"
focusable=\\"false\\"
data-prefix=\\"fas\\"
data-icon=\\"spinner\\"
class=\\"svg-inline--fa fa-spinner fa-w-16 fa-spin \\"
role=\\"img\\"
xmlns=\\"http://www.w3.org/2000/svg\\"
viewbox=\\"0 0 512 512\\"
>
<path fill=\\"currentColor\\"
d=\\"M304 48c0 26.51-21.49 48-48 48s-48-21.49-48-48 21.49-48 48-48 48 21.49 48 48zm-48 368c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zm208-208c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.49-48-48-48zM96 256c0-26.51-21.49-48-48-48S0 229.49 0 256s21.49 48 48 48 48-21.49 48-48zm12.922 99.078c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.491-48-48-48zm294.156 0c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48c0-26.509-21.49-48-48-48zM108.922 60.922c-26.51 0-48 21.49-48 48s21.49 48 48 48 48-21.49 48-48-21.491-48-48-48z\\"
>
</path>
</svg>
</span>
</div>
<div>

View File

@@ -10,7 +10,6 @@ exports[`<MatchCounter /> matches snapshot with empty matcher 1`] = `
>
<span class=\\"badge badge-light badge-pill\\"
style=\\"font-size: 85%;\\"
data-hash=\\"2153b6623363af13fa91f1ad35fa4cfc6462d349\\"
>
0
</span>