badguardhome/client/src/components/Logs/Cells/ClientCell.js
Artem Baskal 8dc0108868 + client: Redesign query logs block/unblock buttons
Close #2050

Squashed commit of the following:

commit 3bc6a409034989b914306e1c33da274730ca623e
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Fri Sep 4 20:58:09 2020 +0300

    Change dashboard block confirm message

commit d4d47c3557e2166ee04db25a71b782bfbfe3b865
Merge: e8865827 fc43e2ac
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Fri Sep 4 14:56:34 2020 +0300

    Merge branch 'master' into feature/2050

commit e8865827879955b1ef62c9ff85798d07bfa4627d
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Fri Sep 4 13:46:10 2020 +0300

    Rename classname

commit 648151c54e493c63622e014cb9cd1cb450f25478
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Thu Sep 3 19:09:21 2020 +0300

    Decrease arrow size

commit 4feadab707c613d31225dfa9443a9a836db37ba1
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Thu Sep 3 18:27:41 2020 +0300

    Rename button class

commit c3919d8ae8d1431657ce61afad2c20e5806f279a
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Thu Sep 3 10:35:15 2020 +0300

    Review changes: extract variables

commit 0ac809584c391e41a1749a844bc1075e05a92345
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Thu Sep 3 10:13:57 2020 +0300

    Display dashboard button on hover

commit 1395287c2383e2248a2a5d39451403bd73141e55
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Sep 2 21:24:04 2020 +0300

    Do not hide button on option open

commit 947f254b7aea26f289b66b66fac46dba11ea3952
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Sep 2 21:20:19 2020 +0300

    Add buttons for mobile screen

commit df05697f87163a2b716d82653884e631f2fa6cf3
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Sep 2 20:18:20 2020 +0300

    Change dashboard button styles

commit 16655f2d6b0d79d1fa027ec2310bb0268fffaf6a
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Sep 2 20:04:28 2020 +0300

    Change button styles, rename button options

commit 1ac22e875d8b26c16830bf6edb85dadcc19ff287
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Sep 2 19:30:16 2020 +0300

    Review changes

commit c590119875439d85927bdd334658e003bc1f0563
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Sep 2 17:58:08 2020 +0300

    Remove default query logs form values

commit 141329563417f5337f5659d5500f4cbe16d64bd2
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Sep 2 17:41:23 2020 +0300

    Update blocking buttons options logic, fix button svg size

commit 9e4f39aa6cb8e134d80d496b8a248b2fe6aceb99
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Wed Sep 2 16:30:48 2020 +0300

    Fix button position

commit 8aabff7daccb87ae02c2302e62e296b3cfc17608
Merge: 415a0334 6b614295
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue Sep 1 17:29:55 2020 +0300

    Merge branch 'master' into feature/2050

commit 415a0334561733d92a0f7badd68101ef554dc689
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue Sep 1 17:05:51 2020 +0300

    Add blocking options

commit bc6aed92b6e12f27c2604501275b53bb8159d5bc
Merge: 0de4fb3a 40b74522
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue Sep 1 15:49:06 2020 +0300

    Merge branch 'feature/infinite_scroll_query_logs' into feature/2050

commit 40b745225112cf8d664220ed8f484b0aa16e997c
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue Sep 1 15:46:27 2020 +0300

    Remove dynamic translation of toasts

commit 0de4fb3a4cd785c6b52e860e204c6e13d356b178
Merge: 1ab14471 f08fa7b8
Author: ArtemBaskal <a.baskal@adguard.com>
Date:   Tue Sep 1 15:07:30 2020 +0300

    Merge branch 'feature/infinite_scroll_query_logs' into feature/2050

... and 51 more commits
2020-09-05 10:22:47 +03:00

175 lines
6.5 KiB
JavaScript

import React, { useState } from 'react';
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import { nanoid } from 'nanoid';
import classNames from 'classnames';
import { useTranslation } from 'react-i18next';
import propTypes from 'prop-types';
import { checkFiltered, getBlockingClientName } from '../../../helpers/helpers';
import { BLOCK_ACTIONS } from '../../../helpers/constants';
import { toggleBlocking, toggleBlockingForClient } from '../../../actions';
import IconTooltip from './IconTooltip';
import { renderFormattedClientCell } from '../../../helpers/renderFormattedClientCell';
import { toggleClientBlock } from '../../../actions/access';
import { getBlockClientInfo } from './helpers';
const ClientCell = ({
client,
domain,
info,
info: { name, whois_info },
reason,
}) => {
const { t } = useTranslation();
const dispatch = useDispatch();
const autoClients = useSelector((state) => state.dashboard.autoClients, shallowEqual);
const processingRules = useSelector((state) => state.filtering.processingRules);
const isDetailed = useSelector((state) => state.queryLogs.isDetailed);
const [isOptionsOpened, setOptionsOpened] = useState(false);
const disallowed_clients = useSelector(
(state) => state.access.disallowed_clients,
shallowEqual,
);
const autoClient = autoClients.find((autoClient) => autoClient.name === client);
const source = autoClient?.source;
const whoisAvailable = whois_info && Object.keys(whois_info).length > 0;
const id = nanoid();
const data = {
address: client,
name,
country: whois_info?.country,
city: whois_info?.city,
network: whois_info?.orgname,
source_label: source,
};
const processedData = Object.entries(data);
const isFiltered = checkFiltered(reason);
const nameClass = classNames('w-90 o-hidden d-flex flex-column', {
'mt-2': isDetailed && !name && !whoisAvailable,
'white-space--nowrap': isDetailed,
});
const hintClass = classNames('icons mr-4 icon--24 icon--lightgray', {
'my-3': isDetailed,
});
const renderBlockingButton = (isFiltered, domain) => {
const buttonType = isFiltered ? BLOCK_ACTIONS.UNBLOCK : BLOCK_ACTIONS.BLOCK;
const clients = useSelector((state) => state.dashboard.clients);
const {
confirmMessage,
buttonKey: blockingClientKey,
type,
} = getBlockClientInfo(client, disallowed_clients);
const blockingForClientKey = isFiltered ? 'unblock_for_this_client_only' : 'block_for_this_client_only';
const clientNameBlockingFor = getBlockingClientName(clients, client);
const BUTTON_OPTIONS_TO_ACTION_MAP = {
[blockingForClientKey]: () => {
dispatch(toggleBlockingForClient(buttonType, domain, clientNameBlockingFor));
},
[blockingClientKey]: () => {
const message = `${type === BLOCK_ACTIONS.BLOCK ? t('adg_will_drop_dns_queries') : ''} ${t(confirmMessage, { ip: client })}`;
if (window.confirm(message)) {
dispatch(toggleClientBlock(type, client));
}
},
};
const onClick = () => dispatch(toggleBlocking(buttonType, domain));
const getOptions = (optionToActionMap) => {
const options = Object.entries(optionToActionMap);
if (options.length === 0) {
return null;
}
return <>{options
.map(([name, onClick]) => <div
key={name}
className="button-action--arrow-option px-4 py-2"
onClick={onClick}
>{t(name)}
</div>)}</>;
};
const content = getOptions(BUTTON_OPTIONS_TO_ACTION_MAP);
const buttonClass = classNames('button-action button-action--main', {
'button-action--unblock': isFiltered,
'button-action--with-options': content,
'button-action--active': isOptionsOpened,
});
const buttonArrowClass = classNames('button-action button-action--arrow', {
'button-action--unblock': isFiltered,
'button-action--active': isOptionsOpened,
});
const containerClass = classNames('button-action__container', {
'button-action__container--detailed': isDetailed,
});
return <div className={containerClass}>
<button type="button"
className={buttonClass}
onClick={onClick}
disabled={processingRules}
>
{t(buttonType)}
</button>
{content && <button className={buttonArrowClass} disabled={processingRules}>
<IconTooltip
className='h-100'
tooltipClass='button-action--arrow-option-container'
xlinkHref='chevron-down'
triggerClass='button-action--icon'
content={content} placement="bottom-end" trigger="click"
onVisibilityChange={setOptionsOpened}
/>
</button>}
</div>;
};
return <div className="o-hidden h-100 logs__cell logs__cell--client" role="gridcell">
<IconTooltip className={hintClass} columnClass='grid grid--limited' tooltipClass='px-5 pb-5 pt-4 mw-75'
xlinkHref='question' contentItemClass="contentItemClass" title="client_details"
content={processedData} placement="bottom" />
<div className={nameClass}>
<div data-tip={true} data-for={id}>
{renderFormattedClientCell(client, info, isDetailed, true)}
</div>
{isDetailed && name && !whoisAvailable
&& <div className="detailed-info d-none d-sm-block logs__text"
title={name}>{name}</div>}
</div>
{renderBlockingButton(isFiltered, domain)}
</div>;
};
ClientCell.propTypes = {
client: propTypes.string.isRequired,
domain: propTypes.string.isRequired,
info: propTypes.oneOfType([
propTypes.string,
propTypes.shape({
name: propTypes.string.isRequired,
whois_info: propTypes.shape({
country: propTypes.string,
city: propTypes.string,
orgname: propTypes.string,
}),
}),
]),
reason: propTypes.string.isRequired,
};
export default ClientCell;