Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New layout for "All Settings" page #3042

Merged
merged 17 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 110 additions & 102 deletions scripts/pi-hole/js/settings-advanced.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,42 +24,24 @@ function addAllowedValues(allowed) {
}
}

function generateRow(topic, key, value) {
// If the value is an object, we need to recurse
if (!("description" in value)) {
Object.keys(value).forEach(function (subkey) {
var subvalue = value[subkey];
generateRow(topic, key + "." + subkey, subvalue);
});
return;
}

// else: we have a setting we can display
var box =
'<div class="box">' +
'<div class="box-header">' +
'<h3 class="box-title" data-key="' +
key +
'" data-modified="' +
(value.modified ? "true" : "false") +
'">' +
key +
function boxIcons(value) {
return (
'<span class="box-icons">' +
(value.modified
? '&nbsp;&nbsp;<i class="far fa-edit text-light-blue" title="Modified from default"></i>'
? '<i class="far fa-edit text-light-blue" title="Modified from default"></i>'
: "") +
(value.flags.restart_dnsmasq
? '&nbsp;&nbsp;<i class="fas fa-redo text-orange" title="Setting requires FTL restart on change"></i>'
? '<i class="fas fa-redo text-orange" title="Setting requires FTL restart on change"></i>'
: "") +
(value.flags.env_var
? '&nbsp;&nbsp;<i class="fas fa-lock text-orange" title="Settings overwritten by an environmental variable are read-only"></i>'
? '<i class="fas fa-lock text-orange" title="Settings overwritten by an environmental variable are read-only"></i>'
: "") +
"</h3>" +
"<p>" +
utils.escapeHtml(value.description).replaceAll("\n", "<br>") +
"</p>" +
"</div>" +
'<div class="box-body">' +
'<div class="form-group">';
"</span>"
);
}

function valueDetails(key, value) {
// Define default hint text
let defaultValueHint = "";
if (value.modified) {
defaultValueHint = "";
Expand Down Expand Up @@ -91,18 +73,21 @@ function generateRow(topic, key, value) {
}
}

// Define extraAttributes, if needed
let extraAttributes = "";
if (value.flags.env_var) {
extraAttributes = " disabled";
}

// Format the output depending on the value type
let content = "";
switch (value.type) {
case "IPv4 address":
case "IPv6 address":
case "string": {
box +=
'<label class="col-sm-4 control-label">Value (string)</label>' +
'<div class="col-sm-8">' +
content +=
'<label class="col-sm-2 control-label">Value <small>(string)</small></label>' +
'<div class="col-sm-10">' +
'<input type="text" class="form-control" value="' +
value.value +
'" data-key="' +
Expand All @@ -118,7 +103,8 @@ function generateRow(topic, key, value) {
}

case "boolean": {
box +=
content +=
'<div class="col-sm-12">' +
'<div><input type="checkbox" ' +
(value.value ? " checked" : "") +
' id="' +
Expand All @@ -131,16 +117,16 @@ function generateRow(topic, key, value) {
key +
'-checkbox">Enabled ' +
defaultValueHint +
"</label>" +
"</label></div>" +
" </div>";

break;
}

case "double": {
box +=
'<label class="col-sm-4 control-label">Value</label>' +
'<div class="col-sm-8">' +
content +=
'<label class="col-sm-2 control-label">Value</label>' +
'<div class="col-sm-10">' +
'<input type="number" class="form-control" value="' +
value.value +
'" data-key="' +
Expand All @@ -155,9 +141,9 @@ function generateRow(topic, key, value) {
}

case "integer": {
box +=
'<label class="col-sm-4 control-label">Value (integer)</label>' +
'<div class="col-sm-8">' +
content +=
'<label class="col-sm-2 control-label">Value <small>(integer)</small></label>' +
'<div class="col-sm-10">' +
'<input type="number" step="1" class="form-control" value="' +
value.value +
'" data-key="' +
Expand All @@ -172,8 +158,8 @@ function generateRow(topic, key, value) {
}

case "unsigned integer": {
box +=
'<label class="col-sm-4 control-label">Value (unsigned integer)</label>' +
content +=
'<label class="col-sm-4 control-label">Value <small>(unsigned integer)</small></label>' +
'<div class="col-sm-8">' +
'<input type="number" step="1" min="0" class="form-control" value="' +
value.value +
Expand All @@ -189,8 +175,8 @@ function generateRow(topic, key, value) {
}

case "unsigned integer (16 bit)": {
box +=
'<label class="col-sm-4 control-label">Value (unsigned 16bit integer)</label>' +
content +=
'<label class="col-sm-4 control-label">Value <small>(unsigned 16bit integer)</small></label>' +
'<div class="col-sm-8">' +
'<input type="number" step="1" min="0" max="65535" class="form-control" value="' +
value.value +
Expand All @@ -206,9 +192,9 @@ function generateRow(topic, key, value) {
}

case "string array": {
box +=
'<label class="col-sm-5 control-label">Values (one item per line)</label>' +
'<div class="col-sm-7">' +
content +=
'<label class="col-sm-12 control-label">Values <small>(one item per line)</small></label>' +
'<div class="col-sm-12">' +
'<textarea class="form-control field-sizing-content" data-key="' +
key +
'"' +
Expand All @@ -225,39 +211,32 @@ function generateRow(topic, key, value) {

case "enum (unsigned integer)": // fallthrough
case "enum (string)": {
box +=
'<label class="col-sm-4 control-label">Selected Option</label>' +
'<div class="col-sm-8">' +
'<select class="form-control" data-key="' +
key +
'"' +
extraAttributes +
">";
value.allowed.forEach(function (option) {
box +=
'<option value="' +
option.item +
'"' +
(option.item === value.value ? " selected" : "") +
content += '<div class="col-sm-12">';
value.allowed.forEach(function (option, i) {
content +=
"<div>" +
// Radio button
'<input type="radio" class="form-control" ' +
`value="${option.item}" name="${key}" id="${key}_${i}" data-key="${key}"${extraAttributes}` +
(option.item === value.value ? " checked" : "") +
">" +
option.item +
"</option>";
// Label
`<label for="${key}_${i}"><strong>${utils.escapeHtml(option.item)}` +
(option.item === value.default ? " <em>(default)</em>" : "") +
"</strong></label>" +
// Paragraph with description
`<p class="help-block">${option.description}</p>` +
"</div>";
});
box +=
"</select> " +
defaultValueHint +
"</div>" +
'<div class="col-sm-12">' +
addAllowedValues(value.allowed) +
"</div>";
content += "</div>";

break;
}

case "password (write-only string)": {
box +=
'<label class="col-sm-4 control-label">Value (string)</label>' +
'<div class="col-sm-8">' +
content +=
'<label class="col-sm-2 control-label">Value <small>(string)</small></label>' +
'<div class="col-sm-10">' +
'<input type="password" class="form-control" value="' +
value.value +
'" data-key="' +
Expand All @@ -273,11 +252,43 @@ function generateRow(topic, key, value) {
}

default: {
box += "TYPE " + value.type + " NOT DEFINED";
content += "TYPE " + value.type + " NOT DEFINED";
}
}

box += "</div></div> ";
return '<div class="row">' + content + "</div>";
}

function generateRow(topic, key, value) {
// If the value is an object, we need to recurse
if (!("description" in value)) {
Object.keys(value).forEach(function (subkey) {
var subvalue = value[subkey];
generateRow(topic, key + "." + subkey, subvalue);
});
return;
}

// else: we have a setting we can display
var box =
'<div class="box settings-box">' +
'<div class="box-header with-border">' +
'<h3 class="box-title" data-key="' +
key +
'" data-modified="' +
(value.modified ? "true" : "false") +
'">' +
key +
boxIcons(value) +
"</h3>" +
"</div>" +
'<div class="box-body">' +
utils.escapeHtml(value.description).replaceAll("\n", "<br>") +
"</div>" +
'<div class="box-footer">' +
valueDetails(key, value) +
"</div></div> ";

var topKey = key.split(".")[0];
var elem = $("#advanced-content-" + topKey + "-flex");
elem.append(box);
Expand All @@ -288,41 +299,38 @@ function createDynamicConfigTabs() {
url: "/api/config?detailed=true",
})
.done(function (data) {
// Create the content for the advanced dynamic config topics
// Create the tabs for the advanced dynamic config topics
Object.keys(data.topics).forEach(function (n) {
var topic = data.topics[n];
$("#advanced-content").append(
'<div class="col-lg-12" id="advanced-content-' +
topic.name +
'">' +
'<div class="box box-success">' +
'<div class="box-header with-border no-user-select">' +
'<h3 class="box-title">' +
topic.description +
" (<code>" +
topic.name +
"</code>)" +
"</h3>" +
"</div>" +
'<div class="box-body">' +
'<div class="row" id="advanced-content-' +
topic.name +
'-body">' +
'<div class="col-xs-12 settings-container" id="advanced-content-' +
topic.name +
'-flex"></div>' +
"</div>" +
"</div>" +
"</div>" +
"</div>"
);

$("#advanced-settings-tabs").append(`
<div id="advanced-content-${topic.name}" role="tabpanel" class="tab-pane fade">
<h3 class="page-header">${topic.description} (<code>${topic.name}</code>)</h3>
rdwebdesign marked this conversation as resolved.
Show resolved Hide resolved
<div class="row" id="advanced-content-${topic.name}-body">
<div class="col-xs-12 settings-container" id="advanced-content-${topic.name}-flex"></div>
</div>
</div>
`);

// Dynamically create the settings menu
$("#advanced-settings-menu ul").append(`
<li role="presentation">
<a href="#advanced-content-${topic.name}" aria-controls="advanced-content-${topic.name}" role="pill" data-toggle="pill">${topic.description.replace(" settings", "")}</a>
</li>
`);
});

// Dynamically fill the tabs with config topics
Object.keys(data.config).forEach(function (topic) {
var value = data.config[topic];
generateRow(topic, topic, value, data);
});
$("#advanced-overlay").hide();

// Select the first tab and show the content
$("#advanced-settings-menu ul li:first-child").addClass("active");
$("#advanced-settings-tabs > div:first-child").addClass("active in");

$("button[id='save']").on("click", function () {
saveSettings();
});
Expand Down
14 changes: 12 additions & 2 deletions settings-all.lp
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,21 @@ PageTitle = "All Settings"
mg.include('scripts/pi-hole/lua/settings_header.lp','r')
?>
<div class="row settings-level-expert" id="advanced-content">
<!-- dynamically filled with content -->
<div class="overlay" id="advanced-overlay">
<i class="fa fa-sync fa-spin"></i>
</div>
<div class="col-lg-12 settings-level-expert save-button-container">

<div class="col-sm-12" id="advanced-settings-menu">
<ul class="nav nav-pills" role="tablist">
<!-- dynamically filled with content -->
</ul>
</div>

<div class="col-sm-12 tab-content" id="advanced-settings-tabs">
<!-- dynamically filled with content -->
</div>

<div class="col-sm-12 settings-level-expert save-button-container">
<button type="button" class="btn btn-primary save-button"><i class="fa-solid fa-fw fa-floppy-disk"></i>&nbsp;Save & Apply</button>
</div>
</div>
Expand Down
Loading