Merged PR 60: System card
- System card - SessionsCount - SystemVersionComponentmaster
commit
9443907cba
|
@ -21,8 +21,10 @@ RUN npm install -g serve
|
|||
|
||||
# environment variables
|
||||
ENV Author="Tudor Stanciu"
|
||||
ARG APP_VERSION=0.0.0.0
|
||||
ARG APP_VERSION=0.0.0
|
||||
ARG APP_DATE=1900-01-01
|
||||
ENV APP_VERSION=${APP_VERSION}
|
||||
ENV APP_DATE=${REACT_APP_DATE}
|
||||
|
||||
#set workdir to root
|
||||
WORKDIR /
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
const dev = {
|
||||
NODE_ENV: "development",
|
||||
APP_VERSION: "0.0.0",
|
||||
APP_DATE: "1900-01-01",
|
||||
REVERSE_PROXY_API_URL: "http://localhost:5050",
|
||||
CHATBOT_API_URL: "http://localhost:5061",
|
||||
REVERSE_PROXY_DOCS_URL: "https://toodle.ddns.net/hedgedoc/s/UkJ6S5NJz"
|
||||
|
@ -7,6 +9,8 @@ const dev = {
|
|||
|
||||
const prod = {
|
||||
NODE_ENV: "production",
|
||||
APP_VERSION: "0.0.0",
|
||||
APP_DATE: "1900-01-01",
|
||||
PUBLIC_URL: "/reverse-proxy",
|
||||
REVERSE_PROXY_API_URL: "https://toodle.ddns.net/reverse-proxy-api",
|
||||
CHATBOT_API_URL: "https://toodle.ddns.net/chatbot-api",
|
||||
|
|
|
@ -2,21 +2,14 @@
|
|||
Material UI v4: https://v4.mui.com/components/lists/
|
||||
https://v4.mui.com/components/material-icons/
|
||||
****************************************************************
|
||||
|
||||
withTranslation()(LegacyComponentClass)
|
||||
const { t } = this.props;
|
||||
TO DO:
|
||||
******
|
||||
Diagrama cu toate redirecturile care trec prin server;
|
||||
https://github.com/projectstorm/react-diagrams
|
||||
https://antonioru.github.io/beautiful-react-diagrams/#/Diagram%20Component
|
||||
****************************************************************
|
||||
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
function MyComponent() {
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
|
||||
|
||||
import { makeStyles, useTheme } from "@material-ui/core/styles";
|
||||
const theme = useTheme();
|
||||
|
||||
https://www.flaticon.com/free-icon/wizard_2534554?term=wizard&page=1&position=64
|
||||
|
||||
https://lucasbassetti.com.br/react-simple-chatbot/#/docs/previous-value
|
|
@ -106,13 +106,13 @@
|
|||
"Subtitle": "Expand to see details",
|
||||
"Thoughts": "This reverse proxy is the only open gate to a secret creation land. There any impulse or thought can fly free and can be materialized without limits. If you don't believe it, ask the ",
|
||||
"Wizard": "wizard",
|
||||
"ServerHostName": "Server host",
|
||||
"ApiHostName": "API host",
|
||||
"HostName": "Server host",
|
||||
"SessionsCount": "Sessions count",
|
||||
"Domain": "Domain",
|
||||
"ActiveSession": "Active session",
|
||||
"ActiveSessionSubtitle": "Expand to see forwards",
|
||||
"DDNSProvider": "Dynamic DNS Provider",
|
||||
"Details": "Details"
|
||||
"About": "About"
|
||||
},
|
||||
"Charts": {
|
||||
"Server": {
|
||||
|
@ -159,6 +159,24 @@
|
|||
}
|
||||
},
|
||||
"System": {
|
||||
"Title": "System",
|
||||
"Subtitle": "Expand to see details",
|
||||
"Server": {
|
||||
"HostName": "Server host",
|
||||
"Platform": "Server platform"
|
||||
},
|
||||
"Api": {
|
||||
"HostName": "API host",
|
||||
"Platform": "API platform"
|
||||
},
|
||||
"Description": "This system is composed of three micro services, each with a well-defined role. The server (reverse proxy) is the only one that can work completely independently of the others, the api and the UI being auxiliary and having a role of visualizing the server's activity.",
|
||||
"Versions": {
|
||||
"Title": "Component versions",
|
||||
"Server": "Server: {{version}}",
|
||||
"Api": "API: {{version}}",
|
||||
"Frontend": "UI: {{version}}"
|
||||
},
|
||||
"LastUpdateDate": "Last update date: {{date}}",
|
||||
"Components": {
|
||||
"Server": "Server:",
|
||||
"Api": "API:",
|
||||
|
|
|
@ -97,13 +97,13 @@
|
|||
"Subtitle": "Extindeţi pentru a vedea detalii",
|
||||
"Thoughts": "Acest reverse proxy este singura poartă deschisă către un teren secret al creației. Acolo orice impuls sau gând poate zbura liber și poate fi materializat fără limite. Dacă nu crezi, întreabă-l pe ",
|
||||
"Wizard": "vrăjitor",
|
||||
"ServerHostName": "Gazdă server",
|
||||
"ApiHostName": "Gazdă API",
|
||||
"HostName": "Gazdă server",
|
||||
"SessionsCount": "Număr sesiuni",
|
||||
"Domain": "Domeniu",
|
||||
"ActiveSession": "Sesiune activă",
|
||||
"ActiveSessionSubtitle": "Extindeţi pentru a vedea redirectările",
|
||||
"DDNSProvider": "Furnizor DNS dinamic",
|
||||
"Details": "Detalii"
|
||||
"About": "Despre"
|
||||
},
|
||||
"Charts": {
|
||||
"Server": {
|
||||
|
@ -150,6 +150,24 @@
|
|||
}
|
||||
},
|
||||
"System": {
|
||||
"Title": "Sistem",
|
||||
"Subtitle": "Extindeţi pentru a vedea detalii",
|
||||
"Server": {
|
||||
"HostName": "Gazdă server",
|
||||
"Platform": "Platformă server"
|
||||
},
|
||||
"Api": {
|
||||
"HostName": "Gazdă API",
|
||||
"Platform": "Platformă API"
|
||||
},
|
||||
"Description": "Acest sistem este compus din trei microservicii, fiecare avand un rol bine definit. Serverul (reverse proxy-ul) este singurul care poate funcționa complet independent de celelalte, API-ul și UI-ul fiind auxiliare și având un rol de vizualizare a activității serverului.",
|
||||
"Versions": {
|
||||
"Title": "Versiuni componente",
|
||||
"Server": "Server: {{version}}",
|
||||
"Api": "API: {{version}}",
|
||||
"Frontend": "UI: {{version}}"
|
||||
},
|
||||
"LastUpdateDate": "Data ultimei actualizări: {{date}}",
|
||||
"Components": {
|
||||
"Server": "Server:",
|
||||
"Api": "API:",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React from "react";
|
||||
import ServerContainer from "../../features/server/components/ServerContainer";
|
||||
import ActiveSessionContainer from "../../features/server/components/ActiveSessionContainer";
|
||||
import SystemContainer from "../../features/system/components/SystemContainer";
|
||||
|
||||
const HomePage = () => {
|
||||
return (
|
||||
|
@ -9,6 +10,10 @@ const HomePage = () => {
|
|||
<br />
|
||||
<br />
|
||||
<ActiveSessionContainer />
|
||||
<br />
|
||||
<br />
|
||||
<SystemContainer />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -4,17 +4,13 @@ import { bindActionCreators } from "redux";
|
|||
import PropTypes from "prop-types";
|
||||
import AboutComponent from "./AboutComponent";
|
||||
import TechnologiesComponent from "./TechnologiesComponent";
|
||||
import { useDocumentation } from "../../../hooks";
|
||||
|
||||
const AboutContainer = () => {
|
||||
const handleOpenDocumentation = event => {
|
||||
const url = process.env.REVERSE_PROXY_DOCS_URL;
|
||||
window.open(url, "_blank");
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
const { openDocumentation } = useDocumentation();
|
||||
return (
|
||||
<>
|
||||
<AboutComponent onOpenDocumentation={handleOpenDocumentation} />
|
||||
<AboutComponent onOpenDocumentation={openDocumentation} />
|
||||
<br />
|
||||
<br />
|
||||
<TechnologiesComponent />
|
||||
|
|
|
@ -13,17 +13,6 @@ export function loadServerData() {
|
|||
};
|
||||
}
|
||||
|
||||
export function loadSystemVersion() {
|
||||
return async function (dispatch) {
|
||||
try {
|
||||
const data = await dispatch(sendHttpRequest(api.getSystemVersion()));
|
||||
dispatch({ type: types.LOAD_SYSTEM_VERSION_SUCCESS, payload: data });
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function loadActiveSession() {
|
||||
return async function(dispatch) {
|
||||
try {
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
export const LOAD_SYSTEM_VERSION_SUCCESS = "LOAD_SYSTEM_VERSION_SUCCESS";
|
||||
export const LOAD_ACTIVE_SESSION_SUCCESS = "LOAD_ACTIVE_SESSION_SUCCESS";
|
||||
export const LOAD_SERVER_DATA_SUCCESS = "LOAD_SERVER_DATA_SUCCESS";
|
||||
|
|
|
@ -2,11 +2,9 @@ import { get } from "../../api/axiosApi";
|
|||
const baseUrl = process.env.REVERSE_PROXY_API_URL;
|
||||
|
||||
const getServerData = () => get(`${baseUrl}/server/data`);
|
||||
const getSystemVersion = () => get(`${baseUrl}/system/version`);
|
||||
const getActiveSession = () => get(`${baseUrl}/server/active-session`);
|
||||
|
||||
export default {
|
||||
getServerData,
|
||||
getSystemVersion,
|
||||
getActiveSession
|
||||
};
|
||||
|
|
|
@ -65,7 +65,7 @@ const ServerComponent = ({
|
|||
open={Boolean(anchorEl)}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<MenuItem onClick={handleDetailsClick}>{t("Server.Details")}</MenuItem>
|
||||
<MenuItem onClick={handleDetailsClick}>{t("Server.About")}</MenuItem>
|
||||
</Menu>
|
||||
<Card>
|
||||
<CardHeader
|
||||
|
|
|
@ -2,7 +2,7 @@ import React, { useEffect } from "react";
|
|||
import { connect } from "react-redux";
|
||||
import { bindActionCreators } from "redux";
|
||||
import PropTypes from "prop-types";
|
||||
import { loadServerData, loadSystemVersion } from "../actionCreators";
|
||||
import { loadServerData } from "../actionCreators";
|
||||
import ServerComponent from "./ServerComponent";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import { summonWizard } from "../../chatbot/actionCreators";
|
||||
|
@ -10,7 +10,6 @@ import { summonWizard } from "../../chatbot/actionCreators";
|
|||
const ServerContainer = ({ actions, data, serverHost, history }) => {
|
||||
useEffect(() => {
|
||||
actions.loadServerData();
|
||||
actions.loadSystemVersion();
|
||||
}, []);
|
||||
|
||||
const openAbout = event => {
|
||||
|
@ -50,10 +49,7 @@ function mapStateToProps(state) {
|
|||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(
|
||||
{ loadServerData, loadSystemVersion, summonWizard },
|
||||
dispatch
|
||||
)
|
||||
actions: bindActionCreators({ loadServerData, summonWizard }, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -24,13 +24,13 @@ const ServerSummary = ({
|
|||
</Grid>
|
||||
|
||||
<Grid item xs={6} sm={3} md={3}>
|
||||
{`${t("Server.ServerHostName")}: `}
|
||||
{`${t("Server.HostName")}: `}
|
||||
<span className={classes.value}>{serverHost || ""}</span>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6} sm={3} md={3}>
|
||||
{`${t("Server.ApiHostName")}: `}
|
||||
<span className={classes.value}>{data.hosts.api}</span>
|
||||
{`${t("Server.SessionsCount")}: `}
|
||||
<span className={classes.value}>{data.sessionsCount}</span>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6} sm={3} md={3}>
|
||||
|
|
|
@ -9,12 +9,6 @@ export default function serverReducer(state = initialState.server, action) {
|
|||
data: { ...action.payload, loading: false, loaded: true }
|
||||
};
|
||||
|
||||
case types.LOAD_SYSTEM_VERSION_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
...action.payload
|
||||
};
|
||||
|
||||
case types.LOAD_ACTIVE_SESSION_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
import * as types from "./actionTypes";
|
||||
import api from "./api";
|
||||
import { sendHttpRequest } from "../../redux/actions/httpActions";
|
||||
|
||||
export function loadSystemData() {
|
||||
return async function(dispatch) {
|
||||
try {
|
||||
const data = await dispatch(sendHttpRequest(api.getSystemData()));
|
||||
dispatch({ type: types.LOAD_SYSTEM_DATA_SUCCESS, payload: data });
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function loadSystemVersion() {
|
||||
return async function(dispatch) {
|
||||
try {
|
||||
const data = await dispatch(sendHttpRequest(api.getSystemVersion()));
|
||||
dispatch({ type: types.LOAD_SYSTEM_VERSION_SUCCESS, payload: data });
|
||||
} catch (error) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
export const LOAD_SYSTEM_DATA_SUCCESS = "LOAD_SYSTEM_DATA_SUCCESS";
|
||||
export const LOAD_SYSTEM_VERSION_SUCCESS = "LOAD_SYSTEM_VERSION_SUCCESS";
|
|
@ -0,0 +1,10 @@
|
|||
import { get } from "../../api/axiosApi";
|
||||
const baseUrl = process.env.REVERSE_PROXY_API_URL;
|
||||
|
||||
const getSystemData = () => get(`${baseUrl}/system/data`);
|
||||
const getSystemVersion = () => get(`${baseUrl}/system/version`);
|
||||
|
||||
export default {
|
||||
getSystemData,
|
||||
getSystemVersion
|
||||
};
|
|
@ -0,0 +1,122 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import clsx from "clsx";
|
||||
import {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardContent,
|
||||
CardActions,
|
||||
Collapse,
|
||||
Avatar,
|
||||
IconButton,
|
||||
Tooltip,
|
||||
Menu,
|
||||
MenuItem
|
||||
} from "@material-ui/core";
|
||||
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
|
||||
import MoreVertIcon from "@material-ui/icons/MoreVert";
|
||||
import BubbleChartIcon from "@material-ui/icons/BubbleChart";
|
||||
import styles from "../../../components/common/styles/expandableCardStyles";
|
||||
import SystemSummary from "./SystemSummary";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import SystemExtensionArea from "./SystemExtensionArea";
|
||||
import LibraryBooksIcon from "@material-ui/icons/LibraryBooks";
|
||||
import { useDocumentation } from "../../../hooks";
|
||||
|
||||
const useStyles = makeStyles(styles);
|
||||
|
||||
const SystemComponent = ({ data, onRedirect }) => {
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslation();
|
||||
const { openDocumentation } = useDocumentation();
|
||||
|
||||
const [expanded, setExpanded] = React.useState(false);
|
||||
const [anchorEl, setAnchorEl] = React.useState(null);
|
||||
|
||||
const handleExpandClick = () => {
|
||||
setExpanded(!expanded);
|
||||
};
|
||||
|
||||
const handleMoreClick = event => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Menu
|
||||
id="system-actions-menu"
|
||||
anchorEl={anchorEl}
|
||||
keepMounted
|
||||
open={Boolean(anchorEl)}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<MenuItem onClick={onRedirect("/about", handleClose)}>
|
||||
{t("Menu.About")}
|
||||
</MenuItem>
|
||||
<MenuItem onClick={onRedirect("/sessions", handleClose)}>
|
||||
{t("Menu.Sessions")}
|
||||
</MenuItem>
|
||||
<MenuItem onClick={onRedirect("/release-notes", handleClose)}>
|
||||
{t("Menu.ReleaseNotes")}
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
<Card>
|
||||
<CardHeader
|
||||
avatar={
|
||||
<Avatar aria-label="recipe" className={classes.avatar}>
|
||||
<BubbleChartIcon />
|
||||
</Avatar>
|
||||
}
|
||||
action={
|
||||
<IconButton
|
||||
aria-label="more"
|
||||
onClick={handleMoreClick}
|
||||
color="primary"
|
||||
>
|
||||
<MoreVertIcon />
|
||||
</IconButton>
|
||||
}
|
||||
title={<strong>{t("System.Title")}</strong>}
|
||||
subheader={t("System.Subtitle")}
|
||||
/>
|
||||
<CardContent>
|
||||
{data.loaded && <SystemSummary data={data} />}
|
||||
</CardContent>
|
||||
<CardActions disableSpacing>
|
||||
<Tooltip title={t("About.Actions.Documentation")}>
|
||||
<IconButton aria-label="documentation" onClick={openDocumentation}>
|
||||
<LibraryBooksIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<IconButton
|
||||
className={clsx(classes.expand, {
|
||||
[classes.expandOpen]: expanded
|
||||
})}
|
||||
onClick={handleExpandClick}
|
||||
aria-expanded={expanded}
|
||||
aria-label="show more"
|
||||
>
|
||||
<ExpandMoreIcon />
|
||||
</IconButton>
|
||||
</CardActions>
|
||||
<Collapse in={expanded} timeout="auto" unmountOnExit>
|
||||
<CardContent>
|
||||
<SystemExtensionArea />
|
||||
</CardContent>
|
||||
</Collapse>
|
||||
</Card>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
SystemComponent.propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
onRedirect: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SystemComponent;
|
|
@ -0,0 +1,44 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { bindActionCreators } from "redux";
|
||||
import PropTypes from "prop-types";
|
||||
import { loadSystemData } from "../actionCreators";
|
||||
import SystemComponent from "./SystemComponent";
|
||||
import { withRouter } from "react-router-dom";
|
||||
|
||||
const SystemContainer = ({ actions, data, history }) => {
|
||||
useEffect(() => {
|
||||
actions.loadSystemData();
|
||||
}, []);
|
||||
|
||||
const handleRedirect = (route, callback) => event => {
|
||||
history.push(route);
|
||||
event.preventDefault();
|
||||
callback && callback();
|
||||
};
|
||||
|
||||
return <SystemComponent data={data} onRedirect={handleRedirect} />;
|
||||
};
|
||||
|
||||
SystemContainer.propTypes = {
|
||||
actions: PropTypes.object.isRequired,
|
||||
data: PropTypes.object.isRequired,
|
||||
history: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
data: state.system.data
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({ loadSystemData }, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(withRouter(SystemContainer));
|
|
@ -0,0 +1,8 @@
|
|||
import React from "react";
|
||||
import SystemVersionContainer from "./version/SystemVersionContainer";
|
||||
|
||||
const SystemExtensionArea = () => {
|
||||
return <SystemVersionContainer />;
|
||||
};
|
||||
|
||||
export default SystemExtensionArea;
|
|
@ -0,0 +1,49 @@
|
|||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Grid, Typography } 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 SystemSummary = ({ data }) => {
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Grid container>
|
||||
<Grid item xs={6} sm={3} md={3}>
|
||||
{`${t("System.Server.HostName")}: `}
|
||||
<span className={classes.value}>{data.server.hostName}</span>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6} sm={3} md={3}>
|
||||
{`${t("System.Server.Platform")}: `}
|
||||
<span className={classes.value}>{data.server.platform}</span>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6} sm={3} md={3}>
|
||||
{`${t("System.Api.HostName")}: `}
|
||||
<span className={classes.value}>{data.api.hostName}</span>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={6} sm={3} md={3}>
|
||||
{`${t("System.Api.Platform")}: `}
|
||||
<span className={classes.value}>{data.api.platform}</span>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} sm={12} md={12}>
|
||||
<Typography variant="body2" gutterBottom color="textSecondary">
|
||||
{t("System.Description")}
|
||||
</Typography>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
SystemSummary.propTypes = {
|
||||
data: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default SystemSummary;
|
|
@ -0,0 +1,134 @@
|
|||
import React, { useMemo } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import {
|
||||
Typography,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
ListItemAvatar
|
||||
} from "@material-ui/core";
|
||||
import Avatar from "@material-ui/core/Avatar";
|
||||
import WebAssetIcon from "@material-ui/icons/WebAsset";
|
||||
import DnsRoundedIcon from "@material-ui/icons/DnsRounded";
|
||||
import SettingsInputSvideoIcon from "@material-ui/icons/SettingsInputSvideo";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const useStyles = makeStyles(theme => {
|
||||
debugger;
|
||||
return {
|
||||
root: {
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
padding: 0
|
||||
},
|
||||
value: {
|
||||
fontSize: "0.9rem",
|
||||
fontWeight: theme.typography.fontWeightMedium
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
const SystemVersionComponent = ({ data }) => {
|
||||
const classes = useStyles();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const lastUpdateDate = useMemo(() => {
|
||||
const format = "DD-MM-YYYY HH:mm:ss";
|
||||
const server = t("DATE_FORMAT", {
|
||||
date: {
|
||||
value: data.server.lastUpdateDate,
|
||||
format
|
||||
}
|
||||
});
|
||||
|
||||
const api = t("DATE_FORMAT", {
|
||||
date: {
|
||||
value: data.api.lastUpdateDate,
|
||||
format
|
||||
}
|
||||
});
|
||||
|
||||
const frontend = t("DATE_FORMAT", {
|
||||
date: {
|
||||
value: process.env.APP_DATE,
|
||||
format
|
||||
}
|
||||
});
|
||||
|
||||
return { server, api, frontend };
|
||||
}, [data, t]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="subtitle1" color="textSecondary">
|
||||
{t("System.Versions.Title")}
|
||||
</Typography>
|
||||
<List className={classes.root}>
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
<DnsRoundedIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={
|
||||
<span className={classes.value}>
|
||||
{t("System.Versions.Server", {
|
||||
version: data.server.version
|
||||
})}
|
||||
</span>
|
||||
}
|
||||
secondary={t("System.LastUpdateDate", {
|
||||
date: lastUpdateDate.server
|
||||
})}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
<SettingsInputSvideoIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={
|
||||
<span className={classes.value}>
|
||||
{t("System.Versions.Api", {
|
||||
version: data.api.version
|
||||
})}
|
||||
</span>
|
||||
}
|
||||
secondary={t("System.LastUpdateDate", {
|
||||
date: lastUpdateDate.api
|
||||
})}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
<WebAssetIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary={
|
||||
<span className={classes.value}>
|
||||
{t("System.Versions.Frontend", {
|
||||
version: process.env.APP_VERSION
|
||||
})}
|
||||
</span>
|
||||
}
|
||||
secondary={t("System.LastUpdateDate", {
|
||||
date: lastUpdateDate.frontend
|
||||
})}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
SystemVersionComponent.propTypes = {
|
||||
data: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default SystemVersionComponent;
|
|
@ -0,0 +1,36 @@
|
|||
import React, { useEffect } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { bindActionCreators } from "redux";
|
||||
import PropTypes from "prop-types";
|
||||
import { loadSystemVersion } from "../../actionCreators";
|
||||
import SystemVersionComponent from "./SystemVersionComponent";
|
||||
|
||||
const SystemVersionContainer = ({ actions, data }) => {
|
||||
useEffect(() => {
|
||||
actions.loadSystemVersion();
|
||||
}, []);
|
||||
|
||||
return <>{data.loaded && <SystemVersionComponent data={data} />}</>;
|
||||
};
|
||||
|
||||
SystemVersionContainer.propTypes = {
|
||||
actions: PropTypes.object.isRequired,
|
||||
data: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
data: state.system.version
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({ loadSystemVersion }, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(SystemVersionContainer);
|
|
@ -0,0 +1,21 @@
|
|||
import * as types from "./actionTypes";
|
||||
import initialState from "../../redux/reducers/initialState";
|
||||
|
||||
export default function systemReducer(state = initialState.system, action) {
|
||||
switch (action.type) {
|
||||
case types.LOAD_SYSTEM_DATA_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
data: { ...action.payload, loading: false, loaded: true }
|
||||
};
|
||||
|
||||
case types.LOAD_SYSTEM_VERSION_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
version: { ...action.payload, loading: false, loaded: true }
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
import useDocumentation from "./useDocumentation";
|
||||
|
||||
export { useDocumentation };
|
|
@ -0,0 +1,10 @@
|
|||
const useDocumentation = () => {
|
||||
const openDocumentation = event => {
|
||||
const url = process.env.REVERSE_PROXY_DOCS_URL;
|
||||
window.open(url, "_blank");
|
||||
event.preventDefault();
|
||||
};
|
||||
return { openDocumentation };
|
||||
};
|
||||
|
||||
export default useDocumentation;
|
|
@ -11,6 +11,7 @@ import frontendSessionReducer from "../../features/frontendSession/reducer";
|
|||
import snackbarReducer from "../../features/snackbar/reducer";
|
||||
import chartsReducer from "../../features/charts/chartsReducer";
|
||||
import chatbotReducer from "../../features/chatbot/reducer";
|
||||
import systemReducer from "../../features/system/reducer";
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
frontendSession: frontendSessionReducer,
|
||||
|
@ -20,6 +21,7 @@ const rootReducer = combineReducers({
|
|||
options: optionsReducer,
|
||||
releaseNotes: releaseNotesReducer,
|
||||
charts: chartsReducer,
|
||||
system: systemReducer,
|
||||
snackbar: snackbarReducer,
|
||||
bot: chatbotReducer,
|
||||
ajaxCallsInProgress: ajaxStatusReducer
|
||||
|
|
|
@ -15,6 +15,10 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
system: {
|
||||
data: { loading: false, loaded: false },
|
||||
version: { loading: false, loaded: false }
|
||||
},
|
||||
snackbar: {
|
||||
message: null,
|
||||
type: null
|
||||
|
|
Loading…
Reference in New Issue