+ client: handle clients find

This commit is contained in:
Ildar Kamalov 2019-11-28 17:59:55 +03:00
parent a6d6e9ec9e
commit f8202a74bd
8 changed files with 67 additions and 39 deletions

View File

@ -299,10 +299,11 @@
"client_edit": "Edit Client", "client_edit": "Edit Client",
"client_identifier": "Identifier", "client_identifier": "Identifier",
"ip_address": "IP address", "ip_address": "IP address",
"client_identifier_desc": "Clients can be identified by the IP address, MAC address, CIDR. Please note, that using MAC as identifier is possible only if AdGuard Home is also a <0>DHCP server</0>", "client_identifier_desc": "Clients can be identified by the IP address, CIDR, MAC address. Please note, that using MAC as identifier is possible only if AdGuard Home is also a <0>DHCP server</0>",
"form_enter_ip": "Enter IP", "form_enter_ip": "Enter IP",
"form_enter_mac": "Enter MAC", "form_enter_mac": "Enter MAC",
"form_enter_id": "Enter identifier", "form_enter_id": "Enter identifier",
"form_add_id": "Add identifier",
"form_client_name": "Enter client name", "form_client_name": "Enter client name",
"client_global_settings": "Use global settings", "client_global_settings": "Use global settings",
"client_deleted": "Client \"{{key}}\" successfully deleted", "client_deleted": "Client \"{{key}}\" successfully deleted",

View File

