Skip to content

Commit

Permalink
feat(ui): use toasts for error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
prymitive committed Sep 7, 2020
1 parent 46ac484 commit c7d97b8
Show file tree
Hide file tree
Showing 18 changed files with 688 additions and 126 deletions.
10 changes: 7 additions & 3 deletions ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ const FaviconBadge = React.lazy(() =>
default: module.FaviconBadge,
}))
);
const AppToasts = React.lazy(() =>
import("Components/Toast/AppToasts").then((module) => ({
default: module.AppToasts,
}))
);

interface AppProps {
defaultFilters: Array<string>;
Expand Down Expand Up @@ -138,11 +143,10 @@ const App: FunctionComponent<AppProps> = ({ defaultFilters, uiDefaults }) => {
settingsStore={settingsStore}
silenceFormStore={silenceFormStore}
/>
<AppToasts alertStore={alertStore} />
<FaviconBadge alertStore={alertStore} />
</React.Suspense>
</ThemeContext.Provider>
<React.Suspense fallback={null}>
<FaviconBadge alertStore={alertStore} />
</React.Suspense>
</ErrorBoundary>
));
};
Expand Down

This file was deleted.

19 changes: 0 additions & 19 deletions ui/src/Components/Grid/UpstreamError/index.test.tsx

This file was deleted.

17 changes: 0 additions & 17 deletions ui/src/Components/Grid/UpstreamError/index.tsx

This file was deleted.

47 changes: 0 additions & 47 deletions ui/src/Components/Grid/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,53 +89,6 @@ describe("<Grid />", () => {
expect(tree.text()).toBe("<FatalError />");
});

it("renders UpstreamError for each unhealthy upstream", () => {
alertStore.data.upstreams = {
counters: { total: 3, healthy: 1, failed: 2 },
instances: [
{
name: "am1",
cluster: "am",
clusterMembers: ["am1"],
uri: "http://am1",
publicURI: "http://am1",
error: "error 1",
version: "0.21.0",
readonly: false,
corsCredentials: "include",
headers: {},
},
{
name: "am2",
cluster: "am",
clusterMembers: ["am2"],
uri: "file:///mock",
publicURI: "file:///mock",
error: "",
version: "0.21.0",
readonly: false,
corsCredentials: "include",
headers: {},
},
{
name: "am3",
cluster: "am",
clusterMembers: ["am3"],
uri: "http://am3",
publicURI: "http://am3",
error: "error 2",
version: "0.21.0",
readonly: false,
corsCredentials: "include",
headers: {},
},
],
clusters: { am1: ["am1"], am2: ["am2"], am3: ["am3"] },
};
const tree = ShallowGrid();
expect(tree.text()).toBe("<UpstreamError /><UpstreamError /><AlertGrid />");
});

