mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-11-22 04:55:33 +03:00
Merge pull request #72 in DNS/adguard-dns from feature/360 to master
* commit '35368619b0d7ed0fb838d749cd7b2f63ae9c9aa3': Fix footer links Add progress bar to the stats tables Add new logo Replace the main Statistics graph with 4 blocks instead Clean static folder on build
This commit is contained in:
commit
47a9c6555e
19 changed files with 519 additions and 168 deletions
|
@ -13,6 +13,13 @@
|
|||
"commonjs": true
|
||||
},
|
||||
|
||||
"settings": {
|
||||
"react": {
|
||||
"pragma": "React",
|
||||
"version": "16.4"
|
||||
}
|
||||
},
|
||||
|
||||
"rules": {
|
||||
"indent": ["error", 4, {
|
||||
"SwitchCase": 1,
|
||||
|
@ -43,6 +50,6 @@
|
|||
}],
|
||||
"no-console": ["warn", { "allow": ["warn", "error"] }],
|
||||
"import/no-extraneous-dependencies": ["error", { "devDependencies": true }],
|
||||
"import/prefer-default-export": "off",
|
||||
"import/prefer-default-export": "off"
|
||||
}
|
||||
}
|
||||
|
|
88
client/package-lock.json
generated
88
client/package-lock.json
generated
|
@ -181,18 +181,32 @@
|
|||
"glob-to-regexp": "^0.3.0"
|
||||
}
|
||||
},
|
||||
"@nivo/axes": {
|
||||
"version": "0.49.1",
|
||||
"resolved": "https://registry.npmjs.org/@nivo/axes/-/axes-0.49.1.tgz",
|
||||
"integrity": "sha512-2ZqpKtnZ9HE30H+r565VCrypKRQzAoMbAg1hsht88dlNQRtghBSxbAS0Y4IUW/wgN/AzvOIBJHvxH7bgaB8Oow==",
|
||||
"requires": {
|
||||
"@nivo/core": "0.49.0",
|
||||
"d3-format": "^1.3.2",
|
||||
"d3-time-format": "^2.1.3",
|
||||
"lodash": "^4.17.4",
|
||||
"react-motion": "^0.5.2",
|
||||
"recompose": "^0.26.0"
|
||||
}
|
||||
},
|
||||
"@nivo/core": {
|
||||
"version": "0.42.1",
|
||||
"resolved": "https://registry.npmjs.org/@nivo/core/-/core-0.42.1.tgz",
|
||||
"integrity": "sha512-T3DgbV9x6snbHxNQ2vWZYJRCnI6iUqh9A6Kn1Fsy1L7Sn97fsf89e1qMp0CpILhyJu7Fj+VXRYtJwby0wH6GAA==",
|
||||
"version": "0.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@nivo/core/-/core-0.49.0.tgz",
|
||||
"integrity": "sha512-TCPMUO2aJ7fI+ZB6t3d3EBQtNxJnTzaxLJsrVyn/3AQIjUwccAeo2aIy81wLBGWGtlGNUDNdAbnFzXiJosH0yg==",
|
||||
"requires": {
|
||||
"d3-color": "^1.0.3",
|
||||
"d3-format": "^1.2.0",
|
||||
"d3-hierarchy": "^1.1.5",
|
||||
"d3-interpolate": "^1.1.5",
|
||||
"d3-scale": "^1.0.6",
|
||||
"d3-scale-chromatic": "^1.1.1",
|
||||
"d3-shape": "^1.2.0",
|
||||
"d3-format": "^1.3.2",
|
||||
"d3-hierarchy": "^1.1.8",
|
||||
"d3-interpolate": "^1.3.2",
|
||||
"d3-scale": "^2.1.2",
|
||||
"d3-scale-chromatic": "^1.3.3",
|
||||
"d3-shape": "^1.2.2",
|
||||
"d3-time-format": "^2.1.3",
|
||||
"lodash": "^4.17.4",
|
||||
"react-measure": "^2.0.2",
|
||||
"react-motion": "^0.5.2",
|
||||
|
@ -200,29 +214,41 @@
|
|||
}
|
||||
},
|
||||
"@nivo/legends": {
|
||||
"version": "0.42.0",
|
||||
"resolved": "https://registry.npmjs.org/@nivo/legends/-/legends-0.42.0.tgz",
|
||||
"integrity": "sha512-t82aKNaFtbY0mlE12caiSkXml73APMibH+gKsXECwhSutfGfgQzUbqBjPsNKJcMiWfG46noJ1MrFhDB3a6204g==",
|
||||
"version": "0.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@nivo/legends/-/legends-0.49.0.tgz",
|
||||
"integrity": "sha512-8KbUFYozqwD+/rj4in0mnF9b9CuyNFjVgXqm2KW3ODVlWIgYgjTVlEhlg9VZIArFPlIyyAjEYC88YSRcALHugg==",
|
||||
"requires": {
|
||||
"lodash": "^4.17.4",
|
||||
"recompose": "^0.26.0"
|
||||
}
|
||||
},
|
||||
"@nivo/line": {
|
||||
"version": "0.42.1",
|
||||
"resolved": "https://registry.npmjs.org/@nivo/line/-/line-0.42.1.tgz",
|
||||
"integrity": "sha512-X/nvNvwMqz10hACBL/owCONDeG78occ6Er0ay6/1n2h+Dm6zn2p6hiFyvu7QtsdwGeHOC5sePcz9O44bycbtoQ==",
|
||||
"version": "0.49.1",
|
||||
"resolved": "https://registry.npmjs.org/@nivo/line/-/line-0.49.1.tgz",
|
||||
"integrity": "sha512-wKkOmpnwK2psmZbJReDq+Eh/WV9r1JA8V4Vl4eIRuf971CW0KUT9nCAoc/FcKio0qsiq5wyFt3J5LuAhfzlV/w==",
|
||||
"requires": {
|
||||
"@nivo/core": "0.42.1",
|
||||
"@nivo/legends": "0.42.0",
|
||||
"d3-format": "^1.2.0",
|
||||
"d3-scale": "^1.0.6",
|
||||
"d3-shape": "^1.2.0",
|
||||
"@nivo/axes": "0.49.1",
|
||||
"@nivo/core": "0.49.0",
|
||||
"@nivo/legends": "0.49.0",
|
||||
"@nivo/scales": "0.49.0",
|
||||
"d3-format": "^1.3.2",
|
||||
"d3-scale": "^2.1.2",
|
||||
"d3-shape": "^1.2.2",
|
||||
"lodash": "^4.17.4",
|
||||
"react-motion": "^0.5.2",
|
||||
"recompose": "^0.26.0"
|
||||
}
|
||||
},
|
||||
"@nivo/scales": {
|
||||
"version": "0.49.0",
|
||||
"resolved": "https://registry.npmjs.org/@nivo/scales/-/scales-0.49.0.tgz",
|
||||
"integrity": "sha512-+5Leu4zX6mDSAunf4ZJHeqVlT+ZsqiKXLB6hT/u7r3GjxZP9A+n3rHePhIzikBiBRMlLjyiBlylLzhKBAYbGWQ==",
|
||||
"requires": {
|
||||
"d3-scale": "^2.1.2",
|
||||
"d3-time-format": "^2.1.3",
|
||||
"lodash": "^4.17.4"
|
||||
}
|
||||
},
|
||||
"@nodelib/fs.stat": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.1.tgz",
|
||||
|
@ -2677,6 +2703,15 @@
|
|||
"source-map": "~0.6.0"
|
||||
}
|
||||
},
|
||||
"clean-webpack-plugin": {
|
||||
"version": "0.1.19",
|
||||
"resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-0.1.19.tgz",
|
||||
"integrity": "sha512-M1Li5yLHECcN2MahoreuODul5LkjohJGFxLPTjl3j1ttKrF5rgjZET1SJduuqxLAuT1gAPOdkhg03qcaaU1KeA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"rimraf": "^2.6.1"
|
||||
}
|
||||
},
|
||||
"cli-cursor": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
|
||||
|
@ -3502,13 +3537,12 @@
|
|||
"integrity": "sha512-q0cW1RpvA5c5ma2rch62mX8AYaiLX0+bdaSM2wxSU9tXjU4DNvkx9qiUvjkuWCj3p22UO/hlPivujqMiR9PDzA=="
|
||||
},
|
||||
"d3-scale": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-1.0.7.tgz",
|
||||
"integrity": "sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==",
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.1.2.tgz",
|
||||
"integrity": "sha512-bESpd64ylaKzCDzvULcmHKZTlzA/6DGSVwx7QSDj/EnX9cpSevsdiwdHFYI9ouo9tNBbV3v5xztHS2uFeOzh8Q==",
|
||||
"requires": {
|
||||
"d3-array": "^1.2.0",
|
||||
"d3-collection": "1",
|
||||
"d3-color": "1",
|
||||
"d3-format": "1",
|
||||
"d3-interpolate": "1",
|
||||
"d3-time": "1",
|
||||
|
@ -12822,9 +12856,9 @@
|
|||
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
|
||||
},
|
||||
"react-measure": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-measure/-/react-measure-2.1.0.tgz",
|
||||
"integrity": "sha512-nHdoq1eTbGVg/jWWAEtxXSHH51j09d1nPabj6PwS+pNSCYYf1H5XLMfcfU2ZTnkDU/Xg0fGY79Xud2Gsp3VsmQ==",
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/react-measure/-/react-measure-2.1.2.tgz",
|
||||
"integrity": "sha512-2xgrlj77Pv8MIYhm+S5s4Q+QnsYFT3CXzoUkx2mWZBIWzQnT7ubMtmsVtCoNdYV5PGKjTlwo9iGAtS3SrTG/Gg==",
|
||||
"requires": {
|
||||
"get-node-dimensions": "^1.2.0",
|
||||
"prop-types": "^15.5.10",
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"lint": "eslint frontend/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nivo/line": "^0.42.1",
|
||||
"@nivo/line": "^0.49.1",
|
||||
"axios": "^0.18.0",
|
||||
"classnames": "^2.2.6",
|
||||
"date-fns": "^1.29.0",
|
||||
|
@ -44,6 +44,7 @@
|
|||
"babel-preset-react": "^6.24.1",
|
||||
"babel-preset-stage-2": "^6.24.1",
|
||||
"babel-runtime": "6.26.0",
|
||||
"clean-webpack-plugin": "^0.1.19",
|
||||
"compression-webpack-plugin": "^1.1.11",
|
||||
"css-loader": "^0.28.11",
|
||||
"eslint": "^4.19.1",
|
||||
|
|
|
@ -1,23 +1,45 @@
|
|||
import React from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import ReactTable from 'react-table';
|
||||
import PropTypes from 'prop-types';
|
||||
import map from 'lodash/map';
|
||||
|
||||
import Card from '../ui/Card';
|
||||
import Cell from '../ui/Cell';
|
||||
|
||||
const Clients = props => (
|
||||
<Card title="Top blocked domains" subtitle="for the last 24 hours" bodyType="card-table" refresh={props.refreshButton}>
|
||||
<ReactTable
|
||||
data={map(props.topBlockedDomains, (value, prop) => (
|
||||
{ ip: prop, domain: value }
|
||||
))}
|
||||
columns={[{
|
||||
import { getPercent } from '../../helpers/helpers';
|
||||
import { STATUS_COLORS } from '../../helpers/constants';
|
||||
|
||||
class BlockedDomains extends Component {
|
||||
columns = [{
|
||||
Header: 'IP',
|
||||
accessor: 'ip',
|
||||
Cell: ({ value }) => (<div className="logs__row logs__row--overflow"><span className="logs__text" title={value}>{value}</span></div>),
|
||||
}, {
|
||||
Header: 'Domain name',
|
||||
Header: 'Requests count',
|
||||
accessor: 'domain',
|
||||
}]}
|
||||
Cell: ({ value }) => {
|
||||
const {
|
||||
blockedFiltering,
|
||||
replacedSafebrowsing,
|
||||
replacedParental,
|
||||
} = this.props;
|
||||
const blocked = blockedFiltering + replacedSafebrowsing + replacedParental;
|
||||
const percent = getPercent(blocked, value);
|
||||
|
||||
return (
|
||||
<Cell value={value} percent={percent} color={STATUS_COLORS.red} />
|
||||
);
|
||||
},
|
||||
}];
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Card title="Top blocked domains" subtitle="for the last 24 hours" bodyType="card-table" refresh={this.props.refreshButton}>
|
||||
<ReactTable
|
||||
data={map(this.props.topBlockedDomains, (value, prop) => (
|
||||
{ ip: prop, domain: value }
|
||||
))}
|
||||
columns={this.columns}
|
||||
showPagination={false}
|
||||
noDataText="No domains found"
|
||||
minRows={6}
|
||||
|
@ -25,10 +47,15 @@ const Clients = props => (
|
|||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Clients.propTypes = {
|
||||
BlockedDomains.propTypes = {
|
||||
topBlockedDomains: PropTypes.object.isRequired,
|
||||
refreshButton: PropTypes.node,
|
||||
blockedFiltering: PropTypes.number.isRequired,
|
||||
replacedSafebrowsing: PropTypes.number.isRequired,
|
||||
replacedParental: PropTypes.number.isRequired,
|
||||
refreshButton: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
export default Clients;
|
||||
export default BlockedDomains;
|
||||
|
|
|
@ -1,23 +1,49 @@
|
|||
import React from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import ReactTable from 'react-table';
|
||||
import PropTypes from 'prop-types';
|
||||
import map from 'lodash/map';
|
||||
|
||||
import Card from '../ui/Card';
|
||||
import Cell from '../ui/Cell';
|
||||
|
||||
const Clients = props => (
|
||||
<Card title="Top clients" subtitle="for the last 24 hours" bodyType="card-table" refresh={props.refreshButton}>
|
||||
<ReactTable
|
||||
data={map(props.topClients, (value, prop) => (
|
||||
{ ip: prop, count: value }
|
||||
))}
|
||||
columns={[{
|
||||
import { getPercent } from '../../helpers/helpers';
|
||||
import { STATUS_COLORS } from '../../helpers/constants';
|
||||
|
||||
class Clients extends Component {
|
||||
getPercentColor = (percent) => {
|
||||
if (percent > 50) {
|
||||
return STATUS_COLORS.green;
|
||||
} else if (percent > 10) {
|
||||
return STATUS_COLORS.yellow;
|
||||
}
|
||||
return STATUS_COLORS.red;
|
||||
}
|
||||
|
||||
columns = [{
|
||||
Header: 'IP',
|
||||
accessor: 'ip',
|
||||
Cell: ({ value }) => (<div className="logs__row logs__row--overflow"><span className="logs__text" title={value}>{value}</span></div>),
|
||||
}, {
|
||||
Header: 'Requests count',
|
||||
accessor: 'count',
|
||||
}]}
|
||||
Cell: ({ value }) => {
|
||||
const percent = getPercent(this.props.dnsQueries, value);
|
||||
const percentColor = this.getPercentColor(percent);
|
||||
|
||||
return (
|
||||
<Cell value={value} percent={percent} color={percentColor} />
|
||||
);
|
||||
},
|
||||
}];
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Card title="Top clients" subtitle="for the last 24 hours" bodyType="card-table" refresh={this.props.refreshButton}>
|
||||
<ReactTable
|
||||
data={map(this.props.topClients, (value, prop) => (
|
||||
{ ip: prop, count: value }
|
||||
))}
|
||||
columns={this.columns}
|
||||
showPagination={false}
|
||||
noDataText="No clients found"
|
||||
minRows={6}
|
||||
|
@ -25,10 +51,13 @@ const Clients = props => (
|
|||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Clients.propTypes = {
|
||||
topClients: PropTypes.object.isRequired,
|
||||
refreshButton: PropTypes.node,
|
||||
dnsQueries: PropTypes.number.isRequired,
|
||||
refreshButton: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
export default Clients;
|
||||
|
|
|
@ -88,7 +88,7 @@ Counters.propTypes = {
|
|||
replacedParental: PropTypes.number.isRequired,
|
||||
replacedSafesearch: PropTypes.number.isRequired,
|
||||
avgProcessingTime: PropTypes.number.isRequired,
|
||||
refreshButton: PropTypes.node,
|
||||
refreshButton: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
export default Counters;
|
||||
|
|
|
@ -1,23 +1,49 @@
|
|||
import React from 'react';
|
||||
import React, { Component } from 'react';
|
||||
import ReactTable from 'react-table';
|
||||
import PropTypes from 'prop-types';
|
||||
import map from 'lodash/map';
|
||||
|
||||
import Card from '../ui/Card';
|
||||
import Cell from '../ui/Cell';
|
||||
|
||||
const QueriedDomains = props => (
|
||||
<Card title="Top queried domains" subtitle="for the last 24 hours" bodyType="card-table" refresh={props.refreshButton}>
|
||||
<ReactTable
|
||||
data={map(props.topQueriedDomains, (value, prop) => (
|
||||
{ ip: prop, count: value }
|
||||
))}
|
||||
columns={[{
|
||||
import { getPercent } from '../../helpers/helpers';
|
||||
import { STATUS_COLORS } from '../../helpers/constants';
|
||||
|
||||
class QueriedDomains extends Component {
|
||||
getPercentColor = (percent) => {
|
||||
if (percent > 10) {
|
||||
return STATUS_COLORS.red;
|
||||
} else if (percent > 5) {
|
||||
return STATUS_COLORS.yellow;
|
||||
}
|
||||
return STATUS_COLORS.green;
|
||||
}
|
||||
|
||||
columns = [{
|
||||
Header: 'IP',
|
||||
accessor: 'ip',
|
||||
Cell: ({ value }) => (<div className="logs__row logs__row--overflow"><span className="logs__text" title={value}>{value}</span></div>),
|
||||
}, {
|
||||
Header: 'Requests count',
|
||||
accessor: 'count',
|
||||
}]}
|
||||
Cell: ({ value }) => {
|
||||
const percent = getPercent(this.props.dnsQueries, value);
|
||||
const percentColor = this.getPercentColor(percent);
|
||||
|
||||
return (
|
||||
<Cell value={value} percent={percent} color={percentColor} />
|
||||
);
|
||||
},
|
||||
}];
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Card title="Top queried domains" subtitle="for the last 24 hours" bodyType="card-table" refresh={this.props.refreshButton}>
|
||||
<ReactTable
|
||||
data={map(this.props.topQueriedDomains, (value, prop) => (
|
||||
{ ip: prop, count: value }
|
||||
))}
|
||||
columns={this.columns}
|
||||
showPagination={false}
|
||||
noDataText="No domains found"
|
||||
minRows={6}
|
||||
|
@ -25,10 +51,13 @@ const QueriedDomains = props => (
|
|||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
QueriedDomains.propTypes = {
|
||||
topQueriedDomains: PropTypes.object.isRequired,
|
||||
refreshButton: PropTypes.node,
|
||||
dnsQueries: PropTypes.number.isRequired,
|
||||
refreshButton: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
export default QueriedDomains;
|
||||
|
|
|
@ -1,59 +1,109 @@
|
|||
import React from 'react';
|
||||
import { ResponsiveLine } from '@nivo/line';
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Card from '../ui/Card';
|
||||
import Line from '../ui/Line';
|
||||
|
||||
const Statistics = props => (
|
||||
<Card title="Statistics" subtitle="for the last 24 hours" bodyType="card-graph" refresh={props.refreshButton}>
|
||||
{props.history ?
|
||||
<ResponsiveLine
|
||||
data={props.history}
|
||||
margin={{
|
||||
top: 50,
|
||||
right: 40,
|
||||
bottom: 80,
|
||||
left: 80,
|
||||
}}
|
||||
minY="auto"
|
||||
stacked={false}
|
||||
curve='monotoneX'
|
||||
axisBottom={{
|
||||
orient: 'bottom',
|
||||
tickSize: 5,
|
||||
tickPadding: 5,
|
||||
tickRotation: -45,
|
||||
legendOffset: 50,
|
||||
legendPosition: 'center',
|
||||
}}
|
||||
axisLeft={{
|
||||
orient: 'left',
|
||||
tickSize: 5,
|
||||
tickPadding: 5,
|
||||
tickRotation: 0,
|
||||
legendOffset: -40,
|
||||
legendPosition: 'center',
|
||||
}}
|
||||
enableArea={true}
|
||||
dotSize={10}
|
||||
dotColor="inherit:darker(0.3)"
|
||||
dotBorderWidth={2}
|
||||
dotBorderColor="#ffffff"
|
||||
dotLabel="y"
|
||||
dotLabelYOffset={-12}
|
||||
animate={true}
|
||||
motionStiffness={90}
|
||||
motionDamping={15}
|
||||
/>
|
||||
:
|
||||
<h2 className="text-muted">Empty data</h2>
|
||||
}
|
||||
import { getPercent } from '../../helpers/helpers';
|
||||
import { STATUS_COLORS } from '../../helpers/constants';
|
||||
|
||||
class Statistics extends Component {
|
||||
render() {
|
||||
const {
|
||||
dnsQueries,
|
||||
blockedFiltering,
|
||||
replacedSafebrowsing,
|
||||
replacedParental,
|
||||
} = this.props;
|
||||
|
||||
const filteringData = [this.props.history[1]];
|
||||
const queriesData = [this.props.history[2]];
|
||||
const parentalData = [this.props.history[3]];
|
||||
const safebrowsingData = [this.props.history[4]];
|
||||
|
||||
return (
|
||||
<div className="row">
|
||||
<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-blue">
|
||||
{dnsQueries}
|
||||
</div>
|
||||
<div className="card-title-stats">
|
||||
DNS Queries
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-chart-bg">
|
||||
<Line data={queriesData} color={STATUS_COLORS.blue}/>
|
||||
</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-red">
|
||||
{blockedFiltering}
|
||||
</div>
|
||||
<div className="card-value card-value-percent text-red">
|
||||
{getPercent(dnsQueries, blockedFiltering)}
|
||||
</div>
|
||||
<div className="card-title-stats">
|
||||
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 = {
|
||||
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;
|
||||
|
|
|
@ -61,6 +61,10 @@ class Dashboard extends Component {
|
|||
<Statistics
|
||||
history={dashboard.statsHistory}
|
||||
refreshButton={refreshButton}
|
||||
dnsQueries={dashboard.stats.dns_queries}
|
||||
blockedFiltering={dashboard.stats.blocked_filtering}
|
||||
replacedSafebrowsing={dashboard.stats.replaced_safebrowsing}
|
||||
replacedParental={dashboard.stats.replaced_parental}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
@ -81,12 +85,14 @@ class Dashboard extends Component {
|
|||
<Fragment>
|
||||
<div className="col-lg-6">
|
||||
<Clients
|
||||
dnsQueries={dashboard.stats.dns_queries}
|
||||
refreshButton={refreshButton}
|
||||
topClients={dashboard.topStats.top_clients}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-lg-6">
|
||||
<QueriedDomains
|
||||
dnsQueries={dashboard.stats.dns_queries}
|
||||
refreshButton={refreshButton}
|
||||
topQueriedDomains={dashboard.topStats.top_queried_domains}
|
||||
/>
|
||||
|
@ -95,6 +101,9 @@ class Dashboard extends Component {
|
|||
<BlockedDomains
|
||||
refreshButton={refreshButton}
|
||||
topBlockedDomains={dashboard.topStats.top_blocked_domains}
|
||||
blockedFiltering={dashboard.stats.blocked_filtering}
|
||||
replacedSafebrowsing={dashboard.stats.replaced_safebrowsing}
|
||||
replacedParental={dashboard.stats.replaced_parental}
|
||||
/>
|
||||
</div>
|
||||
</Fragment>
|
||||
|
|
|
@ -77,7 +77,7 @@
|
|||
}
|
||||
|
||||
.header-brand-img {
|
||||
height: 26px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 992px) {
|
||||
|
|
|
@ -1 +1 @@
|
|||
<svg viewBox="0 0 118 26" xmlns="http://www.w3.org/2000/svg"><path fill="#232323" d="M92.535 18.314l-.897-2.259h-4.47l-.849 2.259h-3.034L88.13 6.809h2.708l4.796 11.505h-3.1zm-3.1-8.434l-1.468 3.949h2.904L89.435 9.88zm-6.607 4.095c0 .693-.117 1.324-.35 1.893a4.115 4.115 0 0 1-1.004 1.463 4.63 4.63 0 0 1-1.574.95c-.614.228-1.297.341-2.047.341-.761 0-1.447-.113-2.056-.34a4.468 4.468 0 0 1-1.55-.951 4.126 4.126 0 0 1-.978-1.463 5.038 5.038 0 0 1-.343-1.893V6.809H75.7v6.939c0 .314.041.612.123.893.081.282.206.534.375.756.169.222.392.398.669.528s.612.195 1.003.195c.392 0 .726-.065 1.003-.195a1.83 1.83 0 0 0 .677-.528 2.1 2.1 0 0 0 .376-.756c.076-.281.114-.58.114-.893v-6.94h2.79v7.167zm-11.446 3.64a8.898 8.898 0 0 1-1.982.715 10.43 10.43 0 0 1-2.472.276c-.924 0-1.775-.146-2.553-.439a5.895 5.895 0 0 1-2.006-1.235 5.63 5.63 0 0 1-1.314-1.909c-.315-.742-.473-1.568-.473-2.478 0-.92.16-1.755.482-2.502a5.567 5.567 0 0 1 1.33-1.91 5.893 5.893 0 0 1 1.99-1.21 7.044 7.044 0 0 1 2.463-.423c.913 0 1.762.138 2.545.414.783.277 1.419.648 1.908 1.114l-1.762 1.998a3.05 3.05 0 0 0-1.076-.772c-.446-.2-.952-.3-1.517-.3-.49 0-.941.09-1.354.268a3.256 3.256 0 0 0-1.077.747 3.39 3.39 0 0 0-.71 1.138 3.977 3.977 0 0 0-.253 1.438c0 .53.077 1.018.229 1.463.152.444.378.826.677 1.145.299.32.669.569 1.11.748.44.178.943.268 1.508.268.326 0 .636-.025.93-.073.294-.05.566-.128.816-.236v-2.096h-2.203V11.52h4.764v6.094zm46.107-5.086c0 1.007-.188 1.877-.563 2.608a5.262 5.262 0 0 1-1.484 1.804 6.199 6.199 0 0 1-2.08 1.04 8.459 8.459 0 0 1-2.35.333h-4.306V6.809h4.176c.816 0 1.62.095 2.414.284.794.19 1.501.504 2.121.943.62.438 1.12 1.026 1.5 1.763.382.736.572 1.646.572 2.73zm-2.904 0c0-.65-.106-1.19-.318-1.617a2.724 2.724 0 0 0-.848-1.024 3.4 3.4 0 0 0-1.208-.544 5.955 5.955 0 0 0-1.394-.163h-1.387v6.728h1.321c.5 0 .982-.057 1.444-.17.462-.115.87-.301 1.224-.562a2.78 2.78 0 0 0 .848-1.04c.212-.433.318-.97.318-1.608zm-55.226 0c0 1.007-.188 1.877-.563 2.608a5.262 5.262 0 0 1-1.484 1.804 6.199 6.199 0 0 1-2.08 1.04 8.459 8.459 0 0 1-2.35.333h-4.306V6.809h4.176c.816 0 1.62.095 2.414.284.794.19 1.501.504 2.121.943.62.438 1.12 1.026 1.5 1.763.382.736.572 1.646.572 2.73zm-2.904 0c0-.65-.106-1.19-.318-1.617a2.724 2.724 0 0 0-.848-1.024 3.4 3.4 0 0 0-1.207-.544 5.955 5.955 0 0 0-1.395-.163H51.3v6.728h1.321c.5 0 .982-.057 1.444-.17.462-.115.87-.301 1.224-.562a2.78 2.78 0 0 0 .848-1.04c.212-.433.318-.97.318-1.608zm-11.86 5.785l-.897-2.259h-4.47l-.848 2.259h-3.034L40.19 6.809h2.708l4.796 11.505h-3.1zm-3.1-8.434l-1.467 3.949h2.903L41.496 9.88zm61.203 8.434l-2.496-4.566h-.946v4.566h-2.74V6.809h4.404c.555 0 1.096.057 1.623.17.528.114 1 .306 1.42.577.418.271.752.629 1.003 1.073.25.444.375.996.375 1.657 0 .78-.212 1.436-.636 1.966-.425.531-1.012.91-1.762 1.138l3.018 4.924h-3.263zm-.114-7.979c0-.27-.057-.49-.171-.658a1.172 1.172 0 0 0-.44-.39 1.919 1.919 0 0 0-.604-.187 4.469 4.469 0 0 0-.645-.049H99.24v2.681h1.321c.228 0 .462-.018.701-.056.24-.038.457-.106.653-.204.196-.097.356-.238.481-.422s.188-.422.188-.715z"/><path fill="#68bc71" d="M12.651 0C8.697 0 3.927.93 0 2.977c0 4.42-.054 15.433 12.651 22.958C25.357 18.41 25.303 7.397 25.303 2.977 21.376.93 16.606 0 12.651 0z"/><path fill="#67b279" d="M12.638 25.927C-.054 18.403 0 7.396 0 2.977 3.923.932 8.687.002 12.638 0v25.927z"/><path fill="#fff" d="M12.19 17.305l7.65-10.311c-.56-.45-1.052-.133-1.323.113h-.01l-6.379 6.636-2.403-2.892c-1.147-1.325-2.705-.314-3.07-.047l5.535 6.5"/></svg>
|
||||
<svg width="340" height="91" viewBox="0 0 340 91" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M265.964 50l-2.615-6.675h-13.03L247.844 50H239l14.124-34h7.894L275 50h-9.036zm-9.035-24.924l-4.28 11.67h8.465l-4.185-11.67zM238 37.231c0 2.054-.342 3.924-1.027 5.609-.685 1.685-1.664 3.129-2.938 4.333-1.274 1.203-2.811 2.142-4.61 2.816-1.8.674-3.799 1.011-5.997 1.011-2.23 0-4.236-.337-6.02-1.011-1.783-.674-3.296-1.613-4.538-2.816-1.242-1.204-2.198-2.648-2.867-4.333S209 39.285 209 37.23V16h8.122v20.557c0 .93.12 1.813.358 2.648a6.82 6.82 0 0 0 1.1 2.239c.493.658 1.146 1.18 1.958 1.564.812.385 1.791.578 2.938.578 1.147 0 2.126-.193 2.938-.578.813-.385 1.473-.906 1.983-1.564a6.248 6.248 0 0 0 1.099-2.239c.223-.835.334-1.717.334-2.648V16H238v21.231zM204 47.134c-1.623.846-3.52 1.535-5.69 2.067-2.17.533-4.534.799-7.094.799-2.654 0-5.096-.423-7.329-1.268-2.232-.846-4.152-2.036-5.76-3.57-1.607-1.536-2.864-3.376-3.769-5.521-.905-2.145-1.358-4.534-1.358-7.164 0-2.663.46-5.074 1.381-7.235.921-2.161 2.194-4.002 3.817-5.52 1.623-1.52 3.528-2.686 5.713-3.5 2.185-.815 4.542-1.222 7.07-1.222 2.623 0 5.058.4 7.306 1.198 2.248.799 4.074 1.871 5.479 3.218l-5.058 5.779c-.78-.909-1.81-1.652-3.09-2.232-1.28-.58-2.732-.869-4.355-.869-1.405 0-2.7.258-3.887.775a9.345 9.345 0 0 0-3.09 2.161c-.875.924-1.554 2.02-2.038 3.289-.483 1.268-.725 2.654-.725 4.158 0 1.534.218 2.944.655 4.228.437 1.284 1.085 2.388 1.944 3.312.858.924 1.92 1.644 3.184 2.16 1.264.518 2.708.776 4.331.776.937 0 1.827-.07 2.67-.211a9.929 9.929 0 0 0 2.341-.682V36h-6.322v-6.483H204v17.617zM340 32.904c0 2.977-.54 5.547-1.618 7.708-1.079 2.16-2.501 3.937-4.268 5.33a17.637 17.637 0 0 1-5.98 3.074c-2.22.656-4.47.984-6.753.984H309V16h12.006c2.345 0 4.659.28 6.941.84 2.282.56 4.315 1.49 6.097 2.786s3.22 3.033 4.315 5.21c1.094 2.177 1.641 4.866 1.641 8.068zm-8.348 0c0-1.921-.305-3.514-.914-4.778-.61-1.265-1.423-2.273-2.44-3.026a9.649 9.649 0 0 0-3.47-1.608 16.677 16.677 0 0 0-4.01-.48h-3.986v19.88h3.799a16.86 16.86 0 0 0 4.15-.504c1.33-.336 2.502-.888 3.518-1.656 1.016-.769 1.829-1.793 2.439-3.074.61-1.28.914-2.865.914-4.754zM169 32.904c0 2.977-.54 5.547-1.618 7.708-1.079 2.16-2.501 3.937-4.268 5.33a17.637 17.637 0 0 1-5.98 3.074c-2.22.656-4.47.984-6.753.984H138V16h12.006c2.345 0 4.659.28 6.941.84 2.282.56 4.315 1.49 6.097 2.786s3.22 3.033 4.315 5.21c1.094 2.177 1.641 4.866 1.641 8.068zm-8.348 0c0-1.921-.305-3.514-.914-4.778-.61-1.265-1.423-2.273-2.44-3.026a9.649 9.649 0 0 0-3.47-1.608 16.677 16.677 0 0 0-4.01-.48h-3.986v19.88h3.799a16.86 16.86 0 0 0 4.15-.504c1.33-.336 2.502-.888 3.518-1.656 1.016-.769 1.829-1.793 2.439-3.074.61-1.28.914-2.865.914-4.754zM126.964 50l-2.615-6.675h-13.03L108.844 50H100l14.124-34h7.894L136 50h-9.036zm-9.035-24.924l-4.28 11.67h8.465l-4.185-11.67zM295.674 50l-7.135-13.494h-2.705V50H278V16h12.59c1.586 0 3.133.168 4.64.504 1.508.336 2.86.905 4.058 1.705 1.196.8 2.152 1.857 2.867 3.17.715 1.312 1.073 2.945 1.073 4.898 0 2.305-.606 4.242-1.819 5.81-1.212 1.57-2.89 2.69-5.036 3.362L305 50h-9.326zm-.327-23.58c0-.8-.163-1.448-.49-1.944a3.39 3.39 0 0 0-1.259-1.153 5.355 5.355 0 0 0-1.725-.552 12.364 12.364 0 0 0-1.842-.144h-4.243v7.924h3.777c.653 0 1.321-.056 2.005-.168a6.257 6.257 0 0 0 1.865-.6 3.596 3.596 0 0 0 1.376-1.25c.357-.543.536-1.248.536-2.112z" fill="#242424"/><path d="M44.477 0C30.575 0 13.805 3.255 0 10.419 0 25.89-.19 64.436 44.477 90.772 89.145 64.436 88.956 25.89 88.956 10.42 75.149 3.255 58.38 0 44.476 0z" fill="#68BC71"/><path d="M44.431 90.746C-.19 64.41 0 25.886 0 10.419 13.79 3.263 30.538.007 44.431 0v90.746z" fill="#67B279"/><path d="M42.854 60.566L69.75 24.477c-1.97-1.572-3.7-.462-4.65.397l-.036.003L42.64 48.102l-8.45-10.123c-4.03-4.636-9.51-1.1-10.79-.165l19.455 22.752" fill="#FFF"/><path d="M102.65 83V64.8h2.054v8.086h10.504V64.8h2.054V83h-2.054v-8.19h-10.504V83h-2.054zm28.21.312c-5.538 0-9.256-4.342-9.256-9.412 0-5.018 3.77-9.412 9.308-9.412s9.256 4.342 9.256 9.412c0 5.018-3.77 9.412-9.308 9.412zm.052-1.898c4.16 0 7.124-3.328 7.124-7.514 0-4.134-3.016-7.514-7.176-7.514s-7.124 3.328-7.124 7.514c0 4.134 3.016 7.514 7.176 7.514zM144.51 83V64.8h2.08l6.63 9.932 6.63-9.932h2.08V83h-2.054V68.258l-6.63 9.75h-.104l-6.63-9.724V83h-2.002zm22.568 0V64.8h13.156v1.872h-11.102v6.214h9.932v1.872h-9.932v6.37h11.232V83h-13.286z" fill="#4D4D4D"/></g></svg>
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 4.2 KiB |
|
@ -26,7 +26,6 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.card-body--status {
|
||||
|
@ -48,3 +47,40 @@
|
|||
.card-refresh:focus:active {
|
||||
background-image: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSJub25lIiBoZWlnaHQ9IjI0IiBzdHJva2U9IiNmZmYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLXdpZHRoPSIyIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtMjMgNHY2aC02Ii8+PHBhdGggZD0ibTEgMjB2LTZoNiIvPjxwYXRoIGQ9Im0zLjUxIDlhOSA5IDAgMCAxIDE0Ljg1LTMuMzZsNC42NCA0LjM2bS0yMiA0IDQuNjQgNC4zNmE5IDkgMCAwIDAgMTQuODUtMy4zNiIvPjwvc3ZnPg==");
|
||||
}
|
||||
|
||||
.card-title-stats {
|
||||
color: #9aa0ac;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-body-stats {
|
||||
position: relative;
|
||||
flex: 1 1 auto;
|
||||
margin: 0;
|
||||
padding: 1rem 1.5rem;
|
||||
}
|
||||
|
||||
.card-value-stats {
|
||||
display: block;
|
||||
font-size: 2.1rem;
|
||||
line-height: 2.7rem;
|
||||
height: 2.7rem;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card-value-percent {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.card-value-percent:after {
|
||||
content: "%";
|
||||
}
|
||||
|
|
30
client/src/components/ui/Cell.js
Normal file
30
client/src/components/ui/Cell.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const Cell = props => (
|
||||
<div className="stats__row">
|
||||
<div className="stats__row-value mb-1">
|
||||
<strong>{props.value}</strong>
|
||||
<small className="ml-3 text-muted">
|
||||
{props.percent}%
|
||||
</small>
|
||||
</div>
|
||||
<div className="progress progress-xs">
|
||||
<div
|
||||
className="progress-bar"
|
||||
style={{
|
||||
width: `${props.percent}%`,
|
||||
backgroundColor: props.color,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Cell.propTypes = {
|
||||
value: PropTypes.number.isRequired,
|
||||
percent: PropTypes.number.isRequired,
|
||||
color: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default Cell;
|
|
@ -12,17 +12,23 @@ class Footer extends Component {
|
|||
<div className="container">
|
||||
<div className="row align-items-center flex-row-reverse">
|
||||
<div className="col-12 col-lg-auto ml-lg-auto">
|
||||
<ul className="list-inline list-inline-dots text-center mb-0">
|
||||
<div className="row align-items-center justify-content-center">
|
||||
<div className="col-auto">
|
||||
<ul className="list-inline text-center mb-0">
|
||||
<li className="list-inline-item">
|
||||
<a href="https://adguard.com/adguard-dns/overview.html" target="_blank" rel="noopener noreferrer">Homepage</a>
|
||||
</li>
|
||||
<li className="list-inline-item">
|
||||
<a href="https://github.com/AdguardTeam/AdguardDNS" target="_blank" rel="noopener noreferrer">Github</a>
|
||||
<a href="https://github.com/AdguardTeam/AdguardDNS" target="_blank" rel="noopener noreferrer">Homepage</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="col-auto">
|
||||
<a href="https://github.com/AdguardTeam/AdguardDNS/issues/new" className="btn btn-outline-primary btn-sm" target="_blank" rel="noopener noreferrer">
|
||||
Report an issue
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 col-lg-auto mt-3 mt-lg-0 text-center">
|
||||
© AdGuard {this.getYear()}
|
||||
Copyright © {this.getYear()} <a href="https://adguard.com/">AdGuard</a>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
9
client/src/components/ui/Line.css
Normal file
9
client/src/components/ui/Line.css
Normal file
|
@ -0,0 +1,9 @@
|
|||
.line__tooltip {
|
||||
padding: 2px 10px 7px;
|
||||
line-height: 1.1;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.line__tooltip-text {
|
||||
font-size: 0.7rem;
|
||||
}
|
62
client/src/components/ui/Line.js
Normal file
62
client/src/components/ui/Line.js
Normal file
|
@ -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 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 round from 'lodash/round';
|
||||
|
||||
import { STATS_NAMES } from './constants';
|
||||
|
||||
const formatTime = (time) => {
|
||||
const parsedTime = dateParse(time);
|
||||
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) => {
|
||||
let id = STATS_NAMES[key];
|
||||
if (!id) {
|
||||
|
@ -81,3 +74,10 @@ export const normalizeFilteringStatus = (filteringStatus) => {
|
|||
const newUserRules = Array.isArray(userRules) ? userRules.join('\n') : '';
|
||||
return { enabled, userRules: newUserRules, filters: newFilters };
|
||||
};
|
||||
|
||||
export const getPercent = (amount, number) => {
|
||||
if (amount > 0 && number > 0) {
|
||||
return round(100 / (amount / number), 2);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
|
|
@ -4,6 +4,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin');
|
|||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||
const webpack = require('webpack');
|
||||
const flexBugsFixes = require('postcss-flexbugs-fixes');
|
||||
const CleanWebpackPlugin = require('clean-webpack-plugin');
|
||||
|
||||
const RESOURCES_PATH = path.resolve(__dirname);
|
||||
const ENTRY_REACT = path.resolve(RESOURCES_PATH, 'src/index.js');
|
||||
|
@ -92,6 +93,11 @@ const config = {
|
|||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
|
||||
}),
|
||||
new CleanWebpackPlugin(['*.*'], {
|
||||
root: PUBLIC_PATH,
|
||||
verbose: false,
|
||||
dry: false,
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
inject: true,
|
||||
cache: false,
|
||||
|
|
Loading…
Reference in a new issue