diff --git a/CHANGELOG.md b/CHANGELOG.md
index cb067fe8..51bb4c40 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,12 +23,17 @@ See also the [v0.107.40 GitHub milestone][ms-v0.107.40].
NOTE: Add new changes BELOW THIS COMMENT.
-->
+### Changed
+
+- "Block" and "Unblock" buttons of the query log moved to the tooltip menu ([#684]).
+
### Fixed
- The time shown in the statistics is one hour less than the current time ([#6296]).
- Issues with QUIC and HTTP/3 upstreams on FreeBSD ([#6301]).
- Panic on clearing query log ([#6304]).
+[#684]: https://github.com/AdguardTeam/AdGuardHome/issues/684
[#6296]: https://github.com/AdguardTeam/AdGuardHome/issues/6296
[#6301]: https://github.com/AdguardTeam/AdGuardHome/issues/6301
[#6304]: https://github.com/AdguardTeam/AdGuardHome/issues/6304
diff --git a/client/src/components/App/index.css b/client/src/components/App/index.css
index 78bd0096..91cd1749 100644
--- a/client/src/components/App/index.css
+++ b/client/src/components/App/index.css
@@ -134,15 +134,6 @@ body {
cursor: not-allowed;
}
-.button-action {
- visibility: hidden;
-}
-
-.logs__row:hover .button-action,
-.button-action--active {
- visibility: visible;
-}
-
.ReactModal__Body--open {
overflow: hidden;
}
diff --git a/client/src/components/Dashboard/Clients.js b/client/src/components/Dashboard/Clients.js
index 76cf998a..ac243491 100644
--- a/client/src/components/Dashboard/Clients.js
+++ b/client/src/components/Dashboard/Clients.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { useState } from 'react';
import ReactTable from 'react-table';
import PropTypes from 'prop-types';
import { Trans, useTranslation } from 'react-i18next';
@@ -13,6 +13,7 @@ import { BLOCK_ACTIONS, STATUS_COLORS } from '../../helpers/constants';
import { toggleClientBlock } from '../../actions/access';
import { renderFormattedClientCell } from '../../helpers/renderFormattedClientCell';
import { getStats } from '../../actions/stats';
+import IconTooltip from '../Logs/Cells/IconTooltip';
const getClientsPercentColor = (percent) => {
if (percent > 50) {
@@ -40,9 +41,7 @@ const renderBlockingButton = (ip, disallowed, disallowed_rule) => {
const processingSet = useSelector((state) => state.access.processingSet);
const allowedСlients = useSelector((state) => state.access.allowed_clients, shallowEqual);
- const buttonClass = classNames('button-action button-action--main', {
- 'button-action--unblock': disallowed,
- });
+ const [isOptionsOpened, setOptionsOpened] = useState(false);
const toggleClientStatus = async (ip, disallowed, disallowed_rule) => {
let confirmMessage;
@@ -62,23 +61,49 @@ const renderBlockingButton = (ip, disallowed, disallowed_rule) => {
}
};
- const onClick = () => toggleClientStatus(ip, disallowed, disallowed_rule);
+ const onClick = () => {
+ toggleClientStatus(ip, disallowed, disallowed_rule);
+ setOptionsOpened(false);
+ };
const text = disallowed ? BLOCK_ACTIONS.UNBLOCK : BLOCK_ACTIONS.BLOCK;
const lastRuleInAllowlist = !disallowed && allowedСlients === disallowed_rule;
const disabled = processingSet || lastRuleInAllowlist;
return (
-
+
+ {isOptionsOpened && (
+
+ {text}
+
+ )}
+ placement="bottom-end"
+ trigger="click"
+ onVisibilityChange={setOptionsOpened}
+ defaultTooltipShown={true}
+ delayHide={0}
+ />
+ )}
);
};
diff --git a/client/src/components/Dashboard/Dashboard.css b/client/src/components/Dashboard/Dashboard.css
index 765c9ed1..67a69aec 100644
--- a/client/src/components/Dashboard/Dashboard.css
+++ b/client/src/components/Dashboard/Dashboard.css
@@ -28,11 +28,13 @@
border-bottom: 6px solid #585965;
}
-@media (max-width: 1279.98px) {
- .table__action {
- position: absolute;
- right: 0;
- }
+.table__action {
+ position: relative;
+ margin-left: auto;
+}
+
+.table__action .btn-icon {
+ margin: 2px;
}
.page-title--dashboard {
diff --git a/client/src/components/Logs/Cells/ClientCell.js b/client/src/components/Logs/Cells/ClientCell.js
index 3590df48..d0dd3168 100644
--- a/client/src/components/Logs/Cells/ClientCell.js
+++ b/client/src/components/Logs/Cells/ClientCell.js
@@ -26,9 +26,7 @@ const ClientCell = ({
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 processingSet = useSelector((state) => state.access.processingSet);
const allowedСlients = useSelector((state) => state.access.allowed_clients, shallowEqual);
const [isOptionsOpened, setOptionsOpened] = useState(false);
@@ -84,11 +82,23 @@ const ClientCell = ({
const blockingForClientKey = isFiltered ? 'unblock_for_this_client_only' : 'block_for_this_client_only';
const clientNameBlockingFor = getBlockingClientName(clients, client);
+ const onClick = async () => {
+ await dispatch(toggleBlocking(buttonType, domain));
+ await dispatch(getStats());
+ setOptionsOpened(false);
+ };
+
const BUTTON_OPTIONS = [
+ {
+ name: buttonType,
+ onClick,
+ className: isFiltered ? 'bg--green' : 'bg--danger',
+ },
{
name: blockingForClientKey,
onClick: () => {
dispatch(toggleBlockingForClient(buttonType, domain, clientNameBlockingFor));
+ setOptionsOpened(false);
},
},
{
@@ -101,27 +111,25 @@ const ClientCell = ({
client_info?.disallowed_rule || '',
));
await dispatch(updateLogs());
+ setOptionsOpened(false);
}
},
- disabled: processingSet || lastRuleInAllowlist,
+ disabled: lastRuleInAllowlist,
},
];
- const onClick = async () => {
- await dispatch(toggleBlocking(buttonType, domain));
- await dispatch(getStats());
- };
-
const getOptions = (options) => {
if (options.length === 0) {
return null;
}
return (
<>
- {options.map(({ name, onClick, disabled }) => (
+ {options.map(({
+ name, onClick, disabled, className,
+ }) => (
{isDetailed && clientName && !whoisAvailable && (
diff --git a/client/src/components/Logs/Cells/IconTooltip.css b/client/src/components/Logs/Cells/IconTooltip.css
index 0b55ee6a..bbaf1604 100644
--- a/client/src/components/Logs/Cells/IconTooltip.css
+++ b/client/src/components/Logs/Cells/IconTooltip.css
@@ -1,4 +1,5 @@
.tooltip-custom__container {
+ min-width: 150px;
padding: 1rem 1.5rem 1.25rem 1.5rem;
font-size: 16px !important;
box-shadow: 2px 4px 8px rgba(0, 0, 0, 0.2);
diff --git a/client/src/components/Logs/Cells/IconTooltip.js b/client/src/components/Logs/Cells/IconTooltip.js
index 8bb3d624..304aded8 100644
--- a/client/src/components/Logs/Cells/IconTooltip.js
+++ b/client/src/components/Logs/Cells/IconTooltip.js
@@ -21,6 +21,8 @@ const IconTooltip = ({
content,
trigger,
onVisibilityChange,
+ defaultTooltipShown,
+ delayHide,
renderContent = content ? React.Children.map(
processContent(content),
(item, idx) =>
@@ -44,6 +46,8 @@ const IconTooltip = ({
trigger={trigger}
onVisibilityChange={onVisibilityChange}
delayShow={trigger === 'click' ? 0 : SHOW_TOOLTIP_DELAY}
+ delayHide={delayHide}
+ defaultTooltipShown={defaultTooltipShown}
>
{xlinkHref &&
);
diff --git a/client/src/components/ui/Tooltip.js b/client/src/components/ui/Tooltip.js
index 87b353de..b72a3667 100644
--- a/client/src/components/ui/Tooltip.js
+++ b/client/src/components/ui/Tooltip.js
@@ -21,6 +21,7 @@ const Tooltip = ({
delayShow = SHOW_TOOLTIP_DELAY,
delayHide = HIDE_TOOLTIP_DELAY,
onVisibilityChange,
+ defaultTooltipShown,
}) => {
const { t } = useTranslation();
const touchEventsAvailable = 'ontouchstart' in window;
@@ -75,6 +76,7 @@ const Tooltip = ({
delayShow={delayShowValue}
tooltip={renderTooltip}
onVisibilityChange={onVisibilityChange}
+ defaultTooltipShown={defaultTooltipShown}
>
{renderTrigger}
@@ -97,6 +99,7 @@ Tooltip.propTypes = {
className: propTypes.string,
triggerClass: propTypes.string,
onVisibilityChange: propTypes.func,
+ defaultTooltipShown: propTypes.bool,
};
export default Tooltip;
diff --git a/client/src/helpers/renderFormattedClientCell.js b/client/src/helpers/renderFormattedClientCell.js
index 3e610430..e70b6548 100644
--- a/client/src/helpers/renderFormattedClientCell.js
+++ b/client/src/helpers/renderFormattedClientCell.js
@@ -43,7 +43,7 @@ export const renderFormattedClientCell = (value, info, isDetailed = false, isLog
const whoisAvailable = whois_info && Object.keys(whois_info).length > 0;
if (name) {
- const nameValue =
+ const nameValue =
{name} {`(${value})`}
;