Merge pull request #2084 from pi-hole/devel

Pi-hole web v5.11
This commit is contained in:
Adam Warner
2022-02-12 20:04:15 +00:00
committed by GitHub
38 changed files with 943 additions and 901 deletions
-2
View File
@@ -1,2 +0,0 @@
memory_limit = 256M
max_execution_time = 300
+57 -29
View File
@@ -18,28 +18,9 @@ $FTL_IP = "127.0.0.1";
$data = array();
// Common API functions
if (isset($_GET['status']))
{
$pistatus = pihole_execute('status web');
if(isset($pistatus[0]))
{
$pistatus = $pistatus[0];
}
else
{
$pistatus = null;
}
if ($pistatus === "1")
{
$data = array_merge($data, array("status" => "enabled"));
}
else
{
$data = array_merge($data, array("status" => "disabled"));
}
}
elseif (isset($_GET['enable']) && $auth)
{
if (isset($_GET['status'])) {
$data = array_merge($data, array("status" => piholeStatusAPI()));
} elseif (isset($_GET['enable']) && $auth) {
if(isset($_GET["auth"]))
{
if($_GET["auth"] !== $pwhash)
@@ -160,17 +141,64 @@ elseif (isset($_GET['list']))
return;
}
elseif(isset($_GET['customdns']) && $auth)
{
if (isset($_GET["auth"])) {
if ($_GET["auth"] !== $pwhash) {
die("Not authorized!");
}
} else {
// Skip token validation if explicit auth string is given
check_csrf($_GET['token']);
}
switch ($_GET["action"]) {
case 'get':
$_POST['action'] = 'get';
break;
case 'add':
$_POST['action'] = 'add';
break;
case 'delete':
$_POST['action'] = 'delete';
break;
}
require("scripts/pi-hole/php/customdns.php");
}
elseif(isset($_GET['customcname']) && $auth)
{
if (isset($_GET["auth"])) {
if ($_GET["auth"] !== $pwhash) {
die("Not authorized!");
}
} else {
// Skip token validation if explicit auth string is given
check_csrf($_GET['token']);
}
switch ($_GET["action"]) {
case 'get':
$_POST['action'] = 'get';
break;
case 'add':
$_POST['action'] = 'add';
break;
case 'delete':
$_POST['action'] = 'delete';
break;
}
require("scripts/pi-hole/php/customcname.php");
}
// Other API functions
require("api_FTL.php");
header('Content-type: application/json');
if(isset($_GET["jsonForceObject"]))
{
echo json_encode($data, JSON_FORCE_OBJECT);
}
else
{
echo json_encode($data);
if(isset($_GET["jsonForceObject"])) {
echo json_encode($data, JSON_FORCE_OBJECT);
} else {
echo json_encode($data);
}
?>
+30 -8
View File
@@ -29,26 +29,48 @@ else
$data["version"] = 3;
}
if (isset($_GET['summary']) || isset($_GET['summaryRaw']) || !count($_GET))
{
if (isset($_GET['summary']) || isset($_GET['summaryRaw']) || !count($_GET)) {
require_once("scripts/pi-hole/php/gravity.php");
sendRequestFTL("stats");
$return = getResponseFTL();
$stats = [];
foreach($return as $line)
{
foreach($return as $line) {
$tmp = explode(" ",$line);
if(($tmp[0] === "domains_being_blocked" && !is_numeric($tmp[1])) || $tmp[0] === "status")
$stats[$tmp[0]] = $tmp[1]; // Expect string response
else
$stats[$tmp[0]] = floatval($tmp[1]); // Expect float response
if($tmp[0] === "domains_being_blocked" && !is_numeric($tmp[1])) {
// Expect string response
$stats[$tmp[0]] = $tmp[1];
} elseif ($tmp[0] === "status") {
// Expect string response
$stats[$tmp[0]] = piholeStatusAPI();
} elseif (isset($_GET['summary'])) {
// "summary" expects a formmated string response
if($tmp[0] !== "ads_percentage_today") {
$stats[$tmp[0]] = number_format($tmp[1]);
} else {
$stats[$tmp[0]] = number_format($tmp[1], 1, '.', '');
}
} else {
// Expect float response
$stats[$tmp[0]] = floatval($tmp[1]);
}
}
$stats['gravity_last_updated'] = gravity_last_update(true);
$data = array_merge($data,$stats);
}
if (isset($_GET["getMaxlogage"]) && $auth) {
sendRequestFTL("maxlogage");
// Convert seconds to hours and rounds to one decimal place.
$ret = round(intval(getResponseFTL()[0]) / 3600, 1);
// Return 24h if value is 0, empty, null or non numeric.
$ret = $ret ?: 24;
$data = array_merge($data, array("maxlogage" => $ret));
}
if (isset($_GET['overTimeData10mins']))
{
sendRequestFTL("overTime");
+27 -8
View File
@@ -87,17 +87,36 @@ if (isset($_GET['getAllQueries']) && $auth)
$stmt->bindValue(":from", intval($from), SQLITE3_INTEGER);
$stmt->bindValue(":until", intval($until), SQLITE3_INTEGER);
$results = $stmt->execute();
if(!is_bool($results))
while ($row = $results->fetchArray())
{
// Convert query type ID to name
$query_type = getQueryTypeStr($row[1]);
if (!is_bool($results)) {
// Start the JSON string
echo '{"data":[';
// Insert into array
// array: time type domain client status upstream destination
$allQueries[] = [$row[0], $query_type, utf8_encode(str_replace("~"," ",$row[2])), $row[3], $row[4], utf8_encode($row[5])];
$first = true;
while ($row = $results->fetchArray()) {
// Insert a comma before the next record (except on the first one)
if (!$first) {
echo ",";
} else {
$first = false;
}
// Convert query type ID to name, encode domain, encode destination
$query_type = getQueryTypeStr($row[1]);
$domain = utf8_encode(str_replace("~"," ",$row[2]));
$destination = utf8_encode($row[5]);
// Insert into array and output it in JSON format
// array: time type domain client status upstream destination
echo json_encode([$row[0], $query_type, $domain, $row[3], $row[4], $destination]);
}
// Finish the JSON string
echo ']}';
}
// exit at the end
exit();
}
// only used if getAllQueries==empty
$result = array('data' => $allQueries);
$data = array_merge($data, $result);
}
+1 -1
View File
@@ -67,7 +67,7 @@
<th>Status</th>
<th>Comment</th>
<th>Group assignment</th>
<th>Action</th>
<th>&nbsp;</th>
</tr>
</thead>
</table>
+1 -1
View File
@@ -73,7 +73,7 @@
<th title="Acceptable values are: IP address, subnet (CIDR notation), MAC address (AA:BB:CC:DD:EE:FF format) or host names.">Client</th>
<th>Comment</th>
<th>Group assignment</th>
<th>Action</th>
<th>&nbsp;</th>
</tr>
</thead>
</table>
+1 -1
View File
@@ -126,7 +126,7 @@
<th>Status</th>
<th>Comment</th>
<th>Group assignment</th>
<th>Action</th>
<th>&nbsp;</th>
</tr>
</thead>
</table>
+1 -1
View File
@@ -64,7 +64,7 @@
<th>Name</th>
<th>Status</th>
<th>Description</th>
<th>Action</th>
<th>&nbsp;</th>
</tr>
</thead>
</table>
+8 -20
View File
@@ -1,26 +1,14 @@
<?php /*
* Pi-hole: A black hole for Internet advertisements
<?php
/* Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
$indexpage = true;
require "scripts/pi-hole/php/header.php";
require_once "scripts/pi-hole/php/gravity.php";
function getinterval()
{
global $piholeFTLConf;
if(isset($piholeFTLConf["MAXLOGAGE"]))
{
return round(floatval($piholeFTLConf["MAXLOGAGE"]), 1);
}
else
{
return "24";
}
}
$indexpage = true;
require "scripts/pi-hole/php/header.php";
require_once "scripts/pi-hole/php/gravity.php";
?>
<!-- Sourceing CSS colors from stylesheet to be used in JS code -->
<span class="queries-permitted"></span>
@@ -72,7 +60,7 @@
<!-- small box -->
<div class="small-box bg-red no-user-select" title="<?php echo gravity_last_update(); ?>">
<div class="inner">
<p>Domains on Blocklist</p>
<p>Domains on Adlists</p>
<h3 class="statistic"><span id="domains_being_blocked">---</span></h3>
</div>
<div class="icon">
@@ -87,7 +75,7 @@
<div class="col-md-12">
<div class="box" id="queries-over-time">
<div class="box-header with-border">
<h3 class="box-title">Total queries over last <?php echo getinterval(); ?> hours</h3>
<h3 class="box-title">Total queries over last <span class="maxlogage-interval">24</span> hours</h3>
</div>
<div class="box-body">
<div class="chart">
@@ -112,7 +100,7 @@
<div class="col-md-12">
<div class="box" id="clients">
<div class="box-header with-border">
<h3 class="box-title">Client activity over last <?php echo getinterval(); ?> hours</h3>
<h3 class="box-title">Client activity over last <span class="maxlogage-interval">24</span> hours</h3>
</div>
<div class="box-body">
<div class="chart">
+271 -632
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -24,12 +24,12 @@
"testpr": "npm run prettier:fix && git diff --ws-error-highlight=all --color=always --exit-code && npm run xo"
},
"devDependencies": {
"autoprefixer": "^10.4.1",
"eslint-plugin-compat": "^4.0.0",
"postcss": "^8.4.5",
"autoprefixer": "^10.4.2",
"eslint-plugin-compat": "^4.0.2",
"postcss": "^8.4.6",
"postcss-cli": "^9.1.0",
"prettier": "2.5.1",
"xo": "^0.47.0"
"xo": "^0.48.0"
},
"browserslist": [
"defaults",
+3 -3
View File
@@ -50,9 +50,9 @@ else if(isset($_GET["client"]))
}
else if(isset($_GET["forwarddest"]))
{
if($_GET["forwarddest"] === "blocklist")
$showing .= " queries answered from blocklists";
elseif($_GET["forwarddest"] === "cache")
if($_GET["forwarddest"] === "blocked")
$showing .= " queries blocked by Pi-hole";
elseif($_GET["forwarddest"] === "cached")
$showing .= " queries answered from cache";
else
$showing .= " queries for upstream destination ".htmlentities($_GET["forwarddest"]);
+3 -2
View File
@@ -84,7 +84,8 @@ function handleAjaxError(xhr, textStatus) {
alert(
"An unknown error occurred while loading the data.\n" +
xhr.responseText +
"\nCheck the server's log files (/var/log/lighttpd/error.log when you're using the default Pi-hole web server) for details. You may need to increase the memory available for Pi-hole in case you requested a lot of data."
"\nCheck the server's log files (/var/log/lighttpd/error.log) for details.\n\nYou may need to increase PHP memory limit." +
"\n\nYou can find more info in pi-hole's FAQ:\nhttps://docs.pi-hole.net/main/faq/#error-while-loading-data-from-the-long-term-database"
);
}
@@ -296,7 +297,7 @@ $(function () {
}
$(row).addClass(blocked === true ? "blocked-row" : "allowed-row");
if (localStorage.getItem("colorfulQueryLog_chkbox") === "true") {
if (localStorage && localStorage.getItem("colorfulQueryLog_chkbox") === "true") {
$(row).addClass(blocked === true ? "text-red" : "text-green");
}
+9 -4
View File
@@ -58,7 +58,9 @@ function countDown() {
} else {
ena.text("Enable");
piholeChanged("enabled");
localStorage.removeItem("countDownTarget");
if (localStorage) {
localStorage.removeItem("countDownTarget");
}
}
}
@@ -148,7 +150,7 @@ function initCheckboxRadioStyle() {
}
// Read from local storage, initialize if needed
var chkboxStyle = localStorage.getItem("theme_icheck");
var chkboxStyle = localStorage ? localStorage.getItem("theme_icheck") : null;
if (chkboxStyle === null) {
chkboxStyle = "primary";
}
@@ -172,7 +174,10 @@ function initCheckboxRadioStyle() {
function initCPUtemp() {
function setCPUtemp(unit) {
localStorage.setItem("tempunit", tempunit);
if (localStorage) {
localStorage.setItem("tempunit", tempunit);
}
var temperature = parseFloat($("#rawtemp").text());
var displaytemp = $("#tempdisplay");
if (!isNaN(temperature)) {
@@ -195,7 +200,7 @@ function initCPUtemp() {
}
// Read from local storage, initialize if needed
var tempunit = localStorage.getItem("tempunit");
var tempunit = localStorage ? localStorage.getItem("tempunit") : null;
if (tempunit === null) {
tempunit = "C";
}
+3 -2
View File
@@ -122,7 +122,7 @@ function initTable() {
{ data: "enabled", searchable: false },
{ data: "comment" },
{ data: "groups", searchable: false },
{ data: null, width: "80px", orderable: false },
{ data: null, width: "22px", orderable: false },
],
columnDefs: [
{
@@ -291,7 +291,8 @@ function initTable() {
$("td:eq(5)", row).html(button);
},
dom:
"<'row'<'col-sm-4'l><'col-sm-8'f>>" +
"<'row'<'col-sm-12'f>>" +
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
lengthMenu: [
+3 -2
View File
@@ -95,7 +95,7 @@ function initTable() {
{ data: "ip", type: "ip-address" },
{ data: "comment" },
{ data: "groups", searchable: false },
{ data: "name", width: "80px", orderable: false },
{ data: "name", width: "22px", orderable: false },
],
columnDefs: [
{
@@ -215,7 +215,8 @@ function initTable() {
$("td:eq(3)", row).html(button);
},
dom:
"<'row'<'col-sm-4'l><'col-sm-8'f>>" +
"<'row'<'col-sm-12'f>>" +
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
lengthMenu: [
+3 -2
View File
@@ -74,7 +74,7 @@ function initTable() {
{ data: "enabled", searchable: false },
{ data: "comment" },
{ data: "groups", searchable: false, visible: showtype === "all" },
{ data: null, width: "80px", orderable: false },
{ data: null, width: "22px", orderable: false },
],
columnDefs: [
{
@@ -244,7 +244,8 @@ function initTable() {
}
},
dom:
"<'row'<'col-sm-4'l><'col-sm-8'f>>" +
"<'row'<'col-sm-12'f>>" +
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
lengthMenu: [
+3 -2
View File
@@ -25,7 +25,7 @@ $(function () {
{ data: "name" },
{ data: "enabled", searchable: false },
{ data: "description" },
{ data: null, width: "60px", orderable: false },
{ data: null, width: "22px", orderable: false },
],
columnDefs: [
{
@@ -84,7 +84,8 @@ $(function () {
}
},
dom:
"<'row'<'col-sm-4'l><'col-sm-8'f>>" +
"<'row'<'col-sm-12'f>>" +
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
lengthMenu: [
+80 -27
View File
@@ -319,24 +319,71 @@ function updateQueryTypesPie() {
queryTypePieChart.update();
// Don't use rotation animation for further updates
queryTypePieChart.options.animation.duration = 0;
queryTypePieChart.options.legendCallback = customLegend;
// Generate legend in separate div
$("#query-types-legend").html(queryTypePieChart.generateLegend());
$("#query-types-legend > ul > li").prepend(createEyeConElement());
$("#query-types-legend > ul > li").click(function (e) {
if (isEyeCon(e.target)) {
if (iscolorBox(e.target)) {
return false;
}
window.location.href = "queries.php?querytype=" + querytypeids[$(this).index()];
});
$("#query-types-legend .colorBoxWrapper").click(function (e) {
hidePieSlice(e);
});
}).done(function () {
// Reload graph after minute
setTimeout(updateQueryTypesPie, 60000);
});
}
function customLegend(chart) {
var text = [];
var data = chart.data;
var datasets = data.datasets;
var labels = data.labels;
text.push('<ul class="' + chart.id + '-legend">');
if (datasets.length > 0) {
for (var i = 0; i < datasets[0].data.length; ++i) {
var color = datasets[0].backgroundColor[i];
var txt = "";
// legend box icon
txt =
'<span class="colorBoxWrapper" style="color: ' +
color +
'" title="Toggle visibility">' +
'<i class="fa fa-check-square"></i>' +
"</span>";
// color block
txt += '<span class="legend-color-box" style="background-color:' + color + '"></span>';
// label
if (labels[i]) {
txt +=
'<span class="legend-label-text" title="List ' +
labels[i] +
' queries">' +
labels[i] +
"</span>";
}
text.push("<li>" + txt + "</li>");
}
}
text.push("</ul>");
return text.join("");
}
function hidePieSlice(event) {
toggleEyeCon(event.target);
togglecolorBox(event.target);
var legendID = $(event.target).closest(".chart-legend").attr("id");
var ci =
@@ -360,19 +407,19 @@ function hidePieSlice(event) {
ci.update();
}
function toggleEyeCon(target) {
function togglecolorBox(target) {
var parentListItem = $(target).closest("li");
var eyeCon = $(parentListItem).find(".fa-eye, .fa-eye-slash");
var colorBox = $(parentListItem).find(".fa-check-square, .fa-square");
if (eyeCon) {
$(eyeCon).toggleClass("fa-eye");
$(eyeCon).toggleClass("fa-eye-slash");
if (colorBox) {
$(colorBox).toggleClass("fa-check-square");
$(colorBox).toggleClass("fa-square");
}
}
function isEyeCon(target) {
// See if click happened on eyeConWrapper or child SVG
if ($(target).closest(".eyeConWrapper")[0]) {
function iscolorBox(target) {
// See if click happened on colorBoxWrapper or child SVG
if ($(target).closest(".colorBoxWrapper")[0]) {
return true;
}
@@ -468,16 +515,6 @@ function updateClientsOverTime() {
});
}
function createEyeConElement() {
var eyeConWrapper = $("<span></span>")
.addClass("eyeConWrapper")
.click(function (e) {
hidePieSlice(e);
});
eyeConWrapper.append($("<i class='fa fa-eye'></i>"));
return eyeConWrapper;
}
function updateForwardDestinationsPie() {
$.getJSON("api.php?getForwardDestinations", function (data) {
if ("FTLnotrunning" in data) {
@@ -519,11 +556,12 @@ function updateForwardDestinationsPie() {
forwardDestinationPieChart.update();
// Don't use rotation animation for further updates
forwardDestinationPieChart.options.animation.duration = 0;
forwardDestinationPieChart.options.legendCallback = customLegend;
// Generate legend in separate div
$("#forward-destinations-legend").html(forwardDestinationPieChart.generateLegend());
$("#forward-destinations-legend > ul > li").prepend(createEyeConElement());
$("#forward-destinations-legend > ul > li").click(function (e) {
if (isEyeCon(e.target)) {
if (iscolorBox(e.target)) {
return false;
}
@@ -532,6 +570,9 @@ function updateForwardDestinationsPie() {
window.location.href = "queries.php?forwarddest=" + obj;
}
});
$("#forward-destinations-legend .colorBoxWrapper").click(function (e) {
hidePieSlice(e);
});
}).done(function () {
// Reload graph after one minute
setTimeout(updateForwardDestinationsPie, 60000);
@@ -723,7 +764,7 @@ function updateSummaryData(runOnce) {
}
};
$.getJSON("api.php?summary", function (data) {
$.getJSON("api.php?summaryRaw", function (data) {
updateSessionTimer();
if ("FTLnotrunning" in data) {
@@ -795,7 +836,7 @@ function updateSummaryData(runOnce) {
function doughnutTooltip(tooltipItems, data) {
var dataset = data.datasets[tooltipItems.datasetIndex];
var label = data.labels[tooltipItems.index];
var label = " " + data.labels[tooltipItems.index];
// Compute share of total and of displayed
var scale = 0,
total = 0;
@@ -813,16 +854,28 @@ function doughnutTooltip(tooltipItems, data) {
return label + ": " + dataset.data[tooltipItems.index].toFixed(1) + "%";
return (
label +
":<br>- " +
":<br>&bull; " +
dataset.data[tooltipItems.index].toFixed(1) +
"% of all queries<br>- " +
"% of all queries<br>&bull; " +
((dataset.data[tooltipItems.index] * 100) / (total - scale)).toFixed(1) +
"% of shown items"
);
}
var maxlogage = "24";
function getMaxlogage() {
$.getJSON("api.php?getMaxlogage", function (data) {
if (!("FTLnotrunning" in data)) {
maxlogage = data.maxlogage;
}
}).done(function () {
$(".maxlogage-interval").html(maxlogage);
});
}
$(function () {
// Pull in data via AJAX
getMaxlogage();
updateSummaryData();
var gridColor = $(".graphs-grid").css("background-color");
+2 -1
View File
@@ -174,7 +174,8 @@ $(function () {
$("td:eq(3)", row).html(button);
},
dom:
"<'row'<'col-sm-4'l><'col-sm-8'f>>" +
"<'row'<'col-sm-12'f>>" +
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
lengthMenu: [
+1 -1
View File
@@ -231,7 +231,7 @@ $(function () {
fieldtext += '<input type="hidden" name="id" value="' + parseInt(data[4], 10) + '">';
$(row).addClass(blocked === true ? "blocked-row" : "allowed-row");
if (localStorage.getItem("colorfulQueryLog_chkbox") === "true") {
if (localStorage && localStorage.getItem("colorfulQueryLog_chkbox") === "true") {
$(row).addClass(blocked === true ? "text-red" : "text-green");
}
+35 -9
View File
@@ -213,9 +213,15 @@ function loadCacheInfo() {
var cachelivefreed = parseInt(data.cacheinfo["cache-live-freed"], 10);
$("#cache-live-freed").text(cachelivefreed);
if (cachelivefreed > 0) {
$("#cache-live-freed").parent("tr").addClass("lookatme");
$("#cache-live-freed").parent("tr").children("th").children("span").addClass("lookatme");
$("#cache-live-freed").parent("tr").children("td").addClass("lookatme");
$("#cache-live-freed")
.parent("tr")
.children("td")
.attr("lookatme-text", cachelivefreed.toString());
} else {
$("#cache-live-freed").parent("tr").removeClass("lookatme");
$("#cache-live-freed").parent("tr").children("th").children("span").removeClass("lookatme");
$("#cache-live-freed").parent("tr").children("td").removeClass("lookatme");
}
// Update cache info every 10 seconds
@@ -228,7 +234,8 @@ $(function () {
if (document.getElementById("DHCPLeasesTable")) {
leasetable = $("#DHCPLeasesTable").DataTable({
dom:
"<'row'<'col-sm-4'l><'col-sm-8'f>>" +
"<'row'<'col-sm-12'f>>" +
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
lengthMenu: [
@@ -238,9 +245,23 @@ $(function () {
columnDefs: [
{ bSortable: false, orderable: false, targets: -1 },
{
targets: [0, 1, 2],
targets: [0, 1],
render: $.fn.dataTable.render.text(),
},
{
targets: 2,
render: function (data) {
// Show "unknown", when host is "*"
var str;
if (data === "*") {
str = "<i>unknown</i>";
} else {
str = typeof data === "string" ? utils.escapeHtml(data) : data;
}
return str;
},
},
],
paging: true,
order: [[2, "asc"]],
@@ -258,7 +279,8 @@ $(function () {
if (document.getElementById("DHCPStaticLeasesTable")) {
staticleasetable = $("#DHCPStaticLeasesTable").DataTable({
dom:
"<'row'<'col-sm-4'l><'col-sm-8'f>>" +
"<'row'<'col-sm-12'f>>" +
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
lengthMenu: [
@@ -342,7 +364,7 @@ $(".nav-tabs a").on("shown.bs.tab", function (e) {
// Bar/Smooth chart toggle
$(function () {
var bargraphs = $("#bargraphs");
var chkboxData = localStorage.getItem("barchart_chkbox");
var chkboxData = localStorage ? localStorage.getItem("barchart_chkbox") : null;
if (chkboxData !== null) {
// Restore checkbox state
@@ -350,7 +372,9 @@ $(function () {
} else {
// Initialize checkbox
bargraphs.prop("checked", true);
localStorage.setItem("barchart_chkbox", true);
if (localStorage) {
localStorage.setItem("barchart_chkbox", true);
}
}
bargraphs.click(function () {
@@ -360,7 +384,7 @@ $(function () {
$(function () {
var colorfulQueryLog = $("#colorfulQueryLog");
var chkboxData = localStorage.getItem("colorfulQueryLog_chkbox");
var chkboxData = localStorage ? localStorage.getItem("colorfulQueryLog_chkbox") : null;
if (chkboxData !== null) {
// Restore checkbox state
@@ -368,7 +392,9 @@ $(function () {
} else {
// Initialize checkbox
colorfulQueryLog.prop("checked", false);
localStorage.setItem("colorfulQueryLog_chkbox", false);
if (localStorage) {
localStorage.setItem("colorfulQueryLog_chkbox", false);
}
}
colorfulQueryLog.click(function () {
+15 -3
View File
@@ -229,13 +229,25 @@ function setBsSelectDefaults() {
};
}
var backupStorage = {};
function stateSaveCallback(itemName, data) {
localStorage.setItem(itemName, JSON.stringify(data));
if (localStorage === null) {
backupStorage[itemName] = JSON.stringify(data);
} else {
localStorage.setItem(itemName, JSON.stringify(data));
}
}
function stateLoadCallback(itemName) {
var data;
// Receive previous state from client's local storage area
var data = localStorage.getItem(itemName);
if (localStorage === null) {
var item = backupStorage[itemName];
data = typeof item === "undefined" ? null : item;
} else {
data = localStorage.getItem(itemName);
}
// Return if not available
if (data === null) {
return null;
@@ -259,7 +271,7 @@ function stateLoadCallback(itemName) {
function getGraphType() {
// Only return line if `barchart_chkbox` is explicitly set to false. Else return bar
return localStorage.getItem("barchart_chkbox") === "false" ? "line" : "bar";
return localStorage && localStorage.getItem("barchart_chkbox") === "false" ? "line" : "bar";
}
function addFromQueryLog(domain, list) {
+2 -2
View File
@@ -73,7 +73,7 @@ function check_cors() {
$server_host = str_replace(array("[","]"), array("",""), $server_host);
if(isset($_SERVER['HTTP_HOST']) && !in_array($server_host, $AUTHORIZED_HOSTNAMES)) {
log_and_die("Failed Host Check: " . $server_host .' vs '. join(', ', $AUTHORIZED_HOSTNAMES));
log_and_die("Failed Host Check: " . $server_host .' vs '. htmlspecialchars(join(', ', $AUTHORIZED_HOSTNAMES)));
}
if(isset($_SERVER['HTTP_ORIGIN'])) {
@@ -88,7 +88,7 @@ function check_cors() {
$server_origin = str_replace(array("[","]","http://","https://"), array("","","",""), $server_origin);
if(!in_array($server_origin, $AUTHORIZED_HOSTNAMES)) {
log_and_die("Failed CORS: " . htmlspecialchars($server_origin) .' vs '. join(', ', $AUTHORIZED_HOSTNAMES));
log_and_die("Failed CORS: " . htmlspecialchars($server_origin) .' vs '. htmlspecialchars(join(', ', $AUTHORIZED_HOSTNAMES)));
}
header("Access-Control-Allow-Origin: ${_SERVER['HTTP_ORIGIN']}");
}
+7 -5
View File
@@ -5,11 +5,13 @@
require_once('auth.php');
// Authentication checks
if (isset($_POST['token'])) {
check_cors();
check_csrf($_POST['token']);
} else {
log_and_die('Not allowed (login session invalid or expired, please relogin on the Pi-hole dashboard)!');
if (!isset($api)) {
if (isset($_POST['token'])) {
check_cors();
check_csrf($_POST['token']);
} else {
log_and_die('Not allowed (login session invalid or expired, please relogin on the Pi-hole dashboard)!');
}
}
+7 -5
View File
@@ -5,11 +5,13 @@
require_once('auth.php');
// Authentication checks
if (isset($_POST['token'])) {
check_cors();
check_csrf($_POST['token']);
} else {
log_and_die('Not allowed (login session invalid or expired, please relogin on the Pi-hole dashboard)!');
if (!isset($api)) {
if (isset($_POST['token'])) {
check_cors();
check_csrf($_POST['token']);
} else {
log_and_die('Not allowed (login session invalid or expired, please relogin on the Pi-hole dashboard)!');
}
}
+12 -5
View File
@@ -49,14 +49,16 @@
$coreVersionStr = $core_current . (isset($core_commit) ? " (" . $core_branch . ", " . $core_commit . ")" : "");
$ftlVersionStr = $FTL_current . (isset($FTL_commit) ? " (" . $FTL_branch . ", " . $FTL_commit . ")" : "");
$webVersionStr = $web_current . (isset($web_commit) ? " (" . $web_branch . ", " . $web_commit . ")" : "");
$dockerTag = getenv('PIHOLE_DOCKER_TAG');
$dockerTag = htmlspecialchars(getenv('PIHOLE_DOCKER_TAG'));
$githubBaseUrl = "https://github.com/pi-hole";
$coreUrl = $githubBaseUrl . "/pi-hole";
$dockerUrl = $githubBaseUrl . "/docker-pi-hole";
$ftlUrl = $githubBaseUrl . "/FTL";
$webUrl = $githubBaseUrl . "/AdminLTE";
$coreReleasesUrl = $coreUrl . "/releases";
$dockerReleasesUrl = $dockerUrl . "/releases";
$ftlReleasesUrl = $ftlUrl . "/releases";
$webReleasesUrl = $webUrl . "/releases";
?>
@@ -78,21 +80,26 @@
</ul>
<?php } else { ?>
<ul class="list-inline">
<?php if($dockerTag) { ?> <li><strong>Docker Tag</strong> <?php echo $dockerTag; ?></li> <?php } ?>
<?php if($dockerTag) { ?>
<li>
<strong>Docker Tag</strong>
<a href="<?php echo $dockerReleasesUrl . "/" . $dockerTag; ?>" rel="noopener" target="_blank"><?php echo $dockerTag; ?></a>
</li>
<?php } ?>
<li>
<strong>Pi-hole</strong>
<a href="<?php echo $coreReleasesUrl . "/" . $core_current; ?>" rel="noopener" target="_blank"><?php echo $core_current; ?></a>
<?php if ($core_update) { ?> &middot; <a class="lookatme" href="<?php echo $coreReleasesUrl . "/latest"; ?>" rel="noopener" target="_blank">Update available!</a><?php } ?>
<?php if ($core_update) { ?> &middot; <a class="lookatme" lookatme-text="Update available!" href="<?php echo $coreReleasesUrl . "/latest"; ?>" rel="noopener" target="_blank">Update available!</a><?php } ?>
</li>
<li>
<strong>FTL</strong>
<a href="<?php echo $ftlReleasesUrl . "/" . $FTL_current; ?>" rel="noopener" target="_blank"><?php echo $FTL_current; ?></a>
<?php if ($FTL_update) { ?> &middot; <a class="lookatme" href="<?php echo $ftlReleasesUrl . "/latest"; ?>" rel="noopener" target="_blank">Update available!</a><?php } ?>
<?php if ($FTL_update) { ?> &middot; <a class="lookatme" lookatme-text="Update available!" href="<?php echo $ftlReleasesUrl . "/latest"; ?>" rel="noopener" target="_blank">Update available!</a><?php } ?>
</li>
<li>
<strong>Web Interface</strong>
<a href="<?php echo $webReleasesUrl . "/" . $web_current; ?>" rel="noopener" target="_blank"><?php echo $web_current; ?></a>
<?php if ($web_update) { ?> &middot; <a class="lookatme" href="<?php echo $webReleasesUrl . "/latest"; ?>" rel="noopener" target="_blank">Update available!</a><?php } ?>
<?php if ($web_update) { ?> &middot; <a class="lookatme" lookatme-text="Update available!" href="<?php echo $webReleasesUrl . "/latest"; ?>" rel="noopener" target="_blank">Update available!</a><?php } ?>
</li>
</ul>
<?php if($core_update || $web_update || $FTL_update) { ?>
+27
View File
@@ -483,4 +483,31 @@ function getQueryTypeStr($querytype)
return "TYPE".($qtype - 100);
}
// Returns an integer representing pihole blocking status
function piholeStatus()
{
// Receive the return of "pihole status web"
$pistatus = pihole_execute('status web');
return isset($pistatus[0]) ? intval($pistatus[0]) : -2;
}
// Returns pihole status, using only valid API responses (enabled/disabled)
function piholeStatusAPI()
{
// Receive the return of "pihole status web"
$pistatus = piholeStatus();
switch ($pistatus) {
case -2: // Unkown
case -1: // DNS service not running"
case 0: // Offline
$response = "disabled";
break;
default:
// DNS service running on port $returncode
$response = "enabled";
}
return $response;
}
?>
+3 -3
View File
@@ -47,15 +47,15 @@ function gravity_last_update($raw = false)
if($gravitydiff->d > 1)
{
// String output (more than one day ago)
return $gravitydiff->format("Blocking list updated %a days, %H:%I (hh:mm) ago");
return $gravitydiff->format("Adlists updated %a days, %H:%I (hh:mm) ago");
}
elseif($gravitydiff->d == 1)
{
// String output (one day ago)
return $gravitydiff->format("Blocking list updated one day, %H:%I (hh:mm) ago");
return $gravitydiff->format("Adlists updated one day, %H:%I (hh:mm) ago");
}
// String output (less than one day ago)
return $gravitydiff->format("Blocking list updated %H:%I (hh:mm) ago");
return $gravitydiff->format("Adlists updated %H:%I (hh:mm) ago");
}
?>
+14 -18
View File
@@ -9,6 +9,7 @@
require "scripts/pi-hole/php/auth.php";
require "scripts/pi-hole/php/password.php";
require_once "scripts/pi-hole/php/FTL.php";
require_once "scripts/pi-hole/php/func.php";
require "scripts/pi-hole/php/theme.php";
$scriptname = basename($_SERVER['SCRIPT_FILENAME']);
$hostname = gethostname() ? gethostname() : "";
@@ -66,6 +67,8 @@
// Nothing can be colder than -273.15 degree Celsius (= 0 Kelvin)
// This is the minimum temperature possible (AKA absolute zero)
$celsius = -273.16;
// Set templimit to null if no tempsensor was found
$temperaturelimit = null;
}
// Get load
@@ -331,19 +334,14 @@ if($auth) {
<div class="pull-left info">
<p>Status</p>
<?php
$pistatus = pihole_execute('status web');
if (isset($pistatus[0])) {
$pistatus = intval($pistatus[0]);
} else {
$pistatus = null;
}
$pistatus = piholeStatus();
if ($pistatus == 53) {
echo '<span id="status"><i class="fa fa-w fa-circle text-green-light"></i> Active</span>';
} elseif ($pistatus == 0) {
echo '<span id="status"><i class="fa fa-w fa-circle text-red"></i> Offline</span>';
} elseif ($pistatus == -1) {
echo '<span id="status"><i class="fa fa-w fa-circle text-red"></i> DNS service not running</span>';
} elseif ($pistatus == -2 || is_null($pistatus)) {
} elseif ($pistatus == -2) {
echo '<span id="status"><i class="fa fa-w fa-circle text-red"></i> Unknown</span>';
} else {
echo '<span id="status"><i class="fa fa-w fa-circle text-orange"></i> DNS service on port '.$pistatus.'</span>';
@@ -375,18 +373,16 @@ if($auth) {
?>
<br/>
<?php
$tempcolor = "text-vivid-blue";
if ($celsius > $temperaturelimit) {
$tempcolor = "text-red";
}
echo '<span id="temperature"><i class="fa fa-w fa-fire '.$tempcolor.'" style="width: 1em !important"></i> ';
if ($celsius >= -273.15) {
if ($celsius >= -273.15) {
// Only show temp info if any data is available -->
$tempcolor = "text-vivid-blue";
if (isset($temperaturelimit) && $celsius > $temperaturelimit) {
$tempcolor = "text-red";
}
echo '<span id="temperature"><i class="fa fa-w fa-fire '.$tempcolor.'" style="width: 1em !important"></i> ';
echo 'Temp:&nbsp;<span id="rawtemp" hidden>' .$celsius. '</span>';
} else {
echo "No temp sensor found";
}
echo '<span id="tempdisplay"></span></span>';
echo '<span id="tempdisplay"></span></span>';
}
?>
</div>
</div>
+1 -1
View File
@@ -17,7 +17,7 @@ header('Cache-Control: no-cache');
function echoEvent($datatext) {
if(!isset($_GET["IE"]))
echo "data: ".implode("\ndata: ", explode("\n", $datatext))."\n\n";
echo "data:".implode("\ndata:", explode("\n", $datatext))."\n\n";
else
echo $datatext;
}
+14 -13
View File
@@ -84,11 +84,15 @@ function archive_restore_table($file, $table, $flush=false)
if(is_null($contents))
return 0;
// Flush table if requested, only flush each table once
// Flush table if requested. Only flush each table once, and only if it exists
if($flush && !in_array($table, $flushed_tables))
{
$db->exec("DELETE FROM \"".$table."\"");
array_push($flushed_tables, $table);
$tableExists = $db->querySingle("SELECT name FROM sqlite_master WHERE type='table' AND name='".$table."';");
if ($tableExists)
{
$db->exec("DELETE FROM \"".$table."\"");
array_push($flushed_tables, $table);
}
}
// Prepare fields depending on the table we restore to
@@ -337,18 +341,15 @@ if(isset($_POST["action"]))
$source = $_FILES["zip_file"]["tmp_name"];
$type = mime_content_type($source);
$name = explode(".", $filename);
// verify the file mime type
$accepted_types = array('application/gzip', 'application/tar', 'application/x-compressed', 'application/x-gzip');
$okay = false;
foreach($accepted_types as $mime_type) {
if($mime_type == $type) {
$okay = true;
break;
}
}
$mime_valid = in_array($type, $accepted_types);
$continue = strtolower($name[1]) == 'tar' && strtolower($name[2]) == 'gz' ? true : false;
if(!$continue || !$okay) {
// verify the file extension (Looking for ".tar.gz" at the end of the file name)
$ext = array_slice(explode(".", $filename), -2, 2);
$ext_valid = strtolower($ext[0]) == "tar" && strtolower($ext[1]) == "gz" ? true : false;
if(!$ext_valid || !$mime_valid) {
die("The file you are trying to upload is not a .tar.gz file (filename: ".htmlentities($filename).", type: ".htmlentities($type)."). Please try again.");
}
+10 -7
View File
@@ -19,6 +19,12 @@ if(isset($last_error) && ($last_error["type"] === E_WARNING || $last_error["type
$error .= "There was a problem applying your settings.<br>Debugging information:<br>PHP error (".htmlspecialchars($last_error["type"])."): ".htmlspecialchars($last_error["message"])." in ".htmlspecialchars($last_error["file"]).":".htmlspecialchars($last_error["line"]);
}
# Timezone is set in docker via ENV otherwise get it from commandline
$timezone=htmlspecialchars(getenv("TZ"));
if (empty($timezone)) {
$timezone=shell_exec("date +'%Z'");
}
?>
<style>
.tooltip-inner {
@@ -253,7 +259,7 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "dns", "piho
</tr>
<tr>
<th scope="row">Time FTL started:</th>
<td><?php print_r(get_FTL_data("lstart")); ?></td>
<td><?php print_r(get_FTL_data("lstart")); echo " ".$timezone; ?></td>
</tr>
<tr>
<th scope="row">User / Group:</th>
@@ -287,7 +293,7 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "dns", "piho
</tr>
<tr>
<th scope="row">
<span title="Number of cache entries that had to be removed although they are not expired (increase cache size to reduce this number)">DNS cache evictions:</span>
<span title="Number of cache entries that had to be removed although they are not expired (increase cache size to reduce this number)" lookatme-text="DNS cache evictions:">DNS cache evictions:</span>
</th>
<td id="cache-live-freed">&nbsp;</td>
</tr>
@@ -457,7 +463,7 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "dns", "piho
<div class="row">
<div class="col-md-12">
<div><input type="checkbox" name="active" id="DHCPchk" <?php if ($DHCP){ ?>checked<?php } ?>><label for="DHCPchk"><strong>DHCP server enabled</strong></label></div><br>
<p id="dhcpnotice" <?php if (!$DHCP){ ?>hidden<?php } ?>>Make sure your router's DHCP server is disabled when using the Pi-hole DHCP server!</p>
<p id="dhcpnotice" lookatme-text="Make sure your router's DHCP server is disabled when using the Pi-hole DHCP server!" <?php if (!$DHCP){ ?>hidden<?php } ?>>Make sure your router's DHCP server is disabled when using the Pi-hole DHCP server!</p>
</div>
</div>
<div class="row">
@@ -595,9 +601,6 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "dns", "piho
}
$host = htmlentities($line[3]);
if ($host == "*") {
$host = "<i>unknown</i>";
}
$clid = $line[4];
if ($clid == "*") {
@@ -1263,7 +1266,7 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "dns", "piho
</div>
<p>The privacy level may be increased at any time without having to restart the DNS resolver. However, note that the DNS resolver needs to be restarted when lowering the privacy level. This restarting is automatically done when saving.</p>
<?php if($privacylevel > 0 && $piHoleLogging){ ?>
<p class="lookatme">Warning: Pi-hole's query logging is activated. Although the dashboard will hide the requested details, all queries are still fully logged to the pihole.log file.</p>
<p class="lookatme" lookatme-text="Warning: Pi-hole's query logging is activated. Although the dashboard will hide the requested details, all queries are still fully logged to the pihole.log file.">Warning: Pi-hole's query logging is activated. Although the dashboard will hide the requested details, all queries are still fully logged to the pihole.log file.</p>
<?php } ?>
</div>
</div>
+169 -31
View File
@@ -19,41 +19,66 @@
@-webkit-keyframes Pulse {
from {
color: #630030;
text-shadow: 0 0 2px transparent;
opacity: 0;
}
50% {
color: #e33100;
text-shadow: 0 0 5px #e33100;
opacity: 1;
}
to {
color: #630030;
text-shadow: 0 0 2px transparent;
opacity: 0;
}
}
@keyframes Pulse {
from {
color: #630030;
text-shadow: 0 0 2px transparent;
opacity: 0;
}
50% {
color: #e33100;
text-shadow: 0 0 5px #e33100;
opacity: 1;
}
to {
color: #630030;
text-shadow: 0 0 2px transparent;
opacity: 0;
}
}
p#dhcpnotice[hidden] {
display: none;
}
.lookatme #dhcpnotice {
display: block;
}
td.lookatme {
display: table-cell;
}
.lookatme {
-webkit-animation: 2s infinite Pulse;
animation: 2s infinite Pulse;
color: #630030;
opacity: 1;
position: relative;
display: inline-block;
}
/* this pseudo element will be faded in and out in front /*
/* of the lookatme element to create an efficient animation. */
.lookatme:after {
color: #e33100;
text-shadow: 0 0 5px #e33100;
/* in the html, the lookatme-text attribute must */
/* contain the same text as the .lookatme element */
content: attr(lookatme-text);
padding: inherit;
position: absolute;
inset: 0 0 0 0;
z-index: 1;
/* 20 steps / 2 seconds = 10fps */
-webkit-animation: 2s infinite Pulse steps(20);
animation: 2s infinite Pulse steps(20);
}
.table-responsive {
@@ -215,21 +240,54 @@
.chart-legend ul {
list-style-type: none;
padding-left: 45px;
}
.chart-legend li {
cursor: pointer;
word-break: break-all;
position: relative;
line-height: 1;
margin: 0 0 6px;
}
.chart-legend li span {
display: inline-block;
width: 20px;
height: 12px;
}
.colorBoxWrapper {
font-size: 14px;
}
.colorBoxWrapper:hover {
transform: scale(1.15);
}
.chart-legend li .colorBoxWrapper {
position: absolute;
width: 20px;
left: -20px;
top: 0;
line-height: 1;
}
.chart-legend li .legend-color-box {
display: none;
width: 12px;
margin-right: 5px;
}
.strike {
.chart-legend li .legend-label-text {
line-height: 1;
word-break: break-word;
}
.chart-legend li .legend-label-text:hover {
text-decoration: underline;
}
.strike,
.strike span {
text-decoration: line-through !important;
}
@@ -442,29 +500,113 @@ td.details-control {
right: 12px;
}
/* Fix some datatables layout on small screens */
@media screen and (max-width: 660px), screen and (min-width: 767px) and (max-width: 960px) {
#domainsTable_wrapper .table-responsive {
border: none;
overflow: unset;
}
#domainsTable {
border: 0;
box-sizing: border-box;
}
#domainsTable thead {
display: none;
}
#domainsTable tr {
display: flex;
padding: 15px 0;
flex-wrap: wrap;
box-sizing: border-box;
align-items: end;
border: 1px solid rgba(127, 127, 127, 0.4);
margin: 10px 0;
border-radius: 6px;
}
#domainsTable td {
flex: 1 1 auto;
width: 100px;
display: block;
border: none;
box-sizing: border-box;
order: 2;
text-align: right;
padding: 4px 8px;
}
#domainsTable td:nth-child(2n) {
width: calc(100% - 120px);
}
#domainsTable td:first-child {
width: calc(100% - 40px);
order: 1;
text-align: left;
padding-bottom: 10px;
border-bottom: 1px solid rgba(127, 127, 127, 0.25);
margin-bottom: 5px;
}
#domainsTable td:last-child {
width: 40px;
order: 1;
padding-bottom: 10px;
border-bottom: 1px solid rgba(127, 127, 127, 0.25);
margin-bottom: 5px;
}
#domainsTable td:nth-child(2),
#domainsTable td:nth-child(4) {
text-align: left;
}
#domainsTable td::before {
display: block;
font-weight: bold;
font-size: smaller;
}
#domainsTable td:nth-child(2)::before {
content: "Type:";
}
#domainsTable td:nth-child(4)::before {
content: "Comment:";
}
}
@media screen and (min-width: 767px) {
#domainsTable select.form-control {
padding: 0 0 0 5px;
width: auto;
}
}
@media screen and (max-width: 767px) {
#domainsTable th {
white-space: normal;
}
}
.icon-bounce {
display: inline-block;
position: relative;
animation: icon-bounce 1.5s infinite linear;
animation: icon-bounce 2.4s 3 ease-in-out;
font-size: 1.6em;
}
@keyframes icon-bounce {
0%,
20%,
15%,
50%,
70%,
90%,
100% {
transform: translateY(0);
}
25% {
transform: translateY(-5px);
}
30% {
transform: translateY(4px);
}
35% {
transform: translateY(-3px);
}
40% {
transform: translateY(-15px);
transform: translateY(2px);
}
60% {
transform: translateY(-8px);
}
80% {
transform: translateY(-4px);
45% {
transform: translateY(-1px);
}
}
@@ -472,10 +614,6 @@ td.details-control {
height: 50px;
}
.eyeConWrapper {
font-size: 14px;
}
#apiTokenIframe {
width: 100%;
border: 0;
+23 -15
View File
@@ -211,6 +211,7 @@ h4 {
.main-header .navbar .nav > li > a,
.main-header .navbar .nav > li > .navbar-text {
color: #bec5cb;
max-height: 50px;
}
.main-header .navbar .nav > li > a:hover,
.main-header .navbar .nav > li > a:active,
@@ -263,24 +264,36 @@ h4 {
.nav-tabs-custom .tab-content {
background-color: #30383f;
}
.nav-tabs-custom > .nav-tabs > li.active > a {
border-left-color: #353c42;
border-right-color: #353c42;
background-color: #272c30;
color: #bec5cb;
}
.nav-tabs-custom > .nav-tabs.pull-right > li:first-of-type.active > a {
border-left-color: #353c42;
.nav-tabs-custom > .nav-tabs {
background: rgba(64, 72, 80, 0.666);
}
.nav-tabs-custom > .nav-tabs > li {
margin-right: 1px;
color: #bec5cb;
}
.nav-tabs-custom > .nav-tabs > li.active > a,
.nav-tabs-custom > .nav-tabs > li.active:hover > a {
border-left-color: #30383f;
border-right-color: #30383f;
background-color: #30383f;
color: #bec5cb;
}
.nav-tabs-custom > .nav-tabs > li:not(.active):hover {
border-top-color: #d2d6de;
background-color: transparent;
}
.nav-tabs-custom > .nav-tabs > li > a {
color: #bec5cb;
color: #8e959b;
}
.nav-tabs-custom > .nav-tabs > li > a:focus {
background: #404850;
color: #3c8dbc;
}
.nav-tabs-custom > .nav-tabs > li:hover > a,
.nav-tabs-custom > .nav-tabs > li.active:hover > a {
background-color: #353c42;
color: #bec5cb;
}
.list-group {
color: #bec5cb;
background-color: #272c30;
@@ -452,11 +465,6 @@ div.dataTables_wrapper div.dataTables_length select {
color: #bec5cb;
border: 1px solid #3d444b;
}
.nav-tabs-custom > .nav-tabs > li:hover > a,
.nav-tabs-custom > .nav-tabs > li.active:hover > a {
background-color: #353c42;
color: #bec5cb;
}
.form-control[disabled],
.form-control[readonly],
fieldset[disabled] .form-control {
+7 -6
View File
@@ -3330,16 +3330,18 @@ a:focus {
box-shadow: rgba(0, 0, 0, 0.1) 0 1px 1px;
}
.nav-tabs-custom > .nav-tabs {
background: rgb(30, 40, 44);
border-bottom-color: rgb(51, 55, 57);
}
.nav-tabs-custom > .nav-tabs > li {
border-top-color: transparent;
margin-right: 1px;
}
.nav-tabs-custom > .nav-tabs > li.disabled > a {
color: rgb(157, 148, 136);
}
.nav-tabs-custom > .nav-tabs > li > a {
color: rgb(189, 183, 175);
color: rgb(140, 144, 154);
}
.nav-tabs-custom > .nav-tabs > li > a.text-muted {
color: rgb(168, 160, 149);
@@ -3352,10 +3354,8 @@ a:focus {
.nav-tabs-custom > .nav-tabs > li > a:hover {
color: rgb(168, 160, 149);
}
.nav-tabs-custom > .nav-tabs > li:not(.active) > a:hover,
.nav-tabs-custom > .nav-tabs > li:not(.active) > a:focus,
.nav-tabs-custom > .nav-tabs > li:not(.active) > a:active {
border-color: transparent;
.nav-tabs-custom > .nav-tabs > li:not(.active):hover {
background: rgb(24, 32, 35);
}
.nav-tabs-custom > .nav-tabs > li.active {
border-top-color: rgb(44, 103, 137);
@@ -3392,7 +3392,7 @@ a:focus {
}
.nav-tabs-custom > .nav-tabs > li > a:focus,
.nav-tabs-custom > .nav-tabs > li.active > a:focus {
color: rgb(95, 142, 170);
color: rgb(60, 140, 188);
}
.nav-tabs-custom.tab-primary > .nav-tabs > li.active {
@@ -5456,6 +5456,7 @@ link-muted {
.main-header .navbar .nav > li > a,
.main-header .navbar .nav > li > .navbar-text {
color: rgb(232, 230, 227);
max-height: 50px;
}
.main-header .navbar .nav > li > a:hover,
.main-header .navbar .nav > li > a:active,
+17 -1
View File
@@ -11,6 +11,7 @@
.main-header .navbar .nav > li > a,
.main-header .navbar .nav > li > .navbar-text {
color: #fff;
max-height: 50px;
}
.main-header .navbar .nav > li > a:hover,
.main-header .navbar .nav > li > a:active,
@@ -130,8 +131,23 @@
border-bottom-right-radius: 2px;
border-bottom-left-radius: 0;
}
.nav-tabs-custom > .nav-tabs {
background: #e4e8f0;
}
.nav-tabs-custom > .nav-tabs > li {
margin-right: 1px;
}
.nav-tabs-custom > .nav-tabs > li:not(.active):hover {
background: #fff;
border-top-color: #d2d6de;
}
.nav-tabs-custom > .nav-tabs > li > a,
.nav-tabs-custom > .nav-tabs > li > a:hover {
color: #567;
}
.nav-tabs-custom > .nav-tabs > li > a:focus {
color: #60a4cc;
color: #3c8dbc;
}
.layout-top-nav .main-header > .logo {
+69 -24
View File
@@ -312,6 +312,13 @@ label {
font-weight: bold !important;
}
div .panel-title,
p.login-box-msg,
.form-group.has-error label {
position: relative;
z-index: 1;
}
.form-control::placeholder {
color: #456;
}
@@ -329,24 +336,34 @@ label {
.form-group.has-error.login-box-msg::before {
content: "ACCESS DENIED";
display: block;
margin: -20px -20px 20px;
padding: calc(45px + 0.7em) 0 0;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 130px;
color: #d43;
inset: 0 0 0 0;
color: #630030;
font-size: 3.825em;
font-size: calc((100vw - var(--sidebar-width) - 60px) / 12);
line-height: 1;
animation: 3s infinite Pulse;
background: rgba(0, 0, 0, 0.88);
z-index: 0;
}
.layout-boxed .form-group.has-error.login-box-msg::before {
.form-group.has-error.login-box-msg::after {
content: "ACCESS DENIED";
margin: -20px -20px 20px;
padding: calc(45px + 0.7em) 0 0;
position: absolute;
inset: 0 0 0 0;
color: #e33100;
font-size: 3.825em;
font-size: calc((100vw - var(--sidebar-width) - 60px) / 12);
line-height: 1;
text-shadow: 0 0 5px #e33100;
animation: 3s infinite Pulse steps(30);
z-index: 1;
}
.layout-boxed .form-group.has-error.login-box-msg::before,
.layout-boxed .form-group.has-error.login-box-msg::after {
padding: calc(50% - 0.5em) 0 0;
}
@@ -1460,37 +1477,54 @@ table.dataTable {
@-webkit-keyframes warningPulse {
0% {
border-color: rgba(255, 153, 0, 0.4);
opacity: 0;
}
50% {
border-color: rgba(255, 150, 0, 1);
opacity: 1;
}
100% {
border-color: rgba(255, 153, 0, 0.4);
opacity: 0;
}
}
@keyframes warningPulse {
0% {
border-color: rgba(255, 153, 0, 0.4);
opacity: 0;
}
50% {
border-color: rgba(255, 150, 0, 1);
opacity: 1;
}
100% {
border-color: rgba(255, 153, 0, 0.4);
opacity: 0;
}
}
.box-warning {
animation: 3s infinite warningPulse;
.box.box-warning {
border-top-color: #71480a;
position: relative;
}
.box.box-warning:after {
content: "";
border-top: 3px solid #f89201;
border-radius: 12px;
position: absolute;
margin-top: -3px;
inset: 0 0 0 0;
z-index: -1;
animation: 3s infinite warningPulse steps(30);
}
.box.box-warning div {
z-index: 2;
}
/*** MEDIA QUERIES ***/
/*--- Media - max-width ---*/
@media (max-width: 991px) {
.form-group.has-error.login-box-msg::before {
.form-group.has-error.login-box-msg::before,
.form-group.has-error.login-box-msg::after {
font-size: calc((100vw - var(--sidebar-width) - 60px) / 9);
}
}
@@ -1581,7 +1615,8 @@ table.dataTable {
.main-footer {
margin-left: 0;
}
.form-group.has-error.login-box-msg::before {
.form-group.has-error.login-box-msg::before,
.form-group.has-error.login-box-msg::after {
font-size: calc((100vw - 60px) / 6);
}
}
@@ -1652,24 +1687,34 @@ table.dataTable {
}
@media (min-width: 1320px) {
.layout-boxed .form-group.has-error.login-box-msg::before {
.layout-boxed .form-group.has-error.login-box-msg::before,
.layout-boxed .form-group.has-error.login-box-msg::after {
font-size: calc((1320px - var(--sidebar-width) - 60px) / 12);
}
}
@media (min-width: 1920px) {
.layout-boxed .form-group.has-error.login-box-msg::before {
@media (min-width: 1960px) {
.layout-boxed .form-group.has-error.login-box-msg::before,
.layout-boxed .form-group.has-error.login-box-msg::after {
font-size: calc((1920px - var(--sidebar-width) - 60px) / 12);
}
}
@media (min-width: 1960px) {
.layout-boxed .wrapper {
box-shadow: none;
max-width: 1920px;
}
}
/*** Fix some datatables layout on small screens ***/
@media screen and (max-width: 660px), screen and (min-width: 767px) and (max-width: 960px) {
#domainsTable td::before {
margin: 0 5px 2px;
}
#domainsTable td:nth-child(2n) {
width: calc(100% - 160px);
}
}
/*** Used by the long-term pages ***/
.daterangepicker {
background-color: #345;