diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.js index f90415016..aaff3bad1 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.js @@ -17,13 +17,18 @@ import { faBellSlash } from "@fortawesome/free-solid-svg-icons/faBellSlash"; import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons/faExternalLinkAlt"; import { APIAlert, APIGroup } from "Models/API"; +import { AlertStore } from "Stores/AlertStore"; import { SilenceFormStore } from "Stores/SilenceFormStore"; import { FetchPauser } from "Components/FetchPauser"; import { DropdownSlide } from "Components/Animations/DropdownSlide"; -const onSilenceClick = (silenceFormStore, group, alert) => { +const onSilenceClick = (alertStore, silenceFormStore, group, alert) => { silenceFormStore.data.resetProgress(); - silenceFormStore.data.fillMatchersFromGroup(group, [alert]); + silenceFormStore.data.fillMatchersFromGroup( + group, + alertStore.settings.values.silenceForm.strip.labels, + [alert] + ); silenceFormStore.toggle.show(); }; @@ -35,6 +40,7 @@ const MenuContent = onClickOutside( group, alert, afterClick, + alertStore, silenceFormStore }) => { return ( @@ -62,7 +68,9 @@ const MenuContent = onClickOutside(
onSilenceClick(silenceFormStore, group, alert)} + onClick={() => + onSilenceClick(alertStore, silenceFormStore, group, alert) + } > Silence this alert @@ -86,6 +94,7 @@ const AlertMenu = observer( static propTypes = { group: APIGroup.isRequired, alert: APIAlert.isRequired, + alertStore: PropTypes.instanceOf(AlertStore).isRequired, silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired }; @@ -108,7 +117,7 @@ const AlertMenu = observer( }); render() { - const { group, alert, silenceFormStore } = this.props; + const { group, alert, alertStore, silenceFormStore } = this.props; const uniqueClass = `components-grid-alert-${group.id}-${hash( alert.labels @@ -148,6 +157,7 @@ const AlertMenu = observer( popperStyle={style} group={group} alert={alert} + alertStore={alertStore} silenceFormStore={silenceFormStore} afterClick={this.collapse.hide} handleClickOutside={this.collapse.hide} 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 4aee57a12..f63b215a3 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.test.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.test.js @@ -29,6 +29,7 @@ const MountedAlertMenu = group => { @@ -70,6 +71,7 @@ const MountedMenuContent = group => { group={group} alert={alert} afterClick={MockAfterClick} + alertStore={alertStore} silenceFormStore={silenceFormStore} /> diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/index.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/index.js index 72db47a43..393aef0d2 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/index.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/index.js @@ -7,6 +7,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faVolumeMute } from "@fortawesome/free-solid-svg-icons/faVolumeMute"; import { APIAlert, APIGroup } from "Models/API"; +import { AlertStore } from "Stores/AlertStore"; import { SilenceFormStore } from "Stores/SilenceFormStore"; import { BorderClassMap } from "Common/Colors"; import { StaticLabels } from "Common/Query"; @@ -26,6 +27,7 @@ const Alert = observer( showAlertmanagers: PropTypes.bool.isRequired, showReceiver: PropTypes.bool.isRequired, afterUpdate: PropTypes.func.isRequired, + alertStore: PropTypes.instanceOf(AlertStore).isRequired, silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired }; @@ -36,6 +38,7 @@ const Alert = observer( showAlertmanagers, showReceiver, afterUpdate, + alertStore, silenceFormStore } = this.props; @@ -87,6 +90,7 @@ const Alert = observer( {alert.alertmanager diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/index.test.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/index.test.js index 047ed8aba..0b25cfe59 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/index.test.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/index.test.js @@ -52,6 +52,7 @@ const MountedAlert = (alert, group, showAlertmanagers, showReceiver) => { showAlertmanagers={showAlertmanagers} showReceiver={showReceiver} afterUpdate={MockAfterUpdate} + alertStore={alertStore} silenceFormStore={silenceFormStore} /> diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js index cd27dd9cc..89255fcbf 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js @@ -16,14 +16,18 @@ import { faBellSlash } from "@fortawesome/free-solid-svg-icons/faBellSlash"; import { APIGroup } from "Models/API"; import { FormatAPIFilterQuery } from "Stores/AlertStore"; +import { AlertStore } from "Stores/AlertStore"; import { SilenceFormStore } from "Stores/SilenceFormStore"; import { QueryOperators, StaticLabels, FormatQuery } from "Common/Query"; import { DropdownSlide } from "Components/Animations/DropdownSlide"; import { FetchPauser } from "Components/FetchPauser"; -const onSilenceClick = (silenceFormStore, group) => { +const onSilenceClick = (alertStore, silenceFormStore, group) => { silenceFormStore.data.resetProgress(); - silenceFormStore.data.fillMatchersFromGroup(group); + silenceFormStore.data.fillMatchersFromGroup( + group, + alertStore.settings.values.silenceForm.strip.labels + ); silenceFormStore.toggle.show(); }; @@ -34,6 +38,7 @@ const MenuContent = onClickOutside( popperStyle, group, afterClick, + alertStore, silenceFormStore }) => { let groupFilters = Object.keys(group.labels).map(name => @@ -65,7 +70,7 @@ const MenuContent = onClickOutside(
onSilenceClick(silenceFormStore, group)} + onClick={() => onSilenceClick(alertStore, silenceFormStore, group)} > Silence this group
@@ -86,6 +91,7 @@ const GroupMenu = observer( class GroupMenu extends Component { static propTypes = { group: APIGroup.isRequired, + alertStore: PropTypes.instanceOf(AlertStore).isRequired, silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired, themed: PropTypes.bool.isRequired }; @@ -109,7 +115,7 @@ const GroupMenu = observer( }); render() { - const { group, silenceFormStore, themed } = this.props; + const { group, alertStore, silenceFormStore, themed } = this.props; return ( @@ -143,6 +149,7 @@ const GroupMenu = observer( popperRef={ref} popperStyle={style} group={group} + alertStore={alertStore} silenceFormStore={silenceFormStore} afterClick={this.collapse.hide} handleClickOutside={this.collapse.hide} 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 216ebaca4..ec6288ec7 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.test.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.test.js @@ -26,6 +26,7 @@ const MountedGroupMenu = (group, themed) => { @@ -71,6 +72,7 @@ const MountedMenuContent = group => { popperStyle={{}} group={group} afterClick={MockAfterClick} + alertStore={alertStore} silenceFormStore={silenceFormStore} /> diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/index.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/index.js index 61c33bfc8..b82535b76 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/index.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/index.js @@ -8,6 +8,7 @@ import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp"; import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown"; import { APIGroup } from "Models/API"; +import { AlertStore } from "Stores/AlertStore"; import { SilenceFormStore } from "Stores/SilenceFormStore"; import { FilteringLabel } from "Components/Labels/FilteringLabel"; import { FilteringCounterBadge } from "Components/Labels/FilteringCounterBadge"; @@ -22,6 +23,7 @@ const GroupHeader = observer( toggle: PropTypes.func.isRequired }).isRequired, group: APIGroup.isRequired, + alertStore: PropTypes.instanceOf(AlertStore).isRequired, silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired, themedCounters: PropTypes.bool.isRequired }; @@ -30,6 +32,7 @@ const GroupHeader = observer( const { collapseStore, group, + alertStore, silenceFormStore, themedCounters } = this.props; @@ -43,6 +46,7 @@ const GroupHeader = observer( diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js index 581ad2621..f7f425d7b 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js @@ -12,6 +12,7 @@ import { faMinus } from "@fortawesome/free-solid-svg-icons/faMinus"; import { APIGroup } from "Models/API"; import { Settings } from "Stores/Settings"; +import { AlertStore } from "Stores/AlertStore"; import { SilenceFormStore } from "Stores/SilenceFormStore"; import { IsMobile } from "Common/Device"; import { BackgroundClassMap } from "Common/Colors"; @@ -55,6 +56,7 @@ const AlertGroup = observer( afterUpdate: PropTypes.func.isRequired, group: APIGroup.isRequired, showAlertmanagers: PropTypes.bool.isRequired, + alertStore: PropTypes.instanceOf(AlertStore).isRequired, settingsStore: PropTypes.instanceOf(Settings).isRequired, silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired, style: PropTypes.object @@ -157,6 +159,7 @@ const AlertGroup = observer( showAlertmanagers, afterUpdate, silenceFormStore, + alertStore, settingsStore, style } = this.props; @@ -198,6 +201,7 @@ const AlertGroup = observer( @@ -216,6 +220,7 @@ const AlertGroup = observer( } showReceiver={group.alerts.length === 1} afterUpdate={afterUpdate} + alertStore={alertStore} silenceFormStore={silenceFormStore} /> ))} diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.test.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.test.js index 16ea8fb2c..0581a56c0 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.test.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.test.js @@ -64,6 +64,7 @@ const MountedAlertGroup = (afterUpdate, showAlertmanagers) => { group={group} showAlertmanagers={showAlertmanagers} settingsStore={settingsStore} + alertStore={alertStore} silenceFormStore={silenceFormStore} /> diff --git a/ui/src/Components/Grid/AlertGrid/index.js b/ui/src/Components/Grid/AlertGrid/index.js index ea15856fa..8cb15912d 100644 --- a/ui/src/Components/Grid/AlertGrid/index.js +++ b/ui/src/Components/Grid/AlertGrid/index.js @@ -240,6 +240,7 @@ const AlertGrid = observer( Object.keys(alertStore.data.upstreams.clusters).length > 1 } afterUpdate={this.masonryRepack} + alertStore={alertStore} settingsStore={settingsStore} silenceFormStore={silenceFormStore} style={{ diff --git a/ui/src/Stores/AlertStore.js b/ui/src/Stores/AlertStore.js index dfd75948b..015ed16e6 100644 --- a/ui/src/Stores/AlertStore.js +++ b/ui/src/Stores/AlertStore.js @@ -177,6 +177,11 @@ class AlertStore { label: "alertname" }, valueMapping: {} + }, + silenceForm: { + strip: { + labels: [] + } } } }, diff --git a/ui/src/Stores/SilenceFormStore.js b/ui/src/Stores/SilenceFormStore.js index 5bb676945..3f41736dd 100644 --- a/ui/src/Stores/SilenceFormStore.js +++ b/ui/src/Stores/SilenceFormStore.js @@ -114,17 +114,19 @@ class SilenceFormStore { }, // if alerts argument is not passed all group alerts will be used - fillMatchersFromGroup(group, alerts) { + fillMatchersFromGroup(group, stripLabels, alerts) { let matchers = []; // add matchers for all shared labels in this group for (const [key, value] of Object.entries( Object.assign({}, group.labels, group.shared.labels) )) { - const matcher = NewEmptyMatcher(); - matcher.name = key; - matcher.values = [MatcherValueToObject(value)]; - matchers.push(matcher); + if (!stripLabels.includes(key)) { + const matcher = NewEmptyMatcher(); + matcher.name = key; + matcher.values = [MatcherValueToObject(value)]; + matchers.push(matcher); + } } // add matchers for all unique labels in this group @@ -132,10 +134,12 @@ class SilenceFormStore { const allAlerts = alerts ? alerts : group.alerts; for (const alert of allAlerts) { for (const [key, value] of Object.entries(alert.labels)) { - if (!labels[key]) { - labels[key] = new Set(); + if (!stripLabels.includes(key)) { + if (!labels[key]) { + labels[key] = new Set(); + } + labels[key].add(value); } - labels[key].add(value); } } for (const [key, values] of Object.entries(labels)) { diff --git a/ui/src/Stores/SilenceFormStore.test.js b/ui/src/Stores/SilenceFormStore.test.js index 4f0e97b5e..f25ec17e2 100644 --- a/ui/src/Stores/SilenceFormStore.test.js +++ b/ui/src/Stores/SilenceFormStore.test.js @@ -120,7 +120,7 @@ describe("SilenceFormStore.data", () => { it("fillMatchersFromGroup() creates correct matcher object for a group", () => { const group = MockGroup(); - store.data.fillMatchersFromGroup(group); + store.data.fillMatchersFromGroup(group, []); expect(store.data.matchers).toHaveLength(4); expect(store.data.matchers).toContainEqual( expect.objectContaining({ @@ -161,7 +161,7 @@ describe("SilenceFormStore.data", () => { it("fillMatchersFromGroup() creates correct matcher object for a group with only a subset of alets passed", () => { const group = MockGroup(); - store.data.fillMatchersFromGroup(group, [group.alerts[0]]); + store.data.fillMatchersFromGroup(group, [], [group.alerts[0]]); expect(store.data.matchers).toHaveLength(4); expect(store.data.matchers).toContainEqual( expect.objectContaining({ @@ -193,10 +193,27 @@ describe("SilenceFormStore.data", () => { ); }); + it("fillMatchersFromGroup() ignores labels from stripLabels list", () => { + const group = MockGroup(); + store.data.fillMatchersFromGroup( + group, + ["job", "instance", "cluster"], + [group.alerts[0]] + ); + expect(store.data.matchers).toHaveLength(1); + expect(store.data.matchers).toContainEqual( + expect.objectContaining({ + name: "alertname", + values: [{ label: "FakeAlert", value: "FakeAlert" }], + isRegex: false + }) + ); + }); + it("fillMatchersFromGroup() resets silenceID if set", () => { store.data.silenceID = "12345"; const group = MockGroup(); - store.data.fillMatchersFromGroup(group, [group.alerts[0]]); + store.data.fillMatchersFromGroup(group, [], [group.alerts[0]]); expect(store.data.silenceID).toBeNull(); }); @@ -259,7 +276,7 @@ describe("SilenceFormStore.data", () => { it("toAlertmanagerPayload creates payload that matches snapshot", () => { const group = MockGroup(); - store.data.fillMatchersFromGroup(group); + store.data.fillMatchersFromGroup(group, []); // add empty matcher so we test empty string rendering store.data.addEmptyMatcher(); store.data.startsAt = moment.utc([2000, 1, 1, 0, 0, 0]); diff --git a/ui/src/__mocks__/Fetch.js b/ui/src/__mocks__/Fetch.js index 1c6430373..f074457a9 100644 --- a/ui/src/__mocks__/Fetch.js +++ b/ui/src/__mocks__/Fetch.js @@ -42,6 +42,11 @@ const EmptyAPIResponse = () => ({ } } }, + silenceForm: { + strip: { + labels: [] + } + }, staticColorLabels: ["job"], annotationsDefaultHidden: false, annotationsHidden: [],