diff --git a/ui/src/Components/MainModal/Configuration/__snapshots__/AlertGroupCollapseConfiguration.test.js.snap b/ui/src/Components/MainModal/Configuration/__snapshots__/AlertGroupCollapseConfiguration.test.js.snap index d8199fe48..a8524df45 100644 --- a/ui/src/Components/MainModal/Configuration/__snapshots__/AlertGroupCollapseConfiguration.test.js.snap +++ b/ui/src/Components/MainModal/Configuration/__snapshots__/AlertGroupCollapseConfiguration.test.js.snap @@ -4,12 +4,12 @@ exports[` matches snapshot with default value "
-
-
-
+
+
+
Collapse on mobile
-
+
@@ -29,7 +29,7 @@ exports[` matches snapshot with default value
-
+
matches snapshot with default values 1`
-
-
-
+
+
+
Use defaults from karma config file
-
+
@@ -31,7 +31,7 @@ exports[` matches snapshot with default values 1`
-
+
matches snapshot with default values 1`] = `
-
-
-
+
+
+
Disable multi-grid
-
+
@@ -31,7 +31,7 @@ exports[` matches snapshot with default values 1`] = `
-
+
matches snapshot with default values 1`] = ` "
-
-
-
+
+
+
Automatic theme, follow browser preference
-
+
@@ -29,7 +29,7 @@ exports[` matches snapshot with default values 1`] = `
-
+
{ + useEffect(() => { + if (silenceFormStore.data.alertmanagers.length === 0) { + silenceFormStore.data.setAlertmanagers( + AlertmanagerClustersToOption(alertStore.data.clustersWithoutReadOnly) + ); + } + }, []); // eslint-disable-line react-hooks/exhaustive-deps - constructor(props) { - super(props); - - const { alertStore, silenceFormStore } = props; - - if (silenceFormStore.data.alertmanagers.length === 0) { - silenceFormStore.data.alertmanagers = AlertmanagerClustersToOption( + useEffect( + // https://mobx-react.netlify.app/recipes-effects + () => + autorun(() => { + // get the list of last known alertmanagers + const currentAlertmanagers = AlertmanagerClustersToOption( alertStore.data.clustersWithoutReadOnly ); - } - } - onChange = action((newValue, actionMeta) => { - const { silenceFormStore } = this.props; - - silenceFormStore.data.alertmanagers = newValue || []; - }); - - componentDidUpdate() { - const { alertStore, silenceFormStore } = this.props; - - // get the list of last known alertmanagers - const currentAlertmanagers = AlertmanagerClustersToOption( - alertStore.data.clustersWithoutReadOnly - ); - - // now iterate what's set as silence form values and reset it if any - // mismatch is detected - for (const silenceAM of silenceFormStore.data.alertmanagers) { - if ( - !currentAlertmanagers.map((am) => am.label).includes(silenceAM.label) - ) { - silenceFormStore.data.alertmanagers = currentAlertmanagers; - } - } - } - - render() { - const { alertStore, silenceFormStore } = this.props; - - const extraProps = {}; - if (silenceFormStore.data.silenceID !== null) { - extraProps.isDisabled = true; - } - - return ( - + ) : ( + "Alertmanager" + ) + } + isMulti + onChange={(newValue) => { + silenceFormStore.data.setAlertmanagers(newValue || []); + }} + isDisabled={silenceFormStore.data.silenceID !== null} + /> + )); +}; +AlertManagerInput.propTypes = { + alertStore: PropTypes.instanceOf(AlertStore).isRequired, + silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired, +}; export { AlertManagerInput }; diff --git a/ui/src/Components/SilenceModal/AlertManagerInput/index.test.js b/ui/src/Components/SilenceModal/AlertManagerInput/index.test.js index 818f4d82e..fa08a3085 100644 --- a/ui/src/Components/SilenceModal/AlertManagerInput/index.test.js +++ b/ui/src/Components/SilenceModal/AlertManagerInput/index.test.js @@ -4,19 +4,17 @@ import { mount } from "enzyme"; import toDiffableHtml from "diffable-html"; +import { MockThemeContext } from "__mocks__/Theme"; import { AlertStore } from "Stores/AlertStore"; import { SilenceFormStore } from "Stores/SilenceFormStore"; -import { ThemeContext } from "Components/Theme"; -import { - ReactSelectColors, - ReactSelectStyles, -} from "Components/Theme/ReactSelect"; import { AlertManagerInput } from "."; let alertStore; let silenceFormStore; beforeEach(() => { + jest.spyOn(React, "useContext").mockImplementation(() => MockThemeContext); + alertStore = new AlertStore([]); alertStore.data.upstreams.clusters = { ha: ["am1", "am2"], @@ -65,16 +63,10 @@ beforeEach(() => { const MountedAlertManagerInput = () => { return mount( - - - + ); }; @@ -162,12 +154,10 @@ describe("", () => { }); it("silenceFormStore.data.alertmanagers gets updated from alertStore.data.upstreams.instances on mismatch", () => { - const tree = MountedAlertManagerInput(); + MountedAlertManagerInput(); alertStore.data.upstreams.clusters = { amNew: ["amNew"], }; - // force update since this is where the mismatch check lives - tree.instance().componentDidUpdate(); expect(silenceFormStore.data.alertmanagers).toContainEqual({ label: "amNew", value: ["amNew"], diff --git a/ui/src/Components/SilenceModal/SilenceForm.test.js b/ui/src/Components/SilenceModal/SilenceForm.test.js index 98620508e..81a63705f 100644 --- a/ui/src/Components/SilenceModal/SilenceForm.test.js +++ b/ui/src/Components/SilenceModal/SilenceForm.test.js @@ -2,6 +2,7 @@ import React from "react"; import { mount } from "enzyme"; +import { MockThemeContext } from "__mocks__/Theme"; import { AlertStore } from "Stores/AlertStore"; import { Settings } from "Stores/Settings"; import { @@ -9,41 +10,46 @@ import { SilenceFormStage, NewEmptyMatcher, } from "Stores/SilenceFormStore"; -import { ThemeContext } from "Components/Theme"; -import { - ReactSelectColors, - ReactSelectStyles, -} from "Components/Theme/ReactSelect"; import { SilenceForm } from "./SilenceForm"; let alertStore; let settingsStore; let silenceFormStore; -beforeAll(() => { - fetch.mockResponse(JSON.stringify([])); -}); - beforeEach(() => { + jest.spyOn(React, "useContext").mockImplementation(() => MockThemeContext); + alertStore = new AlertStore([]); settingsStore = new Settings(); silenceFormStore = new SilenceFormStore(); + + alertStore.data.upstreams.clusters = { + am1: ["am1"], + }; + alertStore.data.upstreams.instances = [ + { + name: "am1", + uri: "http://am1.example.com", + publicURI: "http://am1.example.com", + readonly: false, + headers: {}, + corsCredentials: "include", + error: "", + version: "0.17.0", + cluster: "am1", + clusterMembers: ["am1"], + }, + ]; }); const MountedSilenceForm = () => { return mount( - - - + ); }; @@ -176,7 +182,7 @@ describe("", () => { matcher.name = "job"; matcher.values = [{ label: "node_exporter", value: "node_exporter" }]; silenceFormStore.data.matchers = [matcher]; - silenceFormStore.data.alertmanagers = [{ label: "am1", value: ["am1"] }]; + silenceFormStore.data.setAlertmanagers([{ label: "am1", value: ["am1"] }]); silenceFormStore.data.author = "me@example.com"; silenceFormStore.data.comment = "fake silence"; const tree = MountedSilenceForm(); diff --git a/ui/src/Components/SilenceModal/SilenceMatch/__snapshots__/LabelNameInput.test.js.snap b/ui/src/Components/SilenceModal/SilenceMatch/__snapshots__/LabelNameInput.test.js.snap index 62653c334..d86a0e164 100644 --- a/ui/src/Components/SilenceModal/SilenceMatch/__snapshots__/LabelNameInput.test.js.snap +++ b/ui/src/Components/SilenceModal/SilenceMatch/__snapshots__/LabelNameInput.test.js.snap @@ -3,12 +3,12 @@ exports[` matches snapshot 1`] = ` "
-
-
-
+
+
+
cluster
-
+
@@ -28,7 +28,7 @@ exports[` matches snapshot 1`] = `
-
+
fetches suggestions on mount 1`] = ` "
-
-
+
+
Label value
-
+
@@ -30,7 +30,7 @@ exports[` fetches suggestions on mount 1`] = `
-
+
fetches suggestions on mount 1`] = ` exports[` matches snapshot 1`] = ` "
-
-
+
+
Label value
-
+
@@ -83,7 +83,7 @@ exports[` matches snapshot 1`] = `
-
+
{ return () => { isCancelled = true; }; - - // eslint doesn't like ...deps - // eslint-disable-next-line - }, [uri, options, ...deps]); + }, [uri, options, ...deps]); // eslint-disable-line react-hooks/exhaustive-deps return { response, error, isDeleting }; }; diff --git a/ui/src/Hooks/useFetchGet.js b/ui/src/Hooks/useFetchGet.js index aaae0b7a8..80bf66c87 100644 --- a/ui/src/Hooks/useFetchGet.js +++ b/ui/src/Hooks/useFetchGet.js @@ -65,10 +65,7 @@ const useFetchGet = (uri, { autorun = true, deps = [] } = {}) => { return () => { isCanceled.current = true; }; - - // eslint doesn't like ...deps - // eslint-disable-next-line - }, [uri, get, autorun, ...deps]); + }, [uri, get, autorun, ...deps]); // eslint-disable-line react-hooks/exhaustive-deps return { response, error, isLoading, isRetrying, retryCount, get }; }; diff --git a/ui/src/Stores/SilenceFormStore.js b/ui/src/Stores/SilenceFormStore.js index 1871c3f60..059c0e00f 100644 --- a/ui/src/Stores/SilenceFormStore.js +++ b/ui/src/Stores/SilenceFormStore.js @@ -213,6 +213,10 @@ class SilenceFormStore { this.silenceID = null; }, + setAlertmanagers(val) { + this.alertmanagers = val; + }, + setStageSubmit() { this.currentStage = SilenceFormStage.Submit; }, @@ -313,6 +317,7 @@ class SilenceFormStore { resetStartEnd: action.bound, resetProgress: action.bound, resetSilenceID: action.bound, + setAlertmanagers: action.bound, setStageSubmit: action.bound, addEmptyMatcher: action.bound, deleteMatcher: action.bound, diff --git a/ui/src/__mocks__/Theme.js b/ui/src/__mocks__/Theme.js index e6c13595a..b14e31708 100644 --- a/ui/src/__mocks__/Theme.js +++ b/ui/src/__mocks__/Theme.js @@ -1,8 +1,15 @@ +import { + ReactSelectStyles, + ReactSelectColors, +} from "Components/Theme/ReactSelect"; + const MockThemeContext = { animations: { in: undefined, duration: 500, }, + isDark: false, + reactSelectStyles: ReactSelectStyles(ReactSelectColors.Light), }; export { MockThemeContext };