commit
45e3b3ae83
|
@ -34,6 +34,3 @@ build
|
|||
|
||||
# Mac files
|
||||
.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-redux": "6.0.1",
|
||||
"react-router-dom": "5.0.0",
|
||||
"recharts": "^1.8.5",
|
||||
"redux": "4.0.1",
|
||||
"redux-thunk": "2.3.0",
|
||||
"reselect": "4.0.0"
|
||||
|
@ -57,9 +58,9 @@
|
|||
"rimraf": "2.6.3",
|
||||
"style-loader": "0.23.1",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-bundle-analyzer": "3.1.0",
|
||||
"webpack-cli": "3.3.0",
|
||||
"webpack-dev-server": "3.2.1"
|
||||
"webpack-bundle-analyzer": "^3.8.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
|
|
|
@ -66,6 +66,17 @@
|
|||
},
|
||||
"MessageForAuthor": "Message for author"
|
||||
},
|
||||
"Charts": {
|
||||
"Server": {
|
||||
"Sessions": {
|
||||
"RunningTime": {
|
||||
"Title": "Sessions running time",
|
||||
"Session": "Session",
|
||||
"X": "Running time"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Notifications": {
|
||||
"MessageSaved": "Message saved"
|
||||
}
|
||||
|
|
|
@ -57,6 +57,17 @@
|
|||
},
|
||||
"MessageForAuthor": "Mesaj pentru autor"
|
||||
},
|
||||
"Charts": {
|
||||
"Server": {
|
||||
"Sessions": {
|
||||
"RunningTime": {
|
||||
"Title": "Timp de rulare sesiuni",
|
||||
"Session": "Sesiunea",
|
||||
"X": "Timp de rulare"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Notifications": {
|
||||
"MessageSaved": "Mesaj salvat"
|
||||
}
|
||||
|
|
|
@ -61,6 +61,15 @@ const Header = () => {
|
|||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const getFlagsPath = () => {
|
||||
const basePath = "public/flags";
|
||||
if (process.env.PUBLIC_URL) {
|
||||
return `${process.env.PUBLIC_URL}/${basePath}`;
|
||||
} else {
|
||||
return basePath;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classes.root}>
|
||||
<AppBar position="static">
|
||||
|
@ -94,7 +103,7 @@ const Header = () => {
|
|||
format="png"
|
||||
pngSize={32}
|
||||
shiny={true}
|
||||
basePath={`${process.env.PUBLIC_URL}/public/flags`}
|
||||
basePath={getFlagsPath()}
|
||||
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,
|
||||
Avatar,
|
||||
IconButton,
|
||||
Typography,
|
||||
Tooltip
|
||||
} from "@material-ui/core";
|
||||
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 ServerSummary from "./ServerSummary";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ServerChartsContainer from "../../charts/server/components/ServerChartsContainer";
|
||||
|
||||
const useStyles = makeStyles(styles);
|
||||
|
||||
|
@ -88,33 +88,7 @@ const ServerComponent = ({
|
|||
</CardActions>
|
||||
<Collapse in={expanded} timeout="auto" unmountOnExit>
|
||||
<CardContent>
|
||||
<Typography paragraph>Method:</Typography>
|
||||
<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>
|
||||
<ServerChartsContainer />
|
||||
</CardContent>
|
||||
</Collapse>
|
||||
</Card>
|
||||
|
|
|
@ -12,7 +12,7 @@ const store = configureStore();
|
|||
|
||||
render(
|
||||
<ReduxProvider store={store}>
|
||||
<Router basename={process.env.PUBLIC_URL}>
|
||||
<Router basename={process.env.PUBLIC_URL || ""}>
|
||||
<App />
|
||||
</Router>
|
||||
</ReduxProvider>,
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
import releaseNotesReducer from "../../features/releaseNotes/reducer";
|
||||
import frontendSessionReducer from "../../features/frontendSession/reducer";
|
||||
import snackbarReducer from "../../features/snackbar/reducer";
|
||||
import chartsReducer from "../../features/charts/chartsReducer";
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
frontendSession: frontendSessionReducer,
|
||||
|
@ -15,6 +16,7 @@ const rootReducer = combineReducers({
|
|||
sessions: sessionsReducer,
|
||||
forwards: forwardsReducer,
|
||||
releaseNotes: releaseNotesReducer,
|
||||
charts: chartsReducer,
|
||||
snackbar: snackbarReducer,
|
||||
ajaxCallsInProgress: ajaxStatusReducer
|
||||
});
|
||||
|
|
|
@ -7,6 +7,13 @@ export default {
|
|||
sessions: Object.assign([], { loading: false, loaded: false }),
|
||||
forwards: {},
|
||||
releaseNotes: Object.assign([], { loading: false, loaded: false }),
|
||||
charts: {
|
||||
server: {
|
||||
sessions: {
|
||||
runningTime: Object.assign([], { loading: false, loaded: false })
|
||||
}
|
||||
}
|
||||
},
|
||||
snackbar: {
|
||||
message: null,
|
||||
type: null
|
||||
|
|
|
@ -83,7 +83,9 @@ i18n
|
|||
}
|
||||
},
|
||||
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