- client: Fix query logs UI issues
Close #1828 Squashed commit of the following: commit a3955c989a939866c6772b147547344b3f8769c4 Merge: c91c41cb2759d81a
Author: ArtemBaskal <a.baskal@adguard.com> Date: Mon Jul 13 15:14:47 2020 +0300 Merge branch 'master' into fix/1828 commit c91c41cbc5f616e0af1092424e42b909d2f43f7c Author: ArtemBaskal <a.baskal@adguard.com> Date: Mon Jul 13 13:48:54 2020 +0300 Fix cell overflow commit 19e1d31a40f2e1bb1189a85b72507bcc364d4e0c Merge: af31f48ca33164bf
Author: ArtemBaskal <a.baskal@adguard.com> Date: Mon Jul 13 12:36:44 2020 +0300 Merge branch 'master' into fix/1828 commit af31f48c4d2699ebfbd2034711c51499b42e40f5 Author: ArtemBaskal <a.baskal@adguard.com> Date: Mon Jul 13 10:45:57 2020 +0300 minor commit d9507c5f3f5758e587766ae0fa45f1b9ad703ccf Author: ArtemBaskal <a.baskal@adguard.com> Date: Fri Jul 10 18:34:22 2020 +0300 - client: Fix query logs UI issues
This commit is contained in:
parent
2759d81afe
commit
8a417604a9
|
@ -480,6 +480,7 @@
|
|||
"whois": "Whois",
|
||||
"filtering_rules_learn_more": "<0>Learn more</0> about creating your own hosts lists.",
|
||||
"blocked_by_response": "Blocked by CNAME or IP in response",
|
||||
"blocked_by_cname_or_ip": "Blocked by CNAME or IP",
|
||||
"try_again": "Try again",
|
||||
"domain_desc": "Enter the domain name or wildcard you want to be rewritten.",
|
||||
"example_rewrite_domain": "rewrite responses for this domain name only.",
|
||||
|
@ -560,5 +561,6 @@
|
|||
"filter_category_general_desc": "Lists that block tracking and advertising on most of the devices",
|
||||
"filter_category_security_desc": "Lists that specialize on blocking malware, phishing or scam domains",
|
||||
"filter_category_regional_desc": "Lists that focus on regional ads and tracking servers",
|
||||
"filter_category_other_desc": "Other blocklists"
|
||||
"filter_category_other_desc": "Other blocklists",
|
||||
"original_response": "Original response"
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ const getClientCell = ({
|
|||
|
||||
return (
|
||||
<div className="logs__row o-hidden h-100">
|
||||
{processedData && getHintElement({
|
||||
{getHintElement({
|
||||
className: hintClass,
|
||||
columnClass: 'grid grid--limited',
|
||||
tooltipClass: 'px-5 pb-5 pt-4 mw-75',
|
||||
|
|
|
@ -33,16 +33,6 @@ const getDomainCell = (props) => {
|
|||
'my-3': isDetailed,
|
||||
});
|
||||
|
||||
const dnssecHint = getHintElement({
|
||||
className: lockIconClass,
|
||||
tooltipClass: 'py-4 px-5 pb-45',
|
||||
canShowTooltip: answer_dnssec,
|
||||
xlinkHref: 'lock',
|
||||
columnClass: 'w-100',
|
||||
content: 'validated_with_dnssec',
|
||||
placement: 'bottom',
|
||||
});
|
||||
|
||||
const protocol = t(SCHEME_TO_PROTOCOL_MAP[client_proto]) || '';
|
||||
const ip = type ? `${t('type_table_header')}: ${type}` : '';
|
||||
|
||||
|
@ -100,7 +90,15 @@ const getDomainCell = (props) => {
|
|||
|
||||
return (
|
||||
<div className="logs__row o-hidden">
|
||||
{dnssec_enabled && dnssecHint}
|
||||
{dnssec_enabled && getHintElement({
|
||||
className: lockIconClass,
|
||||
tooltipClass: 'py-4 px-5 pb-45',
|
||||
canShowTooltip: answer_dnssec,
|
||||
xlinkHref: 'lock',
|
||||
columnClass: 'w-100',
|
||||
content: 'validated_with_dnssec',
|
||||
placement: 'bottom',
|
||||
})}
|
||||
{trackerHint}
|
||||
<div className={valueClass}>
|
||||
<div className="text-truncate" title={domain}>{domain}</div>
|
||||
|
|
|
@ -6,6 +6,7 @@ import classNames from 'classnames';
|
|||
import './Tooltip.css';
|
||||
import 'react-popper-tooltip/dist/styles.css';
|
||||
import { HIDE_TOOLTIP_DELAY } from '../../../helpers/constants';
|
||||
import { processContent } from '../../../helpers/helpers';
|
||||
|
||||
const getHintElement = ({
|
||||
className,
|
||||
|
@ -17,34 +18,34 @@ const getHintElement = ({
|
|||
placement,
|
||||
tooltipClass,
|
||||
content,
|
||||
renderContent = React.Children.map(
|
||||
content,
|
||||
renderContent = content ? React.Children.map(
|
||||
processContent(content),
|
||||
(item, idx) => <div key={idx} className={contentItemClass}>
|
||||
<Trans>{item || '—'}</Trans>
|
||||
</div>,
|
||||
),
|
||||
) : null,
|
||||
}) => <TooltipTrigger placement={placement} trigger="hover" delayHide={HIDE_TOOLTIP_DELAY} tooltip={
|
||||
({
|
||||
tooltipRef,
|
||||
getTooltipProps,
|
||||
}) => <div {...getTooltipProps({
|
||||
ref: tooltipRef,
|
||||
className: classNames('tooltip__container', tooltipClass, { 'd-none': !canShowTooltip }),
|
||||
})}
|
||||
>
|
||||
{title && <div className="pb-4 h-25 grid-content font-weight-bold">
|
||||
<Trans>{title}</Trans>
|
||||
</div>}
|
||||
<div className={classNames(columnClass)}>{renderContent}</div>
|
||||
</div>
|
||||
}>{({
|
||||
getTriggerProps, triggerRef,
|
||||
}) => <span {...getTriggerProps({ ref: triggerRef })}>
|
||||
({
|
||||
tooltipRef,
|
||||
getTooltipProps,
|
||||
}) => <div {...getTooltipProps({
|
||||
ref: tooltipRef,
|
||||
className: classNames('tooltip__container', tooltipClass, { 'd-none': !canShowTooltip }),
|
||||
})}
|
||||
>
|
||||
{title && <div className="pb-4 h-25 grid-content font-weight-bold">
|
||||
<Trans>{title}</Trans>
|
||||
</div>}
|
||||
<div className={classNames(columnClass)}>{renderContent}</div>
|
||||
</div>
|
||||
}>{({
|
||||
getTriggerProps, triggerRef,
|
||||
}) => <span {...getTriggerProps({ ref: triggerRef })}>
|
||||
{xlinkHref && <svg className={className}>
|
||||
<use xlinkHref={`#${xlinkHref}`} />
|
||||
</svg>}
|
||||
</span>}
|
||||
</TooltipTrigger>;
|
||||
</TooltipTrigger>;
|
||||
|
||||
getHintElement.propTypes = {
|
||||
className: PropTypes.string,
|
||||
|
|
|
@ -9,18 +9,24 @@ import getHintElement from './getHintElement';
|
|||
|
||||
const getResponseCell = (row, filtering, t, isDetailed, getFilterName) => {
|
||||
const {
|
||||
reason, filterId, rule, status, upstream, elapsedMs, domain, response,
|
||||
reason, filterId, rule, status, upstream, elapsedMs,
|
||||
domain, response, originalResponse,
|
||||
} = row.original;
|
||||
|
||||
const { filters, whitelistFilters } = filtering;
|
||||
const formattedElapsedMs = formatElapsedMs(elapsedMs, t);
|
||||
|
||||
const statusLabel = t(FILTERED_STATUS_TO_META_MAP[reason]?.label || reason);
|
||||
const isBlocked = reason === FILTERED_STATUS.FILTERED_BLACK_LIST
|
||||
|| reason === FILTERED_STATUS.FILTERED_BLOCKED_SERVICE;
|
||||
|
||||
const isBlockedByResponse = originalResponse.length > 0 && isBlocked;
|
||||
|
||||
const statusLabel = t(isBlockedByResponse ? 'blocked_by_cname_or_ip' : FILTERED_STATUS_TO_META_MAP[reason]?.label || reason);
|
||||
const boldStatusLabel = <span className="font-weight-bold">{statusLabel}</span>;
|
||||
const filter = getFilterName(filters, whitelistFilters, filterId, t);
|
||||
|
||||
const renderResponses = (responseArr) => {
|
||||
if (responseArr.length === 0) {
|
||||
if (responseArr?.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
|
@ -50,6 +56,7 @@ const getResponseCell = (row, filtering, t, isDetailed, getFilterName) => {
|
|||
filter,
|
||||
rule_label: rule,
|
||||
response_code: status,
|
||||
original_response: renderResponses(originalResponse),
|
||||
},
|
||||
[FILTERED_STATUS.NOT_FILTERED_WHITE_LIST]: {
|
||||
domain,
|
||||
|
@ -78,9 +85,11 @@ const getResponseCell = (row, filtering, t, isDetailed, getFilterName) => {
|
|||
domain,
|
||||
encryption_status: boldStatusLabel,
|
||||
filter,
|
||||
rule_label: rule,
|
||||
install_settings_dns: upstream,
|
||||
elapsed: formattedElapsedMs,
|
||||
response_code: status,
|
||||
original_response: renderResponses(originalResponse),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -88,13 +97,11 @@ const getResponseCell = (row, filtering, t, isDetailed, getFilterName) => {
|
|||
? Object.entries(FILTERED_STATUS_TO_FIELDS_MAP[reason])
|
||||
: Object.entries(FILTERED_STATUS_TO_FIELDS_MAP.NotFilteredNotFound);
|
||||
|
||||
const detailedInfo = reason === FILTERED_STATUS.FILTERED_BLOCKED_SERVICE
|
||||
|| reason === FILTERED_STATUS.FILTERED_BLACK_LIST
|
||||
? filter : formattedElapsedMs;
|
||||
const detailedInfo = isBlocked ? filter : formattedElapsedMs;
|
||||
|
||||
return (
|
||||
<div className="logs__row">
|
||||
{fields && getHintElement({
|
||||
{getHintElement({
|
||||
className: classNames('icons mr-4 icon--small cursor--pointer icon--light-gray', { 'my-3': isDetailed }),
|
||||
columnClass: 'grid grid--limited',
|
||||
tooltipClass: 'px-5 pb-5 pt-4 mw-75 custom-tooltip__response-details',
|
||||
|
@ -107,7 +114,8 @@ const getResponseCell = (row, filtering, t, isDetailed, getFilterName) => {
|
|||
<div className="text-truncate">
|
||||
<div className="text-truncate" title={statusLabel}>{statusLabel}</div>
|
||||
{isDetailed && <div
|
||||
className="detailed-info d-none d-sm-block pt-1 text-truncate" title={detailedInfo}>{detailedInfo}</div>}
|
||||
className="detailed-info d-none d-sm-block pt-1 text-truncate"
|
||||
title={detailedInfo}>{detailedInfo}</div>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
FILTERED_STATUS_TO_META_MAP,
|
||||
TABLE_DEFAULT_PAGE_SIZE,
|
||||
SCHEME_TO_PROTOCOL_MAP,
|
||||
CUSTOM_FILTERING_RULES_ID,
|
||||
CUSTOM_FILTERING_RULES_ID, FILTERED_STATUS,
|
||||
} from '../../helpers/constants';
|
||||
import getDateCell from './Cells/getDateCell';
|
||||
import getDomainCell from './Cells/getDomainCell';
|
||||
|
@ -300,6 +300,8 @@ const Table = (props) => {
|
|||
type,
|
||||
client_proto,
|
||||
filterId,
|
||||
rule,
|
||||
originalResponse,
|
||||
} = rowInfo.original;
|
||||
|
||||
const hasTracker = !!tracker;
|
||||
|
@ -317,12 +319,16 @@ const Table = (props) => {
|
|||
const formattedElapsedMs = formatElapsedMs(elapsedMs, t);
|
||||
const isFiltered = checkFiltered(reason);
|
||||
|
||||
const isBlocked = reason === FILTERED_STATUS.FILTERED_BLACK_LIST
|
||||
|| reason === FILTERED_STATUS.FILTERED_BLOCKED_SERVICE;
|
||||
|
||||
const buttonType = isFiltered ? BLOCK_ACTIONS.UNBLOCK : BLOCK_ACTIONS.BLOCK;
|
||||
const onToggleBlock = () => {
|
||||
toggleBlocking(buttonType, domain);
|
||||
};
|
||||
|
||||
const status = t(FILTERED_STATUS_TO_META_MAP[reason]?.label || reason);
|
||||
const isBlockedByResponse = originalResponse.length > 0 && isBlocked;
|
||||
const status = t(isBlockedByResponse ? 'blocked_by_cname_or_ip' : FILTERED_STATUS_TO_META_MAP[reason]?.label || reason);
|
||||
const statusBlocked = <div className="bg--danger">{status}</div>;
|
||||
|
||||
const protocol = t(SCHEME_TO_PROTOCOL_MAP[client_proto]) || '';
|
||||
|
@ -379,12 +385,14 @@ const Table = (props) => {
|
|||
install_settings_dns: upstream,
|
||||
elapsed: formattedElapsedMs,
|
||||
filter,
|
||||
rule_label: rule,
|
||||
response_table_header: response?.join('\n'),
|
||||
original_response: originalResponse?.join('\n'),
|
||||
[buttonType]: <div onClick={onToggleBlock}
|
||||
className="title--border text-center">{t(buttonType)}</div>,
|
||||
};
|
||||
|
||||
const detailedDataCurrent = isFiltered ? detailedDataBlocked : detailedData;
|
||||
const detailedDataCurrent = isBlocked ? detailedDataBlocked : detailedData;
|
||||
|
||||
setDetailedDataCurrent(detailedDataCurrent);
|
||||
setButtonType(buttonType);
|
||||
|
|
|
@ -24,6 +24,10 @@ const INITIAL_REQUEST_DATA = ['', TABLE_FIRST_PAGE, INITIAL_REQUEST];
|
|||
|
||||
export const processContent = (data, buttonType) => Object.entries(data)
|
||||
.map(([key, value]) => {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const isTitle = value === 'title';
|
||||
const isButton = key === buttonType;
|
||||
const isBoolean = typeof value === 'boolean';
|
||||
|
|
|
@ -52,7 +52,7 @@ export const formatClientCell = (row, t, isDetailed = false) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="logs__text" title={value}>
|
||||
<div className="logs__text mw-100" title={value}>
|
||||
<>
|
||||
{nameContainer}
|
||||
{whoisContainer}
|
||||
|
|
|
@ -86,18 +86,16 @@ export const normalizeLogs = (logs) => logs.map((log) => {
|
|||
|
||||
const { host: domain, type } = question;
|
||||
|
||||
const response = answer ? answer.map((response) => {
|
||||
const processResponse = (data) => (data ? data.map((response) => {
|
||||
const { value, type, ttl } = response;
|
||||
return `${type}: ${value} (ttl=${ttl})`;
|
||||
}) : [];
|
||||
|
||||
const tracker = getTrackerData(domain);
|
||||
}) : []);
|
||||
|
||||
return {
|
||||
time,
|
||||
domain,
|
||||
type,
|
||||
response,
|
||||
response: processResponse(answer),
|
||||
reason,
|
||||
client,
|
||||
client_proto,
|
||||
|
@ -106,7 +104,8 @@ export const normalizeLogs = (logs) => logs.map((log) => {
|
|||
status,
|
||||
serviceName: service_name,
|
||||
originalAnswer: original_answer,
|
||||
tracker,
|
||||
originalResponse: processResponse(original_answer),
|
||||
tracker: getTrackerData(domain),
|
||||
answer_dnssec,
|
||||
elapsedMs,
|
||||
upstream,
|
||||
|
@ -618,3 +617,8 @@ export const selectCompletedFields = (values) => Object.entries(values)
|
|||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
|
||||
export const processContent = (content) => (Array.isArray(content)
|
||||
? content.filter(([, value]) => value)
|
||||
.flat() : content);
|
||||
|
|
Loading…
Reference in New Issue