Skip to content

Commit

Permalink
Merge pull request #60 from fabric-testbed/rel1.6
Browse files Browse the repository at this point in the history
Rel1.6 changes
  • Loading branch information
kthare10 authored Jan 2, 2024
2 parents 25a2736 + b470181 commit 7b90250
Show file tree
Hide file tree
Showing 53 changed files with 4,603 additions and 838 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,4 @@ docker_build/
# Pyre type checker
.pyre/
env
.idea
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
# SOFTWARE.
#
# Author Komal Thareja ([email protected])
FROM python:3
FROM python:3.11
MAINTAINER Komal Thareja<[email protected]>

RUN mkdir -p /usr/src/app
Expand Down
58 changes: 54 additions & 4 deletions cm-app/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ import Header from "./components/Header";
import Home from './pages/Home';
import CredentialManagerPage from './pages/CredentialManagerPage';
import Footer from "./components/Footer";
import "./styles/App.scss";
import { getWhoAmI } from "./services/coreApiService.js";
import { toast } from "react-toastify";
import { toast, ToastContainer } from "react-toastify";
import SessionTimeoutModal from "./components/Modals/SessionTimeoutModal";
import { default as cmData } from "./services/cmData.json";
import 'react-toastify/dist/ReactToastify.css';
import "./styles/App.scss";

