Merge pull request #1251 from prymitive/centered-message

feat(ui): tweak full page messages / placeholders
This commit is contained in:
Łukasz Mierzwa
2019-12-12 22:58:03 +00:00
committed by GitHub
18 changed files with 213 additions and 58 deletions
@@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<CenteredMessage /> matches snapshot 1`] = `
"
<h1 class=\\"display-1 text-placeholder screen-center\\">
<div>
Foo
</div>
</h1>
"
`;
@@ -0,0 +1,15 @@
import React from "react";
import { MountFade } from "Components/Animations/MountFade";
const CenteredMessage = ({ children, className }) => (
<h1
className={`${
className ? className : "display-1 text-placeholder"
} screen-center`}
>
<MountFade in={true}>{children}</MountFade>
</h1>
);
export { CenteredMessage };
@@ -0,0 +1,41 @@
import React from "react";
import { shallow } from "enzyme";
import toDiffableHtml from "diffable-html";
import { CenteredMessage } from ".";
describe("<CenteredMessage />", () => {
const Message = () => <div>Foo</div>;
it("matches snapshot", () => {
const tree = shallow(
<CenteredMessage>
<Message />
</CenteredMessage>
);
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
});
it("uses 'display-1 text-placeholder' className by default", () => {
const tree = shallow(
<CenteredMessage>
<Message />
</CenteredMessage>
);
expect(toDiffableHtml(tree.html())).toMatch(/display-1 text-placeholder/);
});
it("uses custom className if passed", () => {
const tree = shallow(
<CenteredMessage className="bar-class">
<Message />
</CenteredMessage>
);
expect(toDiffableHtml(tree.html())).toMatch(/bar-class/);
expect(toDiffableHtml(tree.html())).not.toMatch(
/display-1 text-placeholder/
);
});
});
@@ -7,11 +7,10 @@ exports[`<EmptyGrid /> matches snapshot 1`] = `
focusable=\\"false\\"
data-prefix=\\"fas\\"
data-icon=\\"mug-hot\\"
class=\\"svg-inline--fa fa-mug-hot fa-w-16 \\"
class=\\"svg-inline--fa fa-mug-hot fa-w-16 screen-center-icon-big text-placeholder\\"
role=\\"img\\"
xmlns=\\"http://www.w3.org/2000/svg\\"
viewbox=\\"0 0 512 512\\"
style=\\"font-size:14rem\\"
>
<path fill=\\"currentColor\\"
d=\\"M127.1 146.5c1.3 7.7 8 13.5 16 13.5h16.5c9.8 0 17.6-8.5 16.3-18-3.8-28.2-16.4-54.2-36.6-74.7-14.4-14.7-23.6-33.3-26.4-53.5C111.8 5.9 105 0 96.8 0H80.4C70.6 0 63 8.5 64.1 18c3.9 31.9 18 61.3 40.6 84.4 12 12.2 19.7 27.5 22.4 44.1zm112 0c1.3 7.7 8 13.5 16 13.5h16.5c9.8 0 17.6-8.5 16.3-18-3.8-28.2-16.4-54.2-36.6-74.7-14.4-14.7-23.6-33.3-26.4-53.5C223.8 5.9 217 0 208.8 0h-16.4c-9.8 0-17.5 8.5-16.3 18 3.9 31.9 18 61.3 40.6 84.4 12 12.2 19.7 27.5 22.4 44.1zM400 192H32c-17.7 0-32 14.3-32 32v192c0 53 43 96 96 96h192c53 0 96-43 96-96h16c61.8 0 112-50.2 112-112s-50.2-112-112-112zm0 160h-16v-96h16c26.5 0 48 21.5 48 48s-21.5 48-48 48z\\"
+7 -8
View File
@@ -3,16 +3,15 @@ import React from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faMugHot } from "@fortawesome/free-solid-svg-icons/faMugHot";
import { MountFade } from "Components/Animations/MountFade";
import "./index.scss";
import { CenteredMessage } from "Components/CenteredMessage";
const EmptyGrid = () => (
<h1 className="display-1 text-placeholder screen-center">
<MountFade in={true}>
<FontAwesomeIcon icon={faMugHot} style={{ fontSize: "14rem" }} />
</MountFade>
</h1>
<CenteredMessage>
<FontAwesomeIcon
icon={faMugHot}
className="screen-center-icon-big text-placeholder"
/>
</CenteredMessage>
);
export { EmptyGrid };
@@ -2,28 +2,26 @@
exports[`<FatalError /> matches snapshot 1`] = `
"
<div class=\\"jumbotron text-center bg-primary my-4\\">
<div class=\\"container-fluid\\">
<h1 class=\\"display-1 my-5 text-danger\\">
<svg aria-hidden=\\"true\\"
focusable=\\"false\\"
data-prefix=\\"fas\\"
data-icon=\\"exclamation-circle\\"
class=\\"svg-inline--fa fa-exclamation-circle fa-w-16 \\"
role=\\"img\\"
xmlns=\\"http://www.w3.org/2000/svg\\"
viewbox=\\"0 0 512 512\\"
<h1 class=\\"display-1 text-placeholder screen-center\\">
<div class=\\"container-fluid text-center\\">
<svg aria-hidden=\\"true\\"
focusable=\\"false\\"
data-prefix=\\"fas\\"
data-icon=\\"exclamation-circle\\"
class=\\"svg-inline--fa fa-exclamation-circle fa-w-16 screen-center-icon-big text-danger mb-4\\"
role=\\"img\\"
xmlns=\\"http://www.w3.org/2000/svg\\"
viewbox=\\"0 0 512 512\\"
>
<path fill=\\"currentColor\\"
d=\\"M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z\\"
>
<path fill=\\"currentColor\\"
d=\\"M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z\\"
>
</path>
</svg>
</h1>
</path>
</svg>
<p class=\\"lead text-white bg-secondary px-1 py-3 rounded text-wrap text-break\\">
foo bar
</p>
</div>
</div>
</h1>
"
`;
+9 -6
View File
@@ -4,6 +4,8 @@ import PropTypes from "prop-types";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faExclamationCircle } from "@fortawesome/free-solid-svg-icons/faExclamationCircle";
import { CenteredMessage } from "Components/CenteredMessage";
class FatalError extends Component {
static propTypes = {
message: PropTypes.string.isRequired
@@ -12,16 +14,17 @@ class FatalError extends Component {
render() {
const { message } = this.props;
return (
<div className="jumbotron text-center bg-primary my-4">
<div className="container-fluid">
<h1 className="display-1 my-5 text-danger">
<FontAwesomeIcon icon={faExclamationCircle} />
</h1>
<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 px-1 py-3 rounded text-wrap text-break">
{message}
</p>
</div>
</div>
</CenteredMessage>
);
}
}
@@ -2,14 +2,14 @@
exports[`<UpgradeNeeded /> matches snapshot 1`] = `
"
<div class=\\"jumbotron text-center bg-primary my-4\\">
<div class=\\"container-fluid\\">
<h1 class=\\"display-1 my-5 text-success shake-slow shake-constant\\">
<h1 class=\\"display-1 text-placeholder screen-center\\">
<div class=\\"container-fluid text-center\\">
<div class=\\"shake-slow shake-constant mb-4\\">
<svg aria-hidden=\\"true\\"
focusable=\\"false\\"
data-prefix=\\"fas\\"
data-icon=\\"rocket\\"
class=\\"svg-inline--fa fa-rocket fa-w-16 \\"
class=\\"svg-inline--fa fa-rocket fa-w-16 screen-center-icon-big text-success\\"
role=\\"img\\"
xmlns=\\"http://www.w3.org/2000/svg\\"
viewbox=\\"0 0 512 512\\"
@@ -19,7 +19,7 @@ exports[`<UpgradeNeeded /> matches snapshot 1`] = `
>
</path>
</svg>
</h1>
</div>
<p class=\\"lead text-muted\\">
<svg aria-hidden=\\"true\\"
focusable=\\"false\\"
@@ -38,6 +38,6 @@ exports[`<UpgradeNeeded /> matches snapshot 1`] = `
Upgrading to a new version: 1.2.3
</p>
</div>
</div>
</h1>
"
`;
+11 -6
View File
@@ -5,6 +5,8 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faRocket } from "@fortawesome/free-solid-svg-icons/faRocket";
import { faSpinner } from "@fortawesome/free-solid-svg-icons/faSpinner";
import { CenteredMessage } from "Components/CenteredMessage";
import "csshake/scss/csshake-slow.scss";
class UpgradeNeeded extends Component {
@@ -30,17 +32,20 @@ class UpgradeNeeded extends Component {
render() {
const { newVersion } = this.props;
return (
<div className="jumbotron text-center bg-primary my-4">
<div className="container-fluid">
<h1 className="display-1 my-5 text-success shake-slow shake-constant">
<FontAwesomeIcon icon={faRocket} />
</h1>
<CenteredMessage>
<div className="container-fluid text-center">
<div className="shake-slow shake-constant mb-4">
<FontAwesomeIcon
icon={faRocket}
className="screen-center-icon-big text-success"
/>
</div>
<p className="lead text-muted">
<FontAwesomeIcon className="mr-1" icon={faSpinner} spin />
Upgrading to a new version: {newVersion}
</p>
</div>
</div>
</CenteredMessage>
);
}
}
+18
View File
@@ -8,11 +8,22 @@ import { Settings } from "Stores/Settings";
import { SilenceFormStore } from "Stores/SilenceFormStore";
import { FatalError } from "./FatalError";
import { UpgradeNeeded } from "./UpgradeNeeded";
import { EmptyGrid } from "./EmptyGrid";
import { Grid } from ".";
import { InternalError } from "../../ErrorBoundary";
import "Styles/Percy.scss";
storiesOf("Grid", module)
.add("InternalError", () => {
return (
<InternalError
message="React error boundary message"
secondsLeft={45}
progressLeft={66}
/>
);
})
.add("FatalError", () => {
return (
<FatalError message="Something failed with a veryLongStringToTestTextWrappingveryLongStringToTestTextWrappingveryLongStringToTestTextWrappingveryLongStringToTestTextWrappingveryLongStringToTestTextWrappingveryLongStringToTestTextWrappingveryLongStringToTestTextWrappingveryLongStringToTestTextWrapping" />
@@ -21,6 +32,13 @@ storiesOf("Grid", module)
.add("UpgradeNeeded", () => {
return <UpgradeNeeded newVersion="1.2.3" reloadAfter={100000000} />;
})
.add("EmptyGrid", () => {
return (
<div className="text-center">
<EmptyGrid />
</div>
);
})
.add("AlertGrid", () => {
const alertStore = new AlertStore([]);
const settingsStore = new Settings();
@@ -8,18 +8,28 @@ import { OverviewModalContent } from "./OverviewModalContent";
import "Styles/Percy.scss";
storiesOf("OverviewModal", module)
.addDecorator(storyFn => (
storiesOf("OverviewModal", module).add("OverviewModal", () => {
const Modal = ({ children }) => (
<div>
<div className="modal-dialog modal-lg" role="document">
<div className="modal-content">{storyFn()}</div>
<div className="modal-content">{children}</div>
</div>
</div>
))
.add("OverviewModal", () => {
const alertStore = new AlertStore([]);
);
MockGrid(alertStore);
const alertStore = new AlertStore([]);
MockGrid(alertStore);
return <OverviewModalContent alertStore={alertStore} onHide={() => {}} />;
});
const emptyAlertStore = new AlertStore([]);
return (
<div>
<Modal>
<OverviewModalContent alertStore={alertStore} onHide={() => {}} />
</Modal>
<Modal>
<OverviewModalContent alertStore={emptyAlertStore} onHide={() => {}} />
</Modal>
</div>
);
});
@@ -177,6 +177,45 @@ storiesOf("SilenceModal", module)
overwriteRoutes: true
});
return (
<Modal>
<SilenceModalContent
alertStore={alertStore}
silenceFormStore={silenceFormStore}
settingsStore={settingsStore}
onHide={() => {}}
onDeleteModalClose={() => {}}
/>
</Modal>
);
})
.add("Empty Browser", () => {
const alertStore = new AlertStore([]);
const settingsStore = new Settings();
const silenceFormStore = new SilenceFormStore();
silenceFormStore.tab.current = SilenceTabNames.Browser;
alertStore.data.upstreams = {
instances: [
{
name: "am1",
cluster: "am",
clusterMembers: ["am1"],
uri: "http://localhost:9093",
publicURI: "http://example.com",
error: "",
version: "0.15.3",
headers: {}
}
],
clusters: { am: ["am1"] }
};
fetchMock.mock("begin:/silences.json?", [], {
overwriteRoutes: true
});
return (
<Modal>
<SilenceModalContent
+2 -2
View File
@@ -20,7 +20,7 @@ const InternalError: StatelessComponent<InternalErrorProps> = props => (
<div className="jumbotron text-center bg-primary my-4">
<div className="container-fluid">
<h1 className="display-1 my-5">
<FontAwesomeIcon className="text-danger mr-2" icon={faBomb} />
<FontAwesomeIcon className="text-danger mr-4" icon={faBomb} />
<span className="text-muted">Internal error</span>
</h1>
<p className="lead text-white bg-secondary px-1 py-3 rounded">
@@ -102,4 +102,4 @@ class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
}
}
export { ErrorBoundary };
export { ErrorBoundary, InternalError };
@@ -5,3 +5,7 @@
margin-right: -50%;
transform: translate(-50%, -50%);
}
.screen-center-icon-big {
font-size: 14rem;
}
+1
View File
@@ -83,6 +83,7 @@ $datepicker__day-hover-color: $white;
@import "Styles/Components/Alert";
@import "Styles/Components/AlertGroup";
@import "Styles/Components/BaseLabel";
@import "Styles/Components/CenteredMessage";
@import "Styles/Components/FilterInputLabel";
@import "Styles/Components/LabelWithPercent";
@import "Styles/Components/InputRange";
+1
View File
@@ -74,6 +74,7 @@ $datepicker__day-hover-color: $black;
@import "Styles/Components/Alert";
@import "Styles/Components/AlertGroup";
@import "Styles/Components/BaseLabel";
@import "Styles/Components/CenteredMessage";
@import "Styles/Components/FilterInputLabel";
@import "Styles/Components/LabelWithPercent";
@import "Styles/Components/InputRange";
+11
View File
@@ -7,3 +7,14 @@
position: relative !important;
float: none !important;
}
.screen-center {
position: unset !important;
top: unset !important;
left: unset !important;
margin-left: 0 !important;
margin-right: 0 !important;
padding-top: 2rem;
padding-bottom: 2rem;
transform: unset !important;
}
@@ -9,7 +9,7 @@ exports[`<ErrorBoundary /> matches snapshot 1`] = `
focusable=\\"false\\"
data-prefix=\\"fas\\"
data-icon=\\"bomb\\"
class=\\"svg-inline--fa fa-bomb fa-w-16 text-danger mr-2\\"
class=\\"svg-inline--fa fa-bomb fa-w-16 text-danger mr-4\\"
role=\\"img\\"
xmlns=\\"http://www.w3.org/2000/svg\\"
viewbox=\\"0 0 512 512\\"