commit
45e3b3ae83
|
@ -34,6 +34,3 @@ build
|
||||||
|
|
||||||
# Mac files
|
# Mac files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
# json-server db
|
|
||||||
db.json
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -28,6 +28,7 @@
|
||||||
"react-i18next": "^11.4.0",
|
"react-i18next": "^11.4.0",
|
||||||
"react-redux": "6.0.1",
|
"react-redux": "6.0.1",
|
||||||
"react-router-dom": "5.0.0",
|
"react-router-dom": "5.0.0",
|
||||||
|
"recharts": "^1.8.5",
|
||||||
"redux": "4.0.1",
|
"redux": "4.0.1",
|
||||||
"redux-thunk": "2.3.0",
|
"redux-thunk": "2.3.0",
|
||||||
"reselect": "4.0.0"
|
"reselect": "4.0.0"
|
||||||
|
@ -57,9 +58,9 @@
|
||||||
"rimraf": "2.6.3",
|
"rimraf": "2.6.3",
|
||||||
"style-loader": "0.23.1",
|
"style-loader": "0.23.1",
|
||||||
"webpack": "^4.43.0",
|
"webpack": "^4.43.0",
|
||||||
"webpack-bundle-analyzer": "3.1.0",
|
"webpack-bundle-analyzer": "^3.8.0",
|
||||||
"webpack-cli": "3.3.0",
|
"webpack-cli": "^3.3.11",
|
||||||
"webpack-dev-server": "3.2.1"
|
"webpack-dev-server": "^3.11.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
|
|
|
@ -66,6 +66,17 @@
|
||||||
},
|
},
|
||||||
"MessageForAuthor": "Message for author"
|
"MessageForAuthor": "Message for author"
|
||||||
},
|
},
|
||||||
|
"Charts": {
|
||||||
|
"Server": {
|
||||||
|
"Sessions": {
|
||||||
|
"RunningTime": {
|
||||||
|
"Title": "Sessions running time",
|
||||||
|
"Session": "Session",
|
||||||
|
"X": "Running time"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Notifications": {
|
"Notifications": {
|
||||||
"MessageSaved": "Message saved"
|
"MessageSaved": "Message saved"
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,17 @@
|
||||||
},
|
},
|
||||||
"MessageForAuthor": "Mesaj pentru autor"
|
"MessageForAuthor": "Mesaj pentru autor"
|
||||||
},
|
},
|
||||||
|
"Charts": {
|
||||||
|
"Server": {
|
||||||
|
"Sessions": {
|
||||||
|
"RunningTime": {
|
||||||
|
"Title": "Timp de rulare sesiuni",
|
||||||
|
"Session": "Sesiunea",
|
||||||
|
"X": "Timp de rulare"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"Notifications": {
|
"Notifications": {
|
||||||
"MessageSaved": "Mesaj salvat"
|
"MessageSaved": "Mesaj salvat"
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,15 @@ const Header = () => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getFlagsPath = () => {
|
||||||
|
const basePath = "public/flags";
|
||||||
|
if (process.env.PUBLIC_URL) {
|
||||||
|
return `${process.env.PUBLIC_URL}/${basePath}`;
|
||||||
|
} else {
|
||||||
|
return basePath;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<AppBar position="static">
|
<AppBar position="static">
|
||||||
|
@ -94,7 +103,7 @@ const Header = () => {
|
||||||
format="png"
|
format="png"
|
||||||
pngSize={32}
|
pngSize={32}
|
||||||
shiny={true}
|
shiny={true}
|
||||||
basePath={`${process.env.PUBLIC_URL}/public/flags`}
|
basePath={getFlagsPath()}
|
||||||
alt={flag.alt}
|
alt={flag.alt}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { combineReducers } from "redux";
|
||||||
|
import serverChartsReducer from "./server/reducer";
|
||||||
|
|
||||||
|
const chartsReducer = combineReducers({
|
||||||
|
server: serverChartsReducer
|
||||||
|
});
|
||||||
|
|
||||||
|
export default chartsReducer;
|
|
@ -0,0 +1,20 @@
|
||||||
|
import * as types from "./actionTypes";
|
||||||
|
import api from "./api";
|
||||||
|
import { sendHttpRequest } from "../../../redux/actions/httpActions";
|
||||||
|
|
||||||
|
export function loadSessionsRunningTime() {
|
||||||
|
return async function (dispatch) {
|
||||||
|
try {
|
||||||
|
dispatch({ type: types.LOAD_SERVER_CHART_SESSIONS_RUNNING_TIME_STARTED });
|
||||||
|
const data = await dispatch(
|
||||||
|
sendHttpRequest(api.getSessionsRunningTime())
|
||||||
|
);
|
||||||
|
dispatch({
|
||||||
|
type: types.LOAD_SERVER_CHART_SESSIONS_RUNNING_TIME_SUCCESS,
|
||||||
|
payload: data
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export const LOAD_SERVER_CHART_SESSIONS_RUNNING_TIME_STARTED =
|
||||||
|
"LOAD_SERVER_CHART_SESSIONS_RUNNING_TIME_STARTED";
|
||||||
|
export const LOAD_SERVER_CHART_SESSIONS_RUNNING_TIME_SUCCESS =
|
||||||
|
"LOAD_SERVER_CHART_SESSIONS_RUNNING_TIME_SUCCESS";
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { get } from "../../../api/axiosApi";
|
||||||
|
const baseUrl = `${process.env.REVERSE_PROXY_API_URL}/charts`;
|
||||||
|
|
||||||
|
const getSessionsRunningTime = () =>
|
||||||
|
get(`${baseUrl}/server/sessions-running-time`);
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getSessionsRunningTime
|
||||||
|
};
|
|
@ -0,0 +1,40 @@
|
||||||
|
import React, { useEffect } from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { bindActionCreators } from "redux";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import SessionsRunningTimeChart from "./SessionsRunningTimeChart";
|
||||||
|
import { loadSessionsRunningTime } from "../actionCreators";
|
||||||
|
|
||||||
|
const ServerChartsContainer = ({ actions, sessionRunningTime }) => {
|
||||||
|
useEffect(() => {
|
||||||
|
actions.loadSessionsRunningTime();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<SessionsRunningTimeChart data={sessionRunningTime} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ServerChartsContainer.propTypes = {
|
||||||
|
actions: PropTypes.object.isRequired,
|
||||||
|
sessionRunningTime: PropTypes.array.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
function mapStateToProps(state) {
|
||||||
|
return {
|
||||||
|
sessionRunningTime: state.charts.server.sessions.runningTime
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapDispatchToProps(dispatch) {
|
||||||
|
return {
|
||||||
|
actions: bindActionCreators({ loadSessionsRunningTime }, dispatch)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(ServerChartsContainer);
|
|
@ -0,0 +1,88 @@
|
||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import Spinner from "../../../../components/common/Spinner";
|
||||||
|
import {
|
||||||
|
BarChart,
|
||||||
|
Bar,
|
||||||
|
XAxis,
|
||||||
|
YAxis,
|
||||||
|
CartesianGrid,
|
||||||
|
Tooltip,
|
||||||
|
Legend,
|
||||||
|
ResponsiveContainer
|
||||||
|
} from "recharts";
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
import Grid from "@material-ui/core/Grid";
|
||||||
|
import SessionsRunningTimeChartTooltip from "./SessionsRunningTimeChartTooltip";
|
||||||
|
|
||||||
|
const SessionsRunningTimeChart = ({ data }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const chartData = data.map((z) => {
|
||||||
|
return {
|
||||||
|
sessionId: z.sessionId,
|
||||||
|
name: `S${z.orderNo}`,
|
||||||
|
order: z.orderNo,
|
||||||
|
value: z.runningTime.hours,
|
||||||
|
label: z.runningTime.label
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const CustomTooltip = ({ active, payload }) => {
|
||||||
|
if (!active) return null;
|
||||||
|
return <SessionsRunningTimeChartTooltip payload={payload[0].payload} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
CustomTooltip.propTypes = {
|
||||||
|
active: PropTypes.bool,
|
||||||
|
payload: PropTypes.array
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{data.loading || !data.loaded ? (
|
||||||
|
<Spinner />
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Grid container justify="center">
|
||||||
|
<Grid item>
|
||||||
|
<Typography gutterBottom variant="h5">
|
||||||
|
{t("Charts.Server.Sessions.RunningTime.Title")}
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<ResponsiveContainer width="100%" height={500}>
|
||||||
|
<BarChart
|
||||||
|
data={chartData}
|
||||||
|
margin={{
|
||||||
|
top: 5,
|
||||||
|
right: 30,
|
||||||
|
left: 20,
|
||||||
|
bottom: 5
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" />
|
||||||
|
<XAxis dataKey="name" />
|
||||||
|
<YAxis type="number" dataKey="value" unit="h" />
|
||||||
|
<Tooltip content={<CustomTooltip />} />
|
||||||
|
<Legend />
|
||||||
|
|
||||||
|
<Bar
|
||||||
|
dataKey="value"
|
||||||
|
fill="#3f51b5"
|
||||||
|
name={t("Charts.Server.Sessions.RunningTime.X")}
|
||||||
|
/>
|
||||||
|
</BarChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
SessionsRunningTimeChart.propTypes = {
|
||||||
|
data: PropTypes.array.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SessionsRunningTimeChart;
|
|
@ -0,0 +1,76 @@
|
||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
import Chip from "@material-ui/core/Chip";
|
||||||
|
import Grid from "@material-ui/core/Grid";
|
||||||
|
import Divider from "@material-ui/core/Divider";
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
root: {
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: 360,
|
||||||
|
backgroundColor: theme.palette.background.paper,
|
||||||
|
borderStyle: "solid",
|
||||||
|
borderWidth: "1px",
|
||||||
|
borderColor: theme.palette.primary.main
|
||||||
|
},
|
||||||
|
chip: {
|
||||||
|
margin: theme.spacing(0.5)
|
||||||
|
},
|
||||||
|
section1: {
|
||||||
|
margin: theme.spacing(0, 1)
|
||||||
|
},
|
||||||
|
section2: {
|
||||||
|
margin: theme.spacing(1)
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
const SessionsRunningTimeChartTooltip = ({ payload }) => {
|
||||||
|
const classes = useStyles();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.root}>
|
||||||
|
<div className={classes.section1}>
|
||||||
|
<Grid container alignItems="center">
|
||||||
|
<Grid item xs>
|
||||||
|
<Typography gutterBottom variant="h6">
|
||||||
|
{`${t("Charts.Server.Sessions.RunningTime.Session")} ${
|
||||||
|
payload.order
|
||||||
|
}`}
|
||||||
|
</Typography>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<Typography color="textSecondary" variant="body2">
|
||||||
|
{`id: ${payload.sessionId}`}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<Divider variant="middle" />
|
||||||
|
<div className={classes.section2}>
|
||||||
|
<Typography gutterBottom variant="body2">
|
||||||
|
{t("Charts.Server.Sessions.RunningTime.X")}
|
||||||
|
</Typography>
|
||||||
|
<div>
|
||||||
|
{payload.label.split(" ").map((s) => {
|
||||||
|
return (
|
||||||
|
<Chip
|
||||||
|
key={s}
|
||||||
|
className={classes.chip}
|
||||||
|
color="primary"
|
||||||
|
label={s}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
SessionsRunningTimeChartTooltip.propTypes = {
|
||||||
|
payload: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SessionsRunningTimeChartTooltip;
|
|
@ -0,0 +1,33 @@
|
||||||
|
import * as types from "./actionTypes";
|
||||||
|
import initialState from "../../../redux/reducers/initialState";
|
||||||
|
|
||||||
|
export default function serverChartsReducer(
|
||||||
|
state = initialState.charts.server,
|
||||||
|
action
|
||||||
|
) {
|
||||||
|
switch (action.type) {
|
||||||
|
case types.LOAD_SERVER_CHART_SESSIONS_RUNNING_TIME_STARTED:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
sessions: {
|
||||||
|
...state.sessions,
|
||||||
|
runningTime: Object.assign([], { loading: true, loaded: false })
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
case types.LOAD_SERVER_CHART_SESSIONS_RUNNING_TIME_SUCCESS:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
sessions: {
|
||||||
|
...state.sessions,
|
||||||
|
runningTime: Object.assign(action.payload, {
|
||||||
|
loading: false,
|
||||||
|
loaded: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,6 @@ import {
|
||||||
Collapse,
|
Collapse,
|
||||||
Avatar,
|
Avatar,
|
||||||
IconButton,
|
IconButton,
|
||||||
Typography,
|
|
||||||
Tooltip
|
Tooltip
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
import ShareIcon from "@material-ui/icons/Share";
|
import ShareIcon from "@material-ui/icons/Share";
|
||||||
|
@ -21,6 +20,7 @@ import MessageRoundedIcon from "@material-ui/icons/MessageRounded";
|
||||||
import styles from "../../../components/common/styles/expandableCardStyles";
|
import styles from "../../../components/common/styles/expandableCardStyles";
|
||||||
import ServerSummary from "./ServerSummary";
|
import ServerSummary from "./ServerSummary";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import ServerChartsContainer from "../../charts/server/components/ServerChartsContainer";
|
||||||
|
|
||||||
const useStyles = makeStyles(styles);
|
const useStyles = makeStyles(styles);
|
||||||
|
|
||||||
|
@ -88,33 +88,7 @@ const ServerComponent = ({
|
||||||
</CardActions>
|
</CardActions>
|
||||||
<Collapse in={expanded} timeout="auto" unmountOnExit>
|
<Collapse in={expanded} timeout="auto" unmountOnExit>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<Typography paragraph>Method:</Typography>
|
<ServerChartsContainer />
|
||||||
<Typography paragraph>
|
|
||||||
Heat 1/2 cup of the broth in a pot until simmering, add saffron and
|
|
||||||
set aside for 10 minutes.
|
|
||||||
</Typography>
|
|
||||||
<Typography paragraph>
|
|
||||||
Heat oil in a (14- to 16-inch) paella pan or a large, deep skillet
|
|
||||||
over medium-high heat. Add chicken, shrimp and chorizo, and cook,
|
|
||||||
stirring occasionally until lightly browned, 6 to 8 minutes.
|
|
||||||
Transfer shrimp to a large plate and set aside, leaving chicken and
|
|
||||||
chorizo in the pan. Add pimentón, bay leaves, garlic, tomatoes,
|
|
||||||
onion, salt and pepper, and cook, stirring often until thickened and
|
|
||||||
fragrant, about 10 minutes. Add saffron broth and remaining 4 1/2
|
|
||||||
cups chicken broth; bring to a boil.
|
|
||||||
</Typography>
|
|
||||||
<Typography paragraph>
|
|
||||||
Add rice and stir very gently to distribute. Top with artichokes and
|
|
||||||
peppers, and cook without stirring, until most of the liquid is
|
|
||||||
absorbed, 15 to 18 minutes. Reduce heat to medium-low, add reserved
|
|
||||||
shrimp and mussels, tucking them down into the rice, and cook again
|
|
||||||
without stirring, until mussels have opened and rice is just tender,
|
|
||||||
5 to 7 minutes more. (Discard any mussels that don’t open.)
|
|
||||||
</Typography>
|
|
||||||
<Typography>
|
|
||||||
Set aside off of the heat to let rest for 10 minutes, and then
|
|
||||||
serve.
|
|
||||||
</Typography>
|
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Collapse>
|
</Collapse>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
@ -12,7 +12,7 @@ const store = configureStore();
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<ReduxProvider store={store}>
|
<ReduxProvider store={store}>
|
||||||
<Router basename={process.env.PUBLIC_URL}>
|
<Router basename={process.env.PUBLIC_URL || ""}>
|
||||||
<App />
|
<App />
|
||||||
</Router>
|
</Router>
|
||||||
</ReduxProvider>,
|
</ReduxProvider>,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
import releaseNotesReducer from "../../features/releaseNotes/reducer";
|
import releaseNotesReducer from "../../features/releaseNotes/reducer";
|
||||||
import frontendSessionReducer from "../../features/frontendSession/reducer";
|
import frontendSessionReducer from "../../features/frontendSession/reducer";
|
||||||
import snackbarReducer from "../../features/snackbar/reducer";
|
import snackbarReducer from "../../features/snackbar/reducer";
|
||||||
|
import chartsReducer from "../../features/charts/chartsReducer";
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
const rootReducer = combineReducers({
|
||||||
frontendSession: frontendSessionReducer,
|
frontendSession: frontendSessionReducer,
|
||||||
|
@ -15,6 +16,7 @@ const rootReducer = combineReducers({
|
||||||
sessions: sessionsReducer,
|
sessions: sessionsReducer,
|
||||||
forwards: forwardsReducer,
|
forwards: forwardsReducer,
|
||||||
releaseNotes: releaseNotesReducer,
|
releaseNotes: releaseNotesReducer,
|
||||||
|
charts: chartsReducer,
|
||||||
snackbar: snackbarReducer,
|
snackbar: snackbarReducer,
|
||||||
ajaxCallsInProgress: ajaxStatusReducer
|
ajaxCallsInProgress: ajaxStatusReducer
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,6 +7,13 @@ export default {
|
||||||
sessions: Object.assign([], { loading: false, loaded: false }),
|
sessions: Object.assign([], { loading: false, loaded: false }),
|
||||||
forwards: {},
|
forwards: {},
|
||||||
releaseNotes: Object.assign([], { loading: false, loaded: false }),
|
releaseNotes: Object.assign([], { loading: false, loaded: false }),
|
||||||
|
charts: {
|
||||||
|
server: {
|
||||||
|
sessions: {
|
||||||
|
runningTime: Object.assign([], { loading: false, loaded: false })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
snackbar: {
|
snackbar: {
|
||||||
message: null,
|
message: null,
|
||||||
type: null
|
type: null
|
||||||
|
|
|
@ -83,7 +83,9 @@ i18n
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
backend: {
|
backend: {
|
||||||
loadPath: `${process.env.PUBLIC_URL}/public/locales/{{lng}}/{{ns}}.json`
|
loadPath: `${
|
||||||
|
process.env.PUBLIC_URL || ""
|
||||||
|
}/public/locales/{{lng}}/{{ns}}.json`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
|
|
Loading…
Reference in New Issue