+ client: Add block and unblock buttons to 'check the filtering' result
Close #1734
Squashed commit of the following:
commit b7e274318aea773b6b7effba0fcf13859a23d45c
Merge: 77c823a4 2f6f65a8
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Thu Oct 1 23:36:49 2020 +0300
Merge branch 'master' into feature/1734
commit 77c823a46ad6e094d332b40375a32511c8f6ff11
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Thu Sep 24 22:36:56 2020 +0300
Add blocking button
commit bb77029d46ce18e582db04ccf31f7ed7c57de572
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Wed Sep 23 22:02:45 2020 +0300
Refactor check info
commit bd8cf052a0458c767aa65d0d8749648f8e10fdba
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Wed Sep 23 21:15:24 2020 +0300
Fix prop processingCheck
commit 5a1d696f7e15f2e1367ff3f9a1767ee3c2344b1b
Author: ArtemBaskal <a.baskal@adguard.com>
Date: Wed Sep 23 20:35:21 2020 +0300
Refactor Check component
This commit is contained in:
parent
2f6f65a81f
commit
128229ad73
|
@ -1,155 +1,124 @@
|
||||||
import React, { Fragment } from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { withTranslation } from 'react-i18next';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import i18next from 'i18next';
|
||||||
|
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||||
import {
|
import {
|
||||||
checkFiltered,
|
checkFiltered,
|
||||||
checkRewrite,
|
checkRewrite,
|
||||||
checkRewriteHosts,
|
checkRewriteHosts,
|
||||||
checkBlackList,
|
|
||||||
checkNotFilteredNotFound,
|
|
||||||
checkWhiteList,
|
checkWhiteList,
|
||||||
checkSafeSearch,
|
checkSafeSearch,
|
||||||
checkSafeBrowsing,
|
checkSafeBrowsing,
|
||||||
checkParental, getFilterName,
|
checkParental,
|
||||||
|
getFilterName,
|
||||||
} from '../../../helpers/helpers';
|
} from '../../../helpers/helpers';
|
||||||
import { FILTERED } from '../../../helpers/constants';
|
import { BLOCK_ACTIONS, FILTERED, FILTERED_STATUS } from '../../../helpers/constants';
|
||||||
|
import { toggleBlocking } from '../../../actions';
|
||||||
|
|
||||||
const getTitle = (reason, filterName, t, onlyFiltered) => {
|
const renderBlockingButton = (isFiltered, domain) => {
|
||||||
if (checkNotFilteredNotFound(reason)) {
|
const processingRules = useSelector((state) => state.filtering.processingRules);
|
||||||
return t('check_not_found');
|
const dispatch = useDispatch();
|
||||||
}
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (checkRewrite(reason)) {
|
const buttonType = isFiltered ? BLOCK_ACTIONS.UNBLOCK : BLOCK_ACTIONS.BLOCK;
|
||||||
return t('rewrite_applied');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkRewriteHosts(reason)) {
|
const onClick = async () => {
|
||||||
return t('rewrite_hosts_applied');
|
await dispatch(toggleBlocking(buttonType, domain));
|
||||||
}
|
};
|
||||||
|
|
||||||
if (checkBlackList(reason)) {
|
const buttonClass = classNames('mt-3 button-action button-action--main button-action--active button-action--small', {
|
||||||
return filterName;
|
'button-action--unblock': isFiltered,
|
||||||
}
|
});
|
||||||
|
|
||||||
if (checkWhiteList(reason)) {
|
return <button type="button"
|
||||||
return (
|
className={buttonClass}
|
||||||
<div>
|
onClick={onClick}
|
||||||
{filterName}
|
disabled={processingRules}
|
||||||
</div>
|
>
|
||||||
);
|
{t(buttonType)}
|
||||||
}
|
</button>;
|
||||||
|
|
||||||
if (onlyFiltered) {
|
|
||||||
const filterKey = reason.replace(FILTERED, '');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{t('query_log_filtered', { filter: filterKey })}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Fragment>
|
|
||||||
<div>
|
|
||||||
{t('check_reason', { reason })}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
{filterName}
|
|
||||||
</div>
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getColor = (reason) => {
|
const getTitle = (reason) => {
|
||||||
if (checkFiltered(reason)) {
|
const { t } = useTranslation();
|
||||||
return 'red';
|
|
||||||
} if (checkRewrite(reason) || checkRewriteHosts(reason)) {
|
|
||||||
return 'blue';
|
|
||||||
} if (checkWhiteList(reason)) {
|
|
||||||
return 'green';
|
|
||||||
}
|
|
||||||
|
|
||||||
return '';
|
const filters = useSelector((state) => state.filtering.filters, shallowEqual);
|
||||||
};
|
const whitelistFilters = useSelector((state) => state.filtering.whitelistFilters, shallowEqual);
|
||||||
|
const filter_id = useSelector((state) => state.filtering.check.filter_id);
|
||||||
|
|
||||||
const Info = ({
|
const filterName = getFilterName(
|
||||||
filters,
|
filters,
|
||||||
whitelistFilters,
|
whitelistFilters,
|
||||||
|
filter_id,
|
||||||
|
'filtered_custom_rules',
|
||||||
|
(filter) => (filter?.name ? t('query_log_filtered', { filter: filter.name }) : ''),
|
||||||
|
);
|
||||||
|
|
||||||
|
const getReasonFiltered = (reason) => {
|
||||||
|
const filterKey = reason.replace(FILTERED, '');
|
||||||
|
return i18next.t('query_log_filtered', { filter: filterKey });
|
||||||
|
};
|
||||||
|
|
||||||
|
const REASON_TO_TITLE_MAP = {
|
||||||
|
[FILTERED_STATUS.NOT_FILTERED_NOT_FOUND]: t('check_not_found'),
|
||||||
|
[FILTERED_STATUS.REWRITE]: t('rewrite_applied'),
|
||||||
|
[FILTERED_STATUS.REWRITE_HOSTS]: t('rewrite_hosts_applied'),
|
||||||
|
[FILTERED_STATUS.FILTERED_BLACK_LIST]: filterName,
|
||||||
|
[FILTERED_STATUS.NOT_FILTERED_WHITE_LIST]: filterName,
|
||||||
|
[FILTERED_STATUS.FILTERED_SAFE_SEARCH]: getReasonFiltered(reason),
|
||||||
|
[FILTERED_STATUS.FILTERED_SAFE_BROWSING]: getReasonFiltered(reason),
|
||||||
|
[FILTERED_STATUS.FILTERED_PARENTAL]: getReasonFiltered(reason),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Object.prototype.hasOwnProperty.call(REASON_TO_TITLE_MAP, reason)) {
|
||||||
|
return REASON_TO_TITLE_MAP[reason];
|
||||||
|
}
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<div>{t('check_reason', { reason })}</div>
|
||||||
|
<div>{filterName}</div>
|
||||||
|
</>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Info = () => {
|
||||||
|
const {
|
||||||
hostname,
|
hostname,
|
||||||
reason,
|
reason,
|
||||||
filter_id,
|
|
||||||
rule,
|
rule,
|
||||||
service_name,
|
service_name,
|
||||||
cname,
|
cname,
|
||||||
ip_addrs,
|
ip_addrs,
|
||||||
t,
|
} = useSelector((state) => state.filtering.check, shallowEqual);
|
||||||
}) => {
|
const { t } = useTranslation();
|
||||||
const filterName = getFilterName(filters,
|
|
||||||
whitelistFilters,
|
const title = getTitle(reason);
|
||||||
filter_id,
|
|
||||||
'filtered_custom_rules',
|
const className = classNames('card mb-0 p-3', {
|
||||||
(filter) => (filter?.name ? t('query_log_filtered', { filter: filter.name }) : ''));
|
'logs__row--red': checkFiltered(reason),
|
||||||
|
'logs__row--blue': checkRewrite(reason) || checkRewriteHosts(reason),
|
||||||
|
'logs__row--green': checkWhiteList(reason),
|
||||||
|
});
|
||||||
|
|
||||||
const onlyFiltered = checkSafeSearch(reason)
|
const onlyFiltered = checkSafeSearch(reason)
|
||||||
|| checkSafeBrowsing(reason)
|
|| checkSafeBrowsing(reason)
|
||||||
|| checkParental(reason);
|
|| checkParental(reason);
|
||||||
const title = getTitle(reason, filterName, t, onlyFiltered);
|
|
||||||
const color = getColor(reason);
|
|
||||||
|
|
||||||
if (onlyFiltered) {
|
const isFiltered = checkFiltered(reason);
|
||||||
return (
|
|
||||||
<div className={`card mb-0 p-3 ${color}`}>
|
|
||||||
<div>
|
|
||||||
<strong>{hostname}</strong>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
return <div className={className}>
|
||||||
|
<div><strong>{hostname}</strong></div>
|
||||||
<div>{title}</div>
|
<div>{title}</div>
|
||||||
</div>
|
{!onlyFiltered
|
||||||
);
|
&& <>
|
||||||
}
|
{rule && <div>{t('check_rule', { rule })}</div>}
|
||||||
|
{service_name && <div>{t('check_service', { service: service_name })}</div>}
|
||||||
return (
|
{cname && <div>{t('check_cname', { cname })}</div>}
|
||||||
<div className={`card mb-0 p-3 ${color}`}>
|
{ip_addrs && <div>{t('check_ip', { ip: ip_addrs.join(', ') })}</div>}
|
||||||
<div>
|
{renderBlockingButton(isFiltered, hostname)}
|
||||||
<strong>{hostname}</strong>
|
</>}
|
||||||
</div>
|
</div>;
|
||||||
|
|
||||||
<div>{title}</div>
|
|
||||||
|
|
||||||
{rule && (
|
|
||||||
<div>{t('check_rule', { rule })}</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{service_name && (
|
|
||||||
<div>{t('check_service', { service: service_name })}</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{cname && (
|
|
||||||
<div>{t('check_cname', { cname })}</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{ip_addrs && (
|
|
||||||
<div>
|
|
||||||
{t('check_ip', { ip: ip_addrs.join(', ') })}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Info.propTypes = {
|
export default Info;
|
||||||
filters: PropTypes.array.isRequired,
|
|
||||||
whitelistFilters: PropTypes.array.isRequired,
|
|
||||||
hostname: PropTypes.string.isRequired,
|
|
||||||
reason: PropTypes.string.isRequired,
|
|
||||||
filter_id: PropTypes.number,
|
|
||||||
rule: PropTypes.string,
|
|
||||||
service_name: PropTypes.string,
|
|
||||||
cname: PropTypes.string,
|
|
||||||
ip_addrs: PropTypes.array,
|
|
||||||
t: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default withTranslation()(Info);
|
|
||||||
|
|
|
@ -1,38 +1,26 @@
|
||||||
import React, { Fragment } from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Trans, withTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Field, reduxForm } from 'redux-form';
|
import { Field, reduxForm } from 'redux-form';
|
||||||
import flow from 'lodash/flow';
|
import { useSelector } from 'react-redux';
|
||||||
import Card from '../../ui/Card';
|
import Card from '../../ui/Card';
|
||||||
|
|
||||||
import { renderInputField } from '../../../helpers/form';
|
import { renderInputField } from '../../../helpers/form';
|
||||||
import Info from './Info';
|
import Info from './Info';
|
||||||
import { FORM_NAME } from '../../../helpers/constants';
|
import { FORM_NAME } from '../../../helpers/constants';
|
||||||
|
|
||||||
const Check = (props) => {
|
const Check = (props) => {
|
||||||
const {
|
const {
|
||||||
t,
|
|
||||||
handleSubmit,
|
|
||||||
pristine,
|
pristine,
|
||||||
invalid,
|
invalid,
|
||||||
processing,
|
handleSubmit,
|
||||||
check,
|
|
||||||
filters,
|
|
||||||
whitelistFilters,
|
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const {
|
const { t } = useTranslation();
|
||||||
hostname,
|
|
||||||
reason,
|
|
||||||
filter_id,
|
|
||||||
rule,
|
|
||||||
service_name,
|
|
||||||
cname,
|
|
||||||
ip_addrs,
|
|
||||||
} = check;
|
|
||||||
|
|
||||||
return (
|
const processingCheck = useSelector((state) => state.filtering.processingCheck);
|
||||||
<Card
|
const hostname = useSelector((state) => state.filtering.check.hostname);
|
||||||
|
|
||||||
|
return <Card
|
||||||
title={t('check_title')}
|
title={t('check_title')}
|
||||||
subtitle={t('check_desc')}
|
subtitle={t('check_desc')}
|
||||||
>
|
>
|
||||||
|
@ -53,47 +41,26 @@ const Check = (props) => {
|
||||||
className="btn btn-success btn-standard btn-large"
|
className="btn btn-success btn-standard btn-large"
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
disabled={pristine || invalid || processing}
|
disabled={pristine || invalid || processingCheck}
|
||||||
>
|
>
|
||||||
<Trans>check</Trans>
|
{t('check')}
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{check.hostname && (
|
{hostname && <>
|
||||||
<Fragment>
|
|
||||||
<hr />
|
<hr />
|
||||||
<Info
|
<Info />
|
||||||
filters={filters}
|
</>}
|
||||||
whitelistFilters={whitelistFilters}
|
|
||||||
hostname={hostname}
|
|
||||||
reason={reason}
|
|
||||||
filter_id={filter_id}
|
|
||||||
rule={rule}
|
|
||||||
service_name={service_name}
|
|
||||||
cname={cname}
|
|
||||||
ip_addrs={ip_addrs}
|
|
||||||
/>
|
|
||||||
</Fragment>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Card>
|
</Card>;
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Check.propTypes = {
|
Check.propTypes = {
|
||||||
t: PropTypes.func.isRequired,
|
|
||||||
handleSubmit: PropTypes.func.isRequired,
|
handleSubmit: PropTypes.func.isRequired,
|
||||||
pristine: PropTypes.bool.isRequired,
|
pristine: PropTypes.bool.isRequired,
|
||||||
invalid: PropTypes.bool.isRequired,
|
invalid: PropTypes.bool.isRequired,
|
||||||
processing: PropTypes.bool.isRequired,
|
|
||||||
check: PropTypes.object.isRequired,
|
|
||||||
filters: PropTypes.array.isRequired,
|
|
||||||
whitelistFilters: PropTypes.array.isRequired,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default flow([
|
export default reduxForm({ form: FORM_NAME.DOMAIN_CHECK })(Check);
|
||||||
withTranslation(),
|
|
||||||
reduxForm({ form: FORM_NAME.DOMAIN_CHECK }),
|
|
||||||
])(Check);
|
|
||||||
|
|
|
@ -45,11 +45,7 @@ class CustomRules extends Component {
|
||||||
const {
|
const {
|
||||||
t,
|
t,
|
||||||
filtering: {
|
filtering: {
|
||||||
filters,
|
|
||||||
whitelistFilters,
|
|
||||||
userRules,
|
userRules,
|
||||||
processingCheck,
|
|
||||||
check,
|
|
||||||
},
|
},
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
@ -92,13 +88,7 @@ class CustomRules extends Component {
|
||||||
<hr />
|
<hr />
|
||||||
<Examples />
|
<Examples />
|
||||||
</Card>
|
</Card>
|
||||||
<Check
|
<Check onSubmit={this.handleCheck} />
|
||||||
filters={filters}
|
|
||||||
whitelistFilters={whitelistFilters}
|
|
||||||
check={check}
|
|
||||||
onSubmit={this.handleCheck}
|
|
||||||
processing={processingCheck}
|
|
||||||
/>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -238,6 +238,10 @@
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button-action--small {
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
.button-action--unblock {
|
.button-action--unblock {
|
||||||
background: var(--btn-unblock);
|
background: var(--btn-unblock);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue