Pull request: 3313 statistics settings UI

Closes #3313

Squashed commit of the following:

commit 6f2ff98a8282789e2dbb16694ca87a1f4cc8c076
Merge: 1221f02f f4dde3f2
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Wed Jul 14 15:53:18 2021 +0300

    Merge branch 'master' into 3313-statistics

commit 1221f02f40628964febd22967d85d5185f87b08d
Author: Ildar Kamalov <ik@adguard.com>
Date:   Wed Jul 14 15:23:09 2021 +0300

    client: make client names clickable

commit 99770ec065e14ce2522a59820f9851d79001923c
Author: Ildar Kamalov <ik@adguard.com>
Date:   Wed Jul 14 15:06:30 2021 +0300

    client: decreasing interval confirm, disabled stats message
This commit is contained in:
Ildar Kamalov 2021-07-14 16:01:12 +03:00
parent f4dde3f2c1
commit ebade2b6ce
6 changed files with 59 additions and 12 deletions

View File

@ -112,6 +112,8 @@
"for_last_24_hours": "for the last 24 hours", "for_last_24_hours": "for the last 24 hours",
"for_last_days": "for the last {{count}} day", "for_last_days": "for the last {{count}} day",
"for_last_days_plural": "for the last {{count}} days", "for_last_days_plural": "for the last {{count}} days",
"stats_disabled": "The statistics have been disabled. You can turn it on from the <0>settings page</0>.",
"stats_disabled_short": "The statistics have been disabled",
"no_domains_found": "No domains found", "no_domains_found": "No domains found",
"requests_count": "Requests count", "requests_count": "Requests count",
"top_blocked_domains": "Top blocked domains", "top_blocked_domains": "Top blocked domains",

View File