it("renders only FatalError on failed fetch", () => {
alertStore.status.error = "error";
alertStore.data.upstreams = {
Expand Down
22 changes: 5 additions & 17 deletions ui/src/Components/Grid/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { Settings } from "Stores/Settings";
import { SilenceFormStore } from "Stores/SilenceFormStore";
import { AlertGrid } from "./AlertGrid";
import { FatalError } from "./FatalError";
import { UpstreamError } from "./UpstreamError";
import { UpgradeNeeded } from "./UpgradeNeeded";
import { ReloadNeeded } from "./ReloadNeeded";
import { EmptyGrid } from "./EmptyGrid";
Expand All @@ -34,22 +33,11 @@ const Grid: FC<{
alertStore.info.totalAlerts === 0 ? (
<EmptyGrid />
) : (
<React.Fragment>
{alertStore.data.upstreams.instances
.filter((upstream) => upstream.error !== "")
.map((upstream) => (
<UpstreamError
key={upstream.name}
name={upstream.name}
message={upstream.error}
/>
))}
<AlertGrid
alertStore={alertStore}
settingsStore={settingsStore}
silenceFormStore={silenceFormStore}
/>
</React.Fragment>
<AlertGrid
alertStore={alertStore}
settingsStore={settingsStore}
silenceFormStore={silenceFormStore}
/>
)
);
};
Expand Down
77 changes: 77 additions & 0 deletions ui/src/Components/Toast/AppToasts.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from "react";

import { mount } from "enzyme";

import toDiffableHtml from "diffable-html";

import { AlertStore } from "Stores/AlertStore";
import { AppToasts } from "./AppToasts";

let alertStore: AlertStore;

beforeEach(() => {
alertStore = new AlertStore([]);
});

describe("<AppToasts />", () => {
it("doesn't render anything when alertStore.info.upgradeNeeded=true", () => {
alertStore.info.upgradeNeeded = true;
const tree = mount(<AppToasts alertStore={alertStore} />);
expect(tree.html()).toBeNull();
});

it("renders upstream error toasts for each unhealthy upstream", () => {
alertStore.data.upstreams = {
counters: { total: 3, healthy: 1, failed: 2 },
instances: [
{
name: "am1",
cluster: "am",
clusterMembers: ["am1"],
uri: "http://am1",
publicURI: "http://am1",
error: "error 1",
version: "0.21.0",
readonly: false,
corsCredentials: "include",
headers: {},
},
{
name: "am2",
cluster: "am",
clusterMembers: ["am2"],
uri: "file:///mock",
publicURI: "file:///mock",
error: "",
version: "0.21.0",
readonly: false,
corsCredentials: "include",
headers: {},
},
{
name: "am3",
cluster: "am",
clusterMembers: ["am3"],
uri: "http://am3",
publicURI: "http://am3",
error: "error 2",
version: "0.21.0",
readonly: false,
corsCredentials: "include",
headers: {},
},
],
clusters: { am1: ["am1"], am2: ["am2"], am3: ["am3"] },
};
const tree = mount(<AppToasts alertStore={alertStore} />);
expect(tree.find("Toast")).toHaveLength(2);
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
});

it("renders UpgradeToastMessage when alertStore.info.upgradeReady=true", () => {
alertStore.info.upgradeReady = true;
const tree = mount(<AppToasts alertStore={alertStore} />);
expect(tree.find("UpgradeToastMessage")).toHaveLength(1);
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
});
});
46 changes: 46 additions & 0 deletions ui/src/Components/Toast/AppToasts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React, { FC } from "react";

import { useObserver } from "mobx-react-lite";

import { faArrowUp } from "@fortawesome/free-solid-svg-icons/faArrowUp";
import { faExclamation } from "@fortawesome/free-solid-svg-icons/faExclamation";

import { AlertStore } from "Stores/AlertStore";
import { ToastContainer, Toast } from ".";
import { ToastMessage, UpgradeToastMessage } from "./ToastMessages";

const AppToasts: FC<{
alertStore: AlertStore;
}> = ({ alertStore }) => {
return useObserver(() =>
alertStore.info.upgradeNeeded ? null : (
<ToastContainer>
{alertStore.data.upstreams.instances
.filter((upstream) => upstream.error !== "")
.map((upstream) => (
<Toast
key={upstream.name}
icon={faExclamation}
iconClass="text-danger"
message={
<ToastMessage
title={`Alertmanager ${upstream.name} raised an error`}
message={upstream.error}
/>
}
/>
))}
{alertStore.info.upgradeReady ? (
<Toast
key="upgrade"
icon={faArrowUp}
iconClass="text-success"
message={<UpgradeToastMessage alertStore={alertStore} />}
/>
) : null}
</ToastContainer>
)
);
};

export { AppToasts };
51 changes: 51 additions & 0 deletions ui/src/Components/Toast/ToastMessages.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from "react";

import { mount } from "enzyme";

import toDiffableHtml from "diffable-html";

import { AlertStore } from "Stores/AlertStore";
import { ToastMessage, UpgradeToastMessage } from "./ToastMessages";

let alertStore: AlertStore;

beforeEach(() => {
alertStore = new AlertStore([]);
alertStore.info.version = "1.2.3";
});

describe("<ToastMessage />", () => {
it("matches snapshot", () => {
const tree = mount(
<ToastMessage title="title string" message={<div>Div Message</div>} />
);
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
});
});

describe("<UpgradeToastMessage />", () => {
it("matches snapshot", () => {
const tree = mount(<UpgradeToastMessage alertStore={alertStore} />);
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
});

it("clicking on the stop button pauses page reload", () => {
const tree = mount(<UpgradeToastMessage alertStore={alertStore} />);
expect(tree.find("button").html()).toMatch(/fa-stop/);
expect(tree.find("button").text()).toBe("Stop auto-reload");

tree.find("button").simulate("click");
expect(tree.find("button").html()).toMatch(/fa-sync/);
expect(tree.find("button").text()).toBe("Reload now");
});

it("clicking on the reload buton triggers a reload", () => {
const tree = mount(<UpgradeToastMessage alertStore={alertStore} />);

tree.find("button").simulate("click");
expect(tree.find("button").text()).toBe("Reload now");

tree.find("button").simulate("click");
expect(alertStore.info.upgradeNeeded).toBe(true);
});
});
Loading

0 comments on commit c7d97b8

Please sign in to comment.