mirror of
https://github.com/pi-hole/web.git
synced 2024-12-06 19:36:21 +01:00
Query Log: Use responsive design for query details
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
+4
-3
@@ -19,9 +19,10 @@
|
||||
"prettier:check": "prettier -l \"style/*.css\" \"style/themes/*.css\" \"scripts/pi-hole/**/*.js\"",
|
||||
"prettier:fix": "prettier --write \"style/*.css\" \"style/themes/*.css\" \"scripts/pi-hole/**/*.js\"",
|
||||
"xo": "xo",
|
||||
"xo:fix": "npm run xo -- --fix",
|
||||
"test": "npm run prettier:check && npm run xo",
|
||||
"testpr": "npm run prettier:fix && git diff --ws-error-highlight=all --color=always --exit-code && npm run xo"
|
||||
"xo:check": "npm run xo -- \"style/*.css\" \"style/themes/*.css\" \"scripts/pi-hole/**\" \"*.php\"",
|
||||
"xo:fix": "npm run xo -- --fix \"style/*.css\" \"style/themes/*.css\" \"scripts/pi-hole/**\" \"*.php\"",
|
||||
"test": "npm run prettier:check && npm run xo:check",
|
||||
"testpr": "npm run prettier:fix && git diff --ws-error-highlight=all --color=always --exit-code && npm run xo:check"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.13",
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
/* global utils:false */
|
||||
var table;
|
||||
var token = $("#token").text();
|
||||
|
||||
function renderTimestamp(data, type) {
|
||||
// Display and search content
|
||||
@@ -19,7 +18,7 @@ function renderTimestamp(data, type) {
|
||||
return data;
|
||||
}
|
||||
|
||||
function htmlPass(data, type) {
|
||||
function htmlPass(data, _type) {
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -199,33 +198,28 @@ function deleteMessage() {
|
||||
|
||||
// Exploit prevention: Return early for non-numeric IDs
|
||||
for (var id in ids) {
|
||||
if (Object.hasOwnProperty.call(ids, id) && typeof ids[id] !== "number") return;
|
||||
delMsg(ids);
|
||||
if (Object.hasOwnProperty.call(ids, id)) {
|
||||
if (typeof ids[id] !== "number") return;
|
||||
delMsg(ids);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function delMsg(id) {
|
||||
|
||||
utils.disableAll();
|
||||
utils.showAlert("info", "", "Deleting message...");
|
||||
|
||||
$.ajax({
|
||||
url: "/api/info/messages/" + id,
|
||||
method: "DELETE"
|
||||
method: "DELETE",
|
||||
})
|
||||
.done(function (response) {
|
||||
utils.enableAll();
|
||||
console.log(response);
|
||||
if (response === undefined) {
|
||||
utils.showAlert("success", "far fa-trash-alt", "Successfully deleted message", "");
|
||||
table.row(id).remove().draw(false).ajax.reload(null, false);
|
||||
} else {
|
||||
utils.showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while deleting message: " + id,
|
||||
response.message
|
||||
);
|
||||
utils.showAlert("error", "", "Error while deleting message: " + id, response.message);
|
||||
}
|
||||
|
||||
// Clear selection after deletion
|
||||
@@ -237,12 +231,7 @@ function delMsg(id) {
|
||||
)
|
||||
.fail(function (jqXHR, exception) {
|
||||
utils.enableAll();
|
||||
utils.showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while deleting message: " + id,
|
||||
jqXHR.responseText
|
||||
);
|
||||
utils.showAlert("error", "", "Error while deleting message: " + id, jqXHR.responseText);
|
||||
console.log(exception); // eslint-disable-line no-console
|
||||
});
|
||||
}
|
||||
|
||||
@@ -16,7 +16,16 @@ var dateformat = "MMMM Do YYYY, HH:mm";
|
||||
|
||||
var table = null;
|
||||
var cursor = null;
|
||||
var filters = ["client_ip", "client_name", "domain", "upstream", "type", "status", "reply", "dnssec"];
|
||||
var filters = [
|
||||
"client_ip",
|
||||
"client_name",
|
||||
"domain",
|
||||
"upstream",
|
||||
"type",
|
||||
"status",
|
||||
"reply",
|
||||
"dnssec",
|
||||
];
|
||||
|
||||
$(function () {
|
||||
$("#querytime").daterangepicker(
|
||||
@@ -33,21 +42,21 @@ $(function () {
|
||||
Today: [moment().startOf("day"), moment().endOf("day")],
|
||||
Yesterday: [
|
||||
moment().subtract(1, "days").startOf("day"),
|
||||
moment().subtract(1, "days").endOf("day")
|
||||
moment().subtract(1, "days").endOf("day"),
|
||||
],
|
||||
"Last 7 Days": [moment().subtract(6, "days"), moment().endOf("day")],
|
||||
"Last 30 Days": [moment().subtract(29, "days"), moment().endOf("day")],
|
||||
"This Month": [moment().startOf("month"), moment().endOf("month")],
|
||||
"Last Month": [
|
||||
moment().subtract(1, "month").startOf("month"),
|
||||
moment().subtract(1, "month").endOf("month")
|
||||
moment().subtract(1, "month").endOf("month"),
|
||||
],
|
||||
"This Year": [moment().startOf("year"), moment().endOf("year")],
|
||||
"All Time": [moment(beginningOfTime), moment(endOfTime)]
|
||||
"All Time": [moment(beginningOfTime), moment(endOfTime)],
|
||||
},
|
||||
opens: "center",
|
||||
showDropdowns: true,
|
||||
autoUpdateInput: true
|
||||
autoUpdateInput: true,
|
||||
},
|
||||
function (startt, endt) {
|
||||
from = moment(startt).utc().valueOf() / 1000;
|
||||
@@ -79,28 +88,28 @@ function parseQueryStatus(data) {
|
||||
switch (data.status) {
|
||||
case "GRAVITY":
|
||||
colorClass = "text-red";
|
||||
icon = "fa-solid fa-hand";
|
||||
icon = "fa-solid fa-ban";
|
||||
fieldtext = "Blocked (gravity)";
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-green"><i class="fas fa-check"></i> Allow</button>';
|
||||
break;
|
||||
case "FORWARDED":
|
||||
colorClass = "text-green";
|
||||
icon = "fa-solid fa-check";
|
||||
icon = "fa-solid fa-upload";
|
||||
fieldtext = "Forwarded to " + data.upstream;
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-red"><i class="fa fa-ban"></i> Deny</button>';
|
||||
break;
|
||||
case "CACHE":
|
||||
colorClass = "text-green";
|
||||
icon = "fa-solid fa-check";
|
||||
icon = "fa-regular fa-database";
|
||||
fieldtext = "Cached";
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-red"><i class="fa fa-ban"></i> Deny</button>';
|
||||
break;
|
||||
case "REGEX":
|
||||
colorClass = "text-red";
|
||||
icon = "fa-solid fa-hand";
|
||||
icon = "fa-solid fa-ban";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(regex)";
|
||||
regexLink = data.regex > 0;
|
||||
buttontext =
|
||||
@@ -108,32 +117,32 @@ function parseQueryStatus(data) {
|
||||
break;
|
||||
case "DENYLIST":
|
||||
colorClass = "text-red";
|
||||
icon = "fa-solid fa-hand";
|
||||
icon = "fa-solid fa-ban";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(exact)";
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-green"><i class="fas fa-check"></i> Allow</button>';
|
||||
break;
|
||||
case "EXTERNAL_BLOCKED_IP":
|
||||
colorClass = "text-red";
|
||||
icon = "fa-solid fa-hand";
|
||||
icon = "fa-solid fa-ban";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(external, IP)";
|
||||
buttontext = "";
|
||||
break;
|
||||
case "EXTERNAL_BLOCKED_NULL":
|
||||
colorClass = "text-red";
|
||||
icon = "fa-solid fa-hand";
|
||||
icon = "fa-solid fa-ban";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(external, NULL)";
|
||||
buttontext = "";
|
||||
break;
|
||||
case "EXTERNAL_BLOCKED_NXRA":
|
||||
colorClass = "text-red";
|
||||
icon = "fa-solid fa-hand";
|
||||
icon = "fa-solid fa-ban";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(external, NXRA)";
|
||||
buttontext = "";
|
||||
break;
|
||||
case "GRAVITY_CNAME":
|
||||
colorClass = "text-red";
|
||||
icon = "fa-solid fa-hand";
|
||||
icon = "fa-solid fa-ban";
|
||||
fieldtext = "Blocked (gravity, CNAME)";
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-green"><i class="fas fa-check"></i> Allow</button>';
|
||||
@@ -141,7 +150,7 @@ function parseQueryStatus(data) {
|
||||
break;
|
||||
case "REGEX_CNAME":
|
||||
colorClass = "text-red";
|
||||
icon = "fa-solid fa-hand";
|
||||
icon = "fa-solid fa-ban";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(regex diened, CNAME)";
|
||||
regexLink = data.regex > 0;
|
||||
buttontext =
|
||||
@@ -150,7 +159,7 @@ function parseQueryStatus(data) {
|
||||
break;
|
||||
case "DENYLIST_CNAME":
|
||||
colorClass = "text-red";
|
||||
icon = "fa-solid fa-hand";
|
||||
icon = "fa-solid fa-ban";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(exact diened, CNAME)";
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-green"><i class="fas fa-check"></i> Allow</button>';
|
||||
@@ -158,19 +167,19 @@ function parseQueryStatus(data) {
|
||||
break;
|
||||
case "RETRIED":
|
||||
colorClass = "text-green";
|
||||
icon = "fa-solid fa-check";
|
||||
icon = "fa-solid fa-redo"; // fa-repeat
|
||||
fieldtext = "Retried";
|
||||
buttontext = "";
|
||||
break;
|
||||
case "RETRIED_DNSSEC":
|
||||
colorClass = "text-green";
|
||||
icon = "fa-solid fa-check";
|
||||
icon = "fa-solid fa-redo"; // fa-repeat
|
||||
fieldtext = "Retried <br class='hidden-lg'>(ignored)";
|
||||
buttontext = "";
|
||||
break;
|
||||
case "IN_PROGRESS":
|
||||
colorClass = "text-green";
|
||||
icon = "fa-solid fa-check";
|
||||
icon = "fa-solid fa-redo";
|
||||
fieldtext = "OK <br class='hidden-lg'>(already forwarded)";
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-red"><i class="fa fa-ban"></i> Deny</button>';
|
||||
@@ -188,7 +197,7 @@ function parseQueryStatus(data) {
|
||||
colorClass: colorClass,
|
||||
icon: icon,
|
||||
isCNAME: isCNAME,
|
||||
regexLink: regexLink
|
||||
regexLink: regexLink,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -209,7 +218,6 @@ function formatInfo(data) {
|
||||
case "ABANDONED":
|
||||
dnssecClass = "text-red";
|
||||
break;
|
||||
case "UNKNOWN":
|
||||
default:
|
||||
// No DNSSEC or UNKNOWN
|
||||
dnssecStatus = "N/A";
|
||||
@@ -218,13 +226,17 @@ function formatInfo(data) {
|
||||
|
||||
// Parse Query Status
|
||||
var queryStatus = parseQueryStatus(data);
|
||||
var divStart = '<div class="col-xl-2 col-lg-4 col-md-6 col-12">';
|
||||
var statusInfo = "";
|
||||
if (queryStatus.colorClass !== false) {
|
||||
statusInfo =
|
||||
'</td></tr><tr class="dataTables-child"><td>Query status:</td><td class="' +
|
||||
divStart +
|
||||
"Query Status: " +
|
||||
'<strong><span class="' +
|
||||
queryStatus.colorClass +
|
||||
'">' +
|
||||
queryStatus.fieldtext;
|
||||
queryStatus.fieldtext +
|
||||
"</span></strong></div>";
|
||||
}
|
||||
|
||||
var regexInfo = "",
|
||||
@@ -236,75 +248,84 @@ function formatInfo(data) {
|
||||
'target="_blank">Regex ID ' +
|
||||
data.regex +
|
||||
"</a>";
|
||||
regexInfo =
|
||||
'</td></tr><tr class="dataTables-child"><td>Query was blocked by:</td><td>' + regexLink;
|
||||
regexInfo = divStart + "Query was blocked by:</td><td>" + regexLink + "</div>";
|
||||
}
|
||||
|
||||
if (queryStatus.isCNAME) {
|
||||
cnameInfo =
|
||||
'</td></tr><tr class="dataTables-child"><td>Query was blocked during CNAME inspection of</td><td>' +
|
||||
data.cname;
|
||||
divStart + "Query was blocked during CNAME inspection of " + data.cname + "</div>";
|
||||
}
|
||||
|
||||
// Show TTL if applicable
|
||||
var ttlInfo = "";
|
||||
if (data.ttl > 0) {
|
||||
ttlInfo =
|
||||
'</td></tr><tr class="dataTables-child"><td>Time-to-live (TTL):</td><td>' +
|
||||
divStart +
|
||||
"Time-to-live (TTL): " +
|
||||
moment.duration(data.ttl, "s").humanize() +
|
||||
" (" +
|
||||
data.ttl +
|
||||
"s)";
|
||||
"s)</div>";
|
||||
}
|
||||
|
||||
// Show client information, show hostname only if available
|
||||
var ipInfo =
|
||||
data.client.name !== null && data.client.length > 0 ? data.client.name + " (" + data.client.ip + ")" : data.client.ip;
|
||||
var clientInfo = '</td></tr><tr class="dataTables-child"><td>Client:</td><td>' + ipInfo;
|
||||
data.client.name !== null && data.client.name.length > 0
|
||||
? utils.escapeHtml(data.client.name) + " (" + data.client.ip + ")"
|
||||
: data.client.ip;
|
||||
var clientInfo = divStart + "Client: <strong>" + ipInfo + "</strong></div>";
|
||||
|
||||
// Show DNSSEC status if applicable
|
||||
var dnssecInfo = "";
|
||||
if (dnssecClass !== false) {
|
||||
dnssecInfo =
|
||||
'</td></tr><tr class="dataTables-child"><td>DNSSEC status:</td><td class="' +
|
||||
divStart +
|
||||
'DNSSEC status:  <strong><span class="' +
|
||||
dnssecClass +
|
||||
'">' +
|
||||
dnssecStatus;
|
||||
dnssecStatus +
|
||||
"</span></strong></div>";
|
||||
}
|
||||
|
||||
// Show long-term database information if applicable
|
||||
var dbInfo = "";
|
||||
if (data.dbid !== false) {
|
||||
dbInfo = '</td></tr><tr class="dataTables-child"><td>Database ID:</td><td>' + data.id;
|
||||
dbInfo = divStart + "Database ID: " + data.id + "</div>";
|
||||
}
|
||||
|
||||
// Always show reply info, add reply delay if applicable
|
||||
var replyInfo = "";
|
||||
if (data.reply.type !== "UNKNOWN") {
|
||||
replyInfo = '</td></tr><tr class="dataTables-child"><td>Reply type:</td><td>' + data.reply.type;
|
||||
replyInfo = divStart + "Reply:  " + data.reply.type;
|
||||
if (data.reply.time >= 0 && data.reply.type !== "UNKNOWN") {
|
||||
replyInfo +=
|
||||
'</td></tr><tr class="dataTables-child"><td>Reply delay:</td><td>' +
|
||||
(data.reply.time < 1.0 ? (1e3*data.reply.time).toFixed(1) + " ms" : (data.reply.time).toFixed(1) + " s");
|
||||
" (" +
|
||||
(data.reply.time < 1
|
||||
? (1e3 * data.reply.time).toFixed(1) + " ms)"
|
||||
: data.reply.time.toFixed(1) + " s)");
|
||||
}
|
||||
|
||||
replyInfo += "</div>";
|
||||
} else {
|
||||
replyInfo = '</td></tr><tr class="dataTables-child"><td>Reply type:</td><td>No reply received';
|
||||
replyInfo = divStart + "Reply: No reply received</div>";
|
||||
}
|
||||
|
||||
// Compile extra info for displaying
|
||||
return (
|
||||
"<table><tbody>" +
|
||||
'<tr class="dataTables-child"><td>Query received on: </td><td>' +
|
||||
moment.unix(data.time).format("Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss.SSS z") +
|
||||
statusInfo +
|
||||
'<div class="row">' +
|
||||
divStart +
|
||||
"Query received on: " +
|
||||
moment.unix(data.time).format("Y-MM-DD HH:mm:ss.SSS z") +
|
||||
"</div>" +
|
||||
clientInfo +
|
||||
dnssecInfo +
|
||||
statusInfo +
|
||||
cnameInfo +
|
||||
regexInfo +
|
||||
ttlInfo +
|
||||
dnssecInfo +
|
||||
replyInfo +
|
||||
dbInfo +
|
||||
"</td></tr></tbody></table>"
|
||||
"</div>"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -370,7 +391,6 @@ function getSuggestions(dict) {
|
||||
$.get(
|
||||
"/api/queries/suggestions",
|
||||
function (data) {
|
||||
console.log(data);
|
||||
for (var key in filters) {
|
||||
if (Object.hasOwnProperty.call(filters, key)) {
|
||||
var f = filters[key];
|
||||
@@ -434,7 +454,7 @@ $(function () {
|
||||
width: "100%",
|
||||
tags: sel < 3, // Only the first three are allowed to freely specify input
|
||||
placeholder: "Select...",
|
||||
allowClear: true
|
||||
allowClear: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -454,7 +474,7 @@ $(function () {
|
||||
var json = jQuery.parseJSON(d);
|
||||
cursor = json.cursor; // Extract cursor from original data
|
||||
return d;
|
||||
}
|
||||
},
|
||||
},
|
||||
serverSide: true,
|
||||
dom:
|
||||
@@ -474,16 +494,16 @@ $(function () {
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
},
|
||||
},
|
||||
{ data: "status", width: "1%" },
|
||||
{ data: "type", width: "5%" },
|
||||
{ data: "domain", width: "50%" },
|
||||
{ data: "client.ip", width: "34%", type: "ip-address", render: $.fn.dataTable.render.text() }
|
||||
{ data: "client.ip", width: "34%", type: "ip-address", render: $.fn.dataTable.render.text() },
|
||||
],
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, -1],
|
||||
[10, 25, 50, 100, "All"]
|
||||
[10, 25, 50, 100, "All"],
|
||||
],
|
||||
stateSave: true,
|
||||
stateSaveCallback: function (settings, data) {
|
||||
@@ -495,8 +515,10 @@ $(function () {
|
||||
rowCallback: function (row, data) {
|
||||
var querystatus = parseQueryStatus(data);
|
||||
|
||||
if(querystatus.icon !== false) {
|
||||
$("td:eq(1)", row).html("<i class='fa " + querystatus.icon + " " + querystatus.colorClass + "'></i>");
|
||||
if (querystatus.icon !== false) {
|
||||
$("td:eq(1)", row).html(
|
||||
"<i class='fa " + querystatus.icon + " " + querystatus.colorClass + "'></i>"
|
||||
);
|
||||
} else if (querystatus.colorClass !== false) {
|
||||
$(row).addClass(querystatus.colorClass);
|
||||
}
|
||||
@@ -514,11 +536,10 @@ $(function () {
|
||||
// Show hostname instead of IP if available
|
||||
if (data.client.name !== null && data.client.name !== "") {
|
||||
$("td:eq(4)", row).text(data.client.name);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
$("td:eq(4)", row).text(data.client.ip);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
$("#all-queries tbody").on("click", "button", function () {
|
||||
|
||||
@@ -366,7 +366,6 @@ function checkMessages() {
|
||||
: false;
|
||||
var url = "/api/info/messages" + (ignoreNonfatal ? "?filter_dnsmasq_warnings=true" : "");
|
||||
$.getJSON(url, function (data) {
|
||||
console.log(data);
|
||||
if (data.messages.length > 0) {
|
||||
var more = '\nAccess "Tools/Pi-hole diganosis" for further details.';
|
||||
var title =
|
||||
|
||||
Reference in New Issue
Block a user