Pull request: 1333-protection-pause vol.1

Merge in DNS/adguard-home from 1333-protection-pause-1 to master

Squashed commit of the following:

commit 5ff98385bc5ff66e214d80782eb4dc41e344aa38
Merge: 97f94a54 0bc3ef89
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Fri Mar 24 19:08:21 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

commit 97f94a5498ac221f88f2f7dfef4b255f4945329e
Author: Arseny Lisin <a.lisin@adguard.com>
Date:   Fri Mar 24 13:03:20 2023 +0200

    Fix protection timer bugs

commit 1cc61af1996bd803f3fa638cb9e2388470072bf0
Merge: 5a144ea3 235ce458
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Mar 23 22:27:47 2023 +0700

    Merge remote-tracking branch 'origin/1333-protection-pause-1' into 1333-protection-pause-1

commit 5a144ea3a48c3d0d5e57dd14232ab7a8e77a8c1e
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Mar 23 22:25:08 2023 +0700

    dnsforward: imp code

commit 235ce458a62b3152f36e32580ed0226a56580ec6
Author: Ainar Garipov <A.Garipov@AdGuard.COM>
Date:   Thu Mar 23 17:35:06 2023 +0300

    dnsforward: imp locks

commit 0ea3a0a176b810a2b3f0b307aa406fe1670c9219
Merge: 52f66810 df61741f
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Mar 23 19:30:41 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

    # Conflicts:
    #	CHANGELOG.md
    #	openapi/CHANGELOG.md

commit 52f668109673286a50909c042e6352cd803e8eed
Merge: 9a7eb7b3 306c1983
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Mar 23 11:23:50 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

    # Conflicts:
    #	CHANGELOG.md
    #	internal/dnsforward/http.go

commit 9a7eb7b3ab2b5f6ad321aa3245d33839c3aa6fbd
Author: Arseny Lisin <a.lisin@adguard.com>
Date:   Wed Mar 22 06:56:55 2023 +0200

    Review fix

commit 5612d51252ba91842bd6811baec1c91136bb3bf2
Merge: c0a918a5 c3edab43
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Mar 21 22:00:39 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

    # Conflicts:
    #	client/src/__locales/en.json

commit c0a918a518ad9b37041aed159d215516258bc987
Author: Arseny Lisin <a.lisin@adguard.com>
Date:   Tue Mar 21 12:13:18 2023 +0200

    Review fix

commit 34faa61cc1e6210a612e7a2f4895a1504df37680
Author: Arseny Lisin <a.lisin@adguard.com>
Date:   Tue Mar 21 10:43:37 2023 +0200

    Fix props to new api

commit 158e582373863495f0e0ca177d7b365cc66ad671
Author: Arseny Lisin <a.lisin@adguard.com>
Date:   Mon Mar 20 18:44:34 2023 +0200

    Review fix

commit 9e8b8c3778b8e1dfad0d39e44f70886dfd3aeb9a
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Mar 20 22:31:28 2023 +0700

    all: docs

commit 761a203f53b535ca235cfe62f289bd0e02b90be2
Merge: d0b07231 48431f8b
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Mar 20 22:26:13 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

commit d0b07231b6f29b534930f1fcfc82b4934c295ff8
Merge: ea448760 a2053526
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Mar 13 13:00:52 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

    # Conflicts:
    #	CHANGELOG.md
    #	client/src/components/App/index.css
    #	internal/dnsforward/config.go

commit ea4487608a9c81d25f155ff63fee7c9dcf21f448
Merge: dfd0f33f a556ce8f
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Feb 21 11:54:27 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

    # Conflicts:
    #	CHANGELOG.md

commit dfd0f33fb474d497cbc9237ee466276728eea397
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Feb 21 11:51:40 2023 +0700

    all: docs

commit d36df96fba8c6d923faef85c198b6bd0743b7ee8
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Feb 20 12:41:49 2023 +0700

    all: safesearch

commit 60f2ceec563221337f34bb60baa96aa2b2429c40
Merge: 7c514427 6f6ced33
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Feb 20 12:30:42 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

    # Conflicts:
    #	CHANGELOG.md

commit 7c514427e77c5b09d8e148c78220a71046e68cd1
Merge: 0fa4ff99 4d295a38
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Feb 16 11:55:21 2023 +0700

    Merge remote-tracking branch 'origin/master' into 1333-protection-pause-1

    # Conflicts:
    #	CHANGELOG.md

... and 26 more commits
This commit is contained in:
Dimitry Kolyshev
2023-03-24 15:11:47 +03:00
parent 0bc3ef89ea
commit 9c48e96939
23 changed files with 528 additions and 46 deletions

View File

