mirror of
https://github.com/prymitive/karma
synced 2026-05-07 03:26:52 +00:00
feat(ui): add a component to reload the page if needed
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<ReloadNeeded /> matches snapshot 1`] = `
|
||||
"
|
||||
<h1 class=\\"display-1 text-placeholder screen-center\\">
|
||||
<div class=\\"container-fluid text-center\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
focusable=\\"false\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"exclamation-circle\\"
|
||||
class=\\"svg-inline--fa fa-exclamation-circle fa-w-16 screen-center-icon-big text-danger mb-4\\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 512 512\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
<p class=\\"lead text-white bg-secondary p-3 rounded text-wrap text-break\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
focusable=\\"false\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"spinner\\"
|
||||
class=\\"svg-inline--fa fa-spinner fa-w-16 fa-spin mr-2\\"
|
||||
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>
|
||||
All API connection attempts failed. This migth be caused by authentication middleware, will try to reload.
|
||||
</p>
|
||||
</div>
|
||||
</h1>
|
||||
"
|
||||
`;
|
||||
48
ui/src/Components/Grid/ReloadNeeded/index.js
Normal file
48
ui/src/Components/Grid/ReloadNeeded/index.js
Normal file
@@ -0,0 +1,48 @@
|
||||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
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 { CenteredMessage } from "Components/CenteredMessage";
|
||||
|
||||
class ReloadNeeded extends Component {
|
||||
static propTypes = {
|
||||
reloadAfter: PropTypes.number.isRequired
|
||||
};
|
||||
|
||||
reloadApp = () => {
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { reloadAfter } = this.props;
|
||||
this.timer = setTimeout(this.reloadApp, reloadAfter);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearTimeout(this.timer);
|
||||
this.timer = null;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<CenteredMessage>
|
||||
<div className="container-fluid text-center">
|
||||
<FontAwesomeIcon
|
||||
icon={faExclamationCircle}
|
||||
className="screen-center-icon-big text-danger mb-4"
|
||||
/>
|
||||
<p className="lead text-white bg-secondary p-3 rounded text-wrap text-break">
|
||||
<FontAwesomeIcon className="mr-2" icon={faSpinner} spin />
|
||||
All API connection attempts failed. This migth be caused by
|
||||
authentication middleware, will try to reload.
|
||||
</p>
|
||||
</div>
|
||||
</CenteredMessage>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { ReloadNeeded };
|
||||
43
ui/src/Components/Grid/ReloadNeeded/index.test.js
Normal file
43
ui/src/Components/Grid/ReloadNeeded/index.test.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import React from "react";
|
||||
|
||||
import { mount, shallow } from "enzyme";
|
||||
|
||||
import toDiffableHtml from "diffable-html";
|
||||
|
||||
import { ReloadNeeded } from ".";
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
jest.clearAllTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllTimers();
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("<ReloadNeeded />", () => {
|
||||
it("matches snapshot", () => {
|
||||
const tree = shallow(
|
||||
<ReloadNeeded newVersion="1.2.3" reloadAfter={100000000} />
|
||||
);
|
||||
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("calls window.location.reload after timer is done", () => {
|
||||
const reloadSpy = jest
|
||||
.spyOn(global.window.location, "reload")
|
||||
.mockImplementation(() => {});
|
||||
mount(<ReloadNeeded reloadAfter={100000000} />);
|
||||
jest.runOnlyPendingTimers();
|
||||
expect(reloadSpy).toBeCalled();
|
||||
});
|
||||
|
||||
it("timer is cleared on unmount", () => {
|
||||
const tree = mount(<ReloadNeeded reloadAfter={100000000} />);
|
||||
const instance = tree.instance();
|
||||
|
||||
instance.componentWillUnmount();
|
||||
expect(instance.timer).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -25,7 +25,7 @@ exports[`<UpgradeNeeded /> matches snapshot 1`] = `
|
||||
focusable=\\"false\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"spinner\\"
|
||||
class=\\"svg-inline--fa fa-spinner fa-w-16 fa-spin mr-1\\"
|
||||
class=\\"svg-inline--fa fa-spinner fa-w-16 fa-spin mr-2\\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 512 512\\"
|
||||
|
||||
@@ -41,7 +41,7 @@ class UpgradeNeeded extends Component {
|
||||
/>
|
||||
</div>
|
||||
<p className="lead text-muted">
|
||||
<FontAwesomeIcon className="mr-1" icon={faSpinner} spin />
|
||||
<FontAwesomeIcon className="mr-2" icon={faSpinner} spin />
|
||||
Upgrading to a new version: {newVersion}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { AlertGrid } from "./AlertGrid";
|
||||
import { FatalError } from "./FatalError";
|
||||
import { UpstreamError } from "./UpstreamError";
|
||||
import { UpgradeNeeded } from "./UpgradeNeeded";
|
||||
import { ReloadNeeded } from "./ReloadNeeded";
|
||||
import { EmptyGrid } from "./EmptyGrid";
|
||||
|
||||
const Grid = observer(
|
||||
@@ -23,10 +24,6 @@ const Grid = observer(
|
||||
render() {
|
||||
const { alertStore, settingsStore, silenceFormStore } = this.props;
|
||||
|
||||
if (alertStore.status.error) {
|
||||
return <FatalError message={alertStore.status.error} />;
|
||||
}
|
||||
|
||||
if (alertStore.info.upgradeNeeded) {
|
||||
return (
|
||||
<UpgradeNeeded
|
||||
@@ -36,6 +33,14 @@ const Grid = observer(
|
||||
);
|
||||
}
|
||||
|
||||
if (alertStore.info.reloadNeeded) {
|
||||
return <ReloadNeeded reloadAfter={4000} />;
|
||||
}
|
||||
|
||||
if (alertStore.status.error) {
|
||||
return <FatalError message={alertStore.status.error} />;
|
||||
}
|
||||
|
||||
if (
|
||||
alertStore.data.upstreams.counters &&
|
||||
alertStore.data.upstreams.counters.total === 1 &&
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Settings } from "Stores/Settings";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { FatalError } from "./FatalError";
|
||||
import { UpgradeNeeded } from "./UpgradeNeeded";
|
||||
import { ReloadNeeded } from "./ReloadNeeded";
|
||||
import { EmptyGrid } from "./EmptyGrid";
|
||||
import { Grid } from ".";
|
||||
import { InternalError } from "../../ErrorBoundary";
|
||||
@@ -32,6 +33,9 @@ storiesOf("Grid", module)
|
||||
.add("UpgradeNeeded", () => {
|
||||
return <UpgradeNeeded newVersion="1.2.3" reloadAfter={100000000} />;
|
||||
})
|
||||
.add("ReloadNeeded", () => {
|
||||
return <ReloadNeeded reloadAfter={100000000} />;
|
||||
})
|
||||
.add("EmptyGrid", () => {
|
||||
return (
|
||||
<div className="text-center">
|
||||
|
||||
@@ -94,6 +94,12 @@ describe("<Grid />", () => {
|
||||
expect(tree.text()).toBe("<UpgradeNeeded />");
|
||||
});
|
||||
|
||||
it("renders ReloadNeeded when alertStore.info.reloadNeeded=true", () => {
|
||||
alertStore.info.reloadNeeded = true;
|
||||
const tree = ShallowGrid();
|
||||
expect(tree.text()).toBe("<ReloadNeeded />");
|
||||
});
|
||||
|
||||
it("renders AlertGrid before any fetch finished when totalAlerts is 0", () => {
|
||||
alertStore.info.version = "unknown";
|
||||
alertStore.info.totalAlerts = 0;
|
||||
|
||||
@@ -203,7 +203,7 @@ describe("<FilterInput Autosuggest />", () => {
|
||||
tree.find("input").simulate("change", { target: { value: "bar" } });
|
||||
await WaitForFetch(tree);
|
||||
|
||||
expect(fetch.mock.calls).toHaveLength(6);
|
||||
expect(fetch.mock.calls).toHaveLength(11);
|
||||
expect(fetch.mock.calls[0]).toContain("./autocomplete.json?term=bar");
|
||||
expect(instance.inputStore.suggestions).toHaveLength(0);
|
||||
});
|
||||
|
||||
@@ -90,6 +90,7 @@ describe("<SilencePreview />", () => {
|
||||
{
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
mode: "cors",
|
||||
redirect: "follow"
|
||||
}
|
||||
);
|
||||
@@ -108,6 +109,7 @@ describe("<SilencePreview />", () => {
|
||||
{
|
||||
method: "GET",
|
||||
credentials: "include",
|
||||
mode: "cors",
|
||||
redirect: "follow"
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user