diff --git a/ui/.storybook/config.js b/ui/.storybook/config.js index 147acc59f..41c402b9d 100644 --- a/ui/.storybook/config.js +++ b/ui/.storybook/config.js @@ -3,7 +3,7 @@ import { configure, getStorybook, setAddon, - addDecorator + addDecorator, } from "@storybook/react"; import createPercyAddon from "@percy-io/percy-storybook"; @@ -15,7 +15,7 @@ import { advanceTo } from "jest-date-mock"; import { ThemeContext } from "Components/Theme"; import { ReactSelectColors, - ReactSelectStyles + ReactSelectStyles, } from "Components/Theme/ReactSelect"; const { percyAddon, serializeStories } = createPercyAddon(); @@ -24,17 +24,21 @@ setAddon(percyAddon); // mock date so the silence form always shows same preview advanceTo(new Date(Date.UTC(2018, 7, 14, 17, 36, 40))); -addDecorator(story => { +addDecorator((story) => { document.body.style = ""; return story(); }); -addDecorator(story => { +addDecorator((story) => { return (
{story()} @@ -46,13 +50,17 @@ addDecorator(story => { width: "100%", backgroundColor: "#eee", marginTop: "4px", - marginBottom: "4px" + marginBottom: "4px", }} >
{story()} @@ -65,7 +73,7 @@ addDecorator(story => { const req = require.context("../src/Components", true, /\.stories\.(js|tsx)$/); function loadStories() { - req.keys().forEach(filename => req(filename)); + req.keys().forEach((filename) => req(filename)); } configure(loadStories, module); diff --git a/ui/src/App.tsx b/ui/src/App.tsx index 93b6c9321..a5426f5a8 100644 --- a/ui/src/App.tsx +++ b/ui/src/App.tsx @@ -137,6 +137,10 @@ const App = observer( this.settingsStore.themeConfig.options.dark.value ? ReactSelectStyles(ReactSelectColors.Dark) : ReactSelectStyles(ReactSelectColors.Light), + animations: { + enabled: true, + duration: 1000, + }, }} > diff --git a/ui/src/Components/CenteredMessage/index.js b/ui/src/Components/CenteredMessage/index.js index 99bcbe266..e7c6446f7 100644 --- a/ui/src/Components/CenteredMessage/index.js +++ b/ui/src/Components/CenteredMessage/index.js @@ -2,16 +2,21 @@ import React from "react"; import { Fade } from "react-reveal"; -const CenteredMessage = ({ children, className }) => ( -

- - {children} - -

-); +import { ThemeContext } from "Components/Theme"; + +const CenteredMessage = ({ children, className }) => { + const theme = React.useContext(ThemeContext); + return ( +

+ + {children} + +

+ ); +}; export { CenteredMessage }; diff --git a/ui/src/Components/CenteredMessage/index.test.js b/ui/src/Components/CenteredMessage/index.test.js index fa3da4341..a17f4f25d 100644 --- a/ui/src/Components/CenteredMessage/index.test.js +++ b/ui/src/Components/CenteredMessage/index.test.js @@ -4,8 +4,13 @@ import { shallow } from "enzyme"; import toDiffableHtml from "diffable-html"; +import { MockThemeContext } from "__mocks__/Theme"; import { CenteredMessage } from "."; +beforeAll(() => { + jest.spyOn(React, "useContext").mockImplementation(() => MockThemeContext); +}); + describe("", () => { const Message = () =>
Foo
; 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 fde18d86b..5b037d70d 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/index.test.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/Alert/index.test.js @@ -13,10 +13,12 @@ import { MockAnnotation, MockAlertGroup, MockSilence, -} from "__mocks__/Alerts.js"; +} from "__mocks__/Alerts"; +import { MockThemeContext } from "__mocks__/Theme"; import { AlertStore } from "Stores/AlertStore"; import { SilenceFormStore } from "Stores/SilenceFormStore"; import { BorderClassMap } from "Common/Colors"; +import { ThemeContext } from "Components/Theme"; import { Alert } from "."; let alertStore; @@ -60,7 +62,11 @@ const MountedAlert = (alert, group, showAlertmanagers, showReceiver) => { alertStore={alertStore} silenceFormStore={silenceFormStore} setIsMenuOpen={MockSetIsMenuOpen} - /> + />, + { + wrappingComponent: ThemeContext.Provider, + wrappingComponentProps: { value: MockThemeContext }, + } ); }; diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupFooter/index.test.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupFooter/index.test.js index 226b5661e..eed8e1cd7 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupFooter/index.test.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/GroupFooter/index.test.js @@ -12,9 +12,11 @@ import { MockAnnotation, MockAlert, MockSilence, -} from "__mocks__/Alerts.js"; +} from "__mocks__/Alerts"; +import { MockThemeContext } from "__mocks__/Theme"; import { AlertStore } from "Stores/AlertStore"; import { SilenceFormStore } from "Stores/SilenceFormStore"; +import { ThemeContext } from "Components/Theme"; import { GroupFooter } from "."; let group; @@ -63,7 +65,11 @@ const MountedGroupFooter = () => { afterUpdate={MockAfterUpdate} alertStore={alertStore} silenceFormStore={silenceFormStore} - /> + />, + { + wrappingComponent: ThemeContext.Provider, + wrappingComponentProps: { value: MockThemeContext }, + } ); }; diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js index 6702510bf..216521c2b 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.js @@ -18,6 +18,7 @@ import { AlertStore } from "Stores/AlertStore"; import { SilenceFormStore } from "Stores/SilenceFormStore"; import { BackgroundClassMap } from "Common/Colors"; import { TooltipWrapper } from "Components/TooltipWrapper"; +import { ThemeContext } from "Components/Theme"; import { GroupHeader } from "./GroupHeader"; import { Alert } from "./Alert"; import { GroupFooter } from "./GroupFooter"; @@ -237,9 +238,9 @@ const AlertGroup = observer( style={{ ...style, ...extraStyle }} >
@@ -313,5 +314,6 @@ const AlertGroup = observer( } } ); +AlertGroup.contextType = ThemeContext; export { AlertGroup }; diff --git a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.test.js b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.test.js index 487262956..675dd159d 100644 --- a/ui/src/Components/Grid/AlertGrid/AlertGroup/index.test.js +++ b/ui/src/Components/Grid/AlertGrid/AlertGroup/index.test.js @@ -4,10 +4,12 @@ import { mount } from "enzyme"; import moment from "moment"; -import { MockAlert, MockAlertGroup } from "__mocks__/Alerts.js"; +import { MockAlert, MockAlertGroup } from "__mocks__/Alerts"; +import { MockThemeContext } from "__mocks__/Theme"; import { AlertStore } from "Stores/AlertStore"; import { Settings } from "Stores/Settings"; import { SilenceFormStore } from "Stores/SilenceFormStore"; +import { ThemeContext } from "Components/Theme"; import { AlertGroup } from "."; let alertStore; @@ -66,7 +68,11 @@ const MountedAlertGroup = (afterUpdate, showAlertmanagers) => { alertStore={alertStore} silenceFormStore={silenceFormStore} gridLabelValue="" - /> + />, + { + wrappingComponent: ThemeContext.Provider, + wrappingComponentProps: { value: MockThemeContext }, + } ); }; diff --git a/ui/src/Components/Grid/AlertGrid/Grid.js b/ui/src/Components/Grid/AlertGrid/Grid.js index 6ce6a3feb..0e94547b6 100644 --- a/ui/src/Components/Grid/AlertGrid/Grid.js +++ b/ui/src/Components/Grid/AlertGrid/Grid.js @@ -25,6 +25,7 @@ import { APIGrid } from "Models/API"; import { FilteringLabel } from "Components/Labels/FilteringLabel"; import { FilteringCounterBadge } from "Components/Labels/FilteringCounterBadge"; import { TooltipWrapper } from "Components/TooltipWrapper"; +import { ThemeContext } from "Components/Theme"; import { DefaultDetailsCollapseValue } from "./AlertGroup/DetailsToggle"; import { AlertGroup } from "./AlertGroup"; @@ -182,7 +183,10 @@ const Grid = observer( return ( {grid.labelName !== "" && ( - +
{ alertStore={alertStore} settingsStore={settingsStore} silenceFormStore={silenceFormStore} - /> + />, + { + wrappingComponent: ThemeContext.Provider, + wrappingComponentProps: { value: MockThemeContext }, + } ); }; @@ -93,7 +99,11 @@ const MountedGrid = () => { groupWidth={420} grid={MockGrid()} outerPadding={0} - /> + />, + { + wrappingComponent: ThemeContext.Provider, + wrappingComponentProps: { value: MockThemeContext }, + } ); }; diff --git a/ui/src/Components/Grid/EmptyGrid/index.test.js b/ui/src/Components/Grid/EmptyGrid/index.test.js index aa9a767cd..abf7ead48 100644 --- a/ui/src/Components/Grid/EmptyGrid/index.test.js +++ b/ui/src/Components/Grid/EmptyGrid/index.test.js @@ -2,10 +2,15 @@ import React from "react"; import { shallow } from "enzyme"; +import { MockThemeContext } from "__mocks__/Theme"; import toDiffableHtml from "diffable-html"; import { EmptyGrid } from "."; +beforeAll(() => { + jest.spyOn(React, "useContext").mockImplementation(() => MockThemeContext); +}); + describe("", () => { it("matches snapshot", () => { const tree = shallow(); diff --git a/ui/src/Components/Grid/FatalError/index.js b/ui/src/Components/Grid/FatalError/index.js index 94eb4178d..10cef8015 100644 --- a/ui/src/Components/Grid/FatalError/index.js +++ b/ui/src/Components/Grid/FatalError/index.js @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React from "react"; import PropTypes from "prop-types"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -6,27 +6,21 @@ import { faExclamationCircle } from "@fortawesome/free-solid-svg-icons/faExclama import { CenteredMessage } from "Components/CenteredMessage"; -class FatalError extends Component { - static propTypes = { - message: PropTypes.string.isRequired, - }; - - render() { - const { message } = this.props; - return ( - -
- -

- {message} -

-
-
- ); - } -} +const FatalError = ({ message }) => ( + +
+ +

+ {message} +

+
+
+); +FatalError.propTypes = { + message: PropTypes.string.isRequired, +}; export { FatalError }; diff --git a/ui/src/Components/Grid/FatalError/index.test.js b/ui/src/Components/Grid/FatalError/index.test.js index 1462f096c..6cb430282 100644 --- a/ui/src/Components/Grid/FatalError/index.test.js +++ b/ui/src/Components/Grid/FatalError/index.test.js @@ -4,8 +4,13 @@ import { shallow } from "enzyme"; import toDiffableHtml from "diffable-html"; +import { MockThemeContext } from "__mocks__/Theme"; import { FatalError } from "."; +beforeAll(() => { + jest.spyOn(React, "useContext").mockImplementation(() => MockThemeContext); +}); + describe("", () => { it("matches snapshot", () => { const tree = shallow(); diff --git a/ui/src/Components/Grid/ReloadNeeded/index.test.js b/ui/src/Components/Grid/ReloadNeeded/index.test.js index 91fdc7c5a..3866a35f2 100644 --- a/ui/src/Components/Grid/ReloadNeeded/index.test.js +++ b/ui/src/Components/Grid/ReloadNeeded/index.test.js @@ -4,11 +4,13 @@ import { mount, shallow } from "enzyme"; import toDiffableHtml from "diffable-html"; +import { MockThemeContext } from "__mocks__/Theme"; import { ReloadNeeded } from "."; beforeEach(() => { jest.useFakeTimers(); jest.clearAllTimers(); + jest.spyOn(React, "useContext").mockImplementation(() => MockThemeContext); }); afterEach(() => { diff --git a/ui/src/Components/Grid/UpgradeNeeded/index.test.js b/ui/src/Components/Grid/UpgradeNeeded/index.test.js index 3b97c90c5..2c5cce028 100644 --- a/ui/src/Components/Grid/UpgradeNeeded/index.test.js +++ b/ui/src/Components/Grid/UpgradeNeeded/index.test.js @@ -4,11 +4,13 @@ import { mount, shallow } from "enzyme"; import toDiffableHtml from "diffable-html"; +import { MockThemeContext } from "__mocks__/Theme"; import { UpgradeNeeded } from "."; beforeEach(() => { jest.useFakeTimers(); jest.clearAllTimers(); + jest.spyOn(React, "useContext").mockImplementation(() => MockThemeContext); }); afterEach(() => { diff --git a/ui/src/Components/Grid/UpstreamError/index.test.js b/ui/src/Components/Grid/UpstreamError/index.test.js index 9e7da7a31..02cd3deaf 100644 --- a/ui/src/Components/Grid/UpstreamError/index.test.js +++ b/ui/src/Components/Grid/UpstreamError/index.test.js @@ -4,8 +4,13 @@ import { shallow } from "enzyme"; import toDiffableHtml from "diffable-html"; +import { MockThemeContext } from "__mocks__/Theme"; import { UpstreamError } from "."; +beforeAll(() => { + jest.spyOn(React, "useContext").mockImplementation(() => MockThemeContext); +}); + describe("", () => { it("matches snapshot", () => { const tree = shallow(); diff --git a/ui/src/Components/ManagedSilence/index.js b/ui/src/Components/ManagedSilence/index.js index dba945b02..12fec93c5 100644 --- a/ui/src/Components/ManagedSilence/index.js +++ b/ui/src/Components/ManagedSilence/index.js @@ -9,6 +9,7 @@ import { Fade } from "react-reveal"; import { APISilence } from "Models/API"; import { AlertStore } from "Stores/AlertStore"; import { SilenceFormStore, SilenceTabNames } from "Stores/SilenceFormStore"; +import { ThemeContext } from "Components/Theme"; import { SilenceComment } from "./SilenceComment"; import { SilenceDetails } from "./SilenceDetails"; @@ -78,7 +79,10 @@ const ManagedSilence = observer( } = this.props; return ( - +
{ alertStore={alertStore} silenceFormStore={silenceFormStore} onDidUpdate={onDidUpdate} - /> + />, + { + wrappingComponent: ThemeContext.Provider, + wrappingComponentProps: { value: MockThemeContext }, + } ); }; diff --git a/ui/src/Components/SilenceModal/Browser/index.js b/ui/src/Components/SilenceModal/Browser/index.js index b7940cda1..39e0b41f6 100644 --- a/ui/src/Components/SilenceModal/Browser/index.js +++ b/ui/src/Components/SilenceModal/Browser/index.js @@ -1,4 +1,4 @@ -import React, { Component } from "react"; +import React, { Component, useContext } from "react"; import PropTypes from "prop-types"; import { observable, action } from "mobx"; @@ -20,6 +20,7 @@ import { Settings } from "Stores/Settings"; import { FetchGet } from "Common/Fetch"; import { ManagedSilence } from "Components/ManagedSilence"; import { PageSelect } from "Components/Pagination"; +import { ThemeContext } from "Components/Theme"; const FetchError = ({ message }) => (
@@ -33,13 +34,17 @@ FetchError.propTypes = { message: PropTypes.node.isRequired, }; -const Placeholder = ({ content }) => ( - -
-

{content}

-
-
-); +const Placeholder = ({ content }) => { + const theme = useContext(ThemeContext); + + return ( + +
+

{content}

+
+
+ ); +}; Placeholder.propTypes = { content: PropTypes.node.isRequired, }; diff --git a/ui/src/Components/SilenceModal/Browser/index.test.js b/ui/src/Components/SilenceModal/Browser/index.test.js index 562faa295..8bbba5ed6 100644 --- a/ui/src/Components/SilenceModal/Browser/index.test.js +++ b/ui/src/Components/SilenceModal/Browser/index.test.js @@ -8,10 +8,12 @@ import moment from "moment"; import { advanceTo, clear } from "jest-date-mock"; import { MockSilence } from "__mocks__/Alerts"; +import { MockThemeContext } from "__mocks__/Theme"; import { PressKey } from "__mocks__/KeyPress"; import { AlertStore } from "Stores/AlertStore"; import { Settings } from "Stores/Settings"; import { SilenceFormStore } from "Stores/SilenceFormStore"; +import { ThemeContext } from "Components/Theme"; import { Browser } from "."; let alertStore; @@ -80,7 +82,11 @@ const MountedBrowser = () => { silenceFormStore={silenceFormStore} settingsStore={settingsStore} onDeleteModalClose={MockOnDeleteModalClose} - /> + />, + { + wrappingComponent: ThemeContext.Provider, + wrappingComponentProps: { value: MockThemeContext }, + } ); }; diff --git a/ui/src/__mocks__/Theme.js b/ui/src/__mocks__/Theme.js new file mode 100644 index 000000000..e6c13595a --- /dev/null +++ b/ui/src/__mocks__/Theme.js @@ -0,0 +1,8 @@ +const MockThemeContext = { + animations: { + in: undefined, + duration: 500, + }, +}; + +export { MockThemeContext };