diff --git a/ui/src/Components/ManagedSilence/index.js b/ui/src/Components/ManagedSilence/index.js index 12fec93c5..1f00a9807 100644 --- a/ui/src/Components/ManagedSilence/index.js +++ b/ui/src/Components/ManagedSilence/index.js @@ -1,8 +1,7 @@ -import React, { Component } from "react"; +import React, { useEffect } from "react"; import PropTypes from "prop-types"; -import { observable, action } from "mobx"; -import { observer } from "mobx-react"; +import { useObserver, useLocalStore } from "mobx-react"; import { Fade } from "react-reveal"; @@ -13,107 +12,88 @@ import { ThemeContext } from "Components/Theme"; import { SilenceComment } from "./SilenceComment"; import { SilenceDetails } from "./SilenceDetails"; -const ManagedSilence = observer( - class ManagedSilence extends Component { - static propTypes = { - cluster: PropTypes.string.isRequired, - alertCount: PropTypes.number.isRequired, - alertCountAlwaysVisible: PropTypes.bool.isRequired, - silence: APISilence.isRequired, - alertStore: PropTypes.instanceOf(AlertStore).isRequired, - silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired, - onDidUpdate: PropTypes.func, - onDeleteModalClose: PropTypes.func, - isOpen: PropTypes.bool, - }; - static defaultProps = { - isOpen: false, - }; +const GetAlertmanager = (alertStore, cluster) => + alertStore.data.readWriteAlertmanagers + .filter((u) => u.cluster === cluster) + .slice(0, 1)[0]; - constructor(props) { - super(props); +const ManagedSilence = ({ + cluster, + alertCount, + alertCountAlwaysVisible, + silence, + alertStore, + silenceFormStore, + isOpen, + onDidUpdate, + onDeleteModalClose, +}) => { + useEffect(() => { + if (onDidUpdate) onDidUpdate(); + }); - // store collapse state, by default only silence comment is visible - // the rest of the silence is hidden until expanded by a click - this.collapse = observable( - { - value: !props.isOpen, - toggle() { - this.value = !this.value; - }, - }, - { toggle: action.bound } - ); - } + const collapse = useLocalStore(() => ({ + value: !isOpen, + toggle() { + this.value = !this.value; + }, + })); - getAlertmanager = () => - this.props.alertStore.data.readWriteAlertmanagers - .filter((u) => u.cluster === this.props.cluster) - .slice(0, 1)[0]; + const onEditSilence = () => { + const alertmanager = GetAlertmanager(alertStore, cluster); - onEditSilence = () => { - const { silenceFormStore, silence } = this.props; + silenceFormStore.data.fillFormFromSilence(alertmanager, silence); + silenceFormStore.data.resetProgress(); + silenceFormStore.tab.setTab(SilenceTabNames.Editor); + silenceFormStore.toggle.show(); + }; - const alertmanager = this.getAlertmanager(); + const context = React.useContext(ThemeContext); - silenceFormStore.data.fillFormFromSilence(alertmanager, silence); - silenceFormStore.data.resetProgress(); - silenceFormStore.tab.setTab(SilenceTabNames.Editor); - silenceFormStore.toggle.show(); - }; + return useObserver(() => ( + +
+
+ +
- componentDidUpdate() { - const { onDidUpdate } = this.props; - if (onDidUpdate) onDidUpdate(); - } - - render() { - const { - cluster, - alertCount, - alertCountAlwaysVisible, - silence, - alertStore, - silenceFormStore, - onDeleteModalClose, - } = this.props; - - return ( - -
-
- -
- - {this.collapse.value ? null : ( -
- -
- )} + {collapse.value ? null : ( +
+
- - ); - } - } -); -ManagedSilence.contextType = ThemeContext; + )} +
+
+ )); +}; +ManagedSilence.propTypes = { + cluster: PropTypes.string.isRequired, + alertCount: PropTypes.number.isRequired, + alertCountAlwaysVisible: PropTypes.bool.isRequired, + silence: APISilence.isRequired, + alertStore: PropTypes.instanceOf(AlertStore).isRequired, + silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired, + onDidUpdate: PropTypes.func, + onDeleteModalClose: PropTypes.func, + isOpen: PropTypes.bool, +}; +ManagedSilence.defaultProps = { + isOpen: false, +}; -export { ManagedSilence }; +export { ManagedSilence, GetAlertmanager }; diff --git a/ui/src/Components/ManagedSilence/index.test.js b/ui/src/Components/ManagedSilence/index.test.js index ec1b54b08..d2d3bf643 100644 --- a/ui/src/Components/ManagedSilence/index.test.js +++ b/ui/src/Components/ManagedSilence/index.test.js @@ -12,7 +12,7 @@ import { MockThemeContext } from "__mocks__/Theme"; import { AlertStore } from "Stores/AlertStore"; import { SilenceFormStore } from "Stores/SilenceFormStore"; import { ThemeContext } from "Components/Theme"; -import { ManagedSilence } from "."; +import { ManagedSilence, GetAlertmanager } from "."; let alertStore; let silenceFormStore; @@ -80,23 +80,19 @@ describe("", () => { it("clicking on expand toggle shows silence details", () => { const tree = MountedManagedSilence(); - const toggle = tree.find("svg.text-muted.cursor-pointer"); - toggle.simulate("click"); + tree.find("svg.text-muted.cursor-pointer").simulate("click"); const details = tree.find("SilenceDetails"); expect(details).toHaveLength(1); }); it("matches snapshot with expaned details", () => { const tree = MountedManagedSilence(); - tree.instance().collapse.toggle(); - tree.update(); + tree.find("svg.text-muted.cursor-pointer").simulate("click"); expect(toDiffableHtml(tree.html())).toMatchSnapshot(); }); - it("getAlertmanager() returns alertmanager object from alertStore.data.upstreams.instances", () => { - const tree = MountedManagedSilence(); - const instance = tree.instance(); - const am = instance.getAlertmanager(); + it("GetAlertmanager() returns alertmanager object from alertStore.data.upstreams.instances", () => { + const am = GetAlertmanager(alertStore, cluster); expect(am).toEqual({ name: "am1", cluster: "am", @@ -111,7 +107,7 @@ describe("", () => { }); }); - it("getAlertmanager() returns only writable instances", () => { + it("GetAlertmanager() returns only writable instances", () => { alertStore.data.upstreams = { instances: [ { @@ -142,9 +138,7 @@ describe("", () => { clusters: { am: ["am1", "am2"] }, }; - const tree = MountedManagedSilence(); - const instance = tree.instance(); - const am = instance.getAlertmanager(); + const am = GetAlertmanager(alertStore, cluster); expect(am).toEqual({ name: "am1", cluster: "am", @@ -161,8 +155,7 @@ describe("", () => { it("shows Edit button on unexpired silence", () => { const tree = MountedManagedSilence(); - tree.instance().collapse.toggle(); - tree.update(); + tree.find("svg.text-muted.cursor-pointer").simulate("click"); const button = tree.find(".btn-primary"); expect(button.text()).toBe("Edit"); @@ -170,8 +163,7 @@ describe("", () => { it("shows Delete button on unexpired silence", () => { const tree = MountedManagedSilence(); - tree.instance().collapse.toggle(); - tree.update(); + tree.find("svg.text-muted.cursor-pointer").simulate("click"); const button = tree.find(".btn-danger"); expect(button.text()).toBe("Delete"); @@ -180,8 +172,7 @@ describe("", () => { it("shows Recreate button on expired silence", () => { advanceTo(moment.utc([2000, 0, 1, 23, 30, 0])); const tree = MountedManagedSilence(); - tree.instance().collapse.toggle(); - tree.update(); + tree.find("svg.text-muted.cursor-pointer").simulate("click"); const button = tree.find(".btn-primary"); expect(button.text()).toBe("Recreate"); @@ -189,8 +180,7 @@ describe("", () => { it("clicking on Edit calls ", () => { const tree = MountedManagedSilence(); - tree.instance().collapse.toggle(); - tree.update(); + tree.find("svg.text-muted.cursor-pointer").simulate("click"); expect(silenceFormStore.data.silenceID).toBeNull(); @@ -206,8 +196,7 @@ describe("", () => { it("call onDidUpdate if passed", () => { const fakeUpdate = jest.fn(); const tree = MountedManagedSilence(fakeUpdate); - tree.instance().collapse.toggle(); - tree.update(); + tree.find("svg.text-muted.cursor-pointer").simulate("click"); expect(fakeUpdate).toHaveBeenCalled(); }); });