mirror of
https://github.com/prymitive/karma
synced 2026-05-07 03:26:52 +00:00
Merge pull request #46 from prymitive/pause-fetch
feat(ui): pause fetching when alert/group menu is open
This commit is contained in:
29
ui/src/Components/FetchPauser/index.js
Normal file
29
ui/src/Components/FetchPauser/index.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { inject } from "mobx-react";
|
||||
|
||||
const FetchPauser = inject("alertStore")(
|
||||
class FetchPauser extends Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.any,
|
||||
alertStore: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { alertStore } = this.props;
|
||||
alertStore.status.pause();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
const { alertStore } = this.props;
|
||||
alertStore.status.resume();
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export { FetchPauser };
|
||||
37
ui/src/Components/FetchPauser/index.test.js
Normal file
37
ui/src/Components/FetchPauser/index.test.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import React from "react";
|
||||
|
||||
import { Provider } from "mobx-react";
|
||||
|
||||
import { mount } from "enzyme";
|
||||
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { FetchPauser } from ".";
|
||||
|
||||
let alertStore;
|
||||
|
||||
beforeEach(() => {
|
||||
alertStore = new AlertStore([]);
|
||||
});
|
||||
|
||||
const MountedFetchPauser = () => {
|
||||
return mount(
|
||||
<Provider alertStore={alertStore}>
|
||||
<FetchPauser>
|
||||
<div />
|
||||
</FetchPauser>
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
describe("<FetchPauser />", () => {
|
||||
it("mounting FetchPauser pauses alertStore", () => {
|
||||
MountedFetchPauser();
|
||||
expect(alertStore.status.paused).toBe(true);
|
||||
});
|
||||
|
||||
it("unmounting FetchPauser resumes alertStore", () => {
|
||||
const tree = MountedFetchPauser();
|
||||
tree.unmount();
|
||||
expect(alertStore.status.paused).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -43,7 +43,7 @@ const Fetcher = observer(
|
||||
status === AlertStoreStatuses.Fetching.toString() ||
|
||||
status === AlertStoreStatuses.Processing.toString();
|
||||
|
||||
if (pastDeadline && !updateInProgress) {
|
||||
if (pastDeadline && !updateInProgress && !alertStore.status.paused) {
|
||||
this.lastTick.update();
|
||||
alertStore.fetchWithThrottle();
|
||||
}
|
||||
@@ -61,8 +61,10 @@ const Fetcher = observer(
|
||||
componentDidUpdate() {
|
||||
const { alertStore } = this.props;
|
||||
|
||||
this.lastTick.update();
|
||||
alertStore.fetchWithThrottle();
|
||||
if (!alertStore.status.paused) {
|
||||
this.lastTick.update();
|
||||
alertStore.fetchWithThrottle();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
||||
@@ -147,4 +147,34 @@ describe("<Fetcher />", () => {
|
||||
instance.componentWillUnmount();
|
||||
expect(instance.timer).toBeNull();
|
||||
});
|
||||
|
||||
it("doesn't fetch on mount when paused", () => {
|
||||
alertStore.status.pause();
|
||||
MountedFetcher();
|
||||
expect(fetchSpy).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it("doesn't fetch on update when paused", () => {
|
||||
alertStore.status.pause();
|
||||
const tree = MountedFetcher();
|
||||
tree.instance().componentDidUpdate();
|
||||
expect(fetchSpy).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
it("fetches on update when resumed", () => {
|
||||
alertStore.status.pause();
|
||||
const tree = MountedFetcher();
|
||||
alertStore.status.resume();
|
||||
tree.instance().componentDidUpdate();
|
||||
expect(fetchSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("fetches on resume", () => {
|
||||
alertStore.status.pause();
|
||||
MountedFetcher();
|
||||
alertStore.status.resume();
|
||||
advanceBy(2 * 1000);
|
||||
jest.runOnlyPendingTimers();
|
||||
expect(fetchSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,6 +15,8 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faCaretDown } from "@fortawesome/free-solid-svg-icons/faCaretDown";
|
||||
import { faBellSlash } from "@fortawesome/free-solid-svg-icons/faBellSlash";
|
||||
|
||||
import { FetchPauser } from "Components/FetchPauser";
|
||||
|
||||
const onSilenceClick = (silenceFormStore, group, alert) => {
|
||||
silenceFormStore.data.resetProgress();
|
||||
silenceFormStore.data.fillMatchersFromGroup(group, [alert]);
|
||||
@@ -32,33 +34,35 @@ const MenuContent = onClickOutside(
|
||||
silenceFormStore
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className="dropdown-menu d-block"
|
||||
ref={popperRef}
|
||||
style={popperStyle}
|
||||
data-placement={popperPlacement}
|
||||
>
|
||||
<h6 className="dropdown-header">Alert source links:</h6>
|
||||
{alert.alertmanager.map(am => (
|
||||
<a
|
||||
key={am.name}
|
||||
className="dropdown-item"
|
||||
href={am.source}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={afterClick}
|
||||
>
|
||||
{am.name}
|
||||
</a>
|
||||
))}
|
||||
<div className="dropdown-divider" />
|
||||
<FetchPauser>
|
||||
<div
|
||||
className="dropdown-item cursor-pointer"
|
||||
onClick={() => onSilenceClick(silenceFormStore, group, alert)}
|
||||
className="dropdown-menu d-block"
|
||||
ref={popperRef}
|
||||
style={popperStyle}
|
||||
data-placement={popperPlacement}
|
||||
>
|
||||
<FontAwesomeIcon icon={faBellSlash} /> Silence this alert
|
||||
<h6 className="dropdown-header">Alert source links:</h6>
|
||||
{alert.alertmanager.map(am => (
|
||||
<a
|
||||
key={am.name}
|
||||
className="dropdown-item"
|
||||
href={am.source}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={afterClick}
|
||||
>
|
||||
{am.name}
|
||||
</a>
|
||||
))}
|
||||
<div className="dropdown-divider" />
|
||||
<div
|
||||
className="dropdown-item cursor-pointer"
|
||||
onClick={() => onSilenceClick(silenceFormStore, group, alert)}
|
||||
>
|
||||
<FontAwesomeIcon icon={faBellSlash} /> Silence this alert
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</FetchPauser>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
import React from "react";
|
||||
|
||||
import { Provider } from "mobx-react";
|
||||
|
||||
import { mount } from "enzyme";
|
||||
|
||||
import { MockAlertGroup, MockAlert } from "__mocks__/Alerts.js";
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { AlertMenu, MenuContent } from "./AlertMenu";
|
||||
|
||||
let alertStore;
|
||||
let silenceFormStore;
|
||||
let alert;
|
||||
let group;
|
||||
|
||||
beforeEach(() => {
|
||||
alertStore = new AlertStore([]);
|
||||
silenceFormStore = new SilenceFormStore();
|
||||
alert = MockAlert([], { foo: "bar" }, "active");
|
||||
group = MockAlertGroup({ alertname: "Fake Alert" }, [alert], [], {});
|
||||
@@ -20,12 +25,14 @@ const MockAfterClick = jest.fn();
|
||||
|
||||
const MountedAlertMenu = group => {
|
||||
return mount(
|
||||
<AlertMenu
|
||||
group={group}
|
||||
alert={alert}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
);
|
||||
<Provider alertStore={alertStore}>
|
||||
<AlertMenu
|
||||
group={group}
|
||||
alert={alert}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
</Provider>
|
||||
).find("AlertMenu");
|
||||
};
|
||||
|
||||
describe("<AlertMenu />", () => {
|
||||
@@ -55,15 +62,17 @@ describe("<AlertMenu />", () => {
|
||||
|
||||
const MountedMenuContent = group => {
|
||||
return mount(
|
||||
<MenuContent
|
||||
popperPlacement="top"
|
||||
popperRef={null}
|
||||
popperStyle={{}}
|
||||
group={group}
|
||||
alert={alert}
|
||||
afterClick={MockAfterClick}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
<Provider alertStore={alertStore}>
|
||||
<MenuContent
|
||||
popperPlacement="top"
|
||||
popperRef={null}
|
||||
popperStyle={{}}
|
||||
group={group}
|
||||
alert={alert}
|
||||
afterClick={MockAfterClick}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import { faBellSlash } from "@fortawesome/free-solid-svg-icons/faBellSlash";
|
||||
|
||||
import { FormatAPIFilterQuery } from "Stores/AlertStore";
|
||||
import { QueryOperators, StaticLabels, FormatQuery } from "Common/Query";
|
||||
import { FetchPauser } from "Components/FetchPauser";
|
||||
|
||||
const onSilenceClick = (silenceFormStore, group) => {
|
||||
silenceFormStore.data.resetProgress();
|
||||
@@ -43,28 +44,30 @@ const MenuContent = onClickOutside(
|
||||
)}`;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="dropdown-menu d-block"
|
||||
ref={popperRef}
|
||||
style={popperStyle}
|
||||
data-placement={popperPlacement}
|
||||
>
|
||||
<FetchPauser>
|
||||
<div
|
||||
className="dropdown-item cursor-pointer"
|
||||
onClick={() => {
|
||||
copy(groupLink);
|
||||
afterClick();
|
||||
}}
|
||||
className="dropdown-menu d-block"
|
||||
ref={popperRef}
|
||||
style={popperStyle}
|
||||
data-placement={popperPlacement}
|
||||
>
|
||||
<FontAwesomeIcon icon={faShareSquare} /> Copy link to this group
|
||||
<div
|
||||
className="dropdown-item cursor-pointer"
|
||||
onClick={() => {
|
||||
copy(groupLink);
|
||||
afterClick();
|
||||
}}
|
||||
>
|
||||
<FontAwesomeIcon icon={faShareSquare} /> Copy link to this group
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item cursor-pointer"
|
||||
onClick={() => onSilenceClick(silenceFormStore, group)}
|
||||
>
|
||||
<FontAwesomeIcon icon={faBellSlash} /> Silence this group
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="dropdown-item cursor-pointer"
|
||||
onClick={() => onSilenceClick(silenceFormStore, group)}
|
||||
>
|
||||
<FontAwesomeIcon icon={faBellSlash} /> Silence this group
|
||||
</div>
|
||||
</div>
|
||||
</FetchPauser>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,23 +1,32 @@
|
||||
import React from "react";
|
||||
|
||||
import { Provider } from "mobx-react";
|
||||
|
||||
import { mount } from "enzyme";
|
||||
|
||||
import copy from "copy-to-clipboard";
|
||||
|
||||
import { MockAlertGroup } from "__mocks__/Alerts.js";
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { GroupMenu, MenuContent } from "./GroupMenu";
|
||||
|
||||
let alertStore;
|
||||
let silenceFormStore;
|
||||
|
||||
beforeEach(() => {
|
||||
alertStore = new AlertStore([]);
|
||||
silenceFormStore = new SilenceFormStore();
|
||||
});
|
||||
|
||||
const MockAfterClick = jest.fn();
|
||||
|
||||
const MountedGroupMenu = group => {
|
||||
return mount(<GroupMenu group={group} silenceFormStore={silenceFormStore} />);
|
||||
return mount(
|
||||
<Provider alertStore={alertStore}>
|
||||
<GroupMenu group={group} silenceFormStore={silenceFormStore} />
|
||||
</Provider>
|
||||
).find("GroupMenu");
|
||||
};
|
||||
|
||||
describe("<GroupMenu />", () => {
|
||||
@@ -51,14 +60,16 @@ describe("<GroupMenu />", () => {
|
||||
|
||||
const MountedMenuContent = group => {
|
||||
return mount(
|
||||
<MenuContent
|
||||
popperPlacement="top"
|
||||
popperRef={null}
|
||||
popperStyle={{}}
|
||||
group={group}
|
||||
afterClick={MockAfterClick}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
<Provider alertStore={alertStore}>
|
||||
<MenuContent
|
||||
popperPlacement="top"
|
||||
popperRef={null}
|
||||
popperStyle={{}}
|
||||
group={group}
|
||||
afterClick={MockAfterClick}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ exports[`<FetchIndicator /> matches snapshot when idle 1`] = `
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"circle-notch\\"
|
||||
class=\\"svg-inline--fa fa-circle-notch fa-w-16 fa-spin fa-lg mx-1 text-success\\"
|
||||
class=\\"svg-inline--fa fa-circle-notch fa-w-16 fa-lg mx-1 text-muted\\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 512 512\\"
|
||||
@@ -38,6 +38,25 @@ exports[`<FetchIndicator /> matches snapshot when idle 1`] = `
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<FetchIndicator /> matches snapshot when paused 1`] = `
|
||||
"
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"far\\"
|
||||
data-icon=\\"pause-circle\\"
|
||||
class=\\"svg-inline--fa fa-pause-circle fa-w-16 fa-lg mx-1 text-muted\\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 512 512\\"
|
||||
style=\\"opacity: 1;\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm96-280v160c0 8.8-7.2 16-16 16h-48c-8.8 0-16-7.2-16-16V176c0-8.8 7.2-16 16-16h48c8.8 0 16 7.2 16 16zm-112 0v160c0 8.8-7.2 16-16 16h-48c-8.8 0-16-7.2-16-16V176c0-8.8 7.2-16 16-16h48c8.8 0 16 7.2 16 16z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<FetchIndicator /> matches snapshot when response is processed 1`] = `
|
||||
"
|
||||
<svg aria-hidden=\\"true\\"
|
||||
|
||||
@@ -1,37 +1,57 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faCircleNotch } from "@fortawesome/free-solid-svg-icons/faCircleNotch";
|
||||
import { faPauseCircle } from "@fortawesome/free-regular-svg-icons/faPauseCircle";
|
||||
|
||||
import { AlertStoreStatuses } from "Stores/AlertStore";
|
||||
|
||||
class FetchIndicator extends Component {
|
||||
static propTypes = {
|
||||
status: PropTypes.string.isRequired
|
||||
};
|
||||
const FetchIcon = ({ icon, color, visible, spin }) => (
|
||||
<FontAwesomeIcon
|
||||
style={{ opacity: visible ? 1 : 0 }}
|
||||
className={`mx-1 text-${color}`}
|
||||
size="lg"
|
||||
icon={icon}
|
||||
spin={spin}
|
||||
/>
|
||||
);
|
||||
FetchIcon.propTypes = {
|
||||
icon: PropTypes.object.isRequired,
|
||||
color: PropTypes.string,
|
||||
visible: PropTypes.bool,
|
||||
spin: PropTypes.bool
|
||||
};
|
||||
FetchIcon.defaultProps = {
|
||||
color: "muted",
|
||||
visible: true,
|
||||
spin: false
|
||||
};
|
||||
|
||||
render() {
|
||||
const { status } = this.props;
|
||||
const FetchIndicator = observer(
|
||||
class FetchIndicator extends Component {
|
||||
static propTypes = {
|
||||
alertStore: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
const visible =
|
||||
status === AlertStoreStatuses.Fetching.toString() ||
|
||||
status === AlertStoreStatuses.Processing.toString();
|
||||
const textClass =
|
||||
status === AlertStoreStatuses.Fetching.toString()
|
||||
? "text-muted"
|
||||
: "text-success";
|
||||
render() {
|
||||
const { alertStore } = this.props;
|
||||
|
||||
return (
|
||||
<FontAwesomeIcon
|
||||
style={{ opacity: visible ? 1 : 0 }}
|
||||
className={`mx-1 ${textClass}`}
|
||||
icon={faCircleNotch}
|
||||
size="lg"
|
||||
spin
|
||||
/>
|
||||
);
|
||||
if (alertStore.status.paused) return <FetchIcon icon={faPauseCircle} />;
|
||||
|
||||
const status = alertStore.status.value.toString();
|
||||
|
||||
if (status === AlertStoreStatuses.Fetching.toString())
|
||||
return <FetchIcon icon={faCircleNotch} spin />;
|
||||
|
||||
if (status === AlertStoreStatuses.Processing.toString())
|
||||
return <FetchIcon icon={faCircleNotch} color="success" spin />;
|
||||
|
||||
return <FetchIcon icon={faCircleNotch} visible={false} />;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export { FetchIndicator };
|
||||
|
||||
@@ -5,69 +5,88 @@ import { mount } from "enzyme";
|
||||
import toDiffableHtml from "diffable-html";
|
||||
|
||||
import { FetchIndicator } from ".";
|
||||
import { AlertStoreStatuses } from "Stores/AlertStore";
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
|
||||
let alertStore;
|
||||
|
||||
beforeEach(() => {
|
||||
alertStore = new AlertStore([]);
|
||||
});
|
||||
|
||||
const MountedFetchIndicator = () => {
|
||||
return mount(<FetchIndicator alertStore={alertStore} />);
|
||||
};
|
||||
|
||||
describe("<FetchIndicator />", () => {
|
||||
it("shows a pause icon when fetching is paused", () => {
|
||||
alertStore.status.pause();
|
||||
const tree = MountedFetchIndicator();
|
||||
expect(tree.html()).toMatch(/fa-pause-circle/);
|
||||
});
|
||||
|
||||
it("shows a cirle notch icon when fetching is resumed", () => {
|
||||
alertStore.status.resume();
|
||||
const tree = MountedFetchIndicator();
|
||||
expect(tree.html()).toMatch(/fa-circle-notch/);
|
||||
});
|
||||
|
||||
it("opacity is 1 when fetch is in progress", () => {
|
||||
const tree = mount(
|
||||
<FetchIndicator status={AlertStoreStatuses.Fetching.toString()} />
|
||||
);
|
||||
alertStore.status.setFetching();
|
||||
const tree = MountedFetchIndicator();
|
||||
expect(tree.find("FontAwesomeIcon").props().style.opacity).toEqual(1);
|
||||
});
|
||||
|
||||
it("uses text-muted when fetch is in progress", () => {
|
||||
const tree = mount(
|
||||
<FetchIndicator status={AlertStoreStatuses.Fetching.toString()} />
|
||||
);
|
||||
alertStore.status.setFetching();
|
||||
const tree = MountedFetchIndicator();
|
||||
expect(tree.find("FontAwesomeIcon").hasClass("text-muted")).toBe(true);
|
||||
});
|
||||
|
||||
it("opacity is 1 when response is processed", () => {
|
||||
const tree = mount(
|
||||
<FetchIndicator status={AlertStoreStatuses.Processing.toString()} />
|
||||
);
|
||||
alertStore.status.setProcessing();
|
||||
const tree = MountedFetchIndicator();
|
||||
expect(tree.find("FontAwesomeIcon").props().style.opacity).toEqual(1);
|
||||
});
|
||||
|
||||
it("uses text-success when response is processed", () => {
|
||||
const tree = mount(
|
||||
<FetchIndicator status={AlertStoreStatuses.Processing.toString()} />
|
||||
);
|
||||
alertStore.status.setProcessing();
|
||||
const tree = MountedFetchIndicator();
|
||||
expect(tree.find("FontAwesomeIcon").hasClass("text-success")).toBe(true);
|
||||
});
|
||||
|
||||
it("opacity is 0 when idle", () => {
|
||||
const tree = mount(
|
||||
<FetchIndicator status={AlertStoreStatuses.Idle.toString()} />
|
||||
);
|
||||
alertStore.status.setIdle();
|
||||
const tree = MountedFetchIndicator();
|
||||
expect(tree.find("FontAwesomeIcon").props().style.opacity).toEqual(0);
|
||||
});
|
||||
|
||||
it("opacity is 0 when fetch failed", () => {
|
||||
const tree = mount(
|
||||
<FetchIndicator status={AlertStoreStatuses.Failure.toString()} />
|
||||
);
|
||||
alertStore.status.setFailure();
|
||||
const tree = MountedFetchIndicator();
|
||||
expect(tree.find("FontAwesomeIcon").props().style.opacity).toEqual(0);
|
||||
});
|
||||
|
||||
it("matches snapshot when paused", () => {
|
||||
alertStore.status.pause();
|
||||
const tree = MountedFetchIndicator();
|
||||
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("matches snapshot when fetch is in progress", () => {
|
||||
const tree = mount(
|
||||
<FetchIndicator status={AlertStoreStatuses.Fetching.toString()} />
|
||||
);
|
||||
alertStore.status.setFetching();
|
||||
const tree = MountedFetchIndicator();
|
||||
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("matches snapshot when response is processed", () => {
|
||||
const tree = mount(
|
||||
<FetchIndicator status={AlertStoreStatuses.Processing.toString()} />
|
||||
);
|
||||
alertStore.status.setProcessing();
|
||||
const tree = MountedFetchIndicator();
|
||||
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("matches snapshot when idle", () => {
|
||||
const tree = mount(
|
||||
<FetchIndicator status={AlertStoreStatuses.Idle.toString()} />
|
||||
);
|
||||
alertStore.status.setIdle();
|
||||
const tree = MountedFetchIndicator();
|
||||
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -72,7 +72,7 @@ const NavBar = observer(
|
||||
<ReactResizeDetector handleHeight onResize={NavbarOnResize} />
|
||||
<span className="navbar-brand my-0 mx-2 h1 d-none d-sm-block float-left">
|
||||
{alertStore.info.totalAlerts}
|
||||
<FetchIndicator status={alertStore.status.value.toString()} />
|
||||
<FetchIndicator alertStore={alertStore} />
|
||||
</span>
|
||||
<ul className={`navbar-nav float-right d-flex ${flexClass}`}>
|
||||
<SilenceModal
|
||||
|
||||
@@ -172,6 +172,7 @@ class AlertStore {
|
||||
{
|
||||
value: AlertStoreStatuses.Idle,
|
||||
error: null,
|
||||
paused: false,
|
||||
setIdle() {
|
||||
this.value = AlertStoreStatuses.Idle;
|
||||
this.error = null;
|
||||
@@ -187,13 +188,21 @@ class AlertStore {
|
||||
setFailure(err) {
|
||||
this.value = AlertStoreStatuses.Failure;
|
||||
this.error = err;
|
||||
},
|
||||
pause() {
|
||||
this.paused = true;
|
||||
},
|
||||
resume() {
|
||||
this.paused = false;
|
||||
}
|
||||
},
|
||||
{
|
||||
setIdle: action,
|
||||
setFetching: action,
|
||||
setProcessing: action,
|
||||
setFailure: action
|
||||
setFailure: action,
|
||||
pause: action,
|
||||
resume: action
|
||||
},
|
||||
{ name: "Store status" }
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user