mirror of
https://github.com/prymitive/karma
synced 2026-09-04 11:27:19 +00:00
@@ -96,6 +96,7 @@ const Alert = observer(
|
||||
am.silencedBy.map(silenceID => (
|
||||
<Silence
|
||||
key={silenceID}
|
||||
silenceFormStore={silenceFormStore}
|
||||
alertmanagerState={am}
|
||||
silenceID={silenceID}
|
||||
afterUpdate={afterUpdate}
|
||||
|
||||
+105
-28
@@ -87,34 +87,111 @@ exports[`<Silence /> matches snapshot with expaned details 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
<div class=\\"mt-1\\">
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
@alertmanager: default
|
||||
</span>
|
||||
<a class=\\"badge badge-secondary text-nowrap text-truncate px-1 mr-1\\"
|
||||
href=\\"file:///mock/#/silences/4cf5fd82-1edd-4169-99d1-ff8415e72179\\"
|
||||
target=\\"_blank\\"
|
||||
rel=\\"noopener noreferrer\\"
|
||||
>
|
||||
4cf5fd82-1edd-4169-99d1-ff8415e72179
|
||||
</a>
|
||||
<span class=\\"badge badge-secondary text-nowrap text-truncate px-1 mr-1\\">
|
||||
Silenced
|
||||
<time datetime=\\"946720800000\\">
|
||||
5 hours ago
|
||||
</time>
|
||||
</span>
|
||||
<span class=\\"badge badge-secondary text-nowrap text-truncate px-1 mr-1\\">
|
||||
Expires
|
||||
<time datetime=\\"946756800000\\">
|
||||
in 5 hours
|
||||
</time>
|
||||
</span>
|
||||
<span class=\\"badge badge-success text-nowrap text-truncate px-1 mr-1\\">
|
||||
alertname=MockAlert
|
||||
</span>
|
||||
<span class=\\"badge badge-success text-nowrap text-truncate px-1 mr-1\\">
|
||||
instance=~foo[0-9]+
|
||||
</span>
|
||||
<div>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
@alertmanager: default
|
||||
</span>
|
||||
<a href=\\"file:///mock/#/silences/4cf5fd82-1edd-4169-99d1-ff8415e72179\\"
|
||||
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\\"
|
||||
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>
|
||||
4cf5fd82-1edd-4169-99d1-ff8415e72179
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<span class=\\"badge text-nowrap text-truncate px-1 mr-1\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"calendar-check\\"
|
||||
class=\\"svg-inline--fa fa-calendar-check fa-w-14 text-muted mr-1\\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 448 512\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M436 160H12c-6.627 0-12-5.373-12-12v-36c0-26.51 21.49-48 48-48h48V12c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v52h128V12c0-6.627 5.373-12 12-12h40c6.627 0 12 5.373 12 12v52h48c26.51 0 48 21.49 48 48v36c0 6.627-5.373 12-12 12zM12 192h424c6.627 0 12 5.373 12 12v260c0 26.51-21.49 48-48 48H48c-26.51 0-48-21.49-48-48V204c0-6.627 5.373-12 12-12zm333.296 95.947l-28.169-28.398c-4.667-4.705-12.265-4.736-16.97-.068L194.12 364.665l-45.98-46.352c-4.667-4.705-12.266-4.736-16.971-.068l-28.397 28.17c-4.705 4.667-4.736 12.265-.068 16.97l82.601 83.269c4.667 4.705 12.265 4.736 16.97.068l142.953-141.805c4.705-4.667 4.736-12.265.068-16.97z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
Created
|
||||
<time datetime=\\"946720800000\\">
|
||||
5 hours ago
|
||||
</time>
|
||||
</span>
|
||||
<span class=\\"badge text-nowrap text-truncate px-1 mr-1\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"calendar-times\\"
|
||||
class=\\"svg-inline--fa fa-calendar-times fa-w-14 text-muted mr-1\\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 448 512\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M436 160H12c-6.6 0-12-5.4-12-12v-36c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48v36c0 6.6-5.4 12-12 12zM12 192h424c6.6 0 12 5.4 12 12v260c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V204c0-6.6 5.4-12 12-12zm257.3 160l48.1-48.1c4.7-4.7 4.7-12.3 0-17l-28.3-28.3c-4.7-4.7-12.3-4.7-17 0L224 306.7l-48.1-48.1c-4.7-4.7-12.3-4.7-17 0l-28.3 28.3c-4.7 4.7-4.7 12.3 0 17l48.1 48.1-48.1 48.1c-4.7 4.7-4.7 12.3 0 17l28.3 28.3c4.7 4.7 12.3 4.7 17 0l48.1-48.1 48.1 48.1c4.7 4.7 12.3 4.7 17 0l28.3-28.3c4.7-4.7 4.7-12.3 0-17L269.3 352z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
Expires
|
||||
<time datetime=\\"946756800000\\">
|
||||
in 5 hours
|
||||
</time>
|
||||
</span>
|
||||
<span class=\\"badge badge-secondary text-nowrap text-truncate px-1 cursor-pointer components-label-with-hover\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"edit\\"
|
||||
class=\\"svg-inline--fa fa-edit fa-w-18 mr-1\\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 576 512\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M402.6 83.2l90.2 90.2c3.8 3.8 3.8 10 0 13.8L274.4 405.6l-92.8 10.3c-12.4 1.4-22.9-9.1-21.5-21.5l10.3-92.8L388.8 83.2c3.8-3.8 10-3.8 13.8 0zm162-22.9l-48.8-48.8c-15.2-15.2-39.9-15.2-55.2 0l-35.4 35.4c-3.8 3.8-3.8 10 0 13.8l90.2 90.2c3.8 3.8 10 3.8 13.8 0l35.4-35.4c15.2-15.3 15.2-40 0-55.2zM384 346.2V448H64V128h229.8c3.2 0 6.2-1.3 8.5-3.5l40-40c7.6-7.6 2.2-20.5-8.5-20.5H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V306.2c0-10.7-12.9-16-20.5-8.5l-40 40c-2.2 2.3-3.5 5.3-3.5 8.5z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
Edit
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class=\\"badge text-nowrap text-truncate px-1 mr-1\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"filter\\"
|
||||
class=\\"svg-inline--fa fa-filter fa-w-16 text-muted mr-1\\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 512 512\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M487.976 0H24.028C2.71 0-8.047 25.866 7.058 40.971L192 225.941V432c0 7.831 3.821 15.17 10.237 19.662l80 55.98C298.02 518.69 320 507.493 320 487.98V225.941l184.947-184.97C520.021 25.896 509.338 0 487.976 0z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
Matchers:
|
||||
</span>
|
||||
<span class=\\"badge badge-light text-nowrap text-truncate px-1 mr-1\\">
|
||||
alertname=MockAlert
|
||||
</span>
|
||||
<span class=\\"badge badge-light text-nowrap text-truncate px-1 mr-1\\">
|
||||
instance=~foo[0-9]+
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"
|
||||
|
||||
@@ -13,6 +13,10 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons/faExternalLinkAlt";
|
||||
import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp";
|
||||
import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
|
||||
import { faEdit } from "@fortawesome/free-solid-svg-icons/faEdit";
|
||||
import { faCalendarCheck } from "@fortawesome/free-solid-svg-icons/faCalendarCheck";
|
||||
import { faCalendarTimes } from "@fortawesome/free-solid-svg-icons/faCalendarTimes";
|
||||
import { faFilter } from "@fortawesome/free-solid-svg-icons/faFilter";
|
||||
|
||||
import {
|
||||
APIAlertAlertmanagerState,
|
||||
@@ -20,8 +24,10 @@ import {
|
||||
APISilence
|
||||
} from "Models/API";
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { StaticLabels, QueryOperators } from "Common/Query";
|
||||
import { FilteringLabel } from "Components/Labels/FilteringLabel";
|
||||
import { RenderLinkAnnotation } from "../Annotation";
|
||||
|
||||
import "./index.css";
|
||||
|
||||
@@ -80,52 +86,68 @@ SilenceExpiryBadgeWithProgress.propTypes = {
|
||||
progress: PropTypes.number.isRequired
|
||||
};
|
||||
|
||||
const SilenceDetails = ({ alertmanager, silence }) => {
|
||||
let expiresClass = "secondary";
|
||||
const SilenceDetails = ({ alertmanager, silence, onEditSilence }) => {
|
||||
let expiresClass = "";
|
||||
let expiresLabel = "Expires";
|
||||
if (moment(silence.endsAt) < moment()) {
|
||||
expiresClass = "danger";
|
||||
expiresClass = "text-danger";
|
||||
expiresLabel = "Expired";
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mt-1">
|
||||
<FilteringLabel
|
||||
name={StaticLabels.AlertManager}
|
||||
value={alertmanager.name}
|
||||
/>
|
||||
<a
|
||||
className="badge badge-secondary text-nowrap text-truncate px-1 mr-1"
|
||||
href={`${alertmanager.uri}/#/silences/${silence.id}`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{silence.id}
|
||||
</a>
|
||||
<span className="badge badge-secondary text-nowrap text-truncate px-1 mr-1">
|
||||
Silenced <Moment fromNow>{silence.startsAt}</Moment>
|
||||
</span>
|
||||
<span
|
||||
className={`badge badge-${expiresClass} text-nowrap text-truncate px-1 mr-1`}
|
||||
>
|
||||
{expiresLabel} <Moment fromNow>{silence.endsAt}</Moment>
|
||||
</span>
|
||||
{silence.matchers.map(matcher => (
|
||||
<span
|
||||
key={hash(matcher)}
|
||||
className="badge badge-success text-nowrap text-truncate px-1 mr-1"
|
||||
>
|
||||
{matcher.name}
|
||||
{matcher.isRegex ? QueryOperators.Regex : QueryOperators.Equal}
|
||||
{matcher.value}
|
||||
<div>
|
||||
<FilteringLabel
|
||||
name={StaticLabels.AlertManager}
|
||||
value={alertmanager.name}
|
||||
/>
|
||||
<RenderLinkAnnotation
|
||||
name={silence.id}
|
||||
value={`${alertmanager.uri}/#/silences/${silence.id}`}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<span className="badge text-nowrap text-truncate px-1 mr-1">
|
||||
<FontAwesomeIcon className="text-muted mr-1" icon={faCalendarCheck} />
|
||||
Created <Moment fromNow>{silence.startsAt}</Moment>
|
||||
</span>
|
||||
))}
|
||||
<span
|
||||
className={`badge ${expiresClass} text-nowrap text-truncate px-1 mr-1`}
|
||||
>
|
||||
<FontAwesomeIcon className="text-muted mr-1" icon={faCalendarTimes} />
|
||||
{expiresLabel} <Moment fromNow>{silence.endsAt}</Moment>
|
||||
</span>
|
||||
<span
|
||||
className="badge badge-secondary text-nowrap text-truncate px-1 cursor-pointer components-label-with-hover"
|
||||
onClick={onEditSilence}
|
||||
>
|
||||
<FontAwesomeIcon className="mr-1" icon={faEdit} />
|
||||
Edit
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="badge text-nowrap text-truncate px-1 mr-1">
|
||||
<FontAwesomeIcon className="text-muted mr-1" icon={faFilter} />
|
||||
Matchers:
|
||||
</span>
|
||||
{silence.matchers.map(matcher => (
|
||||
<span
|
||||
key={hash(matcher)}
|
||||
className="badge badge-light text-nowrap text-truncate px-1 mr-1"
|
||||
>
|
||||
{matcher.name}
|
||||
{matcher.isRegex ? QueryOperators.Regex : QueryOperators.Equal}
|
||||
{matcher.value}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
SilenceDetails.propTypes = {
|
||||
alertmanager: APIAlertmanagerUpstream.isRequired,
|
||||
silence: APISilence.isRequired
|
||||
silence: APISilence.isRequired,
|
||||
onEditSilence: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
//
|
||||
@@ -148,6 +170,7 @@ const Silence = inject("alertStore")(
|
||||
class Silence extends Component {
|
||||
static propTypes = {
|
||||
alertStore: PropTypes.instanceOf(AlertStore).isRequired,
|
||||
silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired,
|
||||
alertmanagerState: APIAlertAlertmanagerState.isRequired,
|
||||
silenceID: PropTypes.string.isRequired,
|
||||
afterUpdate: PropTypes.func.isRequired
|
||||
@@ -231,6 +254,17 @@ const Silence = inject("alertStore")(
|
||||
}
|
||||
};
|
||||
|
||||
onEditSilence = () => {
|
||||
const { silenceFormStore } = this.props;
|
||||
|
||||
const silence = this.getSilence();
|
||||
const alertmanager = this.getAlertmanager();
|
||||
|
||||
silenceFormStore.data.fillFormFromSilence(alertmanager, silence);
|
||||
silenceFormStore.data.resetProgress();
|
||||
silenceFormStore.toggle.show();
|
||||
};
|
||||
|
||||
componentDidUpdate() {
|
||||
const { afterUpdate } = this.props;
|
||||
afterUpdate();
|
||||
@@ -282,7 +316,11 @@ const Silence = inject("alertStore")(
|
||||
</span>
|
||||
</div>
|
||||
{this.collapse.value ? null : (
|
||||
<SilenceDetails alertmanager={alertmanager} silence={silence} />
|
||||
<SilenceDetails
|
||||
alertmanager={alertmanager}
|
||||
silence={silence}
|
||||
onEditSilence={this.onEditSilence}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -3,13 +3,14 @@ import React from "react";
|
||||
import { toJS } from "mobx";
|
||||
import { Provider } from "mobx-react";
|
||||
|
||||
import { mount, shallow } from "enzyme";
|
||||
import { mount } from "enzyme";
|
||||
|
||||
import toDiffableHtml from "diffable-html";
|
||||
|
||||
import { advanceTo, clear } from "jest-date-mock";
|
||||
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { Silence, SilenceDetails } from ".";
|
||||
|
||||
const mockAfterUpdate = jest.fn();
|
||||
@@ -47,6 +48,7 @@ const silence = {
|
||||
};
|
||||
|
||||
let alertStore;
|
||||
let silenceFormStore;
|
||||
|
||||
beforeEach(() => {
|
||||
advanceTo(new Date(2000, 0, 1, 15, 0, 0));
|
||||
@@ -71,6 +73,7 @@ beforeEach(() => {
|
||||
"4cf5fd82-1edd-4169-99d1-ff8415e72179": silence
|
||||
}
|
||||
};
|
||||
silenceFormStore = new SilenceFormStore();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -83,6 +86,7 @@ const MountedSilence = alertmanagerState => {
|
||||
<Provider alertStore={alertStore}>
|
||||
<Silence
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
alertmanagerState={alertmanagerState}
|
||||
silenceID="4cf5fd82-1edd-4169-99d1-ff8415e72179"
|
||||
afterUpdate={mockAfterUpdate}
|
||||
@@ -91,13 +95,16 @@ const MountedSilence = alertmanagerState => {
|
||||
);
|
||||
};
|
||||
|
||||
const ShallowSilenceDetails = () => {
|
||||
return shallow(
|
||||
<SilenceDetails
|
||||
alertmanager={alertStore.data.upstreams.instances[0]}
|
||||
silence={silence}
|
||||
/>
|
||||
);
|
||||
const MountedSilenceDetails = onEditSilence => {
|
||||
return mount(
|
||||
<Provider alertStore={alertStore}>
|
||||
<SilenceDetails
|
||||
alertmanager={alertStore.data.upstreams.instances[0]}
|
||||
silence={silence}
|
||||
onEditSilence={onEditSilence}
|
||||
/>
|
||||
</Provider>
|
||||
).find("SilenceDetails");
|
||||
};
|
||||
|
||||
describe("<Silence />", () => {
|
||||
@@ -190,24 +197,49 @@ describe("<Silence />", () => {
|
||||
name: "notDefault"
|
||||
});
|
||||
});
|
||||
|
||||
it("clicking on silence edit button calls silenceFormStore.data.fillFormFromSilence", () => {
|
||||
const fillSpy = jest.spyOn(silenceFormStore.data, "fillFormFromSilence");
|
||||
const tree = MountedSilence(alertmanager);
|
||||
|
||||
// expand silence
|
||||
tree.find("a.float-right.cursor-pointer").simulate("click");
|
||||
|
||||
const button = tree.find(".badge-secondary.components-label-with-hover");
|
||||
expect(button.text()).toBe("Edit");
|
||||
button.simulate("click");
|
||||
expect(fillSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("clicking on silence edit button opens the silence form", () => {
|
||||
const tree = MountedSilence(alertmanager);
|
||||
|
||||
// expand silence
|
||||
tree.find("a.float-right.cursor-pointer").simulate("click");
|
||||
|
||||
const button = tree.find(".badge-secondary.components-label-with-hover");
|
||||
expect(button.text()).toBe("Edit");
|
||||
button.simulate("click");
|
||||
expect(silenceFormStore.toggle.visible).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("<SilenceDetails />", () => {
|
||||
it("unexpired silence endsAt label uses 'secondary' class", () => {
|
||||
const tree = ShallowSilenceDetails();
|
||||
it("unexpired silence endsAt label doesn't use 'danger' class", () => {
|
||||
const tree = MountedSilenceDetails(jest.fn());
|
||||
const endsAt = tree.find("span.badge").at(1);
|
||||
expect(endsAt.html()).toMatch(/badge-secondary/);
|
||||
expect(endsAt.html()).not.toMatch(/text-danger/);
|
||||
});
|
||||
|
||||
it("expired silence endsAt label uses 'danger' class", () => {
|
||||
advanceTo(new Date(2000, 0, 1, 23, 0, 0));
|
||||
const tree = ShallowSilenceDetails();
|
||||
const endsAt = tree.find("span.badge").at(1);
|
||||
expect(endsAt.html()).toMatch(/badge-danger/);
|
||||
const tree = MountedSilenceDetails(jest.fn());
|
||||
const endsAt = tree.find("span.badge").at(2);
|
||||
expect(endsAt.html()).toMatch(/text-danger/);
|
||||
});
|
||||
|
||||
it("id links to Alertmanager silence view via alertmanager.uri", () => {
|
||||
const tree = ShallowSilenceDetails();
|
||||
const tree = MountedSilenceDetails(jest.fn());
|
||||
const link = tree.find("a");
|
||||
expect(link.props().href).toBe(
|
||||
"file:///mock/#/silences/4cf5fd82-1edd-4169-99d1-ff8415e72179"
|
||||
|
||||
@@ -163,6 +163,58 @@ exports[`<CustomMultiSelect /> matches snapshot with defaults 1`] = `
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<CustomMultiSelect /> matches snapshot with isDisabled=true 1`] = `
|
||||
"
|
||||
<div class=\\"css-1sontr1\\">
|
||||
<div class=\\"css-rw4imq\\">
|
||||
<div class=\\"css-10fdip\\">
|
||||
<div class=\\"css-142w6gm\\">
|
||||
foo
|
||||
</div>
|
||||
<div class=\\"css-rsyb7x\\">
|
||||
<div class
|
||||
style=\\"display:inline-block\\"
|
||||
>
|
||||
<input type=\\"text\\"
|
||||
disabled
|
||||
autocapitalize=\\"none\\"
|
||||
autocomplete=\\"off\\"
|
||||
autocorrect=\\"off\\"
|
||||
id=\\"react-select-7-input\\"
|
||||
spellcheck=\\"false\\"
|
||||
tabindex=\\"0\\"
|
||||
value
|
||||
aria-autocomplete=\\"list\\"
|
||||
style=\\"box-sizing:content-box;width:1px;background:0;border:0;font-size:inherit;opacity:1;outline:0;padding:0;color:inherit\\"
|
||||
>
|
||||
<div style=\\"position:absolute;top:0;left:0;visibility:hidden;height:0;overflow:scroll;white-space:pre\\">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class=\\"css-191n9vh\\">
|
||||
<span class=\\"css-ln5n5c\\">
|
||||
</span>
|
||||
<div aria-hidden=\\"true\\"
|
||||
class=\\"css-1ep9fjw\\"
|
||||
>
|
||||
<svg height=\\"20\\"
|
||||
width=\\"20\\"
|
||||
viewbox=\\"0 0 20 20\\"
|
||||
aria-hidden=\\"true\\"
|
||||
focusable=\\"false\\"
|
||||
class=\\"css-19bqh2r\\"
|
||||
>
|
||||
<path d=\\"M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z\\">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`<CustomMultiSelect /> matches snapshot with isMulti=true 1`] = `
|
||||
"
|
||||
<div class=\\"css-10nd86i\\">
|
||||
|
||||
@@ -27,7 +27,7 @@ const ReactSelectStyles = {
|
||||
? {
|
||||
...base,
|
||||
borderRadius: "0.25rem",
|
||||
backgroundColor: "#fff",
|
||||
backgroundColor: state.isDisabled ? "#ecf0f1" : "#fff",
|
||||
paddingLeft: "4px",
|
||||
paddingRight: "4px",
|
||||
display: "flex",
|
||||
@@ -39,7 +39,7 @@ const ReactSelectStyles = {
|
||||
: {
|
||||
...base,
|
||||
borderRadius: "0.25rem",
|
||||
backgroundColor: "#fff"
|
||||
backgroundColor: state.isDisabled ? "#ecf0f1" : "#fff"
|
||||
},
|
||||
multiValue: (base, state) => ({
|
||||
...base,
|
||||
@@ -72,7 +72,7 @@ const ReactSelectStyles = {
|
||||
}),
|
||||
indicatorsContainer: (base, state) => ({
|
||||
...base,
|
||||
backgroundColor: "#fff",
|
||||
backgroundColor: state.isDisabled ? "#ecf0f1" : "#fff",
|
||||
borderTopRightRadius: "0.25rem",
|
||||
borderBottomRightRadius: "0.25rem"
|
||||
}),
|
||||
|
||||
@@ -62,4 +62,15 @@ describe("<CustomMultiSelect />", () => {
|
||||
);
|
||||
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("matches snapshot with isDisabled=true", () => {
|
||||
const tree = shallow(
|
||||
<CustomMultiSelect
|
||||
isDisabled
|
||||
defaultValue={Option("foo")}
|
||||
options={[Option("foo"), Option("bar")]}
|
||||
/>
|
||||
);
|
||||
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -70,6 +70,11 @@ const AlertManagerInput = observer(
|
||||
render() {
|
||||
const { alertStore, silenceFormStore } = this.props;
|
||||
|
||||
const extraProps = {};
|
||||
if (silenceFormStore.data.silenceID !== null) {
|
||||
extraProps.isDisabled = true;
|
||||
}
|
||||
|
||||
return (
|
||||
<ReactSelect
|
||||
styles={ReactSelectStyles}
|
||||
@@ -87,6 +92,7 @@ const AlertManagerInput = observer(
|
||||
}
|
||||
isMulti
|
||||
onChange={this.onChange}
|
||||
{...extraProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -148,4 +148,18 @@ describe("<AlertManagerInput />", () => {
|
||||
value: "http://am1.example.com/new"
|
||||
});
|
||||
});
|
||||
|
||||
it("is enabled when silenceFormStore.data.silenceID is null", () => {
|
||||
silenceFormStore.data.silenceID = null;
|
||||
const tree = MountedAlertManagerInput();
|
||||
const select = tree.find("StateManager");
|
||||
expect(select.props().isDisabled).toBeFalsy();
|
||||
});
|
||||
|
||||
it("is disabled when silenceFormStore.data.silenceID is not null", () => {
|
||||
silenceFormStore.data.silenceID = "1234";
|
||||
const tree = MountedAlertManagerInput();
|
||||
const select = tree.find("StateManager");
|
||||
expect(select.props().isDisabled).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faPlus } from "@fortawesome/free-solid-svg-icons/faPlus";
|
||||
import { faUser } from "@fortawesome/free-solid-svg-icons/faUser";
|
||||
import { faCommentDots } from "@fortawesome/free-solid-svg-icons/faCommentDots";
|
||||
import { faUndoAlt } from "@fortawesome/free-solid-svg-icons/faUndoAlt";
|
||||
import { faSave } from "@fortawesome/free-regular-svg-icons/faSave";
|
||||
import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp";
|
||||
import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
|
||||
@@ -78,8 +79,12 @@ const SilenceForm = observer(
|
||||
componentDidMount() {
|
||||
const { silenceFormStore, settingsStore } = this.props;
|
||||
|
||||
// reset startsAt & endsAt on every mount
|
||||
silenceFormStore.data.resetStartEnd();
|
||||
// reset startsAt & endsAt on every mount, unless we're editing a silence
|
||||
if (silenceFormStore.data.silenceID === null) {
|
||||
silenceFormStore.data.resetStartEnd();
|
||||
} else {
|
||||
silenceFormStore.data.verifyStarEnd();
|
||||
}
|
||||
|
||||
if (silenceFormStore.data.matchers.length === 0) {
|
||||
silenceFormStore.data.addEmptyMatcher();
|
||||
@@ -177,10 +182,22 @@ const SilenceForm = observer(
|
||||
icon={this.previewCollapse.hidden ? faChevronUp : faChevronDown}
|
||||
/>
|
||||
</a>
|
||||
<button type="submit" className="btn btn-outline-primary">
|
||||
<FontAwesomeIcon icon={faSave} className="mr-1" />
|
||||
Submit
|
||||
</button>
|
||||
<span>
|
||||
{silenceFormStore.data.silenceID === null ? null : (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-danger mr-2"
|
||||
onClick={silenceFormStore.data.resetSilenceID}
|
||||
>
|
||||
<FontAwesomeIcon icon={faUndoAlt} className="mr-1" />
|
||||
Reset
|
||||
</button>
|
||||
)}
|
||||
<button type="submit" className="btn btn-outline-primary">
|
||||
<FontAwesomeIcon icon={faSave} className="mr-1" />
|
||||
Submit
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
{this.previewCollapse.hidden ? null : (
|
||||
<SilencePreview silenceFormStore={silenceFormStore} />
|
||||
|
||||
@@ -182,3 +182,44 @@ describe("<SilenceForm />", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("<SilenceForm /> in edit mode", () => {
|
||||
it("opening form with silenceID set disables AlertManagerInput", () => {
|
||||
silenceFormStore.data.silenceID = "12345";
|
||||
const tree = MountedSilenceForm();
|
||||
const select = tree.find("StateManager").at(0);
|
||||
expect(select.props().isDisabled).toBe(true);
|
||||
});
|
||||
|
||||
it("opening form with silenceID shows reset button", () => {
|
||||
silenceFormStore.data.silenceID = "12345";
|
||||
const tree = MountedSilenceForm();
|
||||
const button = tree.find("button.btn-outline-danger");
|
||||
expect(button).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("clicking on Reset button unsets silenceFormStore.data.silenceID", () => {
|
||||
silenceFormStore.data.silenceID = "12345";
|
||||
const tree = MountedSilenceForm();
|
||||
const button = tree.find("button.btn-outline-danger");
|
||||
button.simulate("click");
|
||||
expect(silenceFormStore.data.silenceID).toBeNull();
|
||||
});
|
||||
|
||||
it("clicking on Reset button hides it", () => {
|
||||
silenceFormStore.data.silenceID = "12345";
|
||||
const tree = MountedSilenceForm();
|
||||
const button = tree.find("button.btn-outline-danger");
|
||||
button.simulate("click");
|
||||
expect(tree.find("button.btn-outline-danger")).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("clicking on Reset button enables AlertManagerInput", () => {
|
||||
silenceFormStore.data.silenceID = "12345";
|
||||
const tree = MountedSilenceForm();
|
||||
const button = tree.find("button.btn-outline-danger");
|
||||
button.simulate("click");
|
||||
const select = tree.find("StateManager").at(0);
|
||||
expect(select.props().isDisabled).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -42,7 +42,11 @@ const SilenceModalContent = observer(
|
||||
<div className="modal-dialog modal-lg" role="document">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<h5 className="modal-title">Add new silence</h5>
|
||||
<h5 className="modal-title">
|
||||
{silenceFormStore.data.silenceID === null
|
||||
? "Add new silence"
|
||||
: `Editing silence ${silenceFormStore.data.silenceID}`}
|
||||
</h5>
|
||||
<button type="button" className="close" onClick={onHide}>
|
||||
<span className="align-middle">×</span>
|
||||
</button>
|
||||
|
||||
@@ -44,4 +44,18 @@ describe("<SilenceModalContent />", () => {
|
||||
const ctrl = tree.find("SilenceSubmitController");
|
||||
expect(ctrl).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("title is 'Add new silence' when silenceFormStore.data.silenceID is null", () => {
|
||||
silenceFormStore.data.silenceID = null;
|
||||
const tree = ShallowSilenceModalContent();
|
||||
const title = tree.find(".modal-title");
|
||||
expect(title.text()).toBe("Add new silence");
|
||||
});
|
||||
|
||||
it("title is 'Editing silence 12345' when silenceFormStore.data.silenceID is '12345'", () => {
|
||||
silenceFormStore.data.silenceID = "12345";
|
||||
const tree = ShallowSilenceModalContent();
|
||||
const title = tree.find(".modal-title");
|
||||
expect(title.text()).toBe("Editing silence 12345");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,6 +45,7 @@ class SilenceFormStore {
|
||||
{
|
||||
inProgress: false,
|
||||
wasValidated: false,
|
||||
silenceID: null,
|
||||
alertmanagers: [],
|
||||
matchers: [],
|
||||
startsAt: moment(),
|
||||
@@ -79,6 +80,10 @@ class SilenceFormStore {
|
||||
this.wasValidated = false;
|
||||
},
|
||||
|
||||
resetSilenceID() {
|
||||
this.silenceID = null;
|
||||
},
|
||||
|
||||
// append a new empty matcher to the list
|
||||
addEmptyMatcher() {
|
||||
let m = NewEmptyMatcher();
|
||||
@@ -135,6 +140,31 @@ class SilenceFormStore {
|
||||
this.matchers = matchers;
|
||||
},
|
||||
|
||||
fillFormFromSilence(alertmanager, silence) {
|
||||
this.silenceID = silence.id;
|
||||
this.alertmanagers = [
|
||||
{
|
||||
label: alertmanager.name,
|
||||
value: alertmanager.publicURI
|
||||
}
|
||||
];
|
||||
|
||||
const matchers = [];
|
||||
for (const m of silence.matchers) {
|
||||
const matcher = NewEmptyMatcher();
|
||||
matcher.name = m.name;
|
||||
matcher.values = [MatcherValueToObject(m.value)];
|
||||
matcher.isRegex = m.isRegex;
|
||||
matchers.push(matcher);
|
||||
}
|
||||
this.matchers = matchers;
|
||||
|
||||
this.startsAt = moment(silence.startsAt);
|
||||
this.endsAt = moment(silence.endsAt);
|
||||
this.comment = silence.comment;
|
||||
this.author = silence.createdBy;
|
||||
},
|
||||
|
||||
verifyStarEnd() {
|
||||
const now = moment().second(0);
|
||||
if (this.startsAt.isBefore(now)) {
|
||||
@@ -186,8 +216,12 @@ class SilenceFormStore {
|
||||
createdBy: this.author,
|
||||
comment: this.comment
|
||||
};
|
||||
if (this.silenceID !== null) {
|
||||
payload.id = this.silenceID;
|
||||
}
|
||||
return payload;
|
||||
},
|
||||
|
||||
get toDuration() {
|
||||
const data = {
|
||||
days: this.endsAt.diff(this.startsAt, "days"),
|
||||
@@ -200,9 +234,11 @@ class SilenceFormStore {
|
||||
{
|
||||
resetStartEnd: action.bound,
|
||||
resetProgress: action.bound,
|
||||
resetSilenceID: action.bound,
|
||||
addEmptyMatcher: action.bound,
|
||||
deleteMatcher: action.bound,
|
||||
fillMatchersFromGroup: action.bound,
|
||||
fillFormFromSilence: action.bound,
|
||||
verifyStarEnd: action.bound,
|
||||
incStart: action.bound,
|
||||
decStart: action.bound,
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import moment from "moment";
|
||||
|
||||
import { MockAlert, MockAlertGroup } from "__mocks__/Alerts.js";
|
||||
import {
|
||||
MockAlert,
|
||||
MockAlertGroup,
|
||||
MockSilence,
|
||||
MockAlertmanager
|
||||
} from "__mocks__/Alerts.js";
|
||||
import { SilenceFormStore, NewEmptyMatcher } from "./SilenceFormStore";
|
||||
|
||||
let store;
|
||||
@@ -8,6 +13,30 @@ beforeEach(() => {
|
||||
store = new SilenceFormStore();
|
||||
});
|
||||
|
||||
const MockGroup = () => {
|
||||
const alerts = [
|
||||
MockAlert([], { instance: "prod1", cluster: "prod" }),
|
||||
MockAlert([], { instance: "prod2", cluster: "prod" }),
|
||||
MockAlert([], { instance: "dev1", cluster: "dev" })
|
||||
];
|
||||
const group = MockAlertGroup({ alertname: "FakeAlert" }, alerts, [], {
|
||||
job: "mock"
|
||||
});
|
||||
return group;
|
||||
};
|
||||
|
||||
const MockAlertmanagerOption = () => ({
|
||||
label: "default",
|
||||
value: "http://localhost"
|
||||
});
|
||||
|
||||
const MockMatcher = (name, values) => {
|
||||
const matcher = NewEmptyMatcher();
|
||||
matcher.name = name;
|
||||
matcher.values = values;
|
||||
return matcher;
|
||||
};
|
||||
|
||||
describe("SilenceFormStore.toggle", () => {
|
||||
it("toggle() toggles 'visible' correctly", () => {
|
||||
expect(store.toggle.visible).toBe(false);
|
||||
@@ -32,18 +61,6 @@ describe("SilenceFormStore.toggle", () => {
|
||||
});
|
||||
});
|
||||
|
||||
const MockGroup = () => {
|
||||
const alerts = [
|
||||
MockAlert([], { instance: "prod1", cluster: "prod" }),
|
||||
MockAlert([], { instance: "prod2", cluster: "prod" }),
|
||||
MockAlert([], { instance: "dev1", cluster: "dev" })
|
||||
];
|
||||
const group = MockAlertGroup({ alertname: "FakeAlert" }, alerts, [], {
|
||||
job: "mock"
|
||||
});
|
||||
return group;
|
||||
};
|
||||
|
||||
describe("SilenceFormStore.data", () => {
|
||||
it("resetStartEnd() sets startsAt and endsAt to defaults", () => {
|
||||
store.data.startsAt = moment([2000, 1, 1, 0, 1, 0]);
|
||||
@@ -167,6 +184,63 @@ describe("SilenceFormStore.data", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("fillFormFromSilence() sets silenceID", () => {
|
||||
const alertmanager = MockAlertmanager();
|
||||
const silence = MockSilence();
|
||||
store.data.fillFormFromSilence(alertmanager, silence);
|
||||
expect(store.data.silenceID).toBe(silence.id);
|
||||
});
|
||||
|
||||
it("fillFormFromSilence() creates payload that matches silence data", () => {
|
||||
const alertmanager = MockAlertmanager();
|
||||
const silence = MockSilence();
|
||||
store.data.fillFormFromSilence(alertmanager, silence);
|
||||
|
||||
expect(store.data.alertmanagers).toHaveLength(1);
|
||||
expect(store.data.alertmanagers[0]).toMatchObject({
|
||||
label: alertmanager.name,
|
||||
value: alertmanager.publicURI
|
||||
});
|
||||
|
||||
expect(store.data.matchers).toHaveLength(2);
|
||||
expect(store.data.matchers).toContainEqual(
|
||||
expect.objectContaining({
|
||||
name: "foo",
|
||||
values: [{ label: "bar", value: "bar" }],
|
||||
isRegex: false
|
||||
})
|
||||
);
|
||||
expect(store.data.matchers).toContainEqual(
|
||||
expect.objectContaining({
|
||||
name: "baz",
|
||||
values: [{ label: "regex", value: "regex" }],
|
||||
isRegex: true
|
||||
})
|
||||
);
|
||||
|
||||
expect(store.data.startsAt.toISOString()).toBe(
|
||||
moment([2000, 0, 1, 0, 0, 0]).toISOString()
|
||||
);
|
||||
expect(store.data.endsAt.toISOString()).toBe(
|
||||
moment([2000, 0, 1, 1, 0, 0]).toISOString()
|
||||
);
|
||||
|
||||
expect(store.data.author).toBe("me@example.com");
|
||||
expect(store.data.comment).toBe("Mocked Silence");
|
||||
});
|
||||
|
||||
it("toAlertmanagerPayload constains id when store.data.silenceID is set", () => {
|
||||
store.data.silenceID = "12345";
|
||||
expect(store.data.toAlertmanagerPayload).toMatchObject({
|
||||
id: "12345"
|
||||
});
|
||||
});
|
||||
|
||||
it("toAlertmanagerPayload doesn't contain id when store.data.silenceID is null", () => {
|
||||
store.data.silenceID = null;
|
||||
expect(store.data.toAlertmanagerPayload.id).toBeUndefined();
|
||||
});
|
||||
|
||||
it("toAlertmanagerPayload creates payload that matches snapshot", () => {
|
||||
const group = MockGroup();
|
||||
store.data.fillMatchersFromGroup(group);
|
||||
@@ -174,24 +248,12 @@ describe("SilenceFormStore.data", () => {
|
||||
store.data.addEmptyMatcher();
|
||||
store.data.startsAt = moment([2000, 1, 1, 0, 0, 0]);
|
||||
store.data.endsAt = moment([2000, 1, 1, 1, 0, 0]);
|
||||
store.data.createdBy = "me@example.com";
|
||||
store.data.author = "me@example.com";
|
||||
store.data.comment = "toAlertmanagerPayload test";
|
||||
expect(store.data.toAlertmanagerPayload).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
const MockAlertmanager = () => ({
|
||||
label: "default",
|
||||
value: "http://localhost"
|
||||
});
|
||||
|
||||
const MockMatcher = (name, values) => {
|
||||
const matcher = NewEmptyMatcher();
|
||||
matcher.name = name;
|
||||
matcher.values = values;
|
||||
return matcher;
|
||||
};
|
||||
|
||||
describe("SilenceFormStore.data.isValid", () => {
|
||||
it("isValid returns 'false' if alertmanagers list is empty", () => {
|
||||
store.data.matchers = [MockMatcher("foo", ["bar"])];
|
||||
@@ -201,7 +263,7 @@ describe("SilenceFormStore.data.isValid", () => {
|
||||
});
|
||||
|
||||
it("isValid returns 'false' if matchers list is empty", () => {
|
||||
store.data.alertmanagers = [MockAlertmanager];
|
||||
store.data.alertmanagers = [MockAlertmanagerOption];
|
||||
store.data.matchers = [];
|
||||
store.data.author = "me@example.com";
|
||||
store.data.comment = "fake silence";
|
||||
@@ -209,7 +271,7 @@ describe("SilenceFormStore.data.isValid", () => {
|
||||
});
|
||||
|
||||
it("isValid returns 'false' if matchers list is pupulated when a matcher without any name", () => {
|
||||
store.data.alertmanagers = [MockAlertmanager];
|
||||
store.data.alertmanagers = [MockAlertmanagerOption];
|
||||
store.data.matchers = [MockMatcher("", ["bar"])];
|
||||
store.data.author = "me@example.com";
|
||||
store.data.comment = "fake silence";
|
||||
@@ -217,7 +279,7 @@ describe("SilenceFormStore.data.isValid", () => {
|
||||
});
|
||||
|
||||
it("isValid returns 'false' if matchers list is pupulated when a matcher without any value ([])", () => {
|
||||
store.data.alertmanagers = [MockAlertmanager];
|
||||
store.data.alertmanagers = [MockAlertmanagerOption];
|
||||
store.data.matchers = [MockMatcher("foo", [])];
|
||||
store.data.author = "me@example.com";
|
||||
store.data.comment = "fake silence";
|
||||
@@ -225,7 +287,7 @@ describe("SilenceFormStore.data.isValid", () => {
|
||||
});
|
||||
|
||||
it("isValid returns 'false' if matchers list is pupulated when a matcher with empty value ([''])", () => {
|
||||
store.data.alertmanagers = [MockAlertmanager];
|
||||
store.data.alertmanagers = [MockAlertmanagerOption];
|
||||
store.data.matchers = [MockMatcher("foo", [])];
|
||||
store.data.author = "me@example.com";
|
||||
store.data.comment = "fake silence";
|
||||
@@ -233,7 +295,7 @@ describe("SilenceFormStore.data.isValid", () => {
|
||||
});
|
||||
|
||||
it("isValid returns 'false' if author is empty", () => {
|
||||
store.data.alertmanagers = [MockAlertmanager];
|
||||
store.data.alertmanagers = [MockAlertmanagerOption];
|
||||
store.data.matchers = [MockMatcher("foo", ["bar"])];
|
||||
store.data.author = "";
|
||||
store.data.comment = "fake silence";
|
||||
@@ -241,7 +303,7 @@ describe("SilenceFormStore.data.isValid", () => {
|
||||
});
|
||||
|
||||
it("isValid returns 'false' if comment is empty", () => {
|
||||
store.data.alertmanagers = [MockAlertmanager];
|
||||
store.data.alertmanagers = [MockAlertmanagerOption];
|
||||
store.data.matchers = [MockMatcher("foo", ["bar"])];
|
||||
store.data.author = "me@example.com";
|
||||
store.data.comment = "";
|
||||
@@ -249,7 +311,7 @@ describe("SilenceFormStore.data.isValid", () => {
|
||||
});
|
||||
|
||||
it("isValid returns 'true' if all fileds are set", () => {
|
||||
store.data.alertmanagers = [MockAlertmanager];
|
||||
store.data.alertmanagers = [MockAlertmanagerOption];
|
||||
store.data.matchers = [MockMatcher("foo", ["bar"])];
|
||||
store.data.author = "me@example.com";
|
||||
store.data.comment = "fake silence";
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
exports[`SilenceFormStore.data toAlertmanagerPayload creates payload that matches snapshot 1`] = `
|
||||
Object {
|
||||
"comment": "toAlertmanagerPayload test",
|
||||
"createdBy": "",
|
||||
"createdBy": "me@example.com",
|
||||
"endsAt": "2000-02-01T01:00:00.000Z",
|
||||
"matchers": Array [
|
||||
Object {
|
||||
|
||||
@@ -49,4 +49,32 @@ const MockAlertGroup = (
|
||||
}
|
||||
});
|
||||
|
||||
export { MockAnnotation, MockAlert, MockAlertGroup };
|
||||
const MockSilence = () => ({
|
||||
comment: "Mocked Silence",
|
||||
createdAt: "0001-01-01T00:00:00Z",
|
||||
createdBy: "me@example.com",
|
||||
startsAt: "2000-01-01T00:00:00Z",
|
||||
endsAt: "2000-01-01T01:00:00Z",
|
||||
id: "04d37636-2350-4878-b382-e0b50353230f",
|
||||
jiraID: "",
|
||||
jiraURL: "",
|
||||
matchers: [
|
||||
{ name: "foo", value: "bar", isRegex: false },
|
||||
{ name: "baz", value: "regex", isRegex: true }
|
||||
]
|
||||
});
|
||||
|
||||
const MockAlertmanager = () => ({
|
||||
name: "default",
|
||||
uri: "http://localhost",
|
||||
publicURI: "http://am.example.com",
|
||||
error: ""
|
||||
});
|
||||
|
||||
export {
|
||||
MockAnnotation,
|
||||
MockAlert,
|
||||
MockAlertGroup,
|
||||
MockSilence,
|
||||
MockAlertmanager
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user