diff --git a/ui/src/Components/Animations/DropdownSlide/index.css b/ui/src/Components/Animations/DropdownSlide/index.css new file mode 100644 index 000000000..14180e18f --- /dev/null +++ b/ui/src/Components/Animations/DropdownSlide/index.css @@ -0,0 +1,33 @@ +.components-animation-slide-enter, +.components-animation-slide-appear { + opacity: 0.01; + overflow: hidden; + max-height: 0px; + border: 0; + padding: 0; + margin: 0; +} +.components-animation-slide-enter-active, +.components-animation-slide-appear-active { + max-height: 500px; /* can't use auto here */ + opacity: 1; + transition-property: max-height, opacity; + transition-duration: 0.15s; + transition-timing-function: ease-out; +} + +.components-animation-slide-exit { + max-height: 500px; /* can't use auto here */ + opacity: 1; +} +.components-animation-slide-exit-active { + opacity: 0.01; + overflow: hidden; + max-height: 0px; + border: 0; + padding: 0; + margin: 0; + transition-property: max-height, opacity; + transition-duration: 0.15s; + transition-timing-function: ease-out; +} diff --git a/ui/src/Components/Animations/DropdownSlide/index.js b/ui/src/Components/Animations/DropdownSlide/index.js new file mode 100644 index 000000000..549b849af --- /dev/null +++ b/ui/src/Components/Animations/DropdownSlide/index.js @@ -0,0 +1,24 @@ +import React from "react"; +import PropTypes from "prop-types"; + +import { CSSTransition } from "react-transition-group"; + +import "./index.css"; + +const DropdownSlide = ({ children, duration, ...props }) => ( + + {children} + +); +DropdownSlide.propTypes = { + children: PropTypes.node.isRequired +}; + +export { DropdownSlide }; diff --git a/ui/src/Components/Animations/MountFade/index.css b/ui/src/Components/Animations/MountFade/index.css new file mode 100644 index 000000000..61752ab91 --- /dev/null +++ b/ui/src/Components/Animations/MountFade/index.css @@ -0,0 +1,23 @@ +.components-animation-fade-appear { + opacity: 0.01; +} +.components-animation-fade-appear-active { + opacity: 1; + transition: opacity 0.15s ease-in; +} + +.components-animation-fade-enter { + opacity: 0.01; +} +.components-animation-fade-enter-active { + opacity: 1; + transition: opacity 0.15s ease-in; +} + +.components-animation-fade-exit { + opacity: 1; +} +.components-animation-fade-exit-active { + opacity: 0.01; + transition: opacity 0.15s ease-in; +} diff --git a/ui/src/Components/Animations/MountFade/index.js b/ui/src/Components/Animations/MountFade/index.js new file mode 100644 index 000000000..7e46b21c6 --- /dev/null +++ b/ui/src/Components/Animations/MountFade/index.js @@ -0,0 +1,25 @@ +import React from "react"; +import PropTypes from "prop-types"; + +import { CSSTransition } from "react-transition-group"; + +import "./index.css"; + +const MountFade = ({ children, duration, ...props }) => ( + + {children} + +); +MountFade.propTypes = { + children: PropTypes.node.isRequired +}; + +export { MountFade }; diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.js index 4e521bc85..68bbe5832 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/AlertMenu.js @@ -16,6 +16,7 @@ import { faCaretDown } from "@fortawesome/free-solid-svg-icons/faCaretDown"; import { faBellSlash } from "@fortawesome/free-solid-svg-icons/faBellSlash"; import { FetchPauser } from "Components/FetchPauser"; +import { DropdownSlide } from "Components/Animations/DropdownSlide"; const onSilenceClick = (silenceFormStore, group, alert) => { silenceFormStore.data.resetProgress(); @@ -127,7 +128,7 @@ const AlertMenu = observer( )} - {this.collapse.value ? null : ( + )} - )} + ); } diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js index 81244998c..57492a20e 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupHeader/GroupMenu.js @@ -16,6 +16,7 @@ import { faBellSlash } from "@fortawesome/free-solid-svg-icons/faBellSlash"; import { FormatAPIFilterQuery } from "Stores/AlertStore"; import { QueryOperators, StaticLabels, FormatQuery } from "Common/Query"; +import { DropdownSlide } from "Components/Animations/DropdownSlide"; import { FetchPauser } from "Components/FetchPauser"; const onSilenceClick = (silenceFormStore, group) => { @@ -123,7 +124,7 @@ const GroupMenu = observer( )} - {this.collapse.value ? null : ( + )} - )} + ); } diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.css b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.css deleted file mode 100644 index 0d46bb1de..000000000 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.css +++ /dev/null @@ -1,26 +0,0 @@ -.components-grid-alertgrid-alertgroup-fade-enter { - opacity: 0.01; -} - -.components-grid-alertgrid-alertgroup-fade-enter-active { - opacity: 1; - transition: opacity 0.4s ease-in; -} - -.components-grid-alertgrid-alertgroup-fade-exit { - opacity: 1; -} - -.components-grid-alertgrid-alertgroup-fade-exit-active { - opacity: 0.01; - transition: opacity 0.4s ease-in; -} - -.components-grid-alertgrid-alertgroup-fade-appear { - opacity: 0.01; -} - -.components-grid-alertgrid-alertgroup-fade-appear-active { - opacity: 1; - transition: opacity 0.4s ease-in; -} diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js index 99e334b9f..8287590be 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js @@ -6,20 +6,17 @@ import { observable, action, toJS } from "mobx"; import hash from "object-hash"; -import { CSSTransition } from "react-transition-group"; - import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faPlus } from "@fortawesome/free-solid-svg-icons/faPlus"; import { faMinus } from "@fortawesome/free-solid-svg-icons/faMinus"; +import { MountFade } from "Components/Animations/MountFade"; import { Settings } from "Stores/Settings"; import { SilenceFormStore } from "Stores/SilenceFormStore"; import { GroupHeader } from "./GroupHeader"; import { Alert } from "./Alert"; import { GroupFooter } from "./GroupFooter"; -import "./index.css"; - const LoadButton = ({ icon, action }) => { return ( )} - {this.collapse.value ? null : ( + )} - )} + ); } diff --git a/ui/src/Components/SilenceModal/index.js b/ui/src/Components/SilenceModal/index.js index 5ada556d4..b1f8b43d3 100644 --- a/ui/src/Components/SilenceModal/index.js +++ b/ui/src/Components/SilenceModal/index.js @@ -6,6 +6,7 @@ import { observer } from "mobx-react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faBellSlash } from "@fortawesome/free-solid-svg-icons/faBellSlash"; +import { MountFade } from "Components/Animations/MountFade"; import { SilenceModalContent } from "./SilenceModalContent"; import "./index.css"; @@ -53,14 +54,14 @@ const SilenceModal = observer( - {silenceFormStore.toggle.visible ? ( + - ) : null} + ); } diff --git a/ui/src/Components/SilenceModal/index.test.js b/ui/src/Components/SilenceModal/index.test.js index b1aa3d359..5205a0a67 100644 --- a/ui/src/Components/SilenceModal/index.test.js +++ b/ui/src/Components/SilenceModal/index.test.js @@ -1,6 +1,6 @@ import React from "react"; -import { shallow, mount } from "enzyme"; +import { mount } from "enzyme"; import { AlertStore } from "Stores/AlertStore"; import { Settings } from "Stores/Settings"; @@ -12,6 +12,7 @@ let settingsStore; let silenceFormStore; beforeAll(() => { + jest.useFakeTimers(); fetch.mockResponse(JSON.stringify([])); }); @@ -21,16 +22,6 @@ beforeEach(() => { silenceFormStore = new SilenceFormStore(); }); -const ShallowSilenceModal = () => { - return shallow( - - ); -}; - const MountedSilenceModal = () => { return mount( { describe("", () => { it("only renders FontAwesomeIcon when modal is not shown", () => { - const tree = ShallowSilenceModal(); - expect(tree.text()).toBe(""); + const tree = MountedSilenceModal(); + expect(tree.find("FontAwesomeIcon")).toHaveLength(1); + expect(tree.find("SilenceModalContent")).toHaveLength(0); }); it("renders the modal when it is shown", () => { - const tree = ShallowSilenceModal(); + const tree = MountedSilenceModal(); const toggle = tree.find(".nav-link"); toggle.simulate("click"); - expect(tree.text()).toBe(""); + expect(tree.find("FontAwesomeIcon")).not.toHaveLength(0); + expect(tree.find("SilenceModalContent")).toHaveLength(1); }); it("hides the modal when toggle() is called twice", () => { - const tree = ShallowSilenceModal(); + const tree = MountedSilenceModal(); const toggle = tree.find(".nav-link"); + toggle.simulate("click"); + jest.runOnlyPendingTimers(); + tree.update(); + expect(tree.find("SilenceModalContent")).toHaveLength(1); + toggle.simulate("click"); - expect(tree.text()).toBe(""); + jest.runOnlyPendingTimers(); + tree.update(); + expect(tree.find("SilenceModalContent")).toHaveLength(0); }); it("hides the modal when hide() is called", () => { - const tree = ShallowSilenceModal(); + const tree = MountedSilenceModal(); const toggle = tree.find(".nav-link"); + toggle.simulate("click"); - expect(tree.text()).toBe(""); + jest.runOnlyPendingTimers(); + tree.update(); + expect(tree.find("SilenceModalContent")).toHaveLength(1); + silenceFormStore.toggle.hide(); - expect(tree.text()).toBe(""); + jest.runOnlyPendingTimers(); + tree.update(); + expect(tree.find("SilenceModalContent")).toHaveLength(0); }); it("'modal-open' class is appended to body node when modal is visible", () => {