From 09d1196df0e8e7f12b99e630d4727d15aa0785fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Tue, 1 Jan 2019 21:33:24 +0000 Subject: [PATCH 1/4] fix(ui): user alertmanager label as argument for @alertmanager filter --- .../SilenceModal/SilencePreview/index.test.js | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ui/src/Components/SilenceModal/SilencePreview/index.test.js b/ui/src/Components/SilenceModal/SilencePreview/index.test.js index 9288082bc..5b4d278c6 100644 --- a/ui/src/Components/SilenceModal/SilencePreview/index.test.js +++ b/ui/src/Components/SilenceModal/SilencePreview/index.test.js @@ -75,6 +75,34 @@ describe("", () => { expect(fetch).toHaveBeenCalled(); }); + it("fetch uses correct filters with single Alertmanager instance", async () => { + fetch.mockResponse(JSON.stringify(MockAPIResponse())); + silenceFormStore.data.alertmanagers = [ + { label: "amName", value: ["amValue"] } + ]; + + const tree = MountedSilencePreview(); + await expect(tree.instance().matchedAlerts.fetch).resolves.toBeUndefined(); + expect(fetch).toHaveBeenCalledWith( + "./alerts.json?q=foo%3Dbar&q=%40alertmanager%3D~%5E%28amValue%29%24", + { credentials: "include" } + ); + }); + + it("fetch uses correct filters with multiple Alertmanager instances", async () => { + fetch.mockResponse(JSON.stringify(MockAPIResponse())); + silenceFormStore.data.alertmanagers = [ + { label: "cluster", value: ["am1", "am2"] } + ]; + + const tree = MountedSilencePreview(); + await expect(tree.instance().matchedAlerts.fetch).resolves.toBeUndefined(); + expect(fetch).toHaveBeenCalledWith( + "./alerts.json?q=foo%3Dbar&q=%40alertmanager%3D~%5E%28am1%7Cam2%29%24", + { credentials: "include" } + ); + }); + it("matches snapshot", async () => { fetch.mockResponse(JSON.stringify(MockAPIResponse())); From 62db6859eafb53f5bc99c54fde01f8de4b968a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Tue, 1 Jan 2019 21:54:17 +0000 Subject: [PATCH 2/4] fix(ui): use new style alertmanager input values --- .../SilenceModal/AlertManagerInput/index.js | 11 ++++----- ui/src/Stores/SilenceFormStore.js | 23 +++++++++++-------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/ui/src/Components/SilenceModal/AlertManagerInput/index.js b/ui/src/Components/SilenceModal/AlertManagerInput/index.js index 08adab106..a567b7359 100644 --- a/ui/src/Components/SilenceModal/AlertManagerInput/index.js +++ b/ui/src/Components/SilenceModal/AlertManagerInput/index.js @@ -7,16 +7,13 @@ import { observer } from "mobx-react"; import ReactSelect from "react-select"; import { AlertStore } from "Stores/AlertStore"; -import { SilenceFormStore } from "Stores/SilenceFormStore"; +import { + SilenceFormStore, + AlertmanagerClustersToOption +} from "Stores/SilenceFormStore"; import { MultiSelect, ReactSelectStyles } from "Components/MultiSelect"; import { ValidationError } from "Components/MultiSelect/ValidationError"; -const AlertmanagerClustersToOption = clusterDict => - Object.entries(clusterDict).map(([clusterID, clusterMembers]) => ({ - label: clusterMembers.join(" | "), - value: clusterMembers - })); - const AlertManagerInput = observer( class AlertManagerInput extends MultiSelect { static propTypes = { diff --git a/ui/src/Stores/SilenceFormStore.js b/ui/src/Stores/SilenceFormStore.js index 76ca3a5ed..5bb676945 100644 --- a/ui/src/Stores/SilenceFormStore.js +++ b/ui/src/Stores/SilenceFormStore.js @@ -19,6 +19,12 @@ const NewEmptyMatcher = () => { const MatcherValueToObject = value => ({ label: value, value: value }); +const AlertmanagerClustersToOption = clusterDict => + Object.entries(clusterDict).map(([clusterID, clusterMembers]) => ({ + label: clusterMembers.join(" | "), + value: clusterMembers + })); + const SilenceFormStage = Object.freeze({ UserInput: "form", Preview: "preview", @@ -155,12 +161,10 @@ class SilenceFormStore { fillFormFromSilence(alertmanager, silence) { this.silenceID = silence.id; - this.alertmanagers = [ - { - label: alertmanager.name, - value: alertmanager.publicURI - } - ]; + + this.alertmanagers = AlertmanagerClustersToOption({ + [alertmanager.cluster]: alertmanager.clusterMembers + }); const matchers = []; for (const m of silence.matchers) { @@ -214,8 +218,8 @@ class SilenceFormStore { m.values.length > 1 ? `(${m.values.map(v => v.value).join("|")})` : m.values.length === 1 - ? m.values[0].value - : "", + ? m.values[0].value + : "", isRegex: m.isRegex })), startsAt: this.startsAt @@ -270,5 +274,6 @@ export { SilenceFormStore, SilenceFormStage, NewEmptyMatcher, - MatcherValueToObject + MatcherValueToObject, + AlertmanagerClustersToOption }; From 8c80f744873e85d58808889388b812c9ad38d69a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Tue, 1 Jan 2019 22:17:23 +0000 Subject: [PATCH 3/4] fix(ui): prevent duplicated Alertmanager input options Select value is an array, turn it into a string before checking if it's already selected --- ui/src/Components/SilenceModal/AlertManagerInput/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/src/Components/SilenceModal/AlertManagerInput/index.js b/ui/src/Components/SilenceModal/AlertManagerInput/index.js index a567b7359..4d5a5b581 100644 --- a/ui/src/Components/SilenceModal/AlertManagerInput/index.js +++ b/ui/src/Components/SilenceModal/AlertManagerInput/index.js @@ -74,6 +74,7 @@ const AlertManagerInput = observer( options={AlertmanagerClustersToOption( alertStore.data.upstreams.clusters )} + getOptionValue={JSON.stringify} placeholder={ silenceFormStore.data.wasValidated ? ( From abd14bb079700911f49dd5a755180f4c4e3171a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Mierzwa?= Date: Tue, 1 Jan 2019 22:22:15 +0000 Subject: [PATCH 4/4] fix(test): use correct alertmanager option format in tests --- ui/src/Components/SilenceModal/SilenceForm.test.js | 4 +--- ui/src/Stores/SilenceFormStore.test.js | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/ui/src/Components/SilenceModal/SilenceForm.test.js b/ui/src/Components/SilenceModal/SilenceForm.test.js index 1927b6a50..ca7cbc67c 100644 --- a/ui/src/Components/SilenceModal/SilenceForm.test.js +++ b/ui/src/Components/SilenceModal/SilenceForm.test.js @@ -167,9 +167,7 @@ describe("", () => { matcher.name = "job"; matcher.values = [{ label: "node_exporter", value: "node_exporter" }]; silenceFormStore.data.matchers = [matcher]; - silenceFormStore.data.alertmanagers = [ - { label: "am1", value: "http://example.com" } - ]; + silenceFormStore.data.alertmanagers = [{ label: "am1", value: ["am1"] }]; silenceFormStore.data.author = "me@example.com"; silenceFormStore.data.comment = "fake silence"; const tree = ShallowSilenceForm(); diff --git a/ui/src/Stores/SilenceFormStore.test.js b/ui/src/Stores/SilenceFormStore.test.js index ea1b52e15..44b9195bc 100644 --- a/ui/src/Stores/SilenceFormStore.test.js +++ b/ui/src/Stores/SilenceFormStore.test.js @@ -31,7 +31,7 @@ const MockGroup = () => { const MockAlertmanagerOption = () => ({ label: "default", - value: "http://localhost" + value: ["default"] }); const MockMatcher = (name, values) => { @@ -209,7 +209,7 @@ describe("SilenceFormStore.data", () => { expect(store.data.alertmanagers).toHaveLength(1); expect(store.data.alertmanagers[0]).toMatchObject({ label: alertmanager.name, - value: alertmanager.publicURI + value: [alertmanager.name] }); expect(store.data.matchers).toHaveLength(2);