diff --git a/ui/src/Components/SilenceModal/SilenceForm.js b/ui/src/Components/SilenceModal/SilenceForm.js index 0882345d1..18592c79d 100644 --- a/ui/src/Components/SilenceModal/SilenceForm.js +++ b/ui/src/Components/SilenceModal/SilenceForm.js @@ -47,11 +47,9 @@ const SilenceForm = ({ // reset cluster request state silenceFormStore.data.requestsByCluster = {}; - if ( - silenceFormStore.data.matchers.filter( - (m) => m.name !== "" || m.values.length - ).length === 0 - ) { + if (silenceFormStore.data.autofillMatchers) { + silenceFormStore.data.matchers = []; + if (alertStore.filters.values.length > 0) { alertStore.filters.values .filter( @@ -73,10 +71,13 @@ const SilenceForm = ({ }); } } + if (silenceFormStore.data.matchers.length === 0) { silenceFormStore.data.addEmptyMatcher(); } + silenceFormStore.data.autofillMatchers = false; + // populate author if (silenceFormStore.data.author === "") { silenceFormStore.data.author = diff --git a/ui/src/Components/SilenceModal/SilenceForm.test.js b/ui/src/Components/SilenceModal/SilenceForm.test.js index f9f89297c..a82473d35 100644 --- a/ui/src/Components/SilenceModal/SilenceForm.test.js +++ b/ui/src/Components/SilenceModal/SilenceForm.test.js @@ -62,7 +62,7 @@ describe(" matchers", () => { expect(silenceFormStore.data.matchers).toHaveLength(1); }); - it("uses filters to populate default matchers", () => { + it("uses filters to populate default matchers when silenceFormStore.data.autofillMatchers=true", () => { const filter = (name, matcher, value) => { const f = NewUnappliedFilter(`${name}${matcher}${value}`); f.name = name; @@ -85,6 +85,7 @@ describe(" matchers", () => { ...filterCombos("cluster"), ...filterCombos("foo"), ]; + silenceFormStore.data.autofillMatchers = true; const tree = MountedSilenceForm(); const matchers = tree.find("SilenceMatch"); expect(matchers).toHaveLength(6); @@ -151,6 +152,40 @@ describe(" matchers", () => { }); }); + it("doesn't use filters to populate default matchers when silenceFormStore.data.autofillMatchers=false", () => { + const filter = (name, matcher, value) => { + const f = NewUnappliedFilter(`${name}${matcher}${value}`); + f.name = name; + f.matcher = matcher; + f.value = value; + return f; + }; + + const filterCombos = (name) => + Object.entries(QueryOperators).map(([k, v]) => + filter(name, v, `${name}${k}`) + ); + + alertStore.filters.values = [ + ...filterCombos(StaticLabels.AlertName), + ...filterCombos(StaticLabels.AlertManager), + ...filterCombos(StaticLabels.Receiver), + ...filterCombos(StaticLabels.State), + ...filterCombos(StaticLabels.SilenceID), + ...filterCombos("cluster"), + ...filterCombos("foo"), + ]; + silenceFormStore.data.autofillMatchers = false; + const tree = MountedSilenceForm(); + const matchers = tree.find("SilenceMatch"); + expect(matchers).toHaveLength(1); + expect(silenceFormStore.data.matchers[0]).toMatchObject({ + isRegex: false, + name: "", + values: [], + }); + }); + it("clicking 'Add more' button adds another matcher", () => { const tree = MountedSilenceForm(); const button = tree.find("button[type='button']"); @@ -170,6 +205,7 @@ describe(" matchers", () => { }); it("trash icon is visible when there are two matchers", () => { + silenceFormStore.data.autofillMatchers = false; silenceFormStore.data.addEmptyMatcher(); silenceFormStore.data.addEmptyMatcher(); const tree = MountedSilenceForm(); @@ -181,6 +217,7 @@ describe(" matchers", () => { }); it("clicking trash icon on a matcher select removes it", () => { + silenceFormStore.data.autofillMatchers = false; silenceFormStore.data.addEmptyMatcher(); silenceFormStore.data.addEmptyMatcher(); silenceFormStore.data.addEmptyMatcher(); @@ -275,6 +312,7 @@ describe("", () => { silenceFormStore.data.setAlertmanagers([{ label: "am1", value: ["am1"] }]); silenceFormStore.data.author = "me@example.com"; silenceFormStore.data.comment = "fake silence"; + silenceFormStore.data.autofillMatchers = false; const tree = MountedSilenceForm(); tree.simulate("submit", { preventDefault: jest.fn() }); expect(silenceFormStore.data.currentStage).toBe(SilenceFormStage.Preview); diff --git a/ui/src/Components/SilenceModal/index.js b/ui/src/Components/SilenceModal/index.js index 5ee68d670..631347097 100644 --- a/ui/src/Components/SilenceModal/index.js +++ b/ui/src/Components/SilenceModal/index.js @@ -21,6 +21,7 @@ const SilenceModalContent = React.lazy(() => ); const SilenceModal = ({ alertStore, silenceFormStore, settingsStore }) => { + // uses React.useCallback instead of useCallback for tests const onDeleteModalClose = React.useCallback(() => { const event = new CustomEvent("remountModal"); window.dispatchEvent(event); @@ -46,7 +47,10 @@ const SilenceModal = ({ alertStore, silenceFormStore, settingsStore }) => { { + silenceFormStore.data.resetProgress(); + silenceFormStore.data.autofillMatchers = true; + }} > ", () => { // mark form as dirty, resetProgress() should change this value to false silenceFormStore.data.wasValidated = true; + // disable autofill, closing modal should re-enable it + silenceFormStore.data.autofillMatchers = false; // click to hide toggle.simulate("click"); @@ -123,6 +125,7 @@ describe("", () => { // form should be reset expect(silenceFormStore.data.currentStage).toBe(SilenceFormStage.UserInput); expect(silenceFormStore.data.wasValidated).toBe(false); + expect(silenceFormStore.data.autofillMatchers).toBe(true); }); it("'modal-open' class is appended to body node when modal is visible", () => { diff --git a/ui/src/Stores/SilenceFormStore.js b/ui/src/Stores/SilenceFormStore.js index e89108314..9e5af8d6f 100644 --- a/ui/src/Stores/SilenceFormStore.js +++ b/ui/src/Stores/SilenceFormStore.js @@ -198,6 +198,7 @@ class SilenceFormStore { comment: "", author: "", requestsByCluster: {}, + autofillMatchers: true, get isValid() { if (this.alertmanagers.length === 0) return false; @@ -257,6 +258,8 @@ class SilenceFormStore { // 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; }, fillFormFromSilence(alertmanager, silence) { @@ -292,6 +295,9 @@ class SilenceFormStore { this.endsAt = parseISO(silence.endsAt); this.comment = silence.comment; this.author = silence.createdBy; + + // disable matcher autofill + this.autofillMatchers = false; }, verifyStarEnd() {