import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import ReactTable from 'react-table';
import escapeRegExp from 'lodash/escapeRegExp';
import endsWith from 'lodash/endsWith';
import { Trans, withNamespaces } from 'react-i18next';
import { HashLink as Link } from 'react-router-hash-link';
import { formatTime, formatDateTime } from '../../helpers/helpers';
import { SERVICES, FILTERED_STATUS } from '../../helpers/constants';
import { getTrackerData } from '../../helpers/trackers/trackers';
import { formatClientCell } from '../../helpers/formatClientCell';
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 './Logs.css';
const FILTERED_REASON = 'Filtered';
const RESPONSE_FILTER = {
ALL: 'all',
FILTERED: 'filtered',
};
class Logs extends Component {
componentDidMount() {
this.getLogs();
this.props.getFilteringStatus();
this.props.getClients();
this.props.getLogsConfig();
}
componentDidUpdate(prevProps) {
// get logs when queryLog becomes enabled
if (this.props.queryLogs.enabled && !prevProps.queryLogs.enabled) {
this.props.getLogs();
}
}
getLogs = () => {
// get logs on initialization if queryLogIsEnabled
if (this.props.queryLogs.enabled) {
this.props.getLogs();
}
};
renderTooltip = (isFiltered, rule, filter, service) =>
isFiltered && ;
renderResponseList = (response, status) => {
if (response.length > 0) {
const listItems = response.map((response, index) => (
{response}
));
return ;
}
return (
query_log_response_status
);
};
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 (
);
}
checkFiltered = reason => reason.indexOf(FILTERED_REASON) === 0;
checkRewrite = reason => reason === FILTERED_STATUS.REWRITE;
checkWhiteList = reason => reason === FILTERED_STATUS.NOT_FILTERED_WHITE_LIST;
getTimeCell = ({ value }) => (
{formatTime(value)}
);
getDomainCell = (row) => {
const response = row.value;
const trackerData = getTrackerData(response);
return (
{response}
{trackerData &&
}
);
};
getResponseCell = ({ value: responses, original }) => {
const {
reason, filterId, rule, status,
} = original;
const { t, filtering } = this.props;
const { filters } = filtering;
const isFiltered = this.checkFiltered(reason);
const filterKey = reason.replace(FILTERED_REASON, '');
const parsedFilteredReason = t('query_log_filtered', { filter: filterKey });
const isRewrite = this.checkRewrite(reason);
const isWhiteList = this.checkWhiteList(reason);
const isBlockedService = reason === FILTERED_STATUS.FILTERED_BLOCKED_SERVICE;
const currentService = SERVICES.find(service => service.id === original.serviceName);
const serviceName = currentService && currentService.name;
let filterName = '';
if (filterId === 0) {
filterName = t('custom_filter_rules');
} else {
const filterItem = Object.keys(filters).filter(key => filters[key].id === filterId)[0];
if (typeof filterItem !== 'undefined' && typeof filters[filterItem] !== 'undefined') {
filterName = filters[filterItem].name;
}
if (!filterName) {
filterName = t('unknown_filter', { filterId });
}
}
return (
{(isFiltered || isBlockedService) && (
{parsedFilteredReason}
)}
{isBlockedService
? this.renderTooltip(isFiltered, '', '', serviceName)
: this.renderTooltip(isFiltered, rule, filterName)}
{isRewrite && (
rewrite_applied
)}
{this.renderResponseList(responses, status)}
{isWhiteList && this.renderTooltip(isWhiteList, rule, filterName)}
);
};
getClientCell = ({ original, value }) => {
const { dashboard } = this.props;
const { clients, autoClients } = dashboard;
const { reason, domain } = original;
const isFiltered = this.checkFiltered(reason);
const isRewrite = this.checkRewrite(reason);
return (
{formatClientCell(value, clients, autoClients)}
{isRewrite ? (
configure
) : (
this.renderBlockingButton(isFiltered, domain)
)}
);
};
renderLogs(logs) {
const { t } = this.props;
const columns = [
{
Header: t('time_table_header'),
accessor: 'time',
maxWidth: 100,
filterable: false,
Cell: this.getTimeCell,
},
{
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,
filterMethod: (filter, row) => {
if (filter.value === RESPONSE_FILTER.FILTERED) {
// eslint-disable-next-line no-underscore-dangle
const { reason } = row._original;
return this.checkFiltered(reason) || this.checkWhiteList(reason);
}
return true;
},
Filter: ({ filter, onChange }) => (
),
},
{
Header: t('client_table_header'),
accessor: 'client',
maxWidth: 240,
minWidth: 240,
Cell: this.getClientCell,
},
];
if (logs) {
return (
{
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 (this.checkFiltered(reason)) {
return {
className: 'red',
};
} else if (this.checkWhiteList(reason)) {
return {
className: 'green',
};
} else if (this.checkRewrite(reason)) {
return {
className: 'blue',
};
}
return {
className: '',
};
}}
/>
);
}
return null;
}
render() {
const { queryLogs, dashboard, t } = this.props;
const { enabled, processingGetLogs, processingGetConfig } = queryLogs;
const { processingClients } = dashboard;
const isDataReady =
!processingGetLogs && !processingGetConfig && !dashboard.processingClients;
const refreshButton = enabled ? (
) : (
''
);
return (
{refreshButton}
{enabled && (processingGetLogs || processingClients || processingGetConfig) && (
)}
{enabled && isDataReady && this.renderLogs(queryLogs.logs)}
{!enabled && !processingGetConfig && (
link]}>
query_log_disabled
)}
);
}
}
Logs.propTypes = {
getLogs: PropTypes.func.isRequired,
queryLogs: PropTypes.object.isRequired,
dashboard: PropTypes.object.isRequired,
getFilteringStatus: PropTypes.func.isRequired,
filtering: PropTypes.object.isRequired,
setRules: PropTypes.func.isRequired,
addSuccessToast: PropTypes.func.isRequired,
getClients: PropTypes.func.isRequired,
getLogsConfig: PropTypes.func.isRequired,
t: PropTypes.func.isRequired,
};
export default withNamespaces()(Logs);