mirror of
https://github.com/prymitive/karma
synced 2026-05-05 03:16:51 +00:00
feat(ui): show simplified status for single cluster silence submits
This commit is contained in:
committed by
Łukasz Mierzwa
parent
aab937adb8
commit
bdf835ac71
@@ -5,76 +5,144 @@ import { useObserver } from "mobx-react-lite";
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faArrowLeft } from "@fortawesome/free-solid-svg-icons/faArrowLeft";
|
||||
import { faCheckCircle } from "@fortawesome/free-regular-svg-icons/faCheckCircle";
|
||||
import { faCheckCircle } from "@fortawesome/free-solid-svg-icons/faCheckCircle";
|
||||
import { faExclamationCircle } from "@fortawesome/free-solid-svg-icons/faExclamationCircle";
|
||||
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { SilenceSubmitProgress } from "./SilenceSubmitProgress";
|
||||
|
||||
const SingleClusterStatus = ({ silenceFormStore, alertStore }) => {
|
||||
const clusterRequest = Object.values(
|
||||
silenceFormStore.data.requestsByCluster
|
||||
)[0];
|
||||
|
||||
return useObserver(() => (
|
||||
<div className="text-center">
|
||||
<div className="display-1 mb-3">
|
||||
{clusterRequest.isDone ? (
|
||||
clusterRequest.error ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faExclamationCircle}
|
||||
className="text-danger"
|
||||
/>
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faCheckCircle} className="text-success" />
|
||||
)
|
||||
) : (
|
||||
<SilenceSubmitProgress
|
||||
key={clusterRequest.cluster}
|
||||
cluster={clusterRequest.cluster}
|
||||
members={clusterRequest.members}
|
||||
payload={silenceFormStore.data.toAlertmanagerPayload}
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="badge badge-primary">{clusterRequest.cluster}</div>
|
||||
{clusterRequest.isDone ? (
|
||||
<p
|
||||
className={`mt-2 rounded text-center ${
|
||||
clusterRequest.isDone && clusterRequest.error ? "bg-light" : ""
|
||||
}`}
|
||||
>
|
||||
{clusterRequest.error ? (
|
||||
clusterRequest.error
|
||||
) : (
|
||||
<a
|
||||
href={clusterRequest.silenceLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{clusterRequest.silenceID}
|
||||
</a>
|
||||
)}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
));
|
||||
};
|
||||
|
||||
const MultiClusterStatus = ({ silenceFormStore, alertStore }) => {
|
||||
return useObserver(() => (
|
||||
<div className="table-responsive">
|
||||
<table className="table table-borderless">
|
||||
<tbody>
|
||||
{Object.values(silenceFormStore.data.requestsByCluster).map(
|
||||
(clusterRequest) => (
|
||||
<tr key={clusterRequest.cluster}>
|
||||
<td className="align-middle" style={{ width: "1%" }}>
|
||||
{clusterRequest.isDone ? (
|
||||
clusterRequest.error ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faExclamationCircle}
|
||||
className="text-danger"
|
||||
/>
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheckCircle}
|
||||
className="text-success"
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<SilenceSubmitProgress
|
||||
key={clusterRequest.cluster}
|
||||
cluster={clusterRequest.cluster}
|
||||
members={clusterRequest.members}
|
||||
payload={silenceFormStore.data.toAlertmanagerPayload}
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
)}
|
||||
</td>
|
||||
<td className="align-middle">{clusterRequest.cluster}</td>
|
||||
<td>
|
||||
<div
|
||||
className={`rounded text-center ${
|
||||
clusterRequest.isDone && clusterRequest.error
|
||||
? "bg-light"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{clusterRequest.isDone ? (
|
||||
clusterRequest.error ? (
|
||||
clusterRequest.error
|
||||
) : (
|
||||
<a
|
||||
href={clusterRequest.silenceLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{clusterRequest.silenceID}
|
||||
</a>
|
||||
)
|
||||
) : null}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
));
|
||||
};
|
||||
|
||||
const SilenceSubmitController = ({ silenceFormStore, alertStore }) => {
|
||||
return useObserver(() => (
|
||||
<React.Fragment>
|
||||
<div className="table-responsive">
|
||||
<table className="table table-borderless">
|
||||
<tbody>
|
||||
{Object.values(silenceFormStore.data.requestsByCluster).map(
|
||||
(clusterRequest) => (
|
||||
<tr key={clusterRequest.cluster}>
|
||||
<td className="align-middle" style={{ width: "1%" }}>
|
||||
{clusterRequest.isDone ? (
|
||||
clusterRequest.error ? (
|
||||
<FontAwesomeIcon
|
||||
icon={faExclamationCircle}
|
||||
className="text-danger"
|
||||
/>
|
||||
) : (
|
||||
<FontAwesomeIcon
|
||||
icon={faCheckCircle}
|
||||
className="text-success"
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<SilenceSubmitProgress
|
||||
key={clusterRequest.cluster}
|
||||
cluster={clusterRequest.cluster}
|
||||
members={clusterRequest.members}
|
||||
payload={silenceFormStore.data.toAlertmanagerPayload}
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
)}
|
||||
</td>
|
||||
<td className="align-middle">{clusterRequest.cluster}</td>
|
||||
<td>
|
||||
<div
|
||||
className={`rounded text-center ${
|
||||
clusterRequest.isDone && clusterRequest.error
|
||||
? "bg-light"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
{clusterRequest.isDone ? (
|
||||
clusterRequest.error ? (
|
||||
clusterRequest.error
|
||||
) : (
|
||||
<a
|
||||
href={clusterRequest.silenceLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{clusterRequest.silenceID}
|
||||
</a>
|
||||
)
|
||||
) : null}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{Object.keys(silenceFormStore.data.requestsByCluster).length === 1 ? (
|
||||
<SingleClusterStatus
|
||||
silenceFormStore={silenceFormStore}
|
||||
alertStore={alertStore}
|
||||
/>
|
||||
) : (
|
||||
<MultiClusterStatus
|
||||
silenceFormStore={silenceFormStore}
|
||||
alertStore={alertStore}
|
||||
/>
|
||||
)}
|
||||
<div className="d-flex flex-row-reverse">
|
||||
<button
|
||||
type="button"
|
||||
@@ -93,4 +161,4 @@ SilenceSubmitController.propTypes = {
|
||||
silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired,
|
||||
};
|
||||
|
||||
export { SilenceSubmitController };
|
||||
export { SilenceSubmitController, MultiClusterStatus, SingleClusterStatus };
|
||||
|
||||
@@ -8,7 +8,11 @@ import {
|
||||
SilenceFormStage,
|
||||
NewClusterRequest,
|
||||
} from "Stores/SilenceFormStore";
|
||||
import { SilenceSubmitController } from "./SilenceSubmitController";
|
||||
import {
|
||||
SilenceSubmitController,
|
||||
MultiClusterStatus,
|
||||
SingleClusterStatus,
|
||||
} from "./SilenceSubmitController";
|
||||
|
||||
let alertStore;
|
||||
let silenceFormStore;
|
||||
@@ -61,13 +65,59 @@ beforeEach(() => {
|
||||
});
|
||||
|
||||
describe("<SilenceSubmitController />", () => {
|
||||
it("renders MultiClusterStatus when multiple clusters are used", () => {
|
||||
silenceFormStore.data.requestsByCluster = {
|
||||
ha: NewClusterRequest("ha", ["am1", "am2"]),
|
||||
single: NewClusterRequest("single", ["single"]),
|
||||
};
|
||||
|
||||
const tree = shallow(
|
||||
<SilenceSubmitController
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
);
|
||||
expect(tree.find("MultiClusterStatus")).toHaveLength(1);
|
||||
expect(tree.find("SingleClusterStatus")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("renders SingleClusterStatus when multiple clusters are used", () => {
|
||||
silenceFormStore.data.requestsByCluster = {
|
||||
ha: NewClusterRequest("ha", ["am1", "am2"]),
|
||||
};
|
||||
|
||||
const tree = shallow(
|
||||
<SilenceSubmitController
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
);
|
||||
expect(tree.find("MultiClusterStatus")).toHaveLength(0);
|
||||
expect(tree.find("SingleClusterStatus")).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("resets the form on 'Back' button click", () => {
|
||||
silenceFormStore.data.currentStage = SilenceFormStage.Submit;
|
||||
const tree = shallow(
|
||||
<SilenceSubmitController
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
);
|
||||
const button = tree.find("button");
|
||||
button.simulate("click");
|
||||
expect(silenceFormStore.data.currentStage).toBe(SilenceFormStage.UserInput);
|
||||
});
|
||||
});
|
||||
|
||||
describe("<MultiClusterStatus />", () => {
|
||||
it("renders all passed SilenceSubmitProgress", () => {
|
||||
silenceFormStore.data.requestsByCluster = {
|
||||
ha: NewClusterRequest("ha", ["am1", "am2"]),
|
||||
single: NewClusterRequest("single", ["single"]),
|
||||
};
|
||||
const tree = shallow(
|
||||
<SilenceSubmitController
|
||||
<MultiClusterStatus
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
@@ -79,7 +129,7 @@ describe("<SilenceSubmitController />", () => {
|
||||
const single = NewClusterRequest("single", ["single"]);
|
||||
silenceFormStore.data.requestsByCluster = { single: single };
|
||||
const tree = shallow(
|
||||
<SilenceSubmitController
|
||||
<MultiClusterStatus
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
@@ -96,7 +146,7 @@ describe("<SilenceSubmitController />", () => {
|
||||
single.error = "fake error";
|
||||
silenceFormStore.data.requestsByCluster = { single: single };
|
||||
const tree = shallow(
|
||||
<SilenceSubmitController
|
||||
<MultiClusterStatus
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
@@ -114,7 +164,7 @@ describe("<SilenceSubmitController />", () => {
|
||||
single.silenceLink = "http://localhost";
|
||||
silenceFormStore.data.requestsByCluster = { single: single };
|
||||
const tree = shallow(
|
||||
<SilenceSubmitController
|
||||
<MultiClusterStatus
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
@@ -127,17 +177,57 @@ describe("<SilenceSubmitController />", () => {
|
||||
tree.find("td").at(2).find('a[href="http://localhost"]')
|
||||
).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
it("resets the form on 'Back' button click", () => {
|
||||
silenceFormStore.data.currentStage = SilenceFormStage.Submit;
|
||||
describe("<SingleClusterStatus />", () => {
|
||||
it("renders spinner for pending requests", () => {
|
||||
const single = NewClusterRequest("single", ["single"]);
|
||||
silenceFormStore.data.requestsByCluster = { single: single };
|
||||
const tree = shallow(
|
||||
<SilenceSubmitController
|
||||
<SingleClusterStatus
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
);
|
||||
const button = tree.find("button");
|
||||
button.simulate("click");
|
||||
expect(silenceFormStore.data.currentStage).toBe(SilenceFormStage.UserInput);
|
||||
expect(tree.find("div.display-1").at(0).html()).toMatch(/fa-circle-notch/);
|
||||
expect(tree.find("div.badge.badge-primary").text()).toBe("single");
|
||||
expect(tree.find("p")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("renders error for failed requests", () => {
|
||||
const single = NewClusterRequest("single", ["single"]);
|
||||
single.isDone = true;
|
||||
single.error = "fake error";
|
||||
silenceFormStore.data.requestsByCluster = { single: single };
|
||||
const tree = shallow(
|
||||
<SingleClusterStatus
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
);
|
||||
expect(tree.find("div.display-1").at(0).html()).toMatch(
|
||||
/fa-exclamation-circle/
|
||||
);
|
||||
expect(tree.find("div.badge.badge-primary").text()).toBe("single");
|
||||
expect(tree.find("p").text()).toBe("fake error");
|
||||
});
|
||||
|
||||
it("renders silence link for completed requests", () => {
|
||||
const single = NewClusterRequest("single", ["single"]);
|
||||
single.isDone = true;
|
||||
single.silenceID = "123456789";
|
||||
single.silenceLink = "http://localhost";
|
||||
silenceFormStore.data.requestsByCluster = { single: single };
|
||||
const tree = shallow(
|
||||
<SingleClusterStatus
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(tree.find("div.display-1").at(0).html()).toMatch(/fa-check-circle/);
|
||||
expect(tree.find("div.badge.badge-primary").text()).toBe("single");
|
||||
expect(tree.find("p").text()).toBe("123456789");
|
||||
expect(tree.find("p").find('a[href="http://localhost"]')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -68,7 +68,7 @@ const SilenceSubmitProgress = ({
|
||||
}
|
||||
}, [cluster, error, inProgress, publicURIs, response, responseURI]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
return <FontAwesomeIcon icon={faCircleNotch} spin />;
|
||||
return <FontAwesomeIcon className="text-muted" icon={faCircleNotch} spin />;
|
||||
};
|
||||
SilenceSubmitProgress.propTypes = {
|
||||
cluster: PropTypes.string.isRequired,
|
||||
|
||||
Reference in New Issue
Block a user