class App extends React.Component {
state = {
cmUserStatus: ""
cmUserStatus: "",
showSessionTimeoutModal1: false,
showSessionTimeoutModal2: false,
}

async componentDidMount() {
Expand All @@ -21,6 +26,25 @@ class App extends React.Component {
if (user.enrolled) {
localStorage.setItem("cmUserID", user.uuid);
localStorage.setItem("cmUserStatus", "active");
try {
// after user logs in for 3hr55min, pop up first session time-out modal
const sessionTimeoutInterval1 = setInterval(() =>
this.setState({showSessionTimeoutModal1: true})
, cmData["5minBeforeCookieExpires"]);

// after user logs in for 3hr59min, pop up second session time-out modal
const sessionTimeoutInterval2 = setInterval(() => {
this.setState({
showSessionTimeoutModal1: false,
showSessionTimeoutModal2: true,
})
}, cmData["1minBeforeCookieExpires"]);

localStorage.setItem("sessionTimeoutInterval1", sessionTimeoutInterval1);
localStorage.setItem("sessionTimeoutInterval2", sessionTimeoutInterval2);
} catch (err) {
console.log("Failed to get current user's information.");
}
} else {
toast.error("Please enroll to FABRIC in the Portal first.");
}
Expand All @@ -33,19 +57,45 @@ class App extends React.Component {
}

render() {
const { cmUserStatus } = this.state;
const { cmUserStatus, showSessionTimeoutModal1, showSessionTimeoutModal2 } = this.state;

return (
<div className="App">
<Router>
<Header cmUserStatus={cmUserStatus} />
{
showSessionTimeoutModal1 &&
<SessionTimeoutModal
modalId={1}
timeLeft={300000}
/>
}
{
showSessionTimeoutModal2 &&
<SessionTimeoutModal
modalId={2}
timeLeft={60000}
/>
}
<Routes>
<Route path="/" element={<Home cmUserStatus={cmUserStatus} />} />
<Route path="/login" element={<Home cmUserStatus={cmUserStatus} />} />
<Route path="/logout" element={<Home cmUserStatus={cmUserStatus} />} />
<Route path="/cm" element={<CredentialManagerPage cmUserStatus={cmUserStatus}/>} />
</Routes>
<Footer />
<ToastContainer
position="top-right"
autoClose={5000}
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
theme="colored"
/>
</Router>
</div>
);
Expand Down
100 changes: 100 additions & 0 deletions cm-app/src/components/Modals/SessionTimeoutModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import React, { Component } from "react";
import Modal from 'react-bootstrap/Modal'
import Button from 'react-bootstrap/Button'
import clearLocalStorage from "../../utils/clearLocalStorage";

class SessionTimeoutModal extends Component {
state = {
show: true,
minutes: 0,
seconds: 0,
}

handleLogout = () => {
this.setState({ show: false });
clearLocalStorage();
window.location.href = "/logout";
}

handleClose = () => {
this.setState({ show: false });
}

componentDidMount() {
let minutes = Math.floor(this.props.timeLeft / 60000);
let seconds = ((this.props.timeLeft % 60000) / 1000).toFixed(0);
this.setState({ minutes, seconds })

let countdownTimer = setInterval(() => {
if(seconds > 0){
seconds--;
} else if (minutes > 0){
minutes--;
seconds = 59;
} else {
minutes = 0;
seconds = 0;
}
this.setState({ minutes, seconds })
}, 1000);

localStorage.setItem("countdownTimerIntervalId", countdownTimer);
}

parseTimeStr = (minutes, seconds) => {
if (minutes > 0 && seconds > 0) {
return `${minutes} minute${minutes > 1 ? "s" : ""} ${seconds} second${seconds > 1 ? "s" : ""}`;
}

if (minutes > 0 && seconds === 0) {
return `${minutes} minute${minutes > 1 ? "s" : ""}`;
}

if (minutes === 0 && seconds > 1) {
return `${seconds} second${seconds > 1 ? "s" : ""}`;
}

if (minutes === 0 && seconds === 1) {
clearInterval(localStorage.getItem("countdownTimerIntervalId"));
clearInterval(localStorage.getItem(`sessionTimeoutIntervalId${this.props.modalId}`));
this.handleLogout();
}
}

render() {
let { minutes, seconds, show } = this.state;
return (
<div>
{
this.props.timeLeft > 0 && <Modal
size="lg"
show={show}
onHide={this.handleClose}
backdrop="static"
keyboard={false}
>
<Modal.Header closeButton>
<Modal.Title>Session Timeout</Modal.Title>
</Modal.Header>
<Modal.Body>
<p id="countdownTimerModal">
The current session is about to expire in <span className="text-danger font-weight-bold">
{this.parseTimeStr(minutes, seconds)}</span>.
Please save your work to prevent loss of data.
</p>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={this.handleClose}>Close</Button>
<Button variant="primary" onClick={this.handleLogout}>
Logout
</Button>
</Modal.Footer>
</Modal>

}
</div>
);
}
}

export default SessionTimeoutModal;
61 changes: 61 additions & 0 deletions cm-app/src/components/SpinnerFullPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, { useRef } from "react";
import Spinner from 'react-bootstrap/Spinner';
import Overlay from 'react-bootstrap/Overlay';
import Button from 'react-bootstrap/Button';
import { Link } from "react-router-dom";

function SpinnerFullPage(props){
const target = useRef(null);
const {text, showSpinner, btnText, btnPath} = props;

return (
<div>
<Button ref={target}
style={{
position:"absolute",
top: 0,
left: 0,
width: "0.1rem",
height: "0.1rem",
backgroundColor: "transparent",
border: "none",
overflow: "hidden",
outline: "none"
}}
>
Hidden
</Button>
<Overlay target={target.current} show={showSpinner} placement="auto">
{({ placement, arrowProps, show: _show, popper, ...props }) => (
<div
{...props}
style={{
backgroundColor: 'rgba(0, 0, 0, 0.5)',
margin: "-0.4rem 0 0 0",
width: "100%",
height: "100vh",
overflow: "hidden",
color: 'white',
fontSize: "2rem",
...props.style,
}}
className="d-flex flex-column align-items-center justify-content-center"
>
<div className="d-flex flex-column align-items-center justify-content-center mx-5 px-5">
<span className="mr-2 mb-2">{text}</span>
<Spinner animation="border" role="status" variant="white" />
</div>
{
btnText && btnText !== "" &&
<Link to={btnPath} className="btn btn-primary my-4">
{ btnText }
</Link>
}
</div>
)}
</Overlay>
</div>
);
};

export default SpinnerFullPage;
21 changes: 21 additions & 0 deletions cm-app/src/components/SpinnerWithText.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react";
import Spinner from 'react-bootstrap/Spinner';

const SpinnerWithText = (props) => {
return (
<div className="d-flex flex-row justify-content-center my-2">
<Spinner
as="span"
animation="border"
size="sm"
role="status"
aria-hidden="true"
variant="primary"
className="mt-1"
/>
<span className="text-primary ml-2"><b>{props.text}</b></span>
</div>
);
};

export default SpinnerWithText;
Loading

0 comments on commit 7b90250

Please sign in to comment.