@ -1,12 +1,15 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { HashLink as Link } from 'react-router-hash-link';
import { Trans, useTranslation } from 'react-i18next'; import { Trans, useTranslation } from 'react-i18next';
import classNames from 'classnames'; import classNames from 'classnames';
import Statistics from './Statistics'; import Statistics from './Statistics';
import Counters from './Counters'; import Counters from './Counters';
import Clients from './Clients'; import Clients from './Clients';
import QueriedDomains from './QueriedDomains'; import QueriedDomains from './QueriedDomains';
import BlockedDomains from './BlockedDomains'; import BlockedDomains from './BlockedDomains';
import { SETTINGS_URLS } from '../../helpers/constants';
import PageTitle from '../ui/PageTitle'; import PageTitle from '../ui/PageTitle';
import Loading from '../ui/Loading'; import Loading from '../ui/Loading';
@ -34,6 +37,16 @@ const Dashboard = ({
getAllStats(); getAllStats();
}, []); }, []);
const getSubtitle = () => {
if (stats.interval === 0) {
return t('stats_disabled_short');
}
return stats.interval === 1
? t('for_last_24_hours')
: t('for_last_days', { count: stats.interval });
};
const buttonText = protectionEnabled ? 'disable_protection' : 'enable_protection'; const buttonText = protectionEnabled ? 'disable_protection' : 'enable_protection';
const buttonClass = classNames('btn btn-sm dashboard-title__button', { const buttonClass = classNames('btn btn-sm dashboard-title__button', {
@ -52,14 +65,12 @@ const Dashboard = ({
</svg> </svg>
</button>; </button>;
const subtitle = stats.interval === 1
? t('for_last_24_hours')
: t('for_last_days', { count: stats.interval });
const statsProcessing = stats.processingStats const statsProcessing = stats.processingStats
|| stats.processingGetConfig || stats.processingGetConfig
|| access.processing; || access.processing;
const subtitle = getSubtitle();
return <> return <>
<PageTitle title={t('dashboard')} containerClass="page-title--dashboard"> <PageTitle title={t('dashboard')} containerClass="page-title--dashboard">
<button <button
@ -81,6 +92,20 @@ const Dashboard = ({
{statsProcessing && <Loading />} {statsProcessing && <Loading />}
{!statsProcessing && <div className="row row-cards dashboard"> {!statsProcessing && <div className="row row-cards dashboard">
<div className="col-lg-12"> <div className="col-lg-12">
{stats.interval === 0 && (
<div className="alert alert-warning" role="alert">
<Trans components={[
<Link
to={`${SETTINGS_URLS.settings}#stats-config`}
key="0"
>
link
</Link>,
]}>
stats_disabled
</Trans>
</div>
)}
<Statistics <Statistics
interval={stats.interval} interval={stats.interval}
dnsQueries={stats.dnsQueries} dnsQueries={stats.dnsQueries}

View File

@ -3,7 +3,9 @@ import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import { nanoid } from 'nanoid'; import { nanoid } from 'nanoid';
import classNames from 'classnames'; import classNames from 'classnames';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';
import propTypes from 'prop-types'; import propTypes from 'prop-types';
import { checkFiltered, getBlockingClientName } from '../../../helpers/helpers'; import { checkFiltered, getBlockingClientName } from '../../../helpers/helpers';
import { BLOCK_ACTIONS } from '../../../helpers/constants'; import { BLOCK_ACTIONS } from '../../../helpers/constants';
import { toggleBlocking, toggleBlockingForClient } from '../../../actions'; import { toggleBlocking, toggleBlockingForClient } from '../../../actions';
@ -192,12 +194,13 @@ const ClientCell = ({
{renderFormattedClientCell(client, clientInfo, isDetailed, true)} {renderFormattedClientCell(client, clientInfo, isDetailed, true)}
</div> </div>
{isDetailed && clientName && !whoisAvailable && ( {isDetailed && clientName && !whoisAvailable && (
<div <Link
className="detailed-info d-none d-sm-block logs__text" className="detailed-info d-none d-sm-block logs__text logs__text--link"
to={`logs?search=${encodeURIComponent(clientName)}`}
title={clientName} title={clientName}
> >
{clientName} {clientName}
</div> </Link>
)} )}
</div> </div>
{renderBlockingButton(isFiltered, domain)} {renderBlockingButton(isFiltered, domain)}

View File

@ -51,6 +51,15 @@
color: #888888; color: #888888;
} }
.logs__text--link {
color: #467fcf;
}
.logs__text--link:hover,
.logs__text--link:focus {
color: #295a9f;
}
.icon--selected { .icon--selected {
background-color: var(--gray-f3); background-color: var(--gray-f3);
border: solid 1px var(--gray-d8); border: solid 1px var(--gray-d8);

View File

@ -7,11 +7,15 @@ import Form from './Form';
class StatsConfig extends Component { class StatsConfig extends Component {
handleFormSubmit = (values) => { handleFormSubmit = (values) => {
const { t } = this.props; const { t, interval: prevInterval } = this.props;
// eslint-disable-next-line no-alert
if (values.interval < prevInterval) {
if (window.confirm(t('statistics_retention_confirm'))) { if (window.confirm(t('statistics_retention_confirm'))) {
this.props.setStatsConfig(values); this.props.setStatsConfig(values);
} }
} else {
this.props.setStatsConfig(values);
}
}; };
handleReset = () => { handleReset = () => {
@ -28,7 +32,11 @@ class StatsConfig extends Component {
} = this.props; } = this.props;
return ( return (
<Card title={t('statistics_configuration')} bodyType="card-body box-body--settings"> <Card
title={t('statistics_configuration')}
bodyType="card-body box-body--settings"
id="stats-config"
>
<div className="form"> <div className="form">
<Form <Form
initialValues={{ interval }} initialValues={{ interval }}

View File

@ -43,7 +43,7 @@ export const renderFormattedClientCell = (value, info, isDetailed = false, isLog
const whoisAvailable = whois_info && Object.keys(whois_info).length > 0; const whoisAvailable = whois_info && Object.keys(whois_info).length > 0;
if (name) { if (name) {
const nameValue = <div className="logs__text logs__text--nowrap" title={`${name} (${value})`}> const nameValue = <div className="logs__text logs__text--link logs__text--nowrap" title={`${name} (${value})`}>
{name}&nbsp;<small>{`(${value})`}</small> {name}&nbsp;<small>{`(${value})`}</small>
</div>; </div>;