From e60bf9911eff8fbb92e3444e4a71684e5f534d33 Mon Sep 17 00:00:00 2001 From: Benjamin Perez Date: Tue, 28 Sep 2021 22:55:43 -0500 Subject: [PATCH] Changed error modal snackbar Changed error modal snackbar to use a simplified style of global error snackbar. also fixed an issue where error was persistent if you closed the modalbox with an error present Signed-off-by: Benjamin Perez --- .../FormComponents/ModalError/ModalError.tsx | 248 ++++++++++++++++++ .../Common/ModalWrapper/ModalWrapper.tsx | 10 +- 2 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 portal-ui/src/screens/Console/Common/FormComponents/ModalError/ModalError.tsx diff --git a/portal-ui/src/screens/Console/Common/FormComponents/ModalError/ModalError.tsx b/portal-ui/src/screens/Console/Common/FormComponents/ModalError/ModalError.tsx new file mode 100644 index 0000000000..aa36ed7849 --- /dev/null +++ b/portal-ui/src/screens/Console/Common/FormComponents/ModalError/ModalError.tsx @@ -0,0 +1,248 @@ +// This file is part of MinIO Console Server +// Copyright (c) 2021 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +// This file is part of MinIO Console Server +// Copyright (c) 2021 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import React, { Fragment, useState, useEffect, useCallback } from "react"; +import { connect } from "react-redux"; +import get from "lodash/get"; +import ArrowRightIcon from "@material-ui/icons/ArrowRight"; +import ErrorOutlineIcon from "@material-ui/icons/ErrorOutline"; +import CloseIcon from "@material-ui/icons/Close"; +import { createStyles, Theme, withStyles } from "@material-ui/core/styles"; +import { AppState } from "../../../../../store"; +import { setErrorSnackMessage } from "../../../../../actions"; +import { snackBarMessage } from "../../../../../types"; +import { + setModalErrorSnackMessage, + setModalSnackMessage, +} from "../../../../../actions"; + +interface ImodalErrorProps { + customStyle?: any; + classes: any; + modalSnackMessage: snackBarMessage; + displayErrorMessage: typeof setErrorSnackMessage; +} + +const styles = (theme: Theme) => + createStyles({ + modalErrorContainer: { + position: "absolute", + marginTop: 10, + width: "80%", + backgroundColor: "#fff", + border: "#C72C48 1px solid", + borderLeftWidth: 12, + borderRadius: 3, + zIndex: 1000, + padding: "10px 15px", + left: "50%", + transform: "translateX(-50%)", + opacity: 0, + transitionDuration: "0.2s", + }, + modalErrorShow: { + opacity: 1, + }, + closeButton: { + position: "absolute", + right: 5, + fontSize: "small", + border: 0, + backgroundColor: "#fff", + cursor: "pointer", + }, + errorTitle: { + display: "flex", + alignItems: "center", + }, + errorLabel: { + color: "#000", + fontSize: 18, + fontWeight: 500, + marginLeft: 5, + marginRight: 25, + }, + messageIcon: { + color: "#C72C48", + display: "flex", + "& svg": { + width: 32, + height: 32, + }, + }, + simpleError: { + marginTop: 5, + padding: "2px 5px", + fontSize: 16, + color: "#000", + }, + detailsButton: { + color: "#9C9C9C", + display: "flex", + alignItems: "center", + border: 0, + backgroundColor: "transparent", + paddingLeft: 5, + fontSize: 14, + transformDuration: "0.3s", + cursor: "pointer", + }, + extraDetailsContainer: { + fontStyle: "italic", + color: "#9C9C9C", + lineHeight: 0, + padding: "0 10px", + transition: "all .2s ease-in-out", + overflow: "hidden", + }, + extraDetailsOpen: { + lineHeight: 1, + padding: "3px 10px", + }, + arrowElement: { + marginLeft: -5, + }, + arrowOpen: { + transform: "rotateZ(90deg)", + transformDuration: "0.3s", + }, + }); + +var timerI: any; + +const startHideTimer = (callbackFunction: () => void) => { + timerI = setInterval(callbackFunction, 10000); +}; + +const stopHideTimer = () => { + clearInterval(timerI); +}; + +const ModalError = ({ + classes, + modalSnackMessage, + displayErrorMessage, + customStyle, +}: ImodalErrorProps) => { + const [detailsOpen, setDetailsOpen] = useState(false); + const [displayErrorMsg, setDisplayErrorMsg] = useState(false); + + const closeErrorMessage = useCallback(() => { + setDisplayErrorMsg(false); + }, []); + + useEffect(() => { + if (!displayErrorMsg) { + displayErrorMessage({ detailedError: "", errorMessage: "" }); + setDetailsOpen(false); + //clearInterval(timerI); + } + }, [displayErrorMessage, displayErrorMsg]); + + useEffect(() => { + if ( + modalSnackMessage.message !== "" && + modalSnackMessage.type === "error" + ) { + //Error message received, we trigger the animation + setDisplayErrorMsg(true); + //startHideTimer(closeErrorMessage); + } + }, [closeErrorMessage, modalSnackMessage.message, modalSnackMessage.type]); + + const detailsToggle = () => { + setDetailsOpen(!detailsOpen); + }; + + const message = get(modalSnackMessage, "message", ""); + const messageDetails = get(modalSnackMessage, "detailedErrorMsg", ""); + + if (modalSnackMessage.type !== "error" || message === "") { + return null; + } + + return ( + +
startHideTimer(closeErrorMessage)} + > + +
+ + + + {message} +
+ {messageDetails !== "" && ( + +
+ +
+
+ {messageDetails} +
+
+ )} +
+
+ ); +}; + +const mapState = (state: AppState) => ({ + modalSnackMessage: state.system.modalSnackBar, +}); + +const mapDispatchToProps = { + displayErrorMessage: setModalErrorSnackMessage, +}; + +const connector = connect(mapState, mapDispatchToProps); + +export default connector(withStyles(styles)(ModalError)); diff --git a/portal-ui/src/screens/Console/Common/ModalWrapper/ModalWrapper.tsx b/portal-ui/src/screens/Console/Common/ModalWrapper/ModalWrapper.tsx index 398b9e936e..11263d4e77 100644 --- a/portal-ui/src/screens/Console/Common/ModalWrapper/ModalWrapper.tsx +++ b/portal-ui/src/screens/Console/Common/ModalWrapper/ModalWrapper.tsx @@ -23,6 +23,7 @@ import { snackBarCommon } from "../FormComponents/common/styleLibrary"; import { AppState } from "../../../../store"; import { snackBarMessage } from "../../../../types"; import { setModalSnackMessage } from "../../../../actions"; +import ModalError from "../FormComponents/ModalError/ModalError"; interface IModalProps { classes: any; @@ -124,6 +125,10 @@ const ModalWrapper = ({ }: IModalProps) => { const [openSnackbar, setOpenSnackbar] = useState(false); + useEffect(() => { + setModalSnackMessage(""); + }, [setModalSnackMessage]); + useEffect(() => { if (modalSnackMessage) { if (modalSnackMessage.message === "") { @@ -131,7 +136,9 @@ const ModalWrapper = ({ return; } // Open SnackBar - setOpenSnackbar(true); + if(modalSnackMessage.type !== "error") { + setOpenSnackbar(true); + } } }, [modalSnackMessage]); @@ -169,6 +176,7 @@ const ModalWrapper = ({ {...customSize} >
+