Merge: fix #1421
Full rework of the query log Squashed commit of the following: commit e8a72eb223551f17e637136713dae03accf8ab9e Author: Andrey Meshkov <am@adguard.com> Date: Thu Jun 18 00:31:53 2020 +0300 fix race in whois test commit 801d28197f888fa21f83c9a0b49e3c9472c08513 Merge: 9d9787fdb1c951fbAuthor: Andrey Meshkov <am@adguard.com> Date: Thu Jun 18 00:28:13 2020 +0300 Merge branch 'master' into feature/1421 commit 9d9787fd79b17f76c7baed52c12ac462fd00a5e4 Merge: 4ce337ca 08e238ab Author: Andrey Meshkov <am@adguard.com> Date: Thu Jun 18 00:27:32 2020 +0300 Merge commit 4ce337ca7aec163edf87a038bb25fb44e64f8613 Author: Andrey Meshkov <am@adguard.com> Date: Thu Jun 18 00:22:49 2020 +0300 -(home): fix whois test commit 08e238ab0e723b1e354f58245e9a8d5017b392c9 Author: ArtemBaskal <a.baskal@adguard.com> Date: Thu Jun 18 00:13:41 2020 +0300 Add comments commit 5f108065952bcc25dce1c2eee3f9401d2641a6e9 Author: ArtemBaskal <a.baskal@adguard.com> Date: Wed Jun 17 23:47:50 2020 +0300 Make tooltip position absolute for touch commit 4c30a583165e5d007d4b01b657de8751a7bd8c7b Author: ArtemBaskal <a.baskal@adguard.com> Date: Wed Jun 17 20:39:44 2020 +0300 Prevent scroll hide for touch devices commit 62da97931f5921613762614717c62c77ddb6b8db Author: ArtemBaskal <a.baskal@adguard.com> Date: Wed Jun 17 20:06:24 2020 +0300 Review changes: ipad tooltip commit 12dddcca8caca51c157b5d25dfa3ca03ba7f0c06 Author: ArtemBaskal <a.baskal@adguard.com> Date: Wed Jun 17 16:59:16 2020 +0300 Add close tooltip event for ipad commit 62191e41d5bf67317f9f1dc6c6af08cbabb4bf90 Author: ArtemBaskal <a.baskal@adguard.com> Date: Wed Jun 17 16:39:40 2020 +0300 Add success toast on logs refresh commit 2ebdd6a8124269d737c8060c3247aaf35d85cb8b Author: ArtemBaskal <a.baskal@adguard.com> Date: Wed Jun 17 16:01:37 2020 +0300 Fix pagination commit 5820c92bacd93d05a3d66d42ee95f099e1c5d9e9 Author: ArtemBaskal <a.baskal@adguard.com> Date: Wed Jun 17 11:31:15 2020 +0300 Revert "Render table in chunks" This reverts commit cdfcd849ccddc1bc35591edac7904129431470c9. commit cdfcd849ccddc1bc35591edac7904129431470c9 Author: ArtemBaskal <a.baskal@adguard.com> Date: Tue Jun 16 18:42:18 2020 +0300 Render table in chunks commit cc8c5e64274bf6e806e2e8a4bf305af745c3ed2a Author: ArtemBaskal <a.baskal@adguard.com> Date: Tue Jun 16 17:35:24 2020 +0300 Add pagination button hover effect commit f7e134091a1556784a5fea9d83c50353536126ef Author: ArtemBaskal <a.baskal@adguard.com> Date: Tue Jun 16 16:28:00 2020 +0300 Make loader position absolute commit a7b887b57d903f1f7ac967b861b5cc677728efc4 Author: ArtemBaskal <a.baskal@adguard.com> Date: Tue Jun 16 15:42:20 2020 +0300 Ignore clients find without params commit ecb322fefd4a161d79f28d17fe27827ee91701e4 Author: ArtemBaskal <a.baskal@adguard.com> Date: Tue Jun 16 15:30:48 2020 +0300 Styles changes commit 9323ce3938bf04e1290eade09201ba0790a250c0 Author: ArtemBaskal <a.baskal@adguard.com> Date: Tue Jun 16 14:32:23 2020 +0300 Review styles changes commit e0faa04ba3643f01b2ca99524cdd52b0731725c7 Merge: 9857682315e71435Author: ArtemBaskal <a.baskal@adguard.com> Date: Tue Jun 16 12:08:45 2020 +0300 Merge branch '1421-new-qlog-v2' into feature/1421 commit 9857682371e8d9a3a91933cfb58a26b3470675d9 Author: ArtemBaskal <a.baskal@adguard.com> Date: Mon Jun 15 18:32:02 2020 +0300 Fix response cell ... and 88 more commits
This commit is contained in:
@@ -1,457 +1,210 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import React, { Fragment, useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ReactTable from 'react-table';
|
||||
import escapeRegExp from 'lodash/escapeRegExp';
|
||||
import endsWith from 'lodash/endsWith';
|
||||
import { Trans, withTranslation } from 'react-i18next';
|
||||
import { HashLink as Link } from 'react-router-hash-link';
|
||||
|
||||
import { Trans } from 'react-i18next';
|
||||
import Modal from 'react-modal';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import {
|
||||
formatTime,
|
||||
formatDateTime,
|
||||
isToday,
|
||||
checkFiltered,
|
||||
checkRewrite,
|
||||
checkRewriteHosts,
|
||||
checkWhiteList,
|
||||
checkBlackList,
|
||||
checkBlockedService,
|
||||
} from '../../helpers/helpers';
|
||||
import {
|
||||
SERVICES, TABLE_DEFAULT_PAGE_SIZE, CUSTOM_FILTERING_RULES_ID, FILTERED,
|
||||
BLOCK_ACTIONS, smallScreenSize,
|
||||
TABLE_DEFAULT_PAGE_SIZE,
|
||||
TABLE_FIRST_PAGE,
|
||||
} from '../../helpers/constants';
|
||||
import { getTrackerData } from '../../helpers/trackers/trackers';
|
||||
import { formatClientCell } from '../../helpers/formatClientCell';
|
||||
|
||||
import Filters from './Filters';
|
||||
import PageTitle from '../ui/PageTitle';
|
||||
import Card from '../ui/Card';
|
||||
import Loading from '../ui/Loading';
|
||||
import PopoverFiltered from '../ui/PopoverFilter';
|
||||
import Popover from '../ui/Popover';
|
||||
import Filters from './Filters';
|
||||
import Table from './Table';
|
||||
import Disabled from './Disabled';
|
||||
import './Logs.css';
|
||||
import CellWrap from '../ui/CellWrap';
|
||||
import { getFilteringStatus } from '../../actions/filtering';
|
||||
import { getClients } from '../../actions';
|
||||
import { getDnsConfig } from '../../actions/dnsConfig';
|
||||
import { getLogsConfig } from '../../actions/queryLogs';
|
||||
import { addSuccessToast } from '../../actions/toasts';
|
||||
|
||||
const TABLE_FIRST_PAGE = 0;
|
||||
const INITIAL_REQUEST = true;
|
||||
const INITIAL_REQUEST_DATA = ['', TABLE_FIRST_PAGE, INITIAL_REQUEST];
|
||||
|
||||
class Logs extends Component {
|
||||
componentDidMount() {
|
||||
this.props.setLogsPage(TABLE_FIRST_PAGE);
|
||||
this.getLogs(...INITIAL_REQUEST_DATA);
|
||||
this.props.getFilteringStatus();
|
||||
this.props.getLogsConfig();
|
||||
}
|
||||
export const processContent = (data, buttonType) => Object.entries(data)
|
||||
.map(([key, value]) => {
|
||||
const isTitle = value === 'title';
|
||||
const isButton = key === buttonType;
|
||||
const isBoolean = typeof value === 'boolean';
|
||||
const isHidden = isBoolean && value === false;
|
||||
|
||||
getLogs = (older_than, page, initial) => {
|
||||
if (this.props.queryLogs.enabled) {
|
||||
this.props.getLogs({
|
||||
older_than, page, pageSize: TABLE_DEFAULT_PAGE_SIZE, initial,
|
||||
let keyClass = 'key-colon';
|
||||
|
||||
if (isTitle) {
|
||||
keyClass = 'title--border';
|
||||
}
|
||||
if (isButton || isBoolean) {
|
||||
keyClass = '';
|
||||
}
|
||||
|
||||
return isHidden ? null : <Fragment key={key}>
|
||||
<div
|
||||
className={`key__${key} ${keyClass} ${(isBoolean && value === true) ? 'font-weight-bold' : ''}`}>
|
||||
<Trans>{isButton ? value : key}</Trans>
|
||||
</div>
|
||||
<div className={`value__${key} text-pre text-truncate`}>
|
||||
<Trans>{(isTitle || isButton || isBoolean) ? '' : value || '—'}</Trans>
|
||||
</div>
|
||||
</Fragment>;
|
||||
});
|
||||
|
||||
|
||||
const Logs = (props) => {
|
||||
const dispatch = useDispatch();
|
||||
const [isSmallScreen, setIsSmallScreen] = useState(window.innerWidth < smallScreenSize);
|
||||
const [detailedDataCurrent, setDetailedDataCurrent] = useState({});
|
||||
const [buttonType, setButtonType] = useState(BLOCK_ACTIONS.BLOCK);
|
||||
const [isModalOpened, setModalOpened] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const {
|
||||
filtering,
|
||||
setLogsPage,
|
||||
setLogsPagination,
|
||||
setLogsFilter,
|
||||
toggleDetailedLogs,
|
||||
dashboard,
|
||||
dnsConfig,
|
||||
queryLogs: {
|
||||
filter,
|
||||
enabled,
|
||||
processingGetConfig,
|
||||
processingAdditionalLogs,
|
||||
processingGetLogs,
|
||||
oldest,
|
||||
logs,
|
||||
pages,
|
||||
page,
|
||||
isDetailed,
|
||||
},
|
||||
} = props;
|
||||
|
||||
const mediaQuery = window.matchMedia(`(max-width: ${smallScreenSize}px)`);
|
||||
const mediaQueryHandler = (e) => {
|
||||
setIsSmallScreen(e.matches);
|
||||
if (e.matches) {
|
||||
toggleDetailedLogs(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
mediaQuery.addListener(mediaQueryHandler);
|
||||
|
||||
return () => mediaQuery.removeListener(mediaQueryHandler);
|
||||
}, []);
|
||||
|
||||
const closeModal = () => setModalOpened(false);
|
||||
|
||||
const getLogs = (older_than, page, initial) => {
|
||||
if (props.queryLogs.enabled) {
|
||||
props.getLogs({
|
||||
older_than,
|
||||
page,
|
||||
pageSize: TABLE_DEFAULT_PAGE_SIZE,
|
||||
initial,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
refreshLogs = () => {
|
||||
window.location.reload();
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
setIsLoading(true);
|
||||
dispatch(setLogsPage(TABLE_FIRST_PAGE));
|
||||
dispatch(getFilteringStatus());
|
||||
dispatch(getClients());
|
||||
try {
|
||||
await Promise.all([
|
||||
getLogs(...INITIAL_REQUEST_DATA),
|
||||
dispatch(getLogsConfig()),
|
||||
dispatch(getDnsConfig()),
|
||||
]);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const refreshLogs = async () => {
|
||||
setIsLoading(true);
|
||||
await Promise.all([
|
||||
dispatch(setLogsPage(TABLE_FIRST_PAGE)),
|
||||
getLogs(...INITIAL_REQUEST_DATA),
|
||||
]);
|
||||
dispatch(addSuccessToast('query_log_updated'));
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
renderTooltip = (isFiltered, rule, filter, service) => isFiltered
|
||||
&& <PopoverFiltered rule={rule} filter={filter} service={service} />;
|
||||
|
||||
renderResponseList = (response, status) => {
|
||||
if (response.length > 0) {
|
||||
const listItems = response.map((response, index) => (
|
||||
<li key={index} title={response} className="logs__list-item">
|
||||
{response}
|
||||
</li>
|
||||
));
|
||||
|
||||
return <ul className="list-unstyled">{listItems}</ul>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Trans values={{ value: status }}>query_log_response_status</Trans>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
toggleBlocking = (type, domain) => {
|
||||
const { userRules } = this.props.filtering;
|
||||
const { t } = this.props;
|
||||
const lineEnding = !endsWith(userRules, '\n') ? '\n' : '';
|
||||
const baseRule = `||${domain}^$important`;
|
||||
const baseUnblocking = `@@${baseRule}`;
|
||||
const blockingRule = type === 'block' ? baseUnblocking : baseRule;
|
||||
const unblockingRule = type === 'block' ? baseRule : baseUnblocking;
|
||||
const preparedBlockingRule = new RegExp(`(^|\n)${escapeRegExp(blockingRule)}($|\n)`);
|
||||
const preparedUnblockingRule = new RegExp(`(^|\n)${escapeRegExp(unblockingRule)}($|\n)`);
|
||||
|
||||
if (userRules.match(preparedBlockingRule)) {
|
||||
this.props.setRules(userRules.replace(`${blockingRule}`, ''));
|
||||
this.props.addSuccessToast(`${t('rule_removed_from_custom_filtering_toast')}: ${blockingRule}`);
|
||||
} else if (!userRules.match(preparedUnblockingRule)) {
|
||||
this.props.setRules(`${userRules}${lineEnding}${unblockingRule}\n`);
|
||||
this.props.addSuccessToast(`${t('rule_added_to_custom_filtering_toast')}: ${unblockingRule}`);
|
||||
}
|
||||
|
||||
this.props.getFilteringStatus();
|
||||
};
|
||||
|
||||
renderBlockingButton(isFiltered, domain) {
|
||||
const buttonClass = isFiltered ? 'btn-outline-secondary' : 'btn-outline-danger';
|
||||
const buttonText = isFiltered ? 'unblock_btn' : 'block_btn';
|
||||
const buttonType = isFiltered ? 'unblock' : 'block';
|
||||
|
||||
return (
|
||||
<div className="logs__action">
|
||||
<button
|
||||
type="button"
|
||||
className={`btn btn-sm ${buttonClass}`}
|
||||
onClick={() => this.toggleBlocking(buttonType, domain)}
|
||||
disabled={this.props.filtering.processingRules}
|
||||
>
|
||||
<Trans>{buttonText}</Trans>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
getDateCell = (row) => CellWrap(
|
||||
row,
|
||||
(isToday(row.value) ? formatTime : formatDateTime),
|
||||
formatDateTime,
|
||||
return (
|
||||
<>
|
||||
{enabled && processingGetConfig && <Loading />}
|
||||
{enabled && !processingGetConfig && (
|
||||
<Fragment>
|
||||
<Filters
|
||||
filter={filter}
|
||||
setIsLoading={setIsLoading}
|
||||
processingGetLogs={processingGetLogs}
|
||||
processingAdditionalLogs={processingAdditionalLogs}
|
||||
setLogsFilter={setLogsFilter}
|
||||
refreshLogs={refreshLogs}
|
||||
/>
|
||||
<Table
|
||||
isLoading={isLoading}
|
||||
setIsLoading={setIsLoading}
|
||||
logs={logs}
|
||||
pages={pages}
|
||||
page={page}
|
||||
autoClients={dashboard.autoClients}
|
||||
oldest={oldest}
|
||||
filtering={filtering}
|
||||
processingGetLogs={processingGetLogs}
|
||||
processingGetConfig={processingGetConfig}
|
||||
isDetailed={isDetailed}
|
||||
setLogsPagination={setLogsPagination}
|
||||
setLogsPage={setLogsPage}
|
||||
toggleDetailedLogs={toggleDetailedLogs}
|
||||
getLogs={getLogs}
|
||||
setRules={props.setRules}
|
||||
addSuccessToast={props.addSuccessToast}
|
||||
getFilteringStatus={props.getFilteringStatus}
|
||||
dnssec_enabled={dnsConfig.dnssec_enabled}
|
||||
setDetailedDataCurrent={setDetailedDataCurrent}
|
||||
setButtonType={setButtonType}
|
||||
setModalOpened={setModalOpened}
|
||||
isSmallScreen={isSmallScreen}
|
||||
/>
|
||||
<Modal portalClassName='grid' isOpen={isSmallScreen && isModalOpened}
|
||||
onRequestClose={closeModal}
|
||||
style={{
|
||||
content: {
|
||||
width: '100%',
|
||||
height: 'fit-content',
|
||||
left: 0,
|
||||
top: 47,
|
||||
padding: '1rem 1.5rem 1rem',
|
||||
},
|
||||
overlay: {
|
||||
backgroundColor: 'rgba(0,0,0,0.5)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
className="icon icon--small icon-cross d-block d-md-none cursor--pointer"
|
||||
onClick={closeModal}>
|
||||
<use xlinkHref="#cross" />
|
||||
</svg>
|
||||
{processContent(detailedDataCurrent, buttonType)}
|
||||
</Modal>
|
||||
</Fragment>
|
||||
)}
|
||||
{!enabled && !processingGetConfig && (
|
||||
<Disabled />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
getDomainCell = (row) => {
|
||||
const response = row.value;
|
||||
const trackerData = getTrackerData(response);
|
||||
|
||||
return (
|
||||
<div className="logs__row" title={response}>
|
||||
<div className="logs__text">{response}</div>
|
||||
{trackerData && <Popover data={trackerData} />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
normalizeResponse = (response) => (
|
||||
response.map((response) => {
|
||||
const { value, type, ttl } = response;
|
||||
return `${type}: ${value} (ttl=${ttl})`;
|
||||
})
|
||||
);
|
||||
|
||||
getFilterName = (filters, whitelistFilters, filterId, t) => {
|
||||
if (filterId === CUSTOM_FILTERING_RULES_ID) {
|
||||
return t('custom_filter_rules');
|
||||
}
|
||||
|
||||
const filter = filters.find((filter) => filter.id === filterId)
|
||||
|| whitelistFilters.find((filter) => filter.id === filterId);
|
||||
let filterName = '';
|
||||
|
||||
if (filter) {
|
||||
filterName = filter.name;
|
||||
}
|
||||
|
||||
if (!filterName) {
|
||||
filterName = t('unknown_filter', { filterId });
|
||||
}
|
||||
|
||||
return filterName;
|
||||
}
|
||||
|
||||
getResponseCell = ({ value: responses, original }) => {
|
||||
const {
|
||||
reason, filterId, rule, status, originalAnswer,
|
||||
} = original;
|
||||
const { t, filtering } = this.props;
|
||||
const { filters, whitelistFilters } = filtering;
|
||||
|
||||
const isFiltered = checkFiltered(reason);
|
||||
const isBlackList = checkBlackList(reason);
|
||||
const isRewrite = checkRewrite(reason);
|
||||
const isRewriteAuto = checkRewriteHosts(reason);
|
||||
const isWhiteList = checkWhiteList(reason);
|
||||
const isBlockedService = checkBlockedService(reason);
|
||||
const isBlockedCnameIp = originalAnswer;
|
||||
|
||||
const filterKey = reason.replace(FILTERED, '');
|
||||
const parsedFilteredReason = t('query_log_filtered', { filter: filterKey });
|
||||
const currentService = SERVICES.find((service) => service.id === original.serviceName);
|
||||
const serviceName = currentService && currentService.name;
|
||||
const filterName = this.getFilterName(filters, whitelistFilters, filterId, t);
|
||||
|
||||
if (isBlockedCnameIp) {
|
||||
const normalizedAnswer = this.normalizeResponse(originalAnswer);
|
||||
|
||||
return (
|
||||
<div className="logs__row logs__row--column">
|
||||
<div className="logs__text-wrap">
|
||||
<span className="logs__text">
|
||||
<Trans>blocked_by_response</Trans>
|
||||
</span>
|
||||
{this.renderTooltip(isFiltered, rule, filterName)}
|
||||
</div>
|
||||
<div className="logs__list-wrap">
|
||||
{this.renderResponseList(normalizedAnswer, status)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="logs__row logs__row--column">
|
||||
<div className="logs__text-wrap">
|
||||
{(isFiltered || isBlockedService) && !isBlackList && (
|
||||
<span className="logs__text" title={parsedFilteredReason}>
|
||||
{parsedFilteredReason}
|
||||
</span>
|
||||
)}
|
||||
{isBlackList && (
|
||||
<span className="logs__text">
|
||||
<Trans values={{ filter: filterName }}>
|
||||
query_log_filtered
|
||||
</Trans>
|
||||
</span>
|
||||
)}
|
||||
{isBlockedService
|
||||
? this.renderTooltip(isFiltered, '', '', serviceName)
|
||||
: this.renderTooltip(isFiltered, rule, filterName)}
|
||||
{isRewrite && (
|
||||
<strong>
|
||||
<Trans>rewrite_applied</Trans>
|
||||
</strong>
|
||||
)}
|
||||
{isRewriteAuto && (
|
||||
<span className="logs__text">
|
||||
<strong>
|
||||
<Trans>rewrite_hosts_applied</Trans>
|
||||
</strong>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="logs__list-wrap">
|
||||
{this.renderResponseList(responses, status)}
|
||||
{isWhiteList && this.renderTooltip(isWhiteList, rule, filterName)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
getClientCell = (row) => {
|
||||
const { original } = row;
|
||||
const { t } = this.props;
|
||||
const { reason, domain } = original;
|
||||
const isFiltered = checkFiltered(reason);
|
||||
const isRewrite = checkRewrite(reason);
|
||||
const isAutoRewrite = checkRewriteHosts(reason);
|
||||
|
||||
if (isAutoRewrite) {
|
||||
return (
|
||||
<div className="logs__row logs__row--overflow logs__row--column">
|
||||
{formatClientCell(row, t)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="logs__row logs__row--overflow logs__row--column">
|
||||
{formatClientCell(row, t)}
|
||||
</div>
|
||||
{isRewrite ? (
|
||||
<div className="logs__action">
|
||||
<Link to="/dns_rewrites" className="btn btn-sm btn-outline-primary">
|
||||
<Trans>configure</Trans>
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
this.renderBlockingButton(isFiltered, domain)
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
fetchData = (state) => {
|
||||
const { pages } = state;
|
||||
const { oldest, page } = this.props.queryLogs;
|
||||
const isLastPage = pages && (page + 1 === pages);
|
||||
|
||||
if (isLastPage) {
|
||||
this.getLogs(oldest, page);
|
||||
}
|
||||
};
|
||||
|
||||
changePage = (page) => {
|
||||
this.props.setLogsPage(page);
|
||||
this.props.setLogsPagination({ page, pageSize: TABLE_DEFAULT_PAGE_SIZE });
|
||||
};
|
||||
|
||||
renderLogs() {
|
||||
const { queryLogs, t } = this.props;
|
||||
const {
|
||||
processingGetLogs, processingGetConfig, logs, pages, page,
|
||||
} = queryLogs;
|
||||
const isLoading = processingGetLogs || processingGetConfig;
|
||||
|
||||
const columns = [
|
||||
{
|
||||
Header: t('time_table_header'),
|
||||
accessor: 'time',
|
||||
minWidth: 105,
|
||||
Cell: this.getDateCell,
|
||||
},
|
||||
{
|
||||
Header: t('domain_name_table_header'),
|
||||
accessor: 'domain',
|
||||
minWidth: 180,
|
||||
Cell: this.getDomainCell,
|
||||
},
|
||||
{
|
||||
Header: t('type_table_header'),
|
||||
accessor: 'type',
|
||||
maxWidth: 60,
|
||||
},
|
||||
{
|
||||
Header: t('response_table_header'),
|
||||
accessor: 'response',
|
||||
minWidth: 250,
|
||||
Cell: this.getResponseCell,
|
||||
},
|
||||
{
|
||||
Header: t('client_table_header'),
|
||||
accessor: 'client',
|
||||
maxWidth: 240,
|
||||
minWidth: 240,
|
||||
Cell: this.getClientCell,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<ReactTable
|
||||
manual
|
||||
minRows={5}
|
||||
page={page}
|
||||
pages={pages}
|
||||
columns={columns}
|
||||
filterable={false}
|
||||
sortable={false}
|
||||
data={logs || []}
|
||||
loading={isLoading}
|
||||
showPagination={true}
|
||||
showPaginationTop={true}
|
||||
showPageJump={false}
|
||||
showPageSizeOptions={false}
|
||||
onFetchData={this.fetchData}
|
||||
onPageChange={this.changePage}
|
||||
className="logs__table"
|
||||
defaultPageSize={TABLE_DEFAULT_PAGE_SIZE}
|
||||
previousText={t('previous_btn')}
|
||||
nextText={t('next_btn')}
|
||||
loadingText={t('loading_table_status')}
|
||||
rowsText={t('rows_table_footer_text')}
|
||||
noDataText={t('no_logs_found')}
|
||||
pageText={''}
|
||||
ofText={''}
|
||||
renderTotalPagesCount={() => false}
|
||||
defaultFilterMethod={(filter, row) => {
|
||||
const id = filter.pivotId || filter.id;
|
||||
return row[id] !== undefined
|
||||
? String(row[id]).indexOf(filter.value) !== -1
|
||||
: true;
|
||||
}}
|
||||
defaultSorted={[
|
||||
{
|
||||
id: 'time',
|
||||
desc: true,
|
||||
},
|
||||
]}
|
||||
getTrProps={(_state, rowInfo) => {
|
||||
if (!rowInfo) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const { reason } = rowInfo.original;
|
||||
|
||||
if (checkFiltered(reason)) {
|
||||
return {
|
||||
className: 'red',
|
||||
};
|
||||
} if (checkWhiteList(reason)) {
|
||||
return {
|
||||
className: 'green',
|
||||
};
|
||||
} if (checkRewrite(reason) || checkRewriteHosts(reason)) {
|
||||
return {
|
||||
className: 'blue',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
className: '',
|
||||
};
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { queryLogs, t } = this.props;
|
||||
const {
|
||||
enabled, processingGetConfig, processingAdditionalLogs, processingGetLogs,
|
||||
} = queryLogs;
|
||||
|
||||
const refreshButton = enabled ? (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-outline-primary btn-sm ml-3"
|
||||
onClick={this.refreshLogs}
|
||||
>
|
||||
<svg className="icons">
|
||||
<use xlinkHref="#refresh" />
|
||||
</svg>
|
||||
</button>
|
||||
) : (
|
||||
''
|
||||
);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<PageTitle title={t('query_log')}>{refreshButton}</PageTitle>
|
||||
{enabled && processingGetConfig && <Loading />}
|
||||
{enabled && !processingGetConfig && (
|
||||
<Fragment>
|
||||
<Filters
|
||||
filter={queryLogs.filter}
|
||||
processingGetLogs={processingGetLogs}
|
||||
processingAdditionalLogs={processingAdditionalLogs}
|
||||
setLogsFilter={this.props.setLogsFilter}
|
||||
/>
|
||||
<Card>{this.renderLogs()}</Card>
|
||||
</Fragment>
|
||||
)}
|
||||
{!enabled && !processingGetConfig && (
|
||||
<Card>
|
||||
<div className="lead text-center py-6">
|
||||
<Trans
|
||||
components={[
|
||||
<Link to="/settings#logs-config" key="0">
|
||||
link
|
||||
</Link>,
|
||||
]}
|
||||
>
|
||||
query_log_disabled
|
||||
</Trans>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Logs.propTypes = {
|
||||
getLogs: PropTypes.func.isRequired,
|
||||
@@ -461,12 +214,11 @@ Logs.propTypes = {
|
||||
filtering: PropTypes.object.isRequired,
|
||||
setRules: PropTypes.func.isRequired,
|
||||
addSuccessToast: PropTypes.func.isRequired,
|
||||
getClients: PropTypes.func.isRequired,
|
||||
getLogsConfig: PropTypes.func.isRequired,
|
||||
setLogsPagination: PropTypes.func.isRequired,
|
||||
setLogsFilter: PropTypes.func.isRequired,
|
||||
setLogsPage: PropTypes.func.isRequired,
|
||||
t: PropTypes.func.isRequired,
|
||||
toggleDetailedLogs: PropTypes.func.isRequired,
|
||||
dnsConfig: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default withTranslation()(Logs);
|
||||
export default Logs;
|
||||
|
||||
Reference in New Issue
Block a user