Replace the main Statistics graph with 4 blocks instead
This commit is contained in:
parent
599426a1f9
commit
bc11f872fa
client/src
|
@ -1,59 +1,109 @@
|
||||||
import React from 'react';
|
import React, { Component } from 'react';
|
||||||
import { ResponsiveLine } from '@nivo/line';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import Card from '../ui/Card';
|
import Card from '../ui/Card';
|
||||||
|
import Line from '../ui/Line';
|
||||||
|
|
||||||
const Statistics = props => (
|
import { getPercent } from '../../helpers/helpers';
|
||||||
<Card title="Statistics" subtitle="for the last 24 hours" bodyType="card-graph" refresh={props.refreshButton}>
|
import { STATUS_COLORS } from '../../helpers/constants';
|
||||||
{props.history ?
|
|
||||||
<ResponsiveLine
|
class Statistics extends Component {
|
||||||
data={props.history}
|
render() {
|
||||||
margin={{
|
const {
|
||||||
top: 50,
|
dnsQueries,
|
||||||
right: 40,
|
blockedFiltering,
|
||||||
bottom: 80,
|
replacedSafebrowsing,
|
||||||
left: 80,
|
replacedParental,
|
||||||
}}
|
} = this.props;
|
||||||
minY="auto"
|
|
||||||
stacked={false}
|
const filteringData = [this.props.history[1]];
|
||||||
curve='monotoneX'
|
const queriesData = [this.props.history[2]];
|
||||||
axisBottom={{
|
const parentalData = [this.props.history[3]];
|
||||||
orient: 'bottom',
|
const safebrowsingData = [this.props.history[4]];
|
||||||
tickSize: 5,
|
|
||||||
tickPadding: 5,
|
return (
|
||||||
tickRotation: -45,
|
<div className="row">
|
||||||
legendOffset: 50,
|
<div className="col-sm-6 col-lg-3">
|
||||||
legendPosition: 'center',
|
<Card bodyType="card-wrap">
|
||||||
}}
|
<div className="card-body-stats">
|
||||||
axisLeft={{
|
<div className="card-value card-value-stats text-blue">
|
||||||
orient: 'left',
|
{dnsQueries}
|
||||||
tickSize: 5,
|
</div>
|
||||||
tickPadding: 5,
|
<div className="card-title-stats">
|
||||||
tickRotation: 0,
|
DNS Queries
|
||||||
legendOffset: -40,
|
</div>
|
||||||
legendPosition: 'center',
|
</div>
|
||||||
}}
|
<div className="card-chart-bg">
|
||||||
enableArea={true}
|
<Line data={queriesData} color={STATUS_COLORS.blue}/>
|
||||||
dotSize={10}
|
</div>
|
||||||
dotColor="inherit:darker(0.3)"
|
</Card>
|
||||||
dotBorderWidth={2}
|
</div>
|
||||||
dotBorderColor="#ffffff"
|
<div className="col-sm-6 col-lg-3">
|
||||||
dotLabel="y"
|
<Card bodyType="card-wrap">
|
||||||
dotLabelYOffset={-12}
|
<div className="card-body-stats">
|
||||||
animate={true}
|
<div className="card-value card-value-stats text-red">
|
||||||
motionStiffness={90}
|
{blockedFiltering}
|
||||||
motionDamping={15}
|
</div>
|
||||||
/>
|
<div className="card-value card-value-percent text-red">
|
||||||
:
|
{getPercent(dnsQueries, blockedFiltering)}
|
||||||
<h2 className="text-muted">Empty data</h2>
|
</div>
|
||||||
}
|
<div className="card-title-stats">
|
||||||
</Card>
|
Blocked by Filters
|
||||||
);
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="card-chart-bg">
|
||||||
|
<Line data={filteringData} color={STATUS_COLORS.red}/>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-6 col-lg-3">
|
||||||
|
<Card bodyType="card-wrap">
|
||||||
|
<div className="card-body-stats">
|
||||||
|
<div className="card-value card-value-stats text-green">
|
||||||
|
{replacedSafebrowsing}
|
||||||
|
</div>
|
||||||
|
<div className="card-value card-value-percent text-green">
|
||||||
|
{getPercent(dnsQueries, replacedSafebrowsing)}
|
||||||
|
</div>
|
||||||
|
<div className="card-title-stats">
|
||||||
|
Blocked malware/phishing
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="card-chart-bg">
|
||||||
|
<Line data={safebrowsingData} color={STATUS_COLORS.green}/>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
<div className="col-sm-6 col-lg-3">
|
||||||
|
<Card bodyType="card-wrap">
|
||||||
|
<div className="card-body-stats">
|
||||||
|
<div className="card-value card-value-stats text-yellow">
|
||||||
|
{replacedParental}
|
||||||
|
</div>
|
||||||
|
<div className="card-value card-value-percent text-yellow">
|
||||||
|
{getPercent(dnsQueries, replacedParental)}
|
||||||
|
</div>
|
||||||
|
<div className="card-title-stats">
|
||||||
|
Blocked adult websites
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="card-chart-bg">
|
||||||
|
<Line data={parentalData} color={STATUS_COLORS.yellow}/>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Statistics.propTypes = {
|
Statistics.propTypes = {
|
||||||
history: PropTypes.array.isRequired,
|
history: PropTypes.array.isRequired,
|
||||||
refreshButton: PropTypes.node,
|
dnsQueries: PropTypes.number.isRequired,
|
||||||
|
blockedFiltering: PropTypes.number.isRequired,
|
||||||
|
replacedSafebrowsing: PropTypes.number.isRequired,
|
||||||
|
replacedParental: PropTypes.number.isRequired,
|
||||||
|
refreshButton: PropTypes.node.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Statistics;
|
export default Statistics;
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
.line__tooltip {
|
||||||
|
padding: 2px 10px 7px;
|
||||||
|
line-height: 1.1;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line__tooltip-text {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { ResponsiveLine } from '@nivo/line';
|
||||||
|
|
||||||
|
import './Line.css';
|
||||||
|
|
||||||
|
const Line = props => (
|
||||||
|
props.data &&
|
||||||
|
<ResponsiveLine
|
||||||
|
data={props.data}
|
||||||
|
margin={{
|
||||||
|
top: 15,
|
||||||
|
right: 0,
|
||||||
|
bottom: 1,
|
||||||
|
left: 0,
|
||||||
|
}}
|
||||||
|
minY="auto"
|
||||||
|
stacked={false}
|
||||||
|
curve='linear'
|
||||||
|
axisBottom={{
|
||||||
|
tickSize: 0,
|
||||||
|
tickPadding: 0,
|
||||||
|
}}
|
||||||
|
axisLeft={{
|
||||||
|
tickSize: 0,
|
||||||
|
tickPadding: 0,
|
||||||
|
}}
|
||||||
|
enableGridX={false}
|
||||||
|
enableGridY={false}
|
||||||
|
enableDots={false}
|
||||||
|
enableArea={true}
|
||||||
|
animate={false}
|
||||||
|
colorBy={() => (props.color)}
|
||||||
|
tooltip={slice => (
|
||||||
|
<div>
|
||||||
|
{slice.data.map(d => (
|
||||||
|
<div key={d.serie.id} className="line__tooltip">
|
||||||
|
<span className="line__tooltip-text">
|
||||||
|
{d.data.y}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
theme={{
|
||||||
|
tooltip: {
|
||||||
|
container: {
|
||||||
|
padding: '0',
|
||||||
|
background: '#333',
|
||||||
|
borderRadius: '4px',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
Line.propTypes = {
|
||||||
|
data: PropTypes.array.isRequired,
|
||||||
|
color: PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Line;
|
|
@ -1 +1,17 @@
|
||||||
export const R_URL_REQUIRES_PROTOCOL = /^https?:\/\/\w[\w_\-.]*\.[a-z]{2,8}[^\s]*$/;
|
export const R_URL_REQUIRES_PROTOCOL = /^https?:\/\/\w[\w_\-.]*\.[a-z]{2,8}[^\s]*$/;
|
||||||
|
|
||||||
|
export const STATS_NAMES = {
|
||||||
|
avg_processing_time: 'Average processing time',
|
||||||
|
blocked_filtering: 'Blocked by filters',
|
||||||
|
dns_queries: 'DNS queries',
|
||||||
|
replaced_parental: 'Blocked adult websites',
|
||||||
|
replaced_safebrowsing: 'Blocked malware/phishing',
|
||||||
|
replaced_safesearch: 'Enforced safe search',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const STATUS_COLORS = {
|
||||||
|
blue: '#467fcf',
|
||||||
|
red: '#cd201f',
|
||||||
|
green: '#5eba00',
|
||||||
|
yellow: '#f1c40f',
|
||||||
|
};
|
||||||
|
|
|
@ -4,6 +4,8 @@ import subHours from 'date-fns/sub_hours';
|
||||||
import addHours from 'date-fns/add_hours';
|
import addHours from 'date-fns/add_hours';
|
||||||
import round from 'lodash/round';
|
import round from 'lodash/round';
|
||||||
|
|
||||||
|
import { STATS_NAMES } from './constants';
|
||||||
|
|
||||||
const formatTime = (time) => {
|
const formatTime = (time) => {
|
||||||
const parsedTime = dateParse(time);
|
const parsedTime = dateParse(time);
|
||||||
return dateFormat(parsedTime, 'HH:mm:ss');
|
return dateFormat(parsedTime, 'HH:mm:ss');
|
||||||
|
@ -34,15 +36,6 @@ export const normalizeLogs = logs => logs.map((log) => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const STATS_NAMES = {
|
|
||||||
avg_processing_time: 'Average processing time',
|
|
||||||
blocked_filtering: 'Blocked by filters',
|
|
||||||
dns_queries: 'DNS queries',
|
|
||||||
replaced_parental: 'Blocked adult websites',
|
|
||||||
replaced_safebrowsing: 'Blocked malware/phishing',
|
|
||||||
replaced_safesearch: 'Enforced safe search',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const normalizeHistory = history => Object.keys(history).map((key) => {
|
export const normalizeHistory = history => Object.keys(history).map((key) => {
|
||||||
let id = STATS_NAMES[key];
|
let id = STATS_NAMES[key];
|
||||||
if (!id) {
|
if (!id) {
|
||||||
|
@ -81,3 +74,5 @@ export const normalizeFilteringStatus = (filteringStatus) => {
|
||||||
const newUserRules = Array.isArray(userRules) ? userRules.join('\n') : '';
|
const newUserRules = Array.isArray(userRules) ? userRules.join('\n') : '';
|
||||||
return { enabled, userRules: newUserRules, filters: newFilters };
|
return { enabled, userRules: newUserRules, filters: newFilters };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getPercent = (amount, number) => round(100 / (amount / number));
|
||||||
|
|
Loading…
Reference in New Issue