diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.js
index 6e9725fa9..72c052a98 100644
--- a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.js
+++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.js
@@ -12,17 +12,31 @@ import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons/faExternalL
import { APIAlert, APIGroup } from "Models/API";
import { AlertStore } from "Stores/AlertStore";
-import { SilenceFormStore, SilenceTabNames } from "Stores/SilenceFormStore";
+import {
+ SilenceFormStore,
+ SilenceTabNames,
+ AlertmanagerClustersToOption,
+} from "Stores/SilenceFormStore";
import { FetchPauser } from "Components/FetchPauser";
import { DropdownSlide } from "Components/Animations/DropdownSlide";
import { DateFromNow } from "Components/DateFromNow";
import { useOnClickOutside } from "Hooks/useOnClickOutside";
const onSilenceClick = (alertStore, silenceFormStore, group, alert) => {
+ let clusters = {};
+ Object.entries(alertStore.data.clustersWithoutReadOnly).forEach(
+ ([cluster, members]) => {
+ if (alert.alertmanager.map((am) => am.cluster).includes(cluster)) {
+ clusters[cluster] = members;
+ }
+ }
+ );
+
silenceFormStore.data.resetProgress();
silenceFormStore.data.fillMatchersFromGroup(
group,
alertStore.settings.values.silenceForm.strip.labels,
+ AlertmanagerClustersToOption(clusters),
[alert]
);
silenceFormStore.tab.setTab(SilenceTabNames.Editor);
diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.test.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.test.js
index 389b962ab..cb352762c 100644
--- a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.test.js
+++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.test.js
@@ -31,7 +31,7 @@ beforeEach(() => {
group = MockAlertGroup({ alertname: "Fake Alert" }, [alert], [], {}, {});
alertStore.data.upstreams = {
- clusters: { default: ["am1"] },
+ clusters: { default: ["am1"], ro: ["ro"], am2: ["am2"] },
instances: [
{
name: "am1",
@@ -45,6 +45,30 @@ beforeEach(() => {
cluster: "default",
clusterMembers: ["am1"],
},
+ {
+ name: "ro",
+ uri: "http://localhost:8080",
+ publicURI: "http://example.com",
+ readonly: true,
+ headers: {},
+ corsCredentials: "include",
+ error: "",
+ version: "0.17.0",
+ cluster: "ro",
+ clusterMembers: ["ro"],
+ },
+ {
+ name: "am2",
+ uri: "http://localhost:8080",
+ publicURI: "http://example.com",
+ readonly: false,
+ headers: {},
+ corsCredentials: "include",
+ error: "",
+ version: "0.17.0",
+ cluster: "am2",
+ clusterMembers: ["am2"],
+ },
],
};
});
@@ -131,14 +155,19 @@ const MountedMenuContent = (group) => {
describe("", () => {
it("clicking on 'Silence' icon opens the silence form modal", () => {
+ group.alertmanagerCount = { am1: 1, ro: 1 };
const tree = MountedMenuContent(group);
const button = tree.find(".dropdown-item").at(1);
button.simulate("click");
expect(silenceFormStore.toggle.visible).toBe(true);
+ expect(silenceFormStore.data.alertmanagers).toMatchObject([
+ { label: "am1", value: ["am1"] },
+ ]);
});
it("'Silence' menu entry is disabled when all Alertmanager instances are read-only", () => {
alertStore.data.upstreams.instances[0].readonly = true;
+ alertStore.data.upstreams.instances[2].readonly = true;
const tree = MountedMenuContent(group);
const button = tree.find(".dropdown-item").at(1);
expect(button.hasClass("disabled")).toBe(true);
diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js
index 8808d6fd6..bd31a3d18 100644
--- a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js
+++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js
@@ -13,17 +13,33 @@ import { faBellSlash } from "@fortawesome/free-solid-svg-icons/faBellSlash";
import { APIGroup } from "Models/API";
import { FormatAlertsQ } from "Stores/AlertStore";
import { AlertStore } from "Stores/AlertStore";
-import { SilenceFormStore, SilenceTabNames } from "Stores/SilenceFormStore";
+import {
+ SilenceFormStore,
+ SilenceTabNames,
+ AlertmanagerClustersToOption,
+} from "Stores/SilenceFormStore";
import { QueryOperators, StaticLabels, FormatQuery } from "Common/Query";
import { DropdownSlide } from "Components/Animations/DropdownSlide";
import { FetchPauser } from "Components/FetchPauser";
import { useOnClickOutside } from "Hooks/useOnClickOutside";
const onSilenceClick = (alertStore, silenceFormStore, group) => {
+ let clusters = {};
+ Object.entries(alertStore.data.clustersWithoutReadOnly).forEach(
+ ([cluster, members]) => {
+ members.forEach((member) => {
+ if (Object.keys(group.alertmanagerCount).includes(member)) {
+ clusters[cluster] = members;
+ }
+ });
+ }
+ );
+
silenceFormStore.data.resetProgress();
silenceFormStore.data.fillMatchersFromGroup(
group,
- alertStore.settings.values.silenceForm.strip.labels
+ alertStore.settings.values.silenceForm.strip.labels,
+ AlertmanagerClustersToOption(clusters)
);
silenceFormStore.tab.setTab(SilenceTabNames.Editor);
silenceFormStore.toggle.show();
diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.test.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.test.js
index 6c6635b27..07ffa9b90 100644
--- a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.test.js
+++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.test.js
@@ -29,7 +29,7 @@ beforeEach(() => {
MockSetIsMenuOpen = jest.fn();
alertStore.data.upstreams = {
- clusters: { default: ["am1"] },
+ clusters: { default: ["am1"], ro: ["ro"], am2: ["am2"] },
instances: [
{
name: "am1",
@@ -43,6 +43,30 @@ beforeEach(() => {
cluster: "default",
clusterMembers: ["am1"],
},
+ {
+ name: "ro",
+ uri: "http://localhost:8080",
+ publicURI: "http://example.com",
+ readonly: true,
+ headers: {},
+ corsCredentials: "include",
+ error: "",
+ version: "0.17.0",
+ cluster: "ro",
+ clusterMembers: ["ro"],
+ },
+ {
+ name: "am2",
+ uri: "http://localhost:8080",
+ publicURI: "http://example.com",
+ readonly: false,
+ headers: {},
+ corsCredentials: "include",
+ error: "",
+ version: "0.17.0",
+ cluster: "am2",
+ clusterMembers: ["am2"],
+ },
],
};
});
@@ -141,14 +165,19 @@ describe("", () => {
it("clicking on 'Silence' icon opens the silence form modal", () => {
const group = MockAlertGroup({ alertname: "Fake Alert" }, [], [], {}, {});
+ group.alertmanagerCount = { am1: 1, ro: 1 };
const tree = MountedMenuContent(group);
const button = tree.find(".dropdown-item").at(1);
button.simulate("click");
expect(silenceFormStore.toggle.visible).toBe(true);
+ expect(silenceFormStore.data.alertmanagers).toMatchObject([
+ { label: "am1", value: ["am1"] },
+ ]);
});
it("'Silence' menu entry is disabled when all Alertmanager instances are read-only", () => {
alertStore.data.upstreams.instances[0].readonly = true;
+ alertStore.data.upstreams.instances[2].readonly = true;
const group = MockAlertGroup({ alertname: "Fake Alert" }, [], [], {}, {});
const tree = MountedMenuContent(group);
diff --git a/ui/src/Stores/SilenceFormStore.js b/ui/src/Stores/SilenceFormStore.js
index edb05ac80..980234ec6 100644
--- a/ui/src/Stores/SilenceFormStore.js
+++ b/ui/src/Stores/SilenceFormStore.js
@@ -316,13 +316,17 @@ class SilenceFormStore {
},
// if alerts argument is not passed all group alerts will be used
- fillMatchersFromGroup(group, stripLabels, alerts) {
+ fillMatchersFromGroup(group, stripLabels, alertmanagers, alerts) {
+ this.alertmanagers = alertmanagers;
+
this.matchers = MatchersFromGroup(group, stripLabels, alerts);
// ensure that silenceID is nulled, since it's used to edit silences
// and this is used to silence groups
this.silenceID = null;
// disable matcher autofill
this.autofillMatchers = false;
+ // disable alertmanager input reset
+ this.resetInputs = false;
},
fillFormFromSilence(alertmanager, silence) {
diff --git a/ui/src/Stores/SilenceFormStore.test.js b/ui/src/Stores/SilenceFormStore.test.js
index f3a431272..e61ef823e 100644
--- a/ui/src/Stores/SilenceFormStore.test.js
+++ b/ui/src/Stores/SilenceFormStore.test.js
@@ -16,6 +16,7 @@ import {
NewEmptyMatcher,
SilenceTabNames,
MatcherValueToObject,
+ AlertmanagerClustersToOption,
} from "./SilenceFormStore";
let store;
@@ -126,7 +127,14 @@ describe("SilenceFormStore.data", () => {
it("fillMatchersFromGroup() creates correct matcher object for a group", () => {
const group = MockGroup();
- store.data.fillMatchersFromGroup(group, []);
+ store.data.fillMatchersFromGroup(
+ group,
+ [],
+ AlertmanagerClustersToOption({ ha: ["am1", "am2"] })
+ );
+ expect(store.data.alertmanagers).toMatchObject([
+ { label: "Cluster: ha", value: ["am1", "am2"] },
+ ]);
expect(store.data.matchers).toHaveLength(4);
expect(store.data.matchers).toContainEqual(
expect.objectContaining({
@@ -167,7 +175,15 @@ describe("SilenceFormStore.data", () => {
it("fillMatchersFromGroup() creates correct matcher object for a group with only a subset of alerts passed", () => {
const group = MockGroup();
- store.data.fillMatchersFromGroup(group, [], [group.alerts[0]]);
+ store.data.fillMatchersFromGroup(
+ group,
+ [],
+ AlertmanagerClustersToOption({ ha: ["am1", "am2"] }),
+ [group.alerts[0]]
+ );
+ expect(store.data.alertmanagers).toMatchObject([
+ { label: "Cluster: ha", value: ["am1", "am2"] },
+ ]);
expect(store.data.matchers).toHaveLength(4);
expect(store.data.matchers).toContainEqual(
expect.objectContaining({