@ -2,7 +2,7 @@ import { createAction } from 'redux-actions';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
import { addErrorToast, addSuccessToast } from './index'; import { addErrorToast, addSuccessToast } from './index';
import { normalizeLogs } from '../helpers/helpers'; import { normalizeLogs, getParamsForClientsSearch, addClientInfo } from '../helpers/helpers';
import { TABLE_DEFAULT_PAGE_SIZE } from '../helpers/constants'; import { TABLE_DEFAULT_PAGE_SIZE } from '../helpers/constants';
const getLogsWithParams = async (config) => { const getLogsWithParams = async (config) => {
@ -10,9 +10,12 @@ const getLogsWithParams = async (config) => {
const rawLogs = await apiClient.getQueryLog({ ...filter, older_than }); const rawLogs = await apiClient.getQueryLog({ ...filter, older_than });
const { data, oldest } = rawLogs; const { data, oldest } = rawLogs;
const logs = normalizeLogs(data); const logs = normalizeLogs(data);
const clientsParams = getParamsForClientsSearch(logs, 'client');
const clients = await apiClient.findClients(clientsParams);
const logsWithClientInfo = addClientInfo(logs, clients, 'client');
return { return {
logs, oldest, older_than, filter, ...values, logs: logsWithClientInfo, oldest, older_than, filter, ...values,
}; };
}; };

View File

@ -2,7 +2,7 @@ import { createAction } from 'redux-actions';
import apiClient from '../api/Api'; import apiClient from '../api/Api';
import { addErrorToast, addSuccessToast } from './index'; import { addErrorToast, addSuccessToast } from './index';
import { normalizeTopStats, secondsToMilliseconds } from '../helpers/helpers'; import { normalizeTopStats, secondsToMilliseconds, getParamsForClientsSearch, addClientInfo } from '../helpers/helpers';
export const getStatsConfigRequest = createAction('GET_STATS_CONFIG_REQUEST'); export const getStatsConfigRequest = createAction('GET_STATS_CONFIG_REQUEST');
export const getStatsConfigFailure = createAction('GET_STATS_CONFIG_FAILURE'); export const getStatsConfigFailure = createAction('GET_STATS_CONFIG_FAILURE');
@ -43,11 +43,15 @@ export const getStats = () => async (dispatch) => {
dispatch(getStatsRequest()); dispatch(getStatsRequest());
try { try {
const stats = await apiClient.getStats(); const stats = await apiClient.getStats();
const normalizedTopClients = normalizeTopStats(stats.top_clients);
const clientsParams = getParamsForClientsSearch(normalizedTopClients, 'name');
const clients = await apiClient.findClients(clientsParams);
const topClientsWithInfo = addClientInfo(normalizedTopClients, clients, 'name');
const normalizedStats = { const normalizedStats = {
...stats, ...stats,
top_blocked_domains: normalizeTopStats(stats.top_blocked_domains), top_blocked_domains: normalizeTopStats(stats.top_blocked_domains),
top_clients: normalizeTopStats(stats.top_clients), top_clients: topClientsWithInfo,
top_queried_domains: normalizeTopStats(stats.top_queried_domains), top_queried_domains: normalizeTopStats(stats.top_queried_domains),
avg_processing_time: secondsToMilliseconds(stats.avg_processing_time), avg_processing_time: secondsToMilliseconds(stats.avg_processing_time),
}; };

View File

@ -28,19 +28,17 @@ const countCell = dnsQueries =>
return <Cell value={value} percent={percent} color={percentColor} />; return <Cell value={value} percent={percent} color={percentColor} />;
}; };
const clientCell = (clients, autoClients, t) => const clientCell = t =>
function cell(row) { function cell(row) {
const { value } = row;
return ( return (
<div className="logs__row logs__row--overflow logs__row--column"> <div className="logs__row logs__row--overflow logs__row--column">
{formatClientCell(value, clients, autoClients, t)} {formatClientCell(row, t)}
</div> </div>
); );
}; };
const Clients = ({ const Clients = ({
t, refreshButton, topClients, subtitle, clients, autoClients, dnsQueries, t, refreshButton, topClients, subtitle, dnsQueries,
}) => ( }) => (
<Card <Card
title={t('top_clients')} title={t('top_clients')}
@ -49,9 +47,10 @@ const Clients = ({
refresh={refreshButton} refresh={refreshButton}
> >
<ReactTable <ReactTable
data={topClients.map(({ name: ip, count }) => ({ data={topClients.map(({ name: ip, count, info }) => ({
ip, ip,
count, count,
info,
}))} }))}
columns={[ columns={[
{ {
@ -59,7 +58,7 @@ const Clients = ({
accessor: 'ip', accessor: 'ip',
sortMethod: (a, b) => sortMethod: (a, b) =>
parseInt(a.replace(/\./g, ''), 10) - parseInt(b.replace(/\./g, ''), 10), parseInt(a.replace(/\./g, ''), 10) - parseInt(b.replace(/\./g, ''), 10),
Cell: clientCell(clients, autoClients, t), Cell: clientCell(t),
}, },
{ {
Header: <Trans>requests_count</Trans>, Header: <Trans>requests_count</Trans>,

View File

@ -20,7 +20,6 @@ class Dashboard extends Component {
getAllStats = () => { getAllStats = () => {
this.props.getStats(); this.props.getStats();
this.props.getStatsConfig(); this.props.getStatsConfig();
this.props.getClients();
}; };
getToggleFilteringButton = () => { getToggleFilteringButton = () => {
@ -44,7 +43,6 @@ class Dashboard extends Component {
const { dashboard, stats, t } = this.props; const { dashboard, stats, t } = this.props;
const dashboardProcessing = const dashboardProcessing =
dashboard.processing || dashboard.processing ||
dashboard.processingClients ||
stats.processingStats || stats.processingStats ||
stats.processingGetConfig; stats.processingGetConfig;

View File

@ -31,7 +31,6 @@ class Logs extends Component {
this.props.setLogsPage(TABLE_FIRST_PAGE); this.props.setLogsPage(TABLE_FIRST_PAGE);
this.getLogs(...INITIAL_REQUEST_DATA); this.getLogs(...INITIAL_REQUEST_DATA);
this.props.getFilteringStatus(); this.props.getFilteringStatus();
this.props.getClients();
this.props.getLogsConfig(); this.props.getLogsConfig();
} }
@ -191,9 +190,9 @@ class Logs extends Component {
); );
}; };
getClientCell = ({ original, value }) => { getClientCell = (row) => {
const { dashboard, t } = this.props; const { original } = row;
const { clients, autoClients } = dashboard; const { t } = this.props;
const { reason, domain } = original; const { reason, domain } = original;
const isFiltered = this.checkFiltered(reason); const isFiltered = this.checkFiltered(reason);
const isRewrite = this.checkRewrite(reason); const isRewrite = this.checkRewrite(reason);
@ -201,7 +200,7 @@ class Logs extends Component {
return ( return (
<Fragment> <Fragment>
<div className="logs__row logs__row--overflow logs__row--column"> <div className="logs__row logs__row--overflow logs__row--column">
{formatClientCell(value, clients, autoClients, t)} {formatClientCell(row, t)}
</div> </div>
{isRewrite ? ( {isRewrite ? (
<div className="logs__action"> <div className="logs__action">
@ -232,12 +231,11 @@ class Logs extends Component {
}; };
renderLogs() { renderLogs() {
const { queryLogs, dashboard, t } = this.props; const { queryLogs, t } = this.props;
const { processingClients } = dashboard;
const { const {
processingGetLogs, processingGetConfig, logs, pages, page, processingGetLogs, processingGetConfig, logs, pages, page,
} = queryLogs; } = queryLogs;
const isLoading = processingGetLogs || processingClients || processingGetConfig; const isLoading = processingGetLogs || processingGetConfig;
const columns = [ const columns = [
{ {

View File

@ -1,5 +1,5 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import { getClientInfo, getAutoClientInfo, normalizeWhois } from './helpers'; import { normalizeWhois } from './helpers';
import { WHOIS_ICONS } from './constants'; import { WHOIS_ICONS } from './constants';
const getFormattedWhois = (whois, t) => { const getFormattedWhois = (whois, t) => {
@ -22,26 +22,29 @@ const getFormattedWhois = (whois, t) => {
); );
}; };
export const formatClientCell = (value, clients, autoClients, t) => { export const formatClientCell = (row, t) => {
const clientInfo = getClientInfo(clients, value) || getAutoClientInfo(autoClients, value); const { value, original: { info } } = row;
const { name, whois } = clientInfo;
let whoisContainer = ''; let whoisContainer = '';
let nameContainer = value; let nameContainer = value;
if (name) { if (info) {
nameContainer = ( const { name, whois } = info;
<span className="logs__text logs__text--wrap" title={`${name} (${value})`}>
{name} <small>({value})</small>
</span>
);
}
if (whois) { if (name) {
whoisContainer = ( nameContainer = (
<div className="logs__text logs__text--wrap logs__text--whois"> <span className="logs__text logs__text--wrap" title={`${name} (${value})`}>
{getFormattedWhois(whois, t)} {name} <small>({value})</small>
</div> </span>
); );
}
if (whois) {
whoisContainer = (
<div className="logs__text logs__text--wrap logs__text--whois">
{getFormattedWhois(whois, t)}
</div>
);
}
} }
return ( return (

View File

@ -8,6 +8,7 @@ import subDays from 'date-fns/sub_days';
import round from 'lodash/round'; import round from 'lodash/round';
import axios from 'axios'; import axios from 'axios';
import i18n from 'i18next'; import i18n from 'i18next';
import uniqBy from 'lodash/uniqBy';
import versionCompare from './versionCompare'; import versionCompare from './versionCompare';
import { import {
@ -92,6 +93,17 @@ export const normalizeTopStats = stats => (
})) }))
); );
export const addClientInfo = (data, clients, param) => (
data.map((row) => {
const clientIp = row[param];
const info = clients.find(item => item[clientIp]) || '';
return {
...row,
info: (info && info[clientIp]) || '',
};
})
);
export const normalizeFilteringStatus = (filteringStatus) => { export const normalizeFilteringStatus = (filteringStatus) => {
const { const {
enabled, filters, user_rules: userRules, interval, enabled, filters, user_rules: userRules, interval,
@ -342,3 +354,13 @@ export const getPathWithQueryString = (path, params) => {
return `${path}?${searchParams.toString()}`; return `${path}?${searchParams.toString()}`;
}; };
export const getParamsForClientsSearch = (data, param) => {
const uniqueClients = uniqBy(data, param);
return uniqueClients
.reduce((acc, item, idx) => {
const key = `ip${idx}`;
acc[key] = item[param];
return acc;
}, {});
};