fix(ui): add animation settings to the theme context

This commit is contained in:
Łukasz Mierzwa
2020-04-16 10:06:33 +01:00
committed by Łukasz Mierzwa
parent c8dfeb7a66
commit 7eaa7cbf34
21 changed files with 166 additions and 66 deletions
+16 -8
View File
@@ -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 (
<div>
<div className="theme-light">
<ThemeContext.Provider
value={{
reactSelectStyles: ReactSelectStyles(ReactSelectColors.Light)
reactSelectStyles: ReactSelectStyles(ReactSelectColors.Light),
animations: {
in: true,
duration: 0,
},
}}
>
{story()}
@@ -46,13 +50,17 @@ addDecorator(story => {
width: "100%",
backgroundColor: "#eee",
marginTop: "4px",
marginBottom: "4px"
marginBottom: "4px",
}}
></div>
<div className="theme-dark">
<ThemeContext.Provider
value={{
reactSelectStyles: ReactSelectStyles(ReactSelectColors.Dark)
reactSelectStyles: ReactSelectStyles(ReactSelectColors.Dark),
animations: {
in: true,
duration: 0,
},
}}
>
{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);
+4
View File
@@ -137,6 +137,10 @@ const App = observer(
this.settingsStore.themeConfig.options.dark.value
? ReactSelectStyles(ReactSelectColors.Dark)
: ReactSelectStyles(ReactSelectColors.Light),
animations: {
enabled: true,
duration: 1000,
},
}}
>
<BodyTheme />
+16 -11
View File
@@ -2,16 +2,21 @@ import React from "react";
import { Fade } from "react-reveal";
const CenteredMessage = ({ children, className }) => (
<h1
className={`${
className ? className : "display-1 text-placeholder"
} screen-center`}
>
<Fade in={true} duration={500}>
{children}
</Fade>
</h1>
);
import { ThemeContext } from "Components/Theme";
const CenteredMessage = ({ children, className }) => {
const theme = React.useContext(ThemeContext);
return (
<h1
className={`${
className ? className : "display-1 text-placeholder"
} screen-center`}
>
<Fade in={theme.animations.in} duration={theme.animations.duration}>
{children}
</Fade>
</h1>
);
};
export { CenteredMessage };
@@ -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("<CenteredMessage />", () => {
const Message = () => <div>Foo</div>;
@@ -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 },
}
);
};
@@ -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 },
}
);
};
@@ -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 }}
>
<Fade
in={true}
duration={500}
wait={500}
in={this.context.animations.in}
duration={this.context.animations.duration}
wait={this.context.animations.duration}
onReveal={this.renderConfig.setAnimationDone}
>
<div className={`card ${cardBackgroundClass}`}>
@@ -313,5 +314,6 @@ const AlertGroup = observer(
}
}
);
AlertGroup.contextType = ThemeContext;
export { AlertGroup };
@@ -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 },
}
);
};
+6 -1
View File
@@ -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 (
<React.Fragment>
{grid.labelName !== "" && (
<Fade in={true} duration={500}>
<Fade
in={this.context.animations.in}
duration={this.context.animations.duration}
>
<h5 className="components-grid-swimlane d-flex flex-row justify-content-between rounded px-2 py-1 mt-2 mb-0 border border-dark">
<span
className="flex-shrink-1 flex-grow-1"
@@ -297,5 +301,6 @@ const Grid = observer(
}
}
);
Grid.contextType = ThemeContext;
export { Grid };
+13 -3
View File
@@ -4,11 +4,13 @@ import { shallow, mount } from "enzyme";
import { advanceBy, clear } from "jest-date-mock";
import { MockAlert, MockAlertGroup } from "__mocks__/Alerts.js";
import { MockAlert, MockAlertGroup } from "__mocks__/Alerts";
import { MockThemeContext } from "__mocks__/Theme";
import { mockMatchMedia } from "__mocks__/matchMedia";
import { AlertStore } from "Stores/AlertStore";
import { Settings } from "Stores/Settings";
import { SilenceFormStore } from "Stores/SilenceFormStore";
import { ThemeContext } from "Components/Theme";
import { GetGridElementWidth, GridSizesConfig } from "./GridSize";
import { Grid } from "./Grid";
import { AlertGrid } from ".";
@@ -42,7 +44,11 @@ const MountedAlertGrid = () => {
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 },
}
);
};
@@ -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("<EmptyGrid />", () => {
it("matches snapshot", () => {
const tree = shallow(<EmptyGrid />);
+17 -23
View File
@@ -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 (
<CenteredMessage>
<div className="container-fluid text-center">
<FontAwesomeIcon
icon={faExclamationCircle}
className="screen-center-icon-big text-danger mb-4"
/>
<p className="lead text-white bg-secondary p-3 rounded text-wrap text-break">
{message}
</p>
</div>
</CenteredMessage>
);
}
}
const FatalError = ({ message }) => (
<CenteredMessage>
<div className="container-fluid text-center">
<FontAwesomeIcon
icon={faExclamationCircle}
className="screen-center-icon-big text-danger mb-4"
/>
<p className="lead text-white bg-secondary p-3 rounded text-wrap text-break">
{message}
</p>
</div>
</CenteredMessage>
);
FatalError.propTypes = {
message: PropTypes.string.isRequired,
};
export { FatalError };
@@ -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("<FatalError />", () => {
it("matches snapshot", () => {
const tree = shallow(<FatalError message="foo bar" />);
@@ -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(() => {
@@ -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(() => {
@@ -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("<UpstreamError />", () => {
it("matches snapshot", () => {
const tree = shallow(<UpstreamError name="foo" message="bar" />);
+6 -1
View File
@@ -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 (
<Fade in={true} duration={500}>
<Fade
in={this.context.animations.in}
duration={this.context.animations.duration}
>
<div className="card my-1 components-managed-silence">
<div className="card-header rounded-0 border-bottom-0 px-3">
<SilenceComment
@@ -110,5 +114,6 @@ const ManagedSilence = observer(
}
}
);
ManagedSilence.contextType = ThemeContext;
export { ManagedSilence };
@@ -8,8 +8,10 @@ import moment from "moment";
import { advanceTo, clear } from "jest-date-mock";
import { MockSilence } from "__mocks__/Alerts";
import { MockThemeContext } from "__mocks__/Theme";
import { AlertStore } from "Stores/AlertStore";
import { SilenceFormStore } from "Stores/SilenceFormStore";
import { ThemeContext } from "Components/Theme";
import { ManagedSilence } from ".";
let alertStore;
@@ -62,7 +64,11 @@ const MountedManagedSilence = (onDidUpdate) => {
alertStore={alertStore}
silenceFormStore={silenceFormStore}
onDidUpdate={onDidUpdate}
/>
/>,
{
wrappingComponent: ThemeContext.Provider,
wrappingComponentProps: { value: MockThemeContext },
}
);
};
@@ -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 }) => (
<div className="text-center">
@@ -33,13 +34,17 @@ FetchError.propTypes = {
message: PropTypes.node.isRequired,
};
const Placeholder = ({ content }) => (
<Fade in={true} duration={500}>
<div className="jumbotron bg-transparent">
<h1 className="display-5 text-placeholder text-center">{content}</h1>
</div>
</Fade>
);
const Placeholder = ({ content }) => {
const theme = useContext(ThemeContext);
return (
<Fade in={theme.animations.in} duration={theme.animations.duration}>
<div className="jumbotron bg-transparent">
<h1 className="display-5 text-placeholder text-center">{content}</h1>
</div>
</Fade>
);
};
Placeholder.propTypes = {
content: PropTypes.node.isRequired,
};
@@ -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 },
}
);
};
+8
View File
@@ -0,0 +1,8 @@
const MockThemeContext = {
animations: {
in: undefined,
duration: 500,
},
};
export { MockThemeContext };