mirror of
https://github.com/prymitive/karma
synced 2026-05-05 03:16:51 +00:00
feat(ui): deduplicate silences
If all alerts in a group are silenced and the same silence ID is used for all of them then there's no point in rendering silence object for each of the alerts, since they are all identical. Move the silence rendering to the footer if that happens so we save screen space
This commit is contained in:
@@ -18,7 +18,7 @@ beforeEach(() => {
|
||||
alertStore = new AlertStore([]);
|
||||
silenceFormStore = new SilenceFormStore();
|
||||
alert = MockAlert([], { foo: "bar" }, "active");
|
||||
group = MockAlertGroup({ alertname: "Fake Alert" }, [alert], [], {});
|
||||
group = MockAlertGroup({ alertname: "Fake Alert" }, [alert], [], {}, {});
|
||||
});
|
||||
|
||||
const MockAfterClick = jest.fn();
|
||||
|
||||
@@ -58,7 +58,10 @@ const Alert = observer(
|
||||
};
|
||||
}
|
||||
for (let silenceID of am.silencedBy) {
|
||||
if (!silences[am.cluster].silences.includes(silenceID)) {
|
||||
if (
|
||||
!silences[am.cluster].silences.includes(silenceID) &&
|
||||
!(group.shared.silences[am.cluster] === silenceID)
|
||||
) {
|
||||
silences[am.cluster].silences.push(silenceID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ const MountedAlert = (alert, group, showAlertmanagers, showReceiver) => {
|
||||
describe("<Alert />", () => {
|
||||
it("matches snapshot with showAlertmanagers=false showReceiver=false", () => {
|
||||
const alert = MockedAlert();
|
||||
const group = MockAlertGroup({}, [alert], [], {});
|
||||
const group = MockAlertGroup({}, [alert], [], {}, {});
|
||||
const tree = MountedAlert(alert, group, false, false);
|
||||
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
|
||||
});
|
||||
@@ -69,7 +69,7 @@ describe("<Alert />", () => {
|
||||
it("matches snapshot when inhibited", () => {
|
||||
const alert = MockedAlert();
|
||||
alert.alertmanager[0].inhibitedBy = ["123456"];
|
||||
const group = MockAlertGroup({}, [alert], [], {});
|
||||
const group = MockAlertGroup({}, [alert], [], {}, {});
|
||||
const tree = MountedAlert(alert, group, false, false);
|
||||
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
|
||||
});
|
||||
@@ -77,14 +77,14 @@ describe("<Alert />", () => {
|
||||
it("renders inhibition icon when inhibited", () => {
|
||||
const alert = MockedAlert();
|
||||
alert.alertmanager[0].inhibitedBy = ["123456"];
|
||||
const group = MockAlertGroup({}, [alert], [], {});
|
||||
const group = MockAlertGroup({}, [alert], [], {}, {});
|
||||
const tree = MountedAlert(alert, group, false, false);
|
||||
expect(tree.find(".fa-volume-mute")).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("renders @alertmanager label with showAlertmanagers=true", () => {
|
||||
const alert = MockedAlert();
|
||||
const group = MockAlertGroup({}, [alert], [], {});
|
||||
const group = MockAlertGroup({}, [alert], [], {}, {});
|
||||
const tree = MountedAlert(alert, group, true, false);
|
||||
const label = tree
|
||||
.find("FilteringLabel")
|
||||
@@ -94,7 +94,7 @@ describe("<Alert />", () => {
|
||||
|
||||
it("renders @receiver label with showReceiver=true", () => {
|
||||
const alert = MockedAlert();
|
||||
const group = MockAlertGroup({}, [alert], [], {});
|
||||
const group = MockAlertGroup({}, [alert], [], {}, {});
|
||||
const tree = MountedAlert(alert, group, false, true);
|
||||
const label = tree
|
||||
.find("FilteringLabel")
|
||||
@@ -105,7 +105,7 @@ describe("<Alert />", () => {
|
||||
it("renders a silence if alert is silenced", () => {
|
||||
const alert = MockedAlert();
|
||||
alert.alertmanager[0].silencedBy = ["silence123456789"];
|
||||
const group = MockAlertGroup({}, [alert], [], {});
|
||||
const group = MockAlertGroup({}, [alert], [], {}, {});
|
||||
const tree = MountedAlert(alert, group, false, false);
|
||||
const silence = tree.find("Silence");
|
||||
expect(silence).toHaveLength(1);
|
||||
@@ -136,7 +136,7 @@ describe("<Alert />", () => {
|
||||
inhibitedBy: []
|
||||
}
|
||||
];
|
||||
const group = MockAlertGroup({}, [alert], [], {});
|
||||
const group = MockAlertGroup({}, [alert], [], {}, {});
|
||||
const tree = MountedAlert(alert, group, false, false);
|
||||
const silence = tree.find("Silence");
|
||||
expect(silence).toHaveLength(1);
|
||||
@@ -146,7 +146,7 @@ describe("<Alert />", () => {
|
||||
it("uses BorderClassMap.active when @state=active", () => {
|
||||
const alert = MockedAlert();
|
||||
alert.state = "active";
|
||||
const group = MockAlertGroup({}, [alert], [], {});
|
||||
const group = MockAlertGroup({}, [alert], [], {}, {});
|
||||
const tree = MountedAlert(alert, group, false, false);
|
||||
expect(
|
||||
tree
|
||||
@@ -158,7 +158,7 @@ describe("<Alert />", () => {
|
||||
it("uses BorderClassMap.suppressed when @state=suppressed", () => {
|
||||
const alert = MockedAlert();
|
||||
alert.state = "suppressed";
|
||||
const group = MockAlertGroup({}, [alert], [], {});
|
||||
const group = MockAlertGroup({}, [alert], [], {}, {});
|
||||
const tree = MountedAlert(alert, group, false, false);
|
||||
expect(
|
||||
tree
|
||||
@@ -170,7 +170,7 @@ describe("<Alert />", () => {
|
||||
it("uses BorderClassMap.unprocessed when @state=unprocessed", () => {
|
||||
const alert = MockedAlert();
|
||||
alert.state = "unprocessed";
|
||||
const group = MockAlertGroup({}, [alert], [], {});
|
||||
const group = MockAlertGroup({}, [alert], [], {}, {});
|
||||
const tree = MountedAlert(alert, group, false, false);
|
||||
expect(
|
||||
tree
|
||||
@@ -184,7 +184,7 @@ describe("<Alert />", () => {
|
||||
|
||||
const alert = MockedAlert();
|
||||
alert.state = "foobar";
|
||||
const group = MockAlertGroup({}, [alert], [], {});
|
||||
const group = MockAlertGroup({}, [alert], [], {}, {});
|
||||
const tree = MountedAlert(alert, group, false, false);
|
||||
expect(
|
||||
tree
|
||||
|
||||
@@ -128,3 +128,184 @@ exports[`<GroupFooter /> matches snapshot 1`] = `
|
||||
</div>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<GroupFooter /> mathes snapshot when silence is rendered 1`] = `
|
||||
"
|
||||
<div class=\\"card-footer px-2 py-1\\">
|
||||
<div class=\\"mb-1\\">
|
||||
<div class=\\"mr-1 mb-1 p-1 bg-light cursor-pointer d-inline-block rounded components-grid-annotation text-break\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
focusable=\\"false\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"search-minus\\"
|
||||
class=\\"svg-inline--fa fa-search-minus fa-w-16 mr-1\\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 512 512\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M304 192v32c0 6.6-5.4 12-12 12H124c-6.6 0-12-5.4-12-12v-32c0-6.6 5.4-12 12-12h168c6.6 0 12 5.4 12 12zm201 284.7L476.7 505c-9.4 9.4-24.6 9.4-33.9 0L343 405.3c-4.5-4.5-7-10.6-7-17V372c-35.3 27.6-79.7 44-128 44C93.1 416 0 322.9 0 208S93.1 0 208 0s208 93.1 208 208c0 48.3-16.4 92.7-44 128h16.3c6.4 0 12.5 2.5 17 7l99.7 99.7c9.3 9.4 9.3 24.6 0 34zM344 208c0-75.2-60.8-136-136-136S72 132.8 72 208s60.8 136 136 136 136-60.8 136-136z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
<span class=\\"text-muted\\">
|
||||
summary:
|
||||
</span>
|
||||
<span class=\\"Linkify\\">
|
||||
This is summary
|
||||
</span>
|
||||
</div>
|
||||
<div class=\\"mr-1 mb-1 p-1 bg-light cursor-pointer d-inline-block rounded components-grid-annotation text-break\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
focusable=\\"false\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"search-plus\\"
|
||||
class=\\"svg-inline--fa fa-search-plus fa-w-16 mr-1\\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 512 512\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M304 192v32c0 6.6-5.4 12-12 12h-56v56c0 6.6-5.4 12-12 12h-32c-6.6 0-12-5.4-12-12v-56h-56c-6.6 0-12-5.4-12-12v-32c0-6.6 5.4-12 12-12h56v-56c0-6.6 5.4-12 12-12h32c6.6 0 12 5.4 12 12v56h56c6.6 0 12 5.4 12 12zm201 284.7L476.7 505c-9.4 9.4-24.6 9.4-33.9 0L343 405.3c-4.5-4.5-7-10.6-7-17V372c-35.3 27.6-79.7 44-128 44C93.1 416 0 322.9 0 208S93.1 0 208 0s208 93.1 208 208c0 48.3-16.4 92.7-44 128h16.3c6.4 0 12.5 2.5 17 7l99.7 99.7c9.3 9.4 9.3 24.6 0 34zM344 208c0-75.2-60.8-136-136-136S72 132.8 72 208s60.8 136 136 136 136-60.8 136-136z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
hidden
|
||||
</div>
|
||||
</div>
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-9\\"
|
||||
data-original-title=\\"Click to only show alerts with this label or Alt+Click to hide them\\"
|
||||
>
|
||||
<span class=\\"components-label badge text-nowrap text-truncate mw-100 badge-warning components-label-dark components-label-with-hover\\">
|
||||
<span class=\\"components-label-name\\">
|
||||
label1:
|
||||
</span>
|
||||
<span class=\\"components-label-value\\">
|
||||
foo
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-10\\"
|
||||
data-original-title=\\"Click to only show alerts with this label or Alt+Click to hide them\\"
|
||||
>
|
||||
<span class=\\"components-label badge text-nowrap text-truncate mw-100 badge-warning components-label-dark components-label-with-hover\\">
|
||||
<span class=\\"components-label-name\\">
|
||||
label2:
|
||||
</span>
|
||||
<span class=\\"components-label-value\\">
|
||||
bar
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-11\\"
|
||||
data-original-title=\\"Click to only show alerts with this label or Alt+Click to hide them\\"
|
||||
>
|
||||
<span class=\\"components-label badge text-nowrap text-truncate mw-100 badge-warning components-label-dark components-label-with-hover\\">
|
||||
<span class=\\"components-label-name\\">
|
||||
@alertmanager:
|
||||
</span>
|
||||
<span class=\\"components-label-value\\">
|
||||
default
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-12\\"
|
||||
data-original-title=\\"Click to only show alerts with this label or Alt+Click to hide them\\"
|
||||
>
|
||||
<span class=\\"components-label badge text-nowrap text-truncate mw-100 badge-warning components-label-dark components-label-with-hover\\">
|
||||
<span class=\\"components-label-name\\">
|
||||
@receiver:
|
||||
</span>
|
||||
<span class=\\"components-label-value\\">
|
||||
by-name
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<a href=\\"http://link.example.com\\"
|
||||
target=\\"_blank\\"
|
||||
rel=\\"noopener noreferrer\\"
|
||||
class=\\"components-label-with-hover text-nowrap text-truncate badge mr-1 components-grid-annotation-link\\"
|
||||
>
|
||||
<svg aria-hidden=\\"true\\"
|
||||
focusable=\\"false\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"external-link-alt\\"
|
||||
class=\\"svg-inline--fa fa-external-link-alt fa-w-18 \\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 576 512\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M576 24v127.984c0 21.461-25.96 31.98-40.971 16.971l-35.707-35.709-243.523 243.523c-9.373 9.373-24.568 9.373-33.941 0l-22.627-22.627c-9.373-9.373-9.373-24.569 0-33.941L442.756 76.676l-35.703-35.705C391.982 25.9 402.656 0 424.024 0H552c13.255 0 24 10.745 24 24zM407.029 270.794l-16 16A23.999 23.999 0 0 0 384 303.765V448H64V128h264a24.003 24.003 0 0 0 16.97-7.029l16-16C376.089 89.851 365.381 64 344 64H48C21.49 64 0 85.49 0 112v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V287.764c0-21.382-25.852-32.09-40.971-16.97z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
link
|
||||
</a>
|
||||
<div class=\\"components-grid-alertgrid-alertgroup-shared-silence rounded-0 border-left-1 border-right-0 border-top-0 border-bottom-0 border-success \\">
|
||||
<div class=\\"card mt-1 border-0 p-1\\">
|
||||
<div class=\\"card-text mb-0\\">
|
||||
<span class=\\"text-muted my-1\\">
|
||||
<span width=\\"0\\">
|
||||
<span>
|
||||
</span>
|
||||
<span>
|
||||
Mocked Silence
|
||||
</span>
|
||||
<span style=\\"position: fixed; visibility: hidden; top: 0px; left: 0px;\\">
|
||||
…
|
||||
</span>
|
||||
</span>
|
||||
<span class=\\"blockquote-footer pt-1\\">
|
||||
<span class=\\"float-right cursor-pointer\\">
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-13\\"
|
||||
data-original-title=\\"Toggle silence details\\"
|
||||
>
|
||||
<svg aria-hidden=\\"true\\"
|
||||
focusable=\\"false\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"chevron-up\\"
|
||||
class=\\"svg-inline--fa fa-chevron-up fa-w-14 \\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 448 512\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M240.971 130.524l194.343 194.343c9.373 9.373 9.373 24.569 0 33.941l-22.667 22.667c-9.357 9.357-24.522 9.375-33.901.04L224 227.495 69.255 381.516c-9.379 9.335-24.544 9.317-33.901-.04l-22.667-22.667c-9.373-9.373-9.373-24.569 0-33.941L207.03 130.525c9.372-9.373 24.568-9.373 33.941-.001z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
</span>
|
||||
<cite class=\\"components-grid-alertgroup-silences mr-2\\">
|
||||
me@example.com
|
||||
</cite>
|
||||
<span class=\\"badge badge-danger text-nowrap text-truncate mw-100 align-bottom\\">
|
||||
Expired
|
||||
<time datetime=\\"946688400000\\">
|
||||
14 hours ago
|
||||
</time>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
.components-grid-alertgrid-alertgroup-shared-silence {
|
||||
border-width: 3px;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.components-grid-alertgrid-alertgroup-shared-silence > .card {
|
||||
background-color: inherit;
|
||||
}
|
||||
@@ -5,19 +5,29 @@ import { observer } from "mobx-react";
|
||||
|
||||
import { APIGroup } from "Models/API";
|
||||
import { StaticLabels } from "Common/Query";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { FilteringLabel } from "Components/Labels/FilteringLabel";
|
||||
import { RenderNonLinkAnnotation, RenderLinkAnnotation } from "../Annotation";
|
||||
import { Silence } from "../Silence";
|
||||
|
||||
import "./index.css";
|
||||
|
||||
const GroupFooter = observer(
|
||||
class GroupFooter extends Component {
|
||||
static propTypes = {
|
||||
group: APIGroup.isRequired,
|
||||
alertmanagers: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
afterUpdate: PropTypes.func.isRequired
|
||||
afterUpdate: PropTypes.func.isRequired,
|
||||
silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired
|
||||
};
|
||||
|
||||
render() {
|
||||
const { group, alertmanagers, afterUpdate } = this.props;
|
||||
const {
|
||||
group,
|
||||
alertmanagers,
|
||||
afterUpdate,
|
||||
silenceFormStore
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className="card-footer px-2 py-1">
|
||||
@@ -54,6 +64,26 @@ const GroupFooter = observer(
|
||||
value={a.value}
|
||||
/>
|
||||
))}
|
||||
{Object.keys(group.shared.silences).length === 0 ? null : (
|
||||
<div className="components-grid-alertgrid-alertgroup-shared-silence rounded-0 border-left-1 border-right-0 border-top-0 border-bottom-0 border-success ">
|
||||
{Object.entries(group.shared.silences).map(
|
||||
([cluster, silenceID]) => (
|
||||
<Silence
|
||||
key={silenceID}
|
||||
silenceFormStore={silenceFormStore}
|
||||
alertmanagerState={
|
||||
group.alerts.map(
|
||||
a =>
|
||||
a.alertmanager.filter(am => am.cluster === cluster)[0]
|
||||
)[0]
|
||||
}
|
||||
silenceID={silenceID}
|
||||
afterUpdate={afterUpdate}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,23 +6,38 @@ import { mount } from "enzyme";
|
||||
|
||||
import toDiffableHtml from "diffable-html";
|
||||
|
||||
import { MockAlertGroup, MockAnnotation } from "__mocks__/Alerts.js";
|
||||
import moment from "moment";
|
||||
import { advanceTo, clear } from "jest-date-mock";
|
||||
|
||||
import {
|
||||
MockAlertGroup,
|
||||
MockAnnotation,
|
||||
MockAlert,
|
||||
MockSilence
|
||||
} from "__mocks__/Alerts.js";
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { GroupFooter } from ".";
|
||||
|
||||
let group;
|
||||
let alertStore;
|
||||
let silenceFormStore;
|
||||
|
||||
const MockGroup = () => {
|
||||
const group = MockAlertGroup(
|
||||
{ alertname: "Fake Alert" },
|
||||
[],
|
||||
[
|
||||
MockAlert([], {}, "suppressed"),
|
||||
MockAlert([], {}, "suppressed"),
|
||||
MockAlert([], {}, "suppressed")
|
||||
],
|
||||
[
|
||||
MockAnnotation("summary", "This is summary", true, false),
|
||||
MockAnnotation("hidden", "This is hidden annotation", false, false),
|
||||
MockAnnotation("link", "http://link.example.com", true, true)
|
||||
],
|
||||
{ label1: "foo", label2: "bar" }
|
||||
{ label1: "foo", label2: "bar" },
|
||||
{}
|
||||
);
|
||||
return group;
|
||||
};
|
||||
@@ -31,7 +46,15 @@ const MockAfterUpdate = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
alertStore = new AlertStore([]);
|
||||
silenceFormStore = new SilenceFormStore();
|
||||
group = MockGroup();
|
||||
advanceTo(moment.utc([2000, 0, 1, 15, 0, 0]));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
// reset Date() to current time
|
||||
clear();
|
||||
});
|
||||
|
||||
const MountedGroupFooter = () => {
|
||||
@@ -41,6 +64,7 @@ const MountedGroupFooter = () => {
|
||||
group={group}
|
||||
alertmanagers={["default"]}
|
||||
afterUpdate={MockAfterUpdate}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
</Provider>
|
||||
);
|
||||
@@ -51,4 +75,30 @@ describe("<GroupFooter />", () => {
|
||||
const tree = MountedGroupFooter().find("GroupFooter");
|
||||
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("render deduplicated silence if present", () => {
|
||||
for (const id of Object.keys(group.alerts)) {
|
||||
group.alerts[id].alertmanager[0].silencedBy = ["123456789"];
|
||||
}
|
||||
group.shared.silences = { default: "123456789" };
|
||||
const tree = MountedGroupFooter().find("GroupFooter");
|
||||
expect(tree.find("Silence")).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("mathes snapshot when silence is rendered", () => {
|
||||
for (const id of Object.keys(group.alerts)) {
|
||||
group.alerts[id].alertmanager[0].silencedBy = ["123456789"];
|
||||
}
|
||||
group.shared.silences = { default: "123456789" };
|
||||
|
||||
alertStore.data.silences = {
|
||||
default: {
|
||||
"123456789": MockSilence()
|
||||
}
|
||||
};
|
||||
alertStore.data.silences["default"]["123456789"].id = "123456789";
|
||||
|
||||
const tree = MountedGroupFooter().find("GroupFooter");
|
||||
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -31,13 +31,13 @@ const MountedGroupMenu = group => {
|
||||
|
||||
describe("<GroupMenu />", () => {
|
||||
it("is collapsed by default", () => {
|
||||
const group = MockAlertGroup({ alertname: "Fake Alert" }, [], [], {});
|
||||
const group = MockAlertGroup({ alertname: "Fake Alert" }, [], [], {}, {});
|
||||
const tree = MountedGroupMenu(group);
|
||||
expect(tree.instance().collapse.value).toBe(true);
|
||||
});
|
||||
|
||||
it("clicking toggle sets collapse value to 'false'", () => {
|
||||
const group = MockAlertGroup({ alertname: "Fake Alert" }, [], [], {});
|
||||
const group = MockAlertGroup({ alertname: "Fake Alert" }, [], [], {}, {});
|
||||
const tree = MountedGroupMenu(group);
|
||||
const toggle = tree.find(".cursor-pointer");
|
||||
toggle.simulate("click");
|
||||
@@ -45,7 +45,7 @@ describe("<GroupMenu />", () => {
|
||||
});
|
||||
|
||||
it("handleClickOutside() call sets collapse value to 'true'", () => {
|
||||
const group = MockAlertGroup({ alertname: "Fake Alert" }, [], [], {});
|
||||
const group = MockAlertGroup({ alertname: "Fake Alert" }, [], [], {}, {});
|
||||
const tree = MountedGroupMenu(group);
|
||||
|
||||
const toggle = tree.find(".cursor-pointer");
|
||||
@@ -75,7 +75,7 @@ const MountedMenuContent = group => {
|
||||
|
||||
describe("<MenuContent />", () => {
|
||||
it("clicking on 'Copy' icon copies the link to clickboard", () => {
|
||||
const group = MockAlertGroup({ alertname: "Fake Alert" }, [], [], {});
|
||||
const group = MockAlertGroup({ alertname: "Fake Alert" }, [], [], {}, {});
|
||||
const tree = MountedMenuContent(group);
|
||||
const button = tree.find(".dropdown-item").at(0);
|
||||
button.simulate("click");
|
||||
@@ -83,7 +83,7 @@ describe("<MenuContent />", () => {
|
||||
});
|
||||
|
||||
it("clicking on 'Silence' icon opens the silence form modal", () => {
|
||||
const group = MockAlertGroup({ alertname: "Fake Alert" }, [], [], {});
|
||||
const group = MockAlertGroup({ alertname: "Fake Alert" }, [], [], {}, {});
|
||||
const tree = MountedMenuContent(group);
|
||||
const button = tree.find(".dropdown-item").at(1);
|
||||
button.simulate("click");
|
||||
|
||||
@@ -32,7 +32,8 @@ const MockAPIResponse = () => {
|
||||
{ alertname: "foo" },
|
||||
[MockAlert([], { instance: "foo" }, "suppressed")],
|
||||
[],
|
||||
{ job: "foo" }
|
||||
{ job: "foo" },
|
||||
{}
|
||||
)
|
||||
};
|
||||
return response;
|
||||
|
||||
@@ -219,6 +219,7 @@ const AlertGroup = observer(
|
||||
group={group}
|
||||
alertmanagers={footerAlertmanagers}
|
||||
afterUpdate={afterUpdate}
|
||||
silenceFormStore={silenceFormStore}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
@@ -22,6 +22,7 @@ const MockGroup = groupName => {
|
||||
{ alertname: "Fake Alert", groupName: groupName },
|
||||
[],
|
||||
[],
|
||||
{},
|
||||
{}
|
||||
);
|
||||
return group;
|
||||
|
||||
@@ -41,6 +41,7 @@ const MockGroup = (groupName, alertCount) => {
|
||||
{ alertname: "Fake Alert", group: groupName },
|
||||
alerts,
|
||||
[],
|
||||
{},
|
||||
{}
|
||||
);
|
||||
return group;
|
||||
|
||||
@@ -42,7 +42,8 @@ const MockAPIResponse = () => {
|
||||
{ alertname: "foo" },
|
||||
[MockAlert([], { instance: "foo1" }, "active")],
|
||||
[],
|
||||
{ job: "foo" }
|
||||
{ job: "foo" },
|
||||
{}
|
||||
),
|
||||
"2": MockAlertGroup(
|
||||
{ alertname: "bar" },
|
||||
@@ -51,7 +52,8 @@ const MockAPIResponse = () => {
|
||||
MockAlert([], { instance: "bar2" }, "active")
|
||||
],
|
||||
[],
|
||||
{ job: "bar" }
|
||||
{ job: "bar" },
|
||||
{}
|
||||
)
|
||||
};
|
||||
return response;
|
||||
|
||||
@@ -44,7 +44,8 @@ const APIGroup = PropTypes.exact({
|
||||
}),
|
||||
shared: PropTypes.exact({
|
||||
annotations: PropTypes.arrayOf(Annotation).isRequired,
|
||||
labels: PropTypes.object.isRequired
|
||||
labels: PropTypes.object.isRequired,
|
||||
silences: PropTypes.object.isRequired
|
||||
}).isRequired
|
||||
});
|
||||
|
||||
|
||||
@@ -23,9 +23,15 @@ const MockGroup = () => {
|
||||
MockAlert([], { instance: "prod2", cluster: "prod" }),
|
||||
MockAlert([], { instance: "dev1", cluster: "dev" })
|
||||
];
|
||||
const group = MockAlertGroup({ alertname: "FakeAlert" }, alerts, [], {
|
||||
job: "mock"
|
||||
});
|
||||
const group = MockAlertGroup(
|
||||
{ alertname: "FakeAlert" },
|
||||
alerts,
|
||||
[],
|
||||
{
|
||||
job: "mock"
|
||||
},
|
||||
{}
|
||||
);
|
||||
return group;
|
||||
};
|
||||
|
||||
|
||||
@@ -30,7 +30,8 @@ const MockAlertGroup = (
|
||||
rootLabels,
|
||||
alerts,
|
||||
sharedAnnotations,
|
||||
sharedLabels
|
||||
sharedLabels,
|
||||
sharedSilences
|
||||
) => ({
|
||||
receiver: "by-name",
|
||||
labels: rootLabels,
|
||||
@@ -47,7 +48,8 @@ const MockAlertGroup = (
|
||||
},
|
||||
shared: {
|
||||
annotations: sharedAnnotations,
|
||||
labels: sharedLabels
|
||||
labels: sharedLabels,
|
||||
silences: sharedSilences
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user