/** ****************************************************************************
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Licensed under the Apache License Version 2.0 (the 'License'). You may not
* use this file except in compliance with the License. A copy of the License
* is located at
*
* http://www.apache.org/licenses/
* or in the 'license' file accompanying this file. This file is distributed on
* an 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express or
* implied. See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************** */
/* eslint-disable no-underscore-dangle */
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { withStyles } from '@material-ui/core/styles';
import Paper from '@material-ui/core/Paper';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import {
ResponsiveContainer, Line, Area, ReferenceArea, CartesianGrid,
XAxis, YAxis, Tooltip, Legend, ComposedChart, Dot,
} from 'recharts';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
dayjs.extend(utc);
const styles = (theme) => ({
root: {},
header: {
position: 'static',
width: '100%',
display: 'flex',
zIndex: 1100,
boxSizing: 'border-box',
flexShrink: 0,
flexDirection: 'column',
padding: theme.spacing(1, 2),
background: '#f7f7f7',
},
headerInside: {
position: 'relative',
display: 'flex',
alignItems: 'center',
},
toggleReferenceArea: {
marginLeft: 'auto',
},
content: {
paddingTop: theme.spacing(1),
paddingBottom: theme.spacing(1),
},
referenceArea: {
opacity: '0.8',
},
legend: {
padding: 0,
marginTop: '6px',
marginBottom: 0,
textAlign: 'center',
color: '#212121',
fontSize: '14px',
'& li': {
display: 'inline-block',
marginRight: 10,
},
'& .colorBox': {
width: 10,
height: 10,
border: '1px #aaa solid',
display: 'inline-block',
marginRight: 2,
},
},
tooltip: {
border: '1px rgba(0, 0, 0, 0.35) solid',
background: 'rgba(255, 255, 255, 0.96)',
fontSize: '14px',
padding: theme.spacing(0.5),
'&$normal': {
},
'&$abnormal': {
border: '1px rgba(200, 0, 0, 0.35) solid',
background: 'rgba(255, 235, 235, 0.96)',
},
'& .date': {
fontWeight: 'bold',
textAlign: 'right',
},
'& .alert': {
color: 'red',
},
'& p': {
margin: 0,
},
},
normal: {},
abnormal: {},
});
const colorMap = {
Available: '#88ff88',
PendingBusy: '#fff8a2',
Busy: '#ffcc88',
AfterCallWork: '#888888',
FailedConnectAgent: '#ff8488',
FailedConnectCustomer: '#ff8488',
CallingCustomer: '#fff8a2',
MissedCallAgent: '#bbbbff',
__other: '#ffffff',
};
class MetricsView extends React.PureComponent {
constructor(props) {
super(props);
this.state = this.getInitialState();
this.handleToggleReferenceArea = this.handleToggleReferenceArea.bind(this);
this.handleLegendMouseEnter = this.handleLegendMouseEnter.bind(this);
this.handleLegendMouseLeave = this.handleLegendMouseLeave.bind(this);
this.renderCustomAxisTick = this.renderCustomAxisTick.bind(this);
this.renderCustomTooltip = this.renderCustomTooltip.bind(this);
this.renderCustomLegend = this.renderCustomLegend.bind(this);
}
getInitialState() {
return {
skewThreshold: 10000,
hideReferenceArea: false,
hideLatencyGraph: false,
hideSkewGraph: false,
referenceAreaOpacities:
Object.fromEntries(Object.keys(colorMap).map((name) => [name, 1])),
};
}
handleToggleReferenceArea() {
const { hideReferenceArea } = this.state;
this.setState({ hideReferenceArea: !hideReferenceArea });
}
handleToggleLatencyGraph() {
const { hideLatencyGraph } = this.state;
this.setState({ hideLatencyGraph: !hideLatencyGraph });
}
handleToggleSkewGraph() {
const { hideSkewGraph } = this.state;
this.setState({ hideSkewGraph: !hideSkewGraph });
}
handleLegendMouseEnter(name) {
const { referenceAreaOpacities: opacities } = this.state;
const newOpacities = Object.fromEntries(Object.keys(opacities).map((n) => [n, 0.25]));
this.setState({
referenceAreaOpacities: { ...newOpacities, [name]: 1 },
});
}
handleLegendMouseLeave() {
const { referenceAreaOpacities: opacities } = this.state;
const newOpacities = Object.fromEntries(Object.keys(opacities).map((n) => [n, 1.0]));
this.setState({
referenceAreaOpacities: { ...newOpacities },
});
}
// eslint-disable-next-line class-methods-use-this
renderCustomAxisTick({
x, y, payload,
}) {
return (
Server Time: {dayjs(payload[0].payload._snapshotTimestamp).toISOString()}
Local Time: {payload[0].payload.localTimestamp}
{payload[0].payload.state.name}
Local clock {' '} {Math.abs(payload[0].payload.skew)} {' '} ms {' '} {payload[0].payload.skew > 0 ? 'ahead' : 'behind'} {skewTooLarge && ⚠️}
Local Time: {payload[0].payload.localTimestamp}
API: {payload[0].payload.apiName}
Latency: {payload[0].payload.latency} {' '} ms
{ payload[0].payload.status && (Status: {payload[0].payload.status} {' '} {payload[0].payload.status === 'failed' ? '⚠️' : ''}
)}