diff --git a/client/src/__locales/en.json b/client/src/__locales/en.json
index 4e834147..9ff11424 100644
--- a/client/src/__locales/en.json
+++ b/client/src/__locales/en.json
@@ -299,10 +299,11 @@
"client_edit": "Edit Client",
"client_identifier": "Identifier",
"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 server0>",
+ "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 server0>",
"form_enter_ip": "Enter IP",
"form_enter_mac": "Enter MAC",
"form_enter_id": "Enter identifier",
+ "form_add_id": "Add identifier",
"form_client_name": "Enter client name",
"client_global_settings": "Use global settings",
"client_deleted": "Client \"{{key}}\" successfully deleted",
diff --git a/client/src/actions/queryLogs.js b/client/src/actions/queryLogs.js
index 35b4f7af..155f0a76 100644
--- a/client/src/actions/queryLogs.js
+++ b/client/src/actions/queryLogs.js
@@ -2,7 +2,7 @@ import { createAction } from 'redux-actions';
import apiClient from '../api/Api';
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';
const getLogsWithParams = async (config) => {
@@ -10,9 +10,12 @@ const getLogsWithParams = async (config) => {
const rawLogs = await apiClient.getQueryLog({ ...filter, older_than });
const { data, oldest } = rawLogs;
const logs = normalizeLogs(data);
+ const clientsParams = getParamsForClientsSearch(logs, 'client');
+ const clients = await apiClient.findClients(clientsParams);
+ const logsWithClientInfo = addClientInfo(logs, clients, 'client');
return {
- logs, oldest, older_than, filter, ...values,
+ logs: logsWithClientInfo, oldest, older_than, filter, ...values,
};
};
diff --git a/client/src/actions/stats.js b/client/src/actions/stats.js
index d8ab5bf5..25897aab 100644
--- a/client/src/actions/stats.js
+++ b/client/src/actions/stats.js
@@ -2,7 +2,7 @@ import { createAction } from 'redux-actions';
import apiClient from '../api/Api';
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 getStatsConfigFailure = createAction('GET_STATS_CONFIG_FAILURE');
@@ -43,11 +43,15 @@ export const getStats = () => async (dispatch) => {
dispatch(getStatsRequest());
try {
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 = {
...stats,
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),
avg_processing_time: secondsToMilliseconds(stats.avg_processing_time),
};
diff --git a/client/src/components/Dashboard/Clients.js b/client/src/components/Dashboard/Clients.js
index ace7ed21..e83addcb 100644
--- a/client/src/components/Dashboard/Clients.js
+++ b/client/src/components/Dashboard/Clients.js
@@ -28,19 +28,17 @@ const countCell = dnsQueries =>
return | ;
};
-const clientCell = (clients, autoClients, t) =>
+const clientCell = t =>
function cell(row) {
- const { value } = row;
-
return (
- {formatClientCell(value, clients, autoClients, t)}
+ {formatClientCell(row, t)}
);
};
const Clients = ({
- t, refreshButton, topClients, subtitle, clients, autoClients, dnsQueries,
+ t, refreshButton, topClients, subtitle, dnsQueries,
}) => (
({
+ data={topClients.map(({ name: ip, count, info }) => ({
ip,
count,
+ info,
}))}
columns={[
{
@@ -59,7 +58,7 @@ const Clients = ({
accessor: 'ip',
sortMethod: (a, b) =>
parseInt(a.replace(/\./g, ''), 10) - parseInt(b.replace(/\./g, ''), 10),
- Cell: clientCell(clients, autoClients, t),
+ Cell: clientCell(t),
},
{
Header: requests_count,
diff --git a/client/src/components/Dashboard/index.js b/client/src/components/Dashboard/index.js
index 1960a793..b4889db6 100644
--- a/client/src/components/Dashboard/index.js
+++ b/client/src/components/Dashboard/index.js
@@ -20,7 +20,6 @@ class Dashboard extends Component {
getAllStats = () => {
this.props.getStats();
this.props.getStatsConfig();
- this.props.getClients();
};
getToggleFilteringButton = () => {
@@ -44,7 +43,6 @@ class Dashboard extends Component {
const { dashboard, stats, t } = this.props;
const dashboardProcessing =
dashboard.processing ||
- dashboard.processingClients ||
stats.processingStats ||
stats.processingGetConfig;
diff --git a/client/src/components/Logs/index.js b/client/src/components/Logs/index.js
index 68b9cc61..3b52f4e4 100644
--- a/client/src/components/Logs/index.js
+++ b/client/src/components/Logs/index.js
@@ -31,7 +31,6 @@ class Logs extends Component {
this.props.setLogsPage(TABLE_FIRST_PAGE);
this.getLogs(...INITIAL_REQUEST_DATA);
this.props.getFilteringStatus();
- this.props.getClients();
this.props.getLogsConfig();
}
@@ -191,9 +190,9 @@ class Logs extends Component {
);
};
- getClientCell = ({ original, value }) => {
- const { dashboard, t } = this.props;
- const { clients, autoClients } = dashboard;
+ getClientCell = (row) => {
+ const { original } = row;
+ const { t } = this.props;
const { reason, domain } = original;
const isFiltered = this.checkFiltered(reason);
const isRewrite = this.checkRewrite(reason);
@@ -201,7 +200,7 @@ class Logs extends Component {
return (
- {formatClientCell(value, clients, autoClients, t)}
+ {formatClientCell(row, t)}
{isRewrite ? (
@@ -232,12 +231,11 @@ class Logs extends Component {
};
renderLogs() {
- const { queryLogs, dashboard, t } = this.props;
- const { processingClients } = dashboard;
+ const { queryLogs, t } = this.props;
const {
processingGetLogs, processingGetConfig, logs, pages, page,
} = queryLogs;
- const isLoading = processingGetLogs || processingClients || processingGetConfig;
+ const isLoading = processingGetLogs || processingGetConfig;
const columns = [
{
diff --git a/client/src/helpers/formatClientCell.js b/client/src/helpers/formatClientCell.js
index 30e9e99b..c5626061 100644
--- a/client/src/helpers/formatClientCell.js
+++ b/client/src/helpers/formatClientCell.js
@@ -1,5 +1,5 @@
import React, { Fragment } from 'react';
-import { getClientInfo, getAutoClientInfo, normalizeWhois } from './helpers';
+import { normalizeWhois } from './helpers';
import { WHOIS_ICONS } from './constants';
const getFormattedWhois = (whois, t) => {
@@ -22,26 +22,29 @@ const getFormattedWhois = (whois, t) => {
);
};
-export const formatClientCell = (value, clients, autoClients, t) => {
- const clientInfo = getClientInfo(clients, value) || getAutoClientInfo(autoClients, value);
- const { name, whois } = clientInfo;
+export const formatClientCell = (row, t) => {
+ const { value, original: { info } } = row;
let whoisContainer = '';
let nameContainer = value;
- if (name) {
- nameContainer = (
-
- {name} ({value})
-
- );
- }
+ if (info) {
+ const { name, whois } = info;
- if (whois) {
- whoisContainer = (
-
- {getFormattedWhois(whois, t)}
-
- );
+ if (name) {
+ nameContainer = (
+
+ {name} ({value})
+
+ );
+ }
+
+ if (whois) {
+ whoisContainer = (
+
+ {getFormattedWhois(whois, t)}
+
+ );
+ }
}
return (
diff --git a/client/src/helpers/helpers.js b/client/src/helpers/helpers.js
index 82389111..089f0604 100644
--- a/client/src/helpers/helpers.js
+++ b/client/src/helpers/helpers.js
@@ -8,6 +8,7 @@ import subDays from 'date-fns/sub_days';
import round from 'lodash/round';
import axios from 'axios';
import i18n from 'i18next';
+import uniqBy from 'lodash/uniqBy';
import versionCompare from './versionCompare';
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) => {
const {
enabled, filters, user_rules: userRules, interval,
@@ -342,3 +354,13 @@ export const getPathWithQueryString = (path, params) => {
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;
+ }, {});
+};