mirror of
https://github.com/hrfee/jellyfin-accounts.git
synced 2024-12-22 17:10:11 +00:00
Added settings menu to UI
Currently all setting changes require a restart to apply, so there's a bit of commented out code that i implemented before i realized. Still needs tooltips for each setting.
This commit is contained in:
parent
52a11c3905
commit
eb8e04d5a2
@ -82,7 +82,7 @@
|
||||
"name": "Port",
|
||||
"required": true,
|
||||
"requires_restart": true,
|
||||
"type": "int",
|
||||
"type": "number",
|
||||
"value": 8056
|
||||
},
|
||||
"jellyfin_login": {
|
||||
@ -261,7 +261,7 @@
|
||||
"description": "Address to send emails from"
|
||||
},
|
||||
"from": {
|
||||
"Name": "Sent from (name)",
|
||||
"name": "Sent from (name)",
|
||||
"required": false,
|
||||
"requires_restart": false,
|
||||
"depends_true": "method",
|
||||
@ -285,7 +285,7 @@
|
||||
},
|
||||
"watch_directory": {
|
||||
"name": "Jellyfin directory",
|
||||
"required": true,
|
||||
"required": false,
|
||||
"requires_restart": true,
|
||||
"depends_true": "enabled",
|
||||
"type": "text",
|
||||
@ -312,7 +312,7 @@
|
||||
},
|
||||
"subject": {
|
||||
"name": "Email subject",
|
||||
"required": true,
|
||||
"required": false,
|
||||
"requires_restart": false,
|
||||
"depends_true": "enabled",
|
||||
"type": "text",
|
||||
@ -418,7 +418,7 @@
|
||||
"name": "Port",
|
||||
"required": false,
|
||||
"requires_restart": false,
|
||||
"type": "int",
|
||||
"type": "number",
|
||||
"value": 465
|
||||
},
|
||||
"password": {
|
||||
|
@ -241,9 +241,6 @@ $("form#loginForm").submit(function() {
|
||||
});
|
||||
return false;
|
||||
});
|
||||
document.getElementById('openSettings').onclick = function () {
|
||||
$('#settingsMenu').modal('show');
|
||||
}
|
||||
document.getElementById('openDefaultsWizard').onclick = function () {
|
||||
this.disabled = true;
|
||||
this.innerHTML =
|
||||
@ -336,6 +333,7 @@ document.getElementById('storeDefaults').onclick = function () {
|
||||
},
|
||||
error: function() {
|
||||
button.textContent = 'Failed';
|
||||
config_base_path = local_dir / "config-base.json"
|
||||
button.classList.remove('btn-primary');
|
||||
button.classList.add('btn-danger');
|
||||
setTimeout(function(){
|
||||
@ -449,3 +447,210 @@ document.getElementById('openUsers').onclick = function () {
|
||||
};
|
||||
generateInvites(empty = true);
|
||||
$("#login").modal('show');
|
||||
|
||||
var config = {};
|
||||
var modifiedConfig = {};
|
||||
|
||||
document.getElementById('openSettings').onclick = function () {
|
||||
restart_setting_changed = false;
|
||||
$.ajax('getConfig', {
|
||||
type : 'GET',
|
||||
dataType : 'json',
|
||||
contentType : 'json',
|
||||
xhrFields : {
|
||||
withCredentials: true
|
||||
},
|
||||
beforeSend : function (xhr) {
|
||||
xhr.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
|
||||
},
|
||||
complete : function(data) {
|
||||
if (data['status'] == 200) {
|
||||
var settingsList = document.getElementById('settingsList');
|
||||
settingsList.textContent = '';
|
||||
config = data['responseJSON'];
|
||||
for (var section of Object.keys(config)) {
|
||||
var sectionCollapse = document.createElement('div');
|
||||
sectionCollapse.classList.add('collapse');
|
||||
sectionCollapse.id = section;
|
||||
|
||||
var sectionTitle = config[section]['meta']['name'];
|
||||
var sectionDescription = config[section]['meta']['description'];
|
||||
var entryListID = section + '_entryList';
|
||||
var sectionFooter = section + '_footer';
|
||||
|
||||
var innerCollapse = `
|
||||
<div class="card card-body">
|
||||
<small class="text-muted">${sectionDescription}</small>
|
||||
<div class="${entryListID}">
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
sectionCollapse.innerHTML = innerCollapse;
|
||||
|
||||
for (var entry of Object.keys(config[section])) {
|
||||
if (entry != 'meta') {
|
||||
var entryName = config[section][entry]['name'];
|
||||
var required = false;
|
||||
if (config[section][entry]['required']) {
|
||||
entryName += ' <sup class="text-danger">*</sup>';
|
||||
required = true;
|
||||
};
|
||||
// if (config[section][entry]['requires_restart']) {
|
||||
// entryName += ' <sup class="text-danger">R</sup>';
|
||||
// };
|
||||
var entryValue = config[section][entry]['value'];
|
||||
var entryType = config[section][entry]['type'];
|
||||
var entryGroup = document.createElement('div');
|
||||
if (entryType == 'bool') {
|
||||
entryGroup.classList.add('form-check');
|
||||
if (entryValue) {
|
||||
var checked = true;
|
||||
} else {
|
||||
var checked = false;
|
||||
};
|
||||
entryGroup.innerHTML = `
|
||||
<input class="form-check-input" type="checkbox" value="" id="${section}_${entry}">
|
||||
<label class="form-check-label" for="${section}_${entry}">${entryName}</label>
|
||||
`;
|
||||
entryGroup.getElementsByClassName('form-check-input')[0].required = required;
|
||||
entryGroup.getElementsByClassName('form-check-input')[0].checked = checked;
|
||||
entryGroup.getElementsByClassName('form-check-input')[0].onclick = function() {
|
||||
var state = this.checked;
|
||||
for (var sect of Object.keys(config)) {
|
||||
for (var ent of Object.keys(config[sect])) {
|
||||
if ((sect + '_' + config[sect][ent]['depends_true']) == this.id) {
|
||||
document.getElementById(sect + '_' + ent).disabled = !state;
|
||||
} else if ((sect + '_' + config[sect][ent]['depends_false']) == this.id) {
|
||||
document.getElementById(sect + '_' + ent).disabled = state;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
} else if ((entryType == 'text') || (entryType == 'email') || (entryType == 'password') || (entryType == 'number')) {
|
||||
entryGroup.classList.add('form-group');
|
||||
entryGroup.innerHTML = `
|
||||
<label for="${section}_${entry}">${entryName}</label>
|
||||
<input type="${entryType}" class="form-control" id="${section}_${entry}" aria-describedby="${entry}" value="${entryValue}">
|
||||
`;
|
||||
entryGroup.getElementsByClassName('form-control')[0].required = required;
|
||||
} else if (entryType == 'select') {
|
||||
entryGroup.classList.add('form-group');
|
||||
var entryOptions = config[section][entry]['options'];
|
||||
var innerGroup = `
|
||||
<label for="${section}_${entry}">${entryName}</label>
|
||||
<select class="form-control" id="${section}_${entry}">
|
||||
`;
|
||||
for (var i = 0; i < entryOptions.length; i++) {
|
||||
if (entryOptions[i] == entryValue) {
|
||||
var selected = 'selected';
|
||||
} else {
|
||||
var selected = '';
|
||||
}
|
||||
innerGroup += `
|
||||
<option value="${entryOptions[i]}" ${selected}>${entryOptions[i]}</option>
|
||||
`;
|
||||
};
|
||||
innerGroup += '</select>';
|
||||
entryGroup.innerHTML = innerGroup;
|
||||
entryGroup.getElementsByClassName('form-control')[0].required = required;
|
||||
|
||||
};
|
||||
sectionCollapse.getElementsByClassName(entryListID)[0].appendChild(entryGroup);
|
||||
};
|
||||
};
|
||||
var sectionButton = document.createElement('button');
|
||||
sectionButton.setAttribute('type', 'button');
|
||||
sectionButton.classList.add('list-group-item', 'list-group-item-action');
|
||||
sectionButton.appendChild(document.createTextNode(sectionTitle));
|
||||
sectionButton.id = section + '_button';
|
||||
sectionButton.setAttribute('data-toggle', 'collapse');
|
||||
sectionButton.setAttribute('data-target', '#' + section);
|
||||
settingsList.appendChild(sectionButton);
|
||||
settingsList.appendChild(sectionCollapse);
|
||||
};
|
||||
};
|
||||
},
|
||||
});
|
||||
$('#settingsMenu').modal('show');
|
||||
};
|
||||
|
||||
function sendConfig(modalId) {
|
||||
var modal = document.getElementById(modalId);
|
||||
var send = JSON.stringify(modifiedConfig);
|
||||
$.ajax('/modifyConfig', {
|
||||
data : send,
|
||||
contentType : 'application/json',
|
||||
type : 'POST',
|
||||
xhrFields : {
|
||||
withCredentials: true
|
||||
},
|
||||
beforeSend : function (xhr) {
|
||||
xhr.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
|
||||
},
|
||||
success: function() {
|
||||
if (modalId != 'settingsMenu') {
|
||||
$('#' + modalId).modal('hide');
|
||||
$('#settingsMenu').modal('hide');
|
||||
};
|
||||
},
|
||||
fail: function(xhr, textStatus, errorThrown) {
|
||||
var footer = modal.getElementsByClassName('modal-dialog')[0].getElementsByClassName('modal-content')[0].getElementsByClassName('modal-footer')[0];
|
||||
var alert = document.createElement('div');
|
||||
alert.classList.add('alert', 'alert-danger');
|
||||
alert.setAttribute('role', 'alert');
|
||||
alert.appendChild(document.createTextNode('Error: ' + errorThrown));
|
||||
footer.appendChild(alert);
|
||||
},
|
||||
});
|
||||
// placeholder
|
||||
};
|
||||
|
||||
document.getElementById('settingsSave').onclick = function() {
|
||||
modifiedConfig = {};
|
||||
// Live config changes have not yet been implemented, so restart always required.
|
||||
// var restart_setting_changed = false;
|
||||
var settings_changed = false;
|
||||
|
||||
for (var section of Object.keys(config)) {
|
||||
for (var entry of Object.keys(config[section])) {
|
||||
if (entry != 'meta') {
|
||||
var entryID = section + '_' + entry;
|
||||
var el = document.getElementById(entryID);
|
||||
if (el.type == 'checkbox') {
|
||||
var value = el.checked.toString();
|
||||
} else {
|
||||
var value = el.value.toString();
|
||||
};
|
||||
if (value != config[section][entry]['value'].toString()) {
|
||||
if (!modifiedConfig.hasOwnProperty(section)) {
|
||||
modifiedConfig[section] = {};
|
||||
};
|
||||
modifiedConfig[section][entry] = value;
|
||||
settings_changed = true;
|
||||
// if (config[section][entry]['requires_restart']) {
|
||||
// restart_setting_changed = true;
|
||||
// };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
// if (restart_setting_changed) {
|
||||
if (settings_changed) {
|
||||
document.getElementById('applyRestarts').onclick = function(){sendConfig('restartModal');};
|
||||
$('#settingsMenu').modal('hide');
|
||||
$('#restartModal').modal({
|
||||
backdrop: 'static',
|
||||
show: true
|
||||
});
|
||||
} else {
|
||||
// sendConfig('settingsMenu');
|
||||
$('#settingsMenu').modal('hide');
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -93,20 +93,20 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item">
|
||||
<button type="button" class="btn btn-secondary" id="openUsers">
|
||||
<p>Note: <sup class="text-danger">*</sup> Indicates required field.</p>
|
||||
<button type="button" class="list-group-item list-group-item-action" id="openUsers">
|
||||
Users <i class="fa fa-user"></i>
|
||||
</button>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<button type="button" class="btn btn-secondary" id="openDefaultsWizard">
|
||||
<button type="button" class="list-group-item list-group-item-action" id="openDefaultsWizard">
|
||||
New account defaults
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="list-group list-group-flush" id="settingsList">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer" id="settingsFooter">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" id="settingsSave">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -153,6 +153,22 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal fade" id="restartModal" tabindex="-1" role="dialog" aria-labelledby"Restart Warning" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Warning</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>A restart is needed to apply settings. This must be done manually. Apply now?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-primary" id="applyRestarts" data-dismiss="alert">Apply</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pageContainer">
|
||||
<h1>
|
||||
Accounts admin
|
||||
|
@ -344,9 +344,7 @@ def modifyConfig():
|
||||
log.debug(f"{section}/{item} does not exist in config")
|
||||
with open(config_path, "w") as config_file:
|
||||
temp_config.write(config_file)
|
||||
log.info("Config written, reloading")
|
||||
config.read(config_path)
|
||||
log.info("Config reloaded.")
|
||||
log.info("Config written. Restart is needed to load settings.")
|
||||
return resp()
|
||||
|
||||
|
||||
@ -363,6 +361,7 @@ def getConfig():
|
||||
log.debug('Config requested')
|
||||
with open(config_base_path, "r") as f:
|
||||
config_base = json.load(f)
|
||||
config.read(config_path)
|
||||
response_config = config_base
|
||||
for section in config_base:
|
||||
for entry in config_base[section]:
|
||||
|
Loading…
Reference in New Issue
Block a user