2020-06-17 21:36:19 +00:00
|
|
|
import React from 'react';
|
2020-09-01 13:30:30 +00:00
|
|
|
import { useSelector } from 'react-redux';
|
2020-06-17 21:36:19 +00:00
|
|
|
import classNames from 'classnames';
|
2020-09-01 13:30:30 +00:00
|
|
|
import propTypes from 'prop-types';
|
|
|
|
import { useTranslation } from 'react-i18next';
|
2020-06-17 21:36:19 +00:00
|
|
|
import {
|
|
|
|
DEFAULT_SHORT_DATE_FORMAT_OPTIONS,
|
|
|
|
LONG_TIME_FORMAT,
|
|
|
|
SCHEME_TO_PROTOCOL_MAP,
|
|
|
|
} from '../../../helpers/constants';
|
2020-07-03 09:01:03 +00:00
|
|
|
import { captitalizeWords, formatDateTime, formatTime } from '../../../helpers/helpers';
|
|
|
|
import { getSourceData } from '../../../helpers/trackers/trackers';
|
2020-09-01 13:30:30 +00:00
|
|
|
import IconTooltip from './IconTooltip';
|
|
|
|
|
|
|
|
const DomainCell = ({
|
|
|
|
answer_dnssec,
|
2020-09-03 17:35:20 +00:00
|
|
|
service_name,
|
2020-09-01 13:30:30 +00:00
|
|
|
client_proto,
|
|
|
|
domain,
|
|
|
|
time,
|
|
|
|
tracker,
|
|
|
|
type,
|
|
|
|
}) => {
|
|
|
|
const { t } = useTranslation();
|
|
|
|
const dnssec_enabled = useSelector((state) => state.dnsConfig.dnssec_enabled);
|
|
|
|
const isDetailed = useSelector((state) => state.queryLogs.isDetailed);
|
2020-06-17 21:36:19 +00:00
|
|
|
|
|
|
|
const hasTracker = !!tracker;
|
|
|
|
|
2020-07-17 12:24:39 +00:00
|
|
|
const lockIconClass = classNames('icons icon--24 d-none d-sm-block', {
|
|
|
|
'icon--green': answer_dnssec,
|
2020-06-17 21:36:19 +00:00
|
|
|
'icon--disabled': !answer_dnssec,
|
|
|
|
'my-3': isDetailed,
|
|
|
|
});
|
|
|
|
|
2020-07-17 12:24:39 +00:00
|
|
|
const privacyIconClass = classNames('icons mx-2 icon--24 d-none d-sm-block', {
|
|
|
|
'icon--green': hasTracker,
|
2020-06-17 21:36:19 +00:00
|
|
|
'icon--disabled': !hasTracker,
|
|
|
|
'my-3': isDetailed,
|
|
|
|
});
|
|
|
|
|
|
|
|
const protocol = t(SCHEME_TO_PROTOCOL_MAP[client_proto]) || '';
|
|
|
|
const ip = type ? `${t('type_table_header')}: ${type}` : '';
|
|
|
|
|
|
|
|
const requestDetailsObj = {
|
|
|
|
time_table_header: formatTime(time, LONG_TIME_FORMAT),
|
|
|
|
date: formatDateTime(time, DEFAULT_SHORT_DATE_FORMAT_OPTIONS),
|
|
|
|
domain,
|
|
|
|
type_table_header: type,
|
|
|
|
protocol,
|
|
|
|
};
|
|
|
|
|
2020-09-03 17:35:20 +00:00
|
|
|
if (service_name) {
|
|
|
|
requestDetailsObj.check_service = service_name;
|
|
|
|
}
|
|
|
|
|
2020-07-03 09:01:03 +00:00
|
|
|
const sourceData = getSourceData(tracker);
|
|
|
|
|
2020-06-17 21:36:19 +00:00
|
|
|
const knownTrackerDataObj = {
|
2020-07-03 16:17:58 +00:00
|
|
|
name_table_header: tracker?.name,
|
|
|
|
category_label: hasTracker && captitalizeWords(tracker.category),
|
2020-07-03 09:01:03 +00:00
|
|
|
source_label: sourceData
|
2020-09-01 13:30:30 +00:00
|
|
|
&& <a href={sourceData.url} target="_blank" rel="noopener noreferrer"
|
|
|
|
className="link--green">{sourceData.name}</a>,
|
2020-06-17 21:36:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const renderGrid = (content, idx) => {
|
|
|
|
const preparedContent = typeof content === 'string' ? t(content) : content;
|
2020-07-13 13:06:56 +00:00
|
|
|
const className = classNames('text-truncate o-hidden', {
|
2020-06-18 19:53:02 +00:00
|
|
|
'overflow-break': preparedContent.length > 100,
|
2020-06-17 21:36:19 +00:00
|
|
|
});
|
|
|
|
return <div key={idx} className={className}>{preparedContent}</div>;
|
|
|
|
};
|
|
|
|
|
|
|
|
const getGrid = (contentObj, title, className) => [
|
|
|
|
<div key={title} className={classNames('pb-2 grid--title', className)}>{t(title)}</div>,
|
2020-07-03 09:01:03 +00:00
|
|
|
<div key={`${title}-1`}
|
|
|
|
className="grid grid--limited">{React.Children.map(Object.entries(contentObj), renderGrid)}</div>,
|
2020-06-17 21:36:19 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
const requestDetails = getGrid(requestDetailsObj, 'request_details');
|
|
|
|
|
|
|
|
const renderContent = hasTracker ? requestDetails.concat(getGrid(knownTrackerDataObj, 'known_tracker', 'pt-4')) : requestDetails;
|
|
|
|
|
2020-09-01 13:30:30 +00:00
|
|
|
const valueClass = classNames('w-100 text-truncate', {
|
2020-06-17 21:36:19 +00:00
|
|
|
'px-2 d-flex justify-content-center flex-column': isDetailed,
|
|
|
|
});
|
|
|
|
|
|
|
|
const details = [ip, protocol].filter(Boolean)
|
|
|
|
.join(', ');
|
|
|
|
|
2020-09-01 13:30:30 +00:00
|
|
|
return <div className="d-flex o-hidden logs__cell logs__cell logs__cell--domain" role="gridcell">
|
|
|
|
{dnssec_enabled && <IconTooltip
|
|
|
|
className={lockIconClass}
|
|
|
|
tooltipClass='py-4 px-5 pb-45'
|
|
|
|
canShowTooltip={!!answer_dnssec}
|
|
|
|
xlinkHref='lock'
|
|
|
|
columnClass='w-100'
|
|
|
|
content='validated_with_dnssec'
|
|
|
|
placement='bottom'
|
|
|
|
/>}
|
|
|
|
<IconTooltip className={privacyIconClass} tooltipClass='pt-4 pb-5 px-5 mw-75'
|
|
|
|
xlinkHref='privacy' contentItemClass='key-colon' renderContent={renderContent}
|
|
|
|
place='bottom' />
|
|
|
|
<div className={valueClass}>
|
2020-09-03 17:35:20 +00:00
|
|
|
<div className="text-truncate" title={domain}>{service_name || domain}</div>
|
2020-09-01 13:30:30 +00:00
|
|
|
{details && isDetailed
|
|
|
|
&& <div className="detailed-info d-none d-sm-block text-truncate"
|
|
|
|
title={details}>{details}</div>}
|
2020-06-17 21:36:19 +00:00
|
|
|
</div>
|
2020-09-01 13:30:30 +00:00
|
|
|
</div>;
|
2020-06-17 21:36:19 +00:00
|
|
|
};
|
|
|
|
|
2020-09-01 13:30:30 +00:00
|
|
|
DomainCell.propTypes = {
|
|
|
|
answer_dnssec: propTypes.bool.isRequired,
|
|
|
|
client_proto: propTypes.string.isRequired,
|
|
|
|
domain: propTypes.string.isRequired,
|
|
|
|
time: propTypes.string.isRequired,
|
|
|
|
type: propTypes.string.isRequired,
|
2020-09-03 17:35:20 +00:00
|
|
|
service_name: propTypes.string,
|
2020-09-01 13:30:30 +00:00
|
|
|
tracker: propTypes.object,
|
2020-06-17 21:36:19 +00:00
|
|
|
};
|
|
|
|
|
2020-09-01 13:30:30 +00:00
|
|
|
export default DomainCell;
|