@@ -43,6 +43,7 @@ import DnsRewrites from '../../containers/DnsRewrites';
import CustomRules from '../../containers/CustomRules';
import Services from '../Filters/Services';
import Logs from '../Logs';
import ProtectionTimer from '../ProtectionTimer';
const ROUTES = [
{
@@ -191,6 +192,7 @@ const App = () => {
{!processingEncryption && <EncryptionTopline />}
<LoadingBar className="loading-bar" updateTime={1000} />
<Header />
<ProtectionTimer />
<div className="container container--wrap pb-5">
{processing && <Loading />}
{!isCoreRunning && <div className="row row-cards">

View File

@@ -1,3 +1,9 @@
.dashboard-protection-button.btn-gray {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-right-color: #a4a4a4;
}
.stats__table .popover__body {
left: -10px;
min-width: 270px;
@@ -34,20 +40,11 @@
align-items: center;
}
.dashboard-title__button {
margin: 0 0.5rem;
}
@media (max-width: 767.98px) {
.page-title--dashboard {
flex-direction: column;
align-items: flex-start;
}
.dashboard-title__button {
margin: 0.5rem 0;
display: block;
}
}
.counters__row {

View File

@@ -9,18 +9,20 @@ import Counters from './Counters';
import Clients from './Clients';
import QueriedDomains from './QueriedDomains';
import BlockedDomains from './BlockedDomains';
import { SETTINGS_URLS } from '../../helpers/constants';
import { DISABLE_PROTECTION_TIMINGS, ONE_SECOND_IN_MS, SETTINGS_URLS } from '../../helpers/constants';
import { msToSeconds, msToMinutes, msToHours } from '../../helpers/helpers';
import PageTitle from '../ui/PageTitle';
import Loading from '../ui/Loading';
import './Dashboard.css';
import Dropdown from '../ui/Dropdown';
const Dashboard = ({
getAccessList,
getStats,
getStatsConfig,
dashboard,
dashboard: { protectionEnabled, processingProtection },
dashboard: { protectionEnabled, processingProtection, protectionDisabledDuration },
toggleProtection,
stats,
access,
@@ -36,7 +38,6 @@ const Dashboard = ({
useEffect(() => {
getAllStats();
}, []);
const getSubtitle = () => {
if (stats.interval === 0) {
return t('stats_disabled_short');
@@ -47,9 +48,7 @@ const Dashboard = ({
: t('for_last_days', { count: stats.interval });
};
const buttonText = protectionEnabled ? 'disable_protection' : 'enable_protection';
const buttonClass = classNames('btn btn-sm dashboard-title__button', {
const buttonClass = classNames('btn btn-sm dashboard-protection-button', {
'btn-gray': protectionEnabled,
'btn-success': !protectionEnabled,
});
@@ -71,16 +70,87 @@ const Dashboard = ({
const subtitle = getSubtitle();
const DISABLE_PROTECTION_ITEMS = [
{
text: t('disable_for_seconds', { count: msToSeconds(DISABLE_PROTECTION_TIMINGS.HALF_MINUTE) }),
disableTime: DISABLE_PROTECTION_TIMINGS.HALF_MINUTE,
},
{
text: t('disable_for_minutes', { count: msToMinutes(DISABLE_PROTECTION_TIMINGS.MINUTE) }),
disableTime: DISABLE_PROTECTION_TIMINGS.MINUTE,
},
{
text: t('disable_for_minutes', { count: msToMinutes(DISABLE_PROTECTION_TIMINGS.TEN_MINUTES) }),
disableTime: DISABLE_PROTECTION_TIMINGS.TEN_MINUTES,
},
{
text: t('disable_for_hours', { count: msToHours(DISABLE_PROTECTION_TIMINGS.HOUR) }),
disableTime: DISABLE_PROTECTION_TIMINGS.HOUR,
},
{
text: t('disable_until_tomorrow'),
disableTime: DISABLE_PROTECTION_TIMINGS.TOMORROW,
},
];
const getDisableProtectionItems = () => (
Object.values(DISABLE_PROTECTION_ITEMS)
.map((item, index) => (
<div
key={`disable_timings_${index}`}
className="dropdown-item"
onClick={() => {
toggleProtection(protectionEnabled, item.disableTime - ONE_SECOND_IN_MS);
}}
>
{item.text}
</div>
))
);
const getRemaningTimeText = (milliseconds) => {
if (!milliseconds) {
return '';
}
const date = new Date(milliseconds);
const hh = date.getUTCHours();
const mm = `0${date.getUTCMinutes()}`.slice(-2);
const ss = `0${date.getUTCSeconds()}`.slice(-2);
const formattedHH = `0${hh}`.slice(-2);
return hh ? `${formattedHH}:${mm}:${ss}` : `${mm}:${ss}`;
};
const getProtectionBtnText = (status) => (status ? t('disable_protection') : t('enable_protection'));
return <>
<PageTitle title={t('dashboard')} containerClass="page-title--dashboard">
<button
type="button"
className={buttonClass}
onClick={() => toggleProtection(protectionEnabled)}
disabled={processingProtection}
>
<Trans>{buttonText}</Trans>
</button>
<div className="page-title__protection">
<button
type="button"
className={buttonClass}
onClick={() => {
toggleProtection(protectionEnabled);
}}
disabled={processingProtection}
>
{protectionDisabledDuration
? `${t('enable_protection_timer')} ${getRemaningTimeText(protectionDisabledDuration)}`
: getProtectionBtnText(protectionEnabled)
}
</button>
{protectionEnabled && <Dropdown
label=""
baseClassName="dropdown-protection"
icon="arrow-down"
controlClassName="dropdown-protection__toggle"
menuClassName="dropdown-menu dropdown-menu-arrow dropdown-menu--protection"
>
{getDisableProtectionItems()}
</Dropdown>}
</div>
<button
type="button"
className="btn btn-outline-primary btn-sm"

View File

@@ -0,0 +1,52 @@
import { useEffect } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { ONE_SECOND_IN_MS } from '../../helpers/constants';
import { setProtectionTimerTime, toggleProtectionSuccess } from '../../actions';
let interval = null;
const ProtectionTimer = ({
protectionDisabledDuration,
toggleProtectionSuccess,
setProtectionTimerTime,
}) => {
useEffect(() => {
if (protectionDisabledDuration !== null && protectionDisabledDuration < ONE_SECOND_IN_MS) {
toggleProtectionSuccess({ disabledDuration: null });
}
if (protectionDisabledDuration) {
interval = setInterval(() => {
setProtectionTimerTime(protectionDisabledDuration - ONE_SECOND_IN_MS);
}, ONE_SECOND_IN_MS);
}
return () => {
clearInterval(interval);
};
}, [protectionDisabledDuration]);
return null;
};
ProtectionTimer.propTypes = {
setProtectionTimerTime: PropTypes.func.isRequired,
};
const mapStateToProps = (state) => {
const { dashboard } = state;
const { protectionEnabled, protectionDisabledDuration } = dashboard;
return { protectionEnabled, protectionDisabledDuration };
};
const mapDispatchToProps = {
toggleProtectionSuccess,
setProtectionTimerTime,
};
export default connect(
mapStateToProps,
mapDispatchToProps,
)(ProtectionTimer);

View File

@@ -1,3 +1,7 @@
.dropdown-item {
cursor: pointer;
}
.dropdown-item.active,
.dropdown-item:active {
background-color: var(--btn-success-bgcolor);
@@ -6,3 +10,55 @@
.dropdown-menu {
cursor: default;
}
.dropdown-menu.dropdown-menu--protection {
top: calc(100% + 8px);
left: 50%;
transform: translateX(-50%);
}
.dropdown-menu.dropdown-menu-arrow.dropdown-menu--protection::before,
.dropdown-menu.dropdown-menu-arrow.dropdown-menu--protection::after {
left: 50%;
transform: translateX(-50%);
}
.dropdown-protection {
align-self: stretch;
width: 26px;
display: flex;
position: relative;
border: 1px solid #868e96;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
border-left: none;
cursor: pointer;
}
.dropdown-protection__toggle {
width: 100%;
display: block;
position: relative;
background-color: #868e96;
transition: background-color 0.15s ease-in-out;
}
.dropdown-protection__toggle:hover {
background-color: #727b84;
}
.dropdown-protection__toggle .nav-icon {
width: 100%;
height: 100%;
display: block;
position: absolute;
top: 0;
left: 0;
color: var(--white);
transition: 0.15s ease-in-out transform;
transform-origin: center;
}
.dropdown-protection.show .nav-icon {
transform: rotate(180deg);
}

View File

@@ -181,6 +181,12 @@ const Icons = () => (
</svg>
</symbol>
<symbol id="arrow-down" viewBox="0 0 24 24" fill="currentColor">
<svg xmlns="http://www.w3.org/2000/svg">
<path fillRule="evenodd" d="M6.2 8.2a.64.64 0 0 1 .94 0L12 13.32l4.86-5.1a.64.64 0 0 1 .94 0c.27.27.27.71 0 .98l-5.33 5.6a.64.64 0 0 1-.94 0L6.2 9.2a.72.72 0 0 1 0-.98Z" clipRule="evenodd"/>
</svg>
</symbol>
<symbol id="arrow-right" viewBox="0 0 24 24" stroke="currentColor"
strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.5">
<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">

View File

@@ -10216,6 +10216,18 @@ body.fixed-header .page {
line-height: 2.5rem;
}
.page-title__protection {
display: flex;
align-items: stretch;
margin: 0 0.5rem;
}
@media (max-width: 767.98px) {
.page-title__protection {
margin: 0.5rem 0;
}
}
.page-title-icon {
color: #9aa0ac;
font-size: 1.25rem;