diff --git a/public/locales/en/translations.json b/public/locales/en/translations.json index 93db929..07e9abd 100644 --- a/public/locales/en/translations.json +++ b/public/locales/en/translations.json @@ -15,6 +15,7 @@ "Menu": { "Home": "Home", "Sessions": "Sessions", + "ReleaseNotes": "Release notes", "About": "About" }, "General": { @@ -43,5 +44,9 @@ "PathOverwriteTooltip": "Option by which the base path of the application is automatically overwritten in all http text responses received from it." } } + }, + "ReleaseNotes": { + "Title": "Release notes", + "Version": "Version" } } diff --git a/public/locales/ro/translations.json b/public/locales/ro/translations.json index b076f59..3c3b415 100644 --- a/public/locales/ro/translations.json +++ b/public/locales/ro/translations.json @@ -6,6 +6,7 @@ "Menu": { "Home": "Acasă", "Sessions": "Sesiuni", + "ReleaseNotes": "Note lansare", "About": "Despre" }, "General": { @@ -34,5 +35,9 @@ "PathOverwriteTooltip": "Opțiune prin care calea de bază a aplicației este suprascrisă automat în toate răspunsurile de text http primite de la aceasta." } } + }, + "ReleaseNotes": { + "Title": "Note lansare", + "Version": "Versiune" } } diff --git a/src/components/App.js b/src/components/App.js index d913e7f..455faff 100644 --- a/src/components/App.js +++ b/src/components/App.js @@ -7,6 +7,7 @@ import PageNotFound from "./PageNotFound"; import { ToastContainer } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; import SessionContainer from "../features/session/components/SessionContainer"; +import ReleaseNotesContainer from "../features/releaseNotes/components/ReleaseNotesContainer"; function App() { const contentStyle = { @@ -23,6 +24,7 @@ function App() { + diff --git a/src/components/common/styles/divStyles.js b/src/components/common/styles/divStyles.js new file mode 100644 index 0000000..c7281ae --- /dev/null +++ b/src/components/common/styles/divStyles.js @@ -0,0 +1,11 @@ +const styles = (theme) => ({ + root: { + width: "100%" + }, + heading: { + fontSize: theme.typography.pxToRem(15), + fontWeight: theme.typography.fontWeightRegular + } +}); + +export default styles; diff --git a/src/features/session/styles/gridStyles.js b/src/components/common/styles/gridStyles.js similarity index 100% rename from src/features/session/styles/gridStyles.js rename to src/components/common/styles/gridStyles.js diff --git a/src/features/session/styles/tableStyles.js b/src/components/common/styles/tableStyles.js similarity index 100% rename from src/features/session/styles/tableStyles.js rename to src/components/common/styles/tableStyles.js diff --git a/src/components/home/HomePage.js b/src/components/home/HomePage.js index 3e8d067..2e800c9 100644 --- a/src/components/home/HomePage.js +++ b/src/components/home/HomePage.js @@ -5,15 +5,13 @@ import { bindActionCreators } from "redux"; import PropTypes from "prop-types"; import { loadSystemDateTime, - loadSystemVersion, - loadReleaseNotes + loadSystemVersion } from "../../features/system/actionCreators"; const HomePage = ({ actions }) => { const testButton = () => { actions.loadSystemDateTime(); actions.loadSystemVersion(); - actions.loadReleaseNotes(); }; return ( @@ -46,7 +44,7 @@ function mapStateToProps() { function mapDispatchToProps(dispatch) { return { actions: bindActionCreators( - { loadSystemDateTime, loadSystemVersion, loadReleaseNotes }, + { loadSystemDateTime, loadSystemVersion }, dispatch ) }; diff --git a/src/components/layout/Navigation.js b/src/components/layout/Navigation.js index f521827..0797602 100644 --- a/src/components/layout/Navigation.js +++ b/src/components/layout/Navigation.js @@ -17,6 +17,10 @@ const Navigation = () => { {t("Menu.Sessions")} {" | "} + + {t("Menu.ReleaseNotes")} + + {" | "} {t("Menu.About")} diff --git a/src/features/releaseNotes/actionCreators.js b/src/features/releaseNotes/actionCreators.js new file mode 100644 index 0000000..dc45b6b --- /dev/null +++ b/src/features/releaseNotes/actionCreators.js @@ -0,0 +1,18 @@ +import * as types from "./actionTypes"; +import api from "./api"; +import { sendHttpRequest } from "../../redux/actions/httpActions"; + +export function loadReleaseNotes() { + return async function (dispatch, getState) { + try { + const notes = getState().releaseNotes; + if (notes && (notes.loading || notes.loaded)) return; + + dispatch({ type: types.LOAD_RELEASE_NOTES_STARTED }); + const data = await dispatch(sendHttpRequest(api.getReleaseNotes())); + dispatch({ type: types.LOAD_RELEASE_NOTES_SUCCESS, payload: data }); + } catch (error) { + throw error; + } + }; +} diff --git a/src/features/releaseNotes/actionTypes.js b/src/features/releaseNotes/actionTypes.js new file mode 100644 index 0000000..de63cdc --- /dev/null +++ b/src/features/releaseNotes/actionTypes.js @@ -0,0 +1,2 @@ +export const LOAD_RELEASE_NOTES_STARTED = "LOAD_RELEASE_NOTES_STARTED"; +export const LOAD_RELEASE_NOTES_SUCCESS = "LOAD_RELEASE_NOTES_SUCCESS"; diff --git a/src/features/releaseNotes/api.js b/src/features/releaseNotes/api.js new file mode 100644 index 0000000..d6a64cd --- /dev/null +++ b/src/features/releaseNotes/api.js @@ -0,0 +1,8 @@ +import { get } from "../../api/axiosApi"; +const baseUrl = process.env.REVERSE_PROXY_API_URL + "/system"; + +const getReleaseNotes = () => get(`${baseUrl}/release-notes`); + +export default { + getReleaseNotes +}; diff --git a/src/features/releaseNotes/components/ReleaseNotesContainer.js b/src/features/releaseNotes/components/ReleaseNotesContainer.js new file mode 100644 index 0000000..0994868 --- /dev/null +++ b/src/features/releaseNotes/components/ReleaseNotesContainer.js @@ -0,0 +1,36 @@ +import React, { useEffect } from "react"; +import { connect } from "react-redux"; +import { bindActionCreators } from "redux"; +import PropTypes from "prop-types"; +import { loadReleaseNotes } from "../actionCreators"; +import ReleaseNotesListComponent from "./ReleaseNotesListComponent"; + +const ReleaseNotesContainer = ({ actions, releaseNotes }) => { + useEffect(() => { + actions.loadReleaseNotes(); + }, []); + + return ; +}; + +ReleaseNotesContainer.propTypes = { + actions: PropTypes.object.isRequired, + releaseNotes: PropTypes.array.isRequired +}; + +function mapStateToProps(state) { + return { + releaseNotes: state.releaseNotes + }; +} + +function mapDispatchToProps(dispatch) { + return { + actions: bindActionCreators({ loadReleaseNotes }, dispatch) + }; +} + +export default connect( + mapStateToProps, + mapDispatchToProps +)(ReleaseNotesContainer); diff --git a/src/features/releaseNotes/components/ReleaseNotesListComponent.js b/src/features/releaseNotes/components/ReleaseNotesListComponent.js new file mode 100644 index 0000000..1f29d04 --- /dev/null +++ b/src/features/releaseNotes/components/ReleaseNotesListComponent.js @@ -0,0 +1,50 @@ +import React from "react"; +import { makeStyles } from "@material-ui/core/styles"; +import ExpansionPanel from "@material-ui/core/ExpansionPanel"; +import ExpansionPanelSummary from "@material-ui/core/ExpansionPanelSummary"; +import ExpansionPanelDetails from "@material-ui/core/ExpansionPanelDetails"; +import ExpandMoreIcon from "@material-ui/icons/ExpandMore"; +import PropTypes from "prop-types"; +import Spinner from "../../../components/common/Spinner"; +import { useTranslation } from "react-i18next"; +import ReleaseNotesSummary from "./ReleaseNotesSummary"; +import styles from "../../../components/common/styles/divStyles"; + +const useStyles = makeStyles(styles); + +const ReleaseNotesListComponent = ({ releaseNotes }) => { + const classes = useStyles(); + const { t } = useTranslation(); + + return ( +
+

{t("ReleaseNotes.Title")}

+ {releaseNotes.loading ? ( + + ) : ( + releaseNotes.loaded && + releaseNotes.map((note) => { + return ( + + } + id={`panel-${note.version}-header`} + > + + + +
TO DO
+
+
+ ); + }) + )} +
+ ); +}; + +ReleaseNotesListComponent.propTypes = { + releaseNotes: PropTypes.array.isRequired +}; + +export default ReleaseNotesListComponent; diff --git a/src/features/releaseNotes/components/ReleaseNotesSummary.js b/src/features/releaseNotes/components/ReleaseNotesSummary.js new file mode 100644 index 0000000..0ee7087 --- /dev/null +++ b/src/features/releaseNotes/components/ReleaseNotesSummary.js @@ -0,0 +1,33 @@ +import React from "react"; +import PropTypes from "prop-types"; +import { Grid } from "@material-ui/core"; +import { makeStyles } from "@material-ui/core/styles"; +import { useTranslation } from "react-i18next"; +import styles from "../../../components/common/styles/gridStyles"; + +const useStyles = makeStyles(styles); + +const ReleaseNotesSummary = ({ releaseNote }) => { + const classes = useStyles(); + const { t } = useTranslation(); + + return ( + + + {`${t("ReleaseNotes.Version")}: `} + {releaseNote.version} + + + + {`${t("ReleaseNotes.Version")}: `} + {releaseNote.version} + + + ); +}; + +ReleaseNotesSummary.propTypes = { + releaseNote: PropTypes.object.isRequired +}; + +export default ReleaseNotesSummary; diff --git a/src/features/releaseNotes/reducer.js b/src/features/releaseNotes/reducer.js new file mode 100644 index 0000000..4fa5355 --- /dev/null +++ b/src/features/releaseNotes/reducer.js @@ -0,0 +1,18 @@ +import * as types from "./actionTypes"; +import initialState from "../../redux/reducers/initialState"; + +export default function releaseNotesReducer( + state = initialState.releaseNotes, + action +) { + switch (action.type) { + case types.LOAD_RELEASE_NOTES_STARTED: + return Object.assign([], { loading: true, loaded: false }); + + case types.LOAD_RELEASE_NOTES_SUCCESS: + return Object.assign(action.payload, { loading: false, loaded: true }); + + default: + return state; + } +} diff --git a/src/features/session/components/ForwardOptionsComponent.js b/src/features/session/components/ForwardOptionsComponent.js index 438c41f..780955f 100644 --- a/src/features/session/components/ForwardOptionsComponent.js +++ b/src/features/session/components/ForwardOptionsComponent.js @@ -9,7 +9,7 @@ import TableRow from "@material-ui/core/TableRow"; import Paper from "@material-ui/core/Paper"; import Tooltip from "@material-ui/core/Tooltip"; import { useTranslation } from "react-i18next"; -import styles from "../styles/tableStyles"; +import styles from "../../../components/common/styles/tableStyles"; import { StyledTableCell, StyledTableRow diff --git a/src/features/session/components/SessionForwardsComponent.js b/src/features/session/components/SessionForwardsComponent.js index 711a0d4..a99d364 100644 --- a/src/features/session/components/SessionForwardsComponent.js +++ b/src/features/session/components/SessionForwardsComponent.js @@ -14,7 +14,7 @@ import Tooltip from "@material-ui/core/Tooltip"; import SessionForwardsHeaderComponent from "./SessionForwardsHeaderComponent"; import { Grid } from "@material-ui/core"; import { useTranslation } from "react-i18next"; -import styles from "../styles/tableStyles"; +import styles from "../../../components/common/styles/tableStyles"; import { StyledTableCell, StyledTableRow diff --git a/src/features/session/components/SessionForwardsHeaderComponent.js b/src/features/session/components/SessionForwardsHeaderComponent.js index 773e984..4b05c37 100644 --- a/src/features/session/components/SessionForwardsHeaderComponent.js +++ b/src/features/session/components/SessionForwardsHeaderComponent.js @@ -3,7 +3,7 @@ import PropTypes from "prop-types"; import { Grid } from "@material-ui/core"; import { makeStyles } from "@material-ui/core/styles"; import { useTranslation } from "react-i18next"; -import styles from "../styles/gridStyles"; +import styles from "../../../components/common/styles/gridStyles"; const useStyles = makeStyles(styles); diff --git a/src/features/session/components/SessionListComponent.js b/src/features/session/components/SessionListComponent.js index ae59028..d4e603c 100644 --- a/src/features/session/components/SessionListComponent.js +++ b/src/features/session/components/SessionListComponent.js @@ -9,16 +9,9 @@ import SessionSummary from "./SessionSummary"; import SessionForwardsComponent from "./SessionForwardsComponent"; import Spinner from "../../../components/common/Spinner"; import { useTranslation } from "react-i18next"; +import styles from "../../../components/common/styles/divStyles"; -const useStyles = makeStyles((theme) => ({ - root: { - width: "100%" - }, - heading: { - fontSize: theme.typography.pxToRem(15), - fontWeight: theme.typography.fontWeightRegular - } -})); +const useStyles = makeStyles(styles); const SessionListComponent = ({ sessions, diff --git a/src/features/session/components/SessionSummary.js b/src/features/session/components/SessionSummary.js index a55bf78..7f3532e 100644 --- a/src/features/session/components/SessionSummary.js +++ b/src/features/session/components/SessionSummary.js @@ -4,7 +4,7 @@ import { Grid } from "@material-ui/core"; import { makeStyles } from "@material-ui/core/styles"; import ActiveIcon from "../../../components/common/ActiveIcon"; import { useTranslation } from "react-i18next"; -import styles from "../styles/gridStyles"; +import styles from "../../../components/common/styles/gridStyles"; const useStyles = makeStyles(styles); @@ -13,50 +13,48 @@ const SessionSummary = ({ session }) => { const { t } = useTranslation(); return ( - <> - - - {`${t("Session.Session")}: `} - {session.sessionId} - - - {`${t("Session.Active")}: `} - - - - {`${t("Session.StartDate")}: `} - - {t("DATE_FORMAT", { - date: { value: session.startDate, format: "DD-MM-YYYY HH:mm:ss" } - })} - - - - - {`${t("Session.RunningTime")}: `} - {session.runningTime} - - - - {`${t("Session.Host")}: `} - {session.hostName} - - - - {`${t("Session.StopDate")}: `} - - {session.stopDate - ? t("DATE_FORMAT", { - date: { - value: session.stopDate, - format: "DD-MM-YYYY HH:mm:ss" - } - }) - : "---"} - - + + + {`${t("Session.Session")}: `} + {session.sessionId} - + + {`${t("Session.Active")}: `} + + + + {`${t("Session.StartDate")}: `} + + {t("DATE_FORMAT", { + date: { value: session.startDate, format: "DD-MM-YYYY HH:mm:ss" } + })} + + + + + {`${t("Session.RunningTime")}: `} + {session.runningTime} + + + + {`${t("Session.Host")}: `} + {session.hostName} + + + + {`${t("Session.StopDate")}: `} + + {session.stopDate + ? t("DATE_FORMAT", { + date: { + value: session.stopDate, + format: "DD-MM-YYYY HH:mm:ss" + } + }) + : "---"} + + + ); }; diff --git a/src/features/system/actionCreators.js b/src/features/system/actionCreators.js index cb303d3..479717c 100644 --- a/src/features/system/actionCreators.js +++ b/src/features/system/actionCreators.js @@ -23,14 +23,3 @@ export function loadSystemVersion() { } }; } - -export function loadReleaseNotes() { - return async function (dispatch) { - try { - const data = await dispatch(sendHttpRequest(api.getReleaseNotes())); - dispatch({ type: types.LOAD_RELEASE_NOTES_SUCCESS, payload: data }); - } catch (error) { - throw error; - } - }; -} diff --git a/src/features/system/actionTypes.js b/src/features/system/actionTypes.js index b2a45c3..c422e2f 100644 --- a/src/features/system/actionTypes.js +++ b/src/features/system/actionTypes.js @@ -1,3 +1,2 @@ export const LOAD_SYSTEM_DATETIME_SUCCESS = "LOAD_SYSTEM_DATETIME_SUCCESS"; export const LOAD_SYSTEM_VERSION_SUCCESS = "LOAD_SYSTEM_VERSION_SUCCESS"; -export const LOAD_RELEASE_NOTES_SUCCESS = "LOAD_RELEASE_NOTES_SUCCESS"; diff --git a/src/features/system/api.js b/src/features/system/api.js index 7e8dad2..684b3ac 100644 --- a/src/features/system/api.js +++ b/src/features/system/api.js @@ -3,10 +3,8 @@ const baseUrl = process.env.REVERSE_PROXY_API_URL + "/system"; const getSystemDateTime = () => get(`${baseUrl}/datetime`); const getSystemVersion = () => get(`${baseUrl}/version`); -const getReleaseNotes = () => get(`${baseUrl}/release-notes`); export default { getSystemDateTime, - getSystemVersion, - getReleaseNotes + getSystemVersion }; diff --git a/src/features/system/reducer.js b/src/features/system/reducer.js index 7bcef8e..1199eab 100644 --- a/src/features/system/reducer.js +++ b/src/features/system/reducer.js @@ -14,13 +14,6 @@ export default function systemReducer(state = initialState.system, action) { ...state, ...action.payload }; - - case types.LOAD_RELEASE_NOTES_SUCCESS: - return { - ...state, - releaseNotes: action.payload - }; - default: return state; } diff --git a/src/redux/reducers/index.js b/src/redux/reducers/index.js index 2c72f7a..f42ef8e 100644 --- a/src/redux/reducers/index.js +++ b/src/redux/reducers/index.js @@ -5,11 +5,13 @@ import { sessionsReducer, forwardsReducer } from "../../features/session/reducers"; +import releaseNotesReducer from "../../features/releaseNotes/reducer"; const rootReducer = combineReducers({ system: systemReducer, sessions: sessionsReducer, forwards: forwardsReducer, + releaseNotes: releaseNotesReducer, ajaxCallsInProgress: ajaxStatusReducer }); diff --git a/src/redux/reducers/initialState.js b/src/redux/reducers/initialState.js index 12f8350..b8ca7c3 100644 --- a/src/redux/reducers/initialState.js +++ b/src/redux/reducers/initialState.js @@ -2,5 +2,6 @@ export default { system: {}, sessions: Object.assign([], { loading: false, loaded: false }), forwards: {}, + releaseNotes: Object.assign([], { loading: false, loaded: false }), ajaxCallsInProgress: 0 };