UI overhaul (#383)

This commit is contained in:
Michael Green
2024-09-01 01:00:54 +10:00
committed by GitHub
parent fd7b354571
commit deef919d5b
179 changed files with 18355 additions and 8819 deletions

View File

@@ -2,91 +2,130 @@
<h1 id="gametitle_label">About Gaseous</h1>
</div>
<table style="width: 100%;">
<tr>
<th style="width: 20%;">Home Page</th>
<td><a href="https://github.com/gaseous-project/gaseous-server" class="romlink">https://github.com/gaseous-project/gaseous-server</a></td>
<td rowspan="5" style="text-align: center; width: 128px;">
<img src="/images/logo.png" style="display: block; margin: 20px auto; width: 100px;" />
<span style="display: block;">The Gaseous logo was designed by Tom2.0</span>
</td>
</tr>
<tr>
<th>Bugs and Feature Requests</th>
<td><a href="https://github.com/gaseous-project/gaseous-server/issues" class="romlink">https://github.com/gaseous-project/gaseous-server/issues</a></td>
</tr>
<tr>
<th>Join our Discord</th>
<td><a href="https://discord.gg/Nhu7wpT3k4" class="romlink">https://discord.gg/Nhu7wpT3k4</a></td>
</tr>
<tr>
<th>Server Version</th>
<td id="settings_appversion"></td>
</tr>
<tr>
<th>Database Schema Version</th>
<td id="settings_dbversion"></td>
</tr>
<tr>
<td colspan="3">
<h3>Projects That Make Gaseous Possible</h3>
</td>
</tr>
<tr>
<td style="text-align: center;"><a href="https://github.com/EmulatorJS/EmulatorJS" target="_blank"><img src="/images/EmulatorJS.png" style="height: 36px;" /></a></td>
<td colspan="3">
The EmulatorJS Project<br />
<a href="https://github.com/EmulatorJS/EmulatorJS" target="_blank" class="romlink">https://github.com/EmulatorJS/EmulatorJS</a>
</td>
</tr>
<tr>
<td colspan="3">
<h3>Data Sources</h2>
<h4>Game data</h4>
</td>
</tr>
<tr>
<td style="text-align: center;">
<a href="https://www.igdb.com/" target="_blank"><img src="/images/IGDB_logo.svg" style="filter: invert(100%); height: 36px;" /></a>
</td>
<td colspan="2">
The Internet Game Database<br />
<a href="https://www.igdb.com/" target="_blank" class="romlink">https://www.igdb.com/</a>
</td>
</tr>
<tr>
<td colspan="3">
<h4>Signature data sources</h4>
</td>
</tr>
<tr>
<td style="text-align: center;">
<a href="https://www.tosecdev.org/" target="_blank"><img src="/images/TOSEC_logo.gif" style="height: 36px;" /></a>
</td>
<td colspan="2">
The Old School Emulation Center<br />
<a href="https://www.tosecdev.org/" target="_blank" class="romlink">https://www.tosecdev.org/</a>
</td>
</tr>
<tr>
<td style="text-align: center;">
<a href="https://www.progettosnaps.net/index.php" target="_blank"><img src="/images/ProgettoSnaps.gif" style="height: 36px;" /></a>
</td>
<td colspan="2">
Progetto-Snaps<br />
<a href="https://www.progettosnaps.net/index.php" target="_blank" class="romlink">https://www.progettosnaps.net/index.php</a>
</td>
</tr>
</table>
<div class="section">
<div class="section-body">
<table style="width: 100%;">
<tr>
<td style="width: 20%;">Home Page</td>
<td><a href="https://github.com/gaseous-project/gaseous-server" class="romlink" target="_blank"
rel="noopener noreferrer">https://github.com/gaseous-project/gaseous-server</a></td>
<td rowspan="5" style="text-align: center; width: 128px;">
<img src="/images/logo.png" style="display: block; margin: 20px auto; width: 100px;" />
<span style="display: block;">The Gaseous logo was designed by Tom1243</span>
</td>
</tr>
<tr>
<td>Bugs and Feature Requests</td>
<td><a href="https://github.com/gaseous-project/gaseous-server/issues" class="romlink" target="_blank"
rel="noopener noreferrer">https://github.com/gaseous-project/gaseous-server/issues</a></td>
</tr>
<tr>
<td>Join our Discord</td>
<td><a href="https://discord.gg/Nhu7wpT3k4" class="romlink" target="_blank"
rel="noopener noreferrer">https://discord.gg/Nhu7wpT3k4</a></td>
</tr>
<tr>
<td>Server Version</td>
<td id="settings_appversion"></td>
</tr>
<tr>
<td>Database Schema Version</td>
<td id="settings_dbversion"></td>
</tr>
</table>
</div>
</div>
<div class="section">
<div class="section-header">Projects That Make Gaseous Possible</div>
<div class="section-body">
<table style="width: 100%;">
<tr>
<td style="text-align: center; width: 20%;"><a href="https://github.com/EmulatorJS/EmulatorJS"
target="_blank" rel="noopener noreferrer"><img src="/images/EmulatorJS.png"
style="height: 36px;" /></a></td>
<td colspan="3">
The EmulatorJS Project<br />
<a href="https://github.com/EmulatorJS/EmulatorJS" class="romlink" target="_blank"
rel="noopener noreferrer">https://github.com/EmulatorJS/EmulatorJS</a>
</td>
</tr>
</table>
</div>
</div>
<div class="section">
<div class="section-header">Data Sources</div>
<div class="section-body">
<table style="width: 100%;">
<tr>
<td colspan="3">
<h4>Metadata sources</h4>
</td>
</tr>
<tr>
<td style="text-align: center; width: 20%;">
<a href="https://www.igdb.com/" target="_blank" rel="noopener noreferrer"><img
src="/images/IGDB_logo.svg" style="filter: invert(100%); height: 36px;" /></a>
</td>
<td colspan="2">
The Internet Game Database<br />
<a href="https://www.igdb.com/" target="_blank" rel="noopener noreferrer"
class="romlink">https://www.igdb.com/</a>
</td>
</tr>
<tr>
<td colspan="3">
<h4>Signature data sources</h4>
</td>
</tr>
<tr>
<td style="text-align: center;">
<a href="https://hasheous.org/" target="_blank" rel="noopener noreferrer"><img
src="/images/hasheous.svg" style="height: 36px;" /></a>
</td>
<td colspan="2">
Hasheous<br />
<a href="https://hasheous.org/" target="_blank" rel="noopener noreferrer"
class="romlink">https://hasheous.org/</a>
</td>
</tr>
<tr>
<td style="text-align: center;">
<a href="https://www.tosecdev.org/" target="_blank" rel="noopener noreferrer"><img
src="/images/TOSEC_logo.gif" style="height: 36px;" /></a>
</td>
<td colspan="2">
The Old School Emulation Center<br />
<a href="https://www.tosecdev.org/" target="_blank" rel="noopener noreferrer"
class="romlink">https://www.tosecdev.org/</a>
</td>
</tr>
<tr>
<td style="text-align: center;">
<a href="https://www.progettosnaps.net/index.php" target="_blank" rel="noopener noreferrer"><img
src="/images/ProgettoSnaps.gif" style="height: 36px;" /></a>
</td>
<td colspan="2">
Progetto-Snaps<br />
<a href="https://www.progettosnaps.net/index.php" target="_blank" rel="noopener noreferrer"
class="romlink">https://www.progettosnaps.net/index.php</a>
</td>
</tr>
<tr>
<td style="text-align: center;">
<a href="https://no-intro.org" target="_blank" rel="noopener noreferrer"><img
src="/images/NoIntro-logo.svg" style="height: 36px;" /></a>
</td>
<td colspan="2">
No-Intro<br />
<a href="https://no-intro.org" target="_blank" rel="noopener noreferrer"
class="romlink">https://no-intro.org</a>
</td>
</tr>
</table>
</div>
</div>
<script type="text/javascript">
var versionBox = document.getElementById('settings_appversion');
if (AppVersion == "1.5.0.0") {
versionBox.innerHTML = "Built from source";
} else {
versionBox.innerHTML = AppVersion;
}
var versionBox = document.getElementById('settings_dbversion');
versionBox.innerHTML = DBSchemaVersion;
// populate the page with the server version and database schema version
populatePage();
</script>

View File

@@ -0,0 +1,11 @@
function populatePage() {
let appVersionBox = document.getElementById('settings_appversion');
if (AppVersion == "1.5.0.0") {
appVersionBox.innerHTML = "Built from source";
} else {
appVersionBox.innerHTML = AppVersion;
}
let dbVersionBox = document.getElementById('settings_dbversion');
dbVersionBox.innerHTML = DBSchemaVersion;
}

View File

@@ -2,121 +2,26 @@
<h1 id="gametitle_label">Firmware</h1>
</div>
<h3>Firmware Availablility <span id="firmware_totalcount" style="float: right;"></span></h3>
<p>
Display:
<ul style="list-style-type:none;">
<li><input type="checkbox" id="firmware_showavailable" checked="checked" onclick="displayFirmwareList();"/><label for="firmware_showavailable"> Available</label></li>
<li><input type="checkbox" id="firmware_showunavailable" checked="checked" onclick="displayFirmwareList();"/><label for="firmware_showunavailable"> Unavailable</label></li>
</ul>
</p>
<table id="table_firmware" class="romtable" cellspacing="0">
<div class="section">
<div class="section-header">Firmware Availablility <span id="firmware_totalcount" style="float: right;"></span>
</div>
<div class="section-body">
<p>
Display:
<ul style="list-style-type:none;">
<li><input type="checkbox" id="firmware_showavailable" checked="checked"
onclick="displayFirmwareList();" /><label for="firmware_showavailable"> Available</label></li>
<li><input type="checkbox" id="firmware_showunavailable" checked="checked"
onclick="displayFirmwareList();" /><label for="firmware_showunavailable"> Unavailable</label></li>
</ul>
</p>
<table id="table_firmware" class="romtable" cellspacing="0">
</table>
</table>
</div>
</div>
<script type="text/javascript">
var biosDict = {};
ajaxCall('/api/v1.1/Bios', 'GET', function (result) {
result.sort((a, b) => a.platformname.charCodeAt(0) - b.platformname.charCodeAt(0));
// sort into a dictionary
for (var i = 0; i < result.length; i++) {
var tempArray = [];
if (biosDict.hasOwnProperty(result[i].platformname)) {
tempArray = biosDict[result[i].platformname];
tempArray.push(result[i]);
} else {
tempArray.push(result[i]);
biosDict[result[i].platformname] = tempArray;
}
biosDict[result[i].platformname] = tempArray;
}
console.log(biosDict);
displayFirmwareList();
});
function displayFirmwareList() {
var lastPlatform = '';
var newTable = document.getElementById('table_firmware');
newTable.innerHTML = '';
newTable.appendChild(createTableRow(true, ['Description', 'File name', 'MD5 Hash', 'Available']));
var totalAvailable = 0;
var totalCount = 0;
for (const [key, value] of Object.entries(biosDict)) {
// new platform - show a header
var platformRow = document.createElement('tr');
var platformHeader = document.createElement('th');
platformHeader.setAttribute('colspan', 4);
var platformHeaderValue = document.createElement('span');
platformHeaderValue.innerHTML = key;
platformHeader.appendChild(platformHeaderValue);
var platformHeaderCounter = document.createElement('span');
platformHeaderCounter.style.float = 'right';
platformHeader.appendChild(platformHeaderCounter);
platformRow.appendChild(platformHeader);
newTable.appendChild(platformRow);
var totalPlatformAvailable = 0;
var showAvailable = document.getElementById('firmware_showavailable').checked;
var showUnavailable = document.getElementById('firmware_showunavailable').checked;
for (var i = 0; i < value.length; i++) {
// update counters
if (value[i].available == true) {
totalAvailable += 1;
totalPlatformAvailable += 1;
}
if (
(value[i].available == true && showAvailable == true) ||
(value[i].available == false && showUnavailable == true)
) {
var biosFilename = document.createElement('a');
biosFilename.href = '/api/v1.1/Bios/' + value[i].platformid + '/' + value[i].filename;
biosFilename.innerHTML = value[i].filename;
biosFilename.className = 'romlink';
var availableText = document.createElement('span');
if (value[i].available == true) {
availableText.innerHTML = 'Available';
availableText.className = 'greentext';
biosFilename = document.createElement('a');
biosFilename.href = '/api/v1.1/Bios/' + value[i].platformid + '/' + value[i].filename;
biosFilename.innerHTML = value[i].filename;
biosFilename.className = 'romlink';
} else {
availableText.innerHTML = 'Unavailable';
availableText.className = 'redtext';
biosFilename = document.createElement('span');
biosFilename.innerHTML = value[i].filename;
}
var newRow = [
value[i].description,
biosFilename,
value[i].hash,
availableText
];
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell'));
}
totalCount += 1;
}
platformHeaderCounter.innerHTML = totalPlatformAvailable + ' / ' + value.length + ' available';
}
document.getElementById('firmware_totalcount').innerHTML = totalAvailable + ' / ' + totalCount + ' available';
}
// load the bios list
loadBios();
</script>

View File

@@ -0,0 +1,303 @@
let biosDict = {};
function loadBios() {
biosDict = {};
ajaxCall('/api/v1.1/Bios', 'GET', function (result) {
result.sort((a, b) => a.platformname.charCodeAt(0) - b.platformname.charCodeAt(0));
// sort into a dictionary
for (let i = 0; i < result.length; i++) {
let tempArray = [];
if (biosDict.hasOwnProperty(result[i].platformname)) {
tempArray = biosDict[result[i].platformname];
tempArray.push(result[i]);
} else {
tempArray.push(result[i]);
biosDict[result[i].platformname] = tempArray;
}
biosDict[result[i].platformname] = tempArray;
}
displayFirmwareList();
});
}
function displayFirmwareList() {
let lastPlatform = '';
let targetDiv = document.getElementById('table_firmware');
targetDiv.innerHTML = '';
let totalAvailable = 0;
let totalCount = 0;
for (const [key, value] of Object.entries(biosDict)) {
// new platform - show a header
let platformRow = document.createElement('div');
platformRow.classList.add('section')
let platformHeader = document.createElement('div');
platformHeader.classList.add('section-header');
let platformHeaderValue = document.createElement('span');
platformHeaderValue.innerHTML = key;
platformHeader.appendChild(platformHeaderValue);
let platformHeaderEdit = document.createElement('a');
platformHeaderEdit.href = '#';
platformHeaderEdit.style.float = 'right';
platformHeaderEdit.onclick = function () {
let biosEditor = new BiosEditor(value[0].platformid, loadBios);
biosEditor.open();
};
let platformHeaderEditIcon = document.createElement('img');
platformHeaderEditIcon.src = '/images/edit.svg';
platformHeaderEditIcon.classList.add('banner_button_image');
platformHeaderEdit.appendChild(platformHeaderEditIcon);
platformHeader.appendChild(platformHeaderEdit);
let platformHeaderCounter = document.createElement('span');
platformHeaderCounter.style.float = 'right';
platformHeaderCounter.style.marginRight = '10px';
platformHeader.appendChild(platformHeaderCounter);
platformRow.appendChild(platformHeader);
let platformBody = document.createElement('div');
platformBody.classList.add('section-body');
// create new table
let newTable = document.createElement('table');
newTable.classList.add('romtable');
newTable.setAttribute('cellspacing', 0);
newTable.appendChild(createTableRow(true, ['Description', 'File name', 'MD5 Hash', 'Available']));
let totalPlatformAvailable = 0;
let showAvailable = document.getElementById('firmware_showavailable').checked;
let showUnavailable = document.getElementById('firmware_showunavailable').checked;
for (let i = 0; i < value.length; i++) {
// update counters
if (value[i].available == true) {
totalAvailable += 1;
totalPlatformAvailable += 1;
}
if (
(value[i].available == true && showAvailable == true) ||
(value[i].available == false && showUnavailable == true)
) {
let biosFilename = document.createElement('a');
biosFilename.href = '/api/v1.1/Bios/' + value[i].platformid + '/' + value[i].filename;
biosFilename.innerHTML = value[i].filename;
biosFilename.className = 'romlink';
let availableText = document.createElement('span');
if (value[i].available == true) {
availableText.innerHTML = 'Available';
availableText.className = 'greentext';
biosFilename = document.createElement('a');
biosFilename.href = '/api/v1.1/Bios/' + value[i].platformid + '/' + value[i].filename;
biosFilename.innerHTML = value[i].filename;
biosFilename.className = 'romlink';
} else {
availableText.innerHTML = 'Unavailable';
availableText.className = 'redtext';
biosFilename = document.createElement('span');
biosFilename.innerHTML = value[i].filename;
}
let newRow = [
value[i].description,
biosFilename,
value[i].hash,
availableText
];
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell bioscell'));
}
totalCount += 1;
}
platformHeaderCounter.innerHTML = totalPlatformAvailable + ' / ' + value.length + ' available';
platformBody.append(newTable);
platformRow.append(platformBody);
targetDiv.append(platformRow);
}
document.getElementById('firmware_totalcount').innerHTML = totalAvailable + ' / ' + totalCount + ' available';
}
class BiosEditor {
constructor(PlatformId, OKCallback, CancelCallback) {
this.PlatformId = PlatformId;
this.OKCallback = OKCallback;
this.CancelCallback = CancelCallback;
}
BiosItems = [];
async open() {
// Create the modal
this.dialog = await new Modal("bios");
await this.dialog.BuildModal();
// Get the platform data
await fetch('/api/v1.1/PlatformMaps/' + this.PlatformId, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}).then(async response => {
if (response.ok) {
let result = await response.json();
this.PlatformData = result;
// setup the dialog
this.dialog.modalElement.querySelector('#modal-header-text').innerHTML = this.PlatformData.igdbName;
// setup the bios editor page
let biosEditor = this.dialog.modalElement.querySelector('#bios_editor');
biosEditor.innerHTML = '';
for (let i = 0; i < this.PlatformData.bios.length; i++) {
let biosItem = new MappingBiosItem(this.PlatformData.bios[i].hash, this.PlatformData.bios[i].description, this.PlatformData.bios[i].filename);
biosEditor.appendChild(biosItem.Item);
this.BiosItems.push(biosItem);
}
let newBiosItem = new MappingBiosItem('', '', '');
biosEditor.appendChild(newBiosItem.Item);
this.BiosItems.push(newBiosItem);
let addBiosButton = this.dialog.modalElement.querySelector('#mapping_edit_bios_add');
addBiosButton.addEventListener('click', () => {
let newBiosItem = new MappingBiosItem('', '', '');
biosEditor.appendChild(newBiosItem.Item);
this.BiosItems.push(newBiosItem);
});
// setup the buttons
let okButton = new ModalButton("OK", 1, this, async function (callingObject) {
// build bios items list
let biosItems = [];
for (let i = 0; i < callingObject.BiosItems.length; i++) {
// only add items that are not deleted and have a hash and filename
if (callingObject.BiosItems[i].Deleted == false && callingObject.BiosItems[i].HashInput.value != '' && callingObject.BiosItems[i].FilenameInput.value != '') {
let biosItem = {
hash: callingObject.BiosItems[i].HashInput.value,
description: callingObject.BiosItems[i].DescriptionInput.value,
filename: callingObject.BiosItems[i].FilenameInput.value
};
biosItems.push(biosItem);
}
}
callingObject.PlatformData.bios = biosItems;
await fetch('/api/v1.1/PlatformMaps/' + callingObject.PlatformId, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(callingObject.PlatformData)
}).then(async response => {
if (response.ok) {
let result = await response.json();
console.log(result);
if (callingObject.OKCallback) {
callingObject.OKCallback();
}
callingObject.dialog.close();
} else {
let warningDialog = new Dialog("Error", "Failed to save platform data", "OK");
warningDialog.open();
}
});
});
this.dialog.addButton(okButton);
// create the cancel button
let cancelButton = new ModalButton("Cancel", 0, this, function (callingObject) {
if (callingObject.CancelCallback) {
callingObject.CancelCallback();
}
callingObject.dialog.close();
});
this.dialog.addButton(cancelButton);
// Show the modal
this.dialog.open();
} else {
let warningDialog = new MessageBox("Error", "Failed to load platform data", "OK");
warningDialog.open();
return;
}
});
}
}
class MappingBiosItem {
constructor(Hash, Description, Filename) {
this.Hash = Hash;
this.Description = Description;
this.Filename = Filename;
this.Deleted = false;
this.Item = document.createElement('div');
this.Item.classList.add('biositem');
this.Item.classList.add('romrow');
this.HashInput = document.createElement('input');
this.HashInput.type = 'text';
this.HashInput.value = this.Hash;
this.HashInput.classList.add('biosinput');
this.HashInput.classList.add('bioshash');
this.HashInput.placeholder = 'Hash';
this.Item.appendChild(this.HashInput);
this.DescriptionInput = document.createElement('input');
this.DescriptionInput.type = 'text';
this.DescriptionInput.value = this.Description;
this.DescriptionInput.classList.add('biosinput');
this.DescriptionInput.classList.add('biosdescription');
this.DescriptionInput.placeholder = 'Description';
this.Item.appendChild(this.DescriptionInput);
this.FilenameInput = document.createElement('input');
this.FilenameInput.type = 'text';
this.FilenameInput.value = this.Filename;
this.FilenameInput.classList.add('biosinput');
this.FilenameInput.classList.add('biosfilename');
this.FilenameInput.placeholder = 'Filename';
this.Item.appendChild(this.FilenameInput);
this.DeleteButton = document.createElement('a');
this.DeleteButton.href = '#';
this.DeleteButton.classList.add('biositemcontrol');
this.DeleteButton.classList.add('biosdelete');
this.DeleteButton.addEventListener('click', () => {
this.Item.parentElement.removeChild(this.Item);
this.Deleted = true;
});
this.DeleteImage = document.createElement('img');
this.DeleteImage.src = '/images/delete.svg';
this.DeleteImage.alt = 'Delete';
this.DeleteImage.title = 'Delete';
this.DeleteImage.classList.add('banner_button_image');
this.DeleteButton.appendChild(this.DeleteImage);
this.Item.appendChild(this.DeleteButton);
}
}

View File

@@ -2,62 +2,18 @@
<h1 id="gametitle_label">Libraries</h1>
</div>
<table id="settings_libraries" class="romtable" style="width: 100%;" cellspacing="0">
<div class="section">
<div class="section-body">
<table id="settings_libraries" class="romtable" style="width: 100%;" cellspacing="0">
</table>
<div style="text-align: right;"><button id="settings_newlibrary" onclick="showDialog('librarynew');">New
Library</button></div>
</table>
<div style="text-align: right;"><button id="settings_newlibrary">New
Library</button></div>
</div>
</div>
<script type="text/javascript">
function drawLibrary() {
ajaxCall(
'/api/v1.1/Library',
'GET',
function (result) {
var newTable = document.getElementById('settings_libraries');
newTable.innerHTML = '';
newTable.appendChild(createTableRow(true, ['Name', 'Path', 'Default Platform', 'Default Library', '']));
for (var i = 0; i < result.length; i++) {
var platformName = '';
if (result[i].defaultPlatformId == 0) {
if (result[i].isDefaultLibrary == true) {
platformName = "n/a";
} else {
platformName = "";
}
} else {
platformName = result[i].defaultPlatformName;
}
var defaultLibrary = '';
if (result[i].isDefaultLibrary == true) {
defaultLibrary = "Yes";
} else {
defaultLibrary = "";
}
var deleteButton = '';
if (result[i].isDefaultLibrary == false) {
var deleteButton = '<a href="#" onclick="showSubDialog(\'librarydelete\', ' + result[i].id + ');" class="romlink"><img src="/images/delete.svg" class="banner_button_image" alt="Delete" title="Delete" /></a>';
}
newTable.appendChild(createTableRow(
false,
[
result[i].name,
result[i].path,
platformName,
defaultLibrary,
'<div style="text-align: right;">' + deleteButton + '</div>'
],
'romrow',
'romcell'
));
}
}
);
}
// Load the libraries
setupButtons();
drawLibrary();
</script>

View File

@@ -0,0 +1,91 @@
function setupButtons() {
document.getElementById('settings_newlibrary').addEventListener('click', function () {
let newLibrary = new NewLibrary();
newLibrary.open();
});
}
function drawLibrary() {
ajaxCall(
'/api/v1.1/Library',
'GET',
function (result) {
let newTable = document.getElementById('settings_libraries');
newTable.innerHTML = '';
newTable.appendChild(createTableRow(true, ['Name', 'Path', 'Default Platform', 'Default Library', '']));
for (let i = 0; i < result.length; i++) {
let platformName = '';
if (result[i].defaultPlatformId == 0) {
if (result[i].isDefaultLibrary == true) {
platformName = "n/a";
} else {
platformName = "";
}
} else {
platformName = result[i].defaultPlatformName;
}
let defaultLibrary = '';
if (result[i].isDefaultLibrary == true) {
defaultLibrary = "Yes";
} else {
defaultLibrary = "";
}
let controls = document.createElement('div');
controls.style.textAlign = 'right';
let deleteButton = '';
if (result[i].isDefaultLibrary == false) {
deleteButton = document.createElement('a');
deleteButton.href = '#';
deleteButton.addEventListener('click', () => {
let deleteLibrary = new MessageBox('Delete Library', 'Are you sure you want to delete this library?<br /><br /><strong>Warning</strong>: This cannot be undone!');
deleteLibrary.addButton(new ModalButton('OK', 2, deleteLibrary, function (callingObject) {
ajaxCall(
'/api/v1.1/Library/' + result[i].id,
'DELETE',
function () {
callingObject.msgDialog.close();
drawLibrary();
},
function () {
callingObject.msgDialog.close();
drawLibrary();
}
);
}));
deleteLibrary.addButton(new ModalButton('Cancel', 0, deleteLibrary, function (callingObject) {
callingObject.msgDialog.close();
}));
deleteLibrary.open();
});
let deleteButtonImage = document.createElement('img');
deleteButtonImage.src = '/images/delete.svg';
deleteButtonImage.className = 'banner_button_image';
deleteButtonImage.alt = 'Delete';
deleteButtonImage.title = 'Delete';
deleteButton.appendChild(deleteButtonImage);
controls.appendChild(deleteButton);
}
newTable.appendChild(createTableRow(
false,
[
result[i].name,
result[i].path,
platformName,
defaultLibrary,
controls
],
'romrow',
'romcell'
));
}
}
);
}

View File

@@ -5,7 +5,8 @@
<table style="width: 960px; max-width: 960px;" cellspacing="0">
<tr>
<td>
<input type="datetime-local" id="logs_startdate" style="width: 30%;" /> <input type="datetime-local" id="logs_enddate" style="width: 30%;" />
<input type="datetime-local" id="logs_startdate" style="width: 30%;" /> <input type="datetime-local"
id="logs_enddate" style="width: 30%;" />
</td>
<td>
<input type="checkbox" id="logs_type_info"><label for="logs_type_info">Information</label>
@@ -35,7 +36,7 @@
<!-- <a href="#" class="romlink" onclick="loadLogs();" style="float: right;"><img src="/images/refresh.svg" alt="Refresh" title="Refresh" class="banner_button_image" /></a> -->
<table id="settings_events_table" style="width: 960px; max-width: 960px;" cellspacing="0">
</table>
<div style="width: 960px; text-align: center;">
@@ -43,189 +44,7 @@
</div>
<script type="text/javascript">
var lastStartIndex = 0;
var currentPage = 1;
var searchModel = {};
var correlationIdParam = getQueryString('correlationid', 'string');
if (correlationIdParam) {
if (correlationIdParam.length > 0) {
document.getElementById('logs_correlationid').value = correlationIdParam;
}
}
function resetFilters() {
document.getElementById('logs_startdate').value = '';
document.getElementById('logs_enddate').value = '';
document.getElementById('logs_type_info').checked = false;
document.getElementById('logs_type_warning').checked = false;
document.getElementById('logs_type_critical').checked = false;
document.getElementById('logs_textsearch').value = '';
document.getElementById('logs_correlationid').value = '';
loadLogs();
}
function loadLogs(StartIndex, PageNumber) {
var model = {}
if (StartIndex && PageNumber) {
currentPage += 1;
// get saved search model
model = searchModel;
model.StartIndex = StartIndex;
model.PageNumber = PageNumber;
} else {
currentPage = 1;
// create search model
var statusList = [];
if (document.getElementById('logs_type_info').checked == true) { statusList.push(0); }
if (document.getElementById('logs_type_warning').checked == true) { statusList.push(2); }
if (document.getElementById('logs_type_critical').checked == true) { statusList.push(3); }
var startDate = null;
var startDateObj = document.getElementById('logs_startdate');
if (startDateObj.value != null) { startDate = new Date(startDateObj.value); }
var endDate = null;
var endDateObj = document.getElementById('logs_enddate');
if (endDateObj.value != null) { endDate = new Date(endDateObj.value); }
var searchText = null;
var searchTextObj = document.getElementById('logs_textsearch');
if (searchTextObj.value != null) { searchText = searchTextObj.value; }
var correlationId = null;
var correlationIdTextObj = document.getElementById('logs_correlationid');
if (correlationIdTextObj.value != null) { correlationId = correlationIdTextObj.value; }
model = {
"StartIndex": StartIndex,
"PageNumber": PageNumber,
"PageSize": 100,
"Status": statusList,
"StartDateTime": startDate,
"EndDateTime": endDate,
"SearchText": searchText,
"CorrelationId": correlationId
}
searchModel = model;
}
console.log(model);
ajaxCall(
'/api/v1.1/Logs',
'POST',
function (result) {
var newTable = document.getElementById('settings_events_table');
if (currentPage == 1) {
newTable.innerHTML = '';
newTable.appendChild(
createTableRow(
true,
[
//'Id',
['Event Time', 'logs_table_cell_150px'],
['Severity', 'logs_table_cell_150px'],
'Process',
'Message'
],
'',
''
)
);
}
for (var i = 0; i < result.length; i++) {
lastStartIndex = result[i].id;
console.log(result[i]);
var surroundingRow = document.createElement('tbody');
surroundingRow.setAttribute('colspan', 4);
surroundingRow.className = 'logs_table_row_' + result[i].eventType;
var newRow = [
moment(result[i].eventTime).format("YYYY-MM-DD h:mm:ss a"),
result[i].eventType,
result[i].process,
result[i].message.replaceAll("\n", "<br />")
];
surroundingRow.appendChild(createTableRow(false, newRow, '', 'romcell logs_table_cell'));
// exception
var exceptionString = '';
if (result[i].exceptionValue) {
exceptionString = "<strong>Exception</strong><pre class='logs_table_exception' style='width: 795px; word-wrap: break-word; overflow-wrap: break-word; overflow-y: scroll;'>" + syntaxHighlight(JSON.stringify(result[i].exceptionValue, null, 2)).replace(/\\n/g, "<br /> ") + "</pre>";
var exRow = document.createElement('tr');
var leadCell = document.createElement('td');
exRow.appendChild(leadCell);
var exCell = document.createElement('td');
exCell.colSpan = '3';
exCell.innerHTML = exceptionString;
exRow.appendChild(exCell);
surroundingRow.appendChild(exRow);
}
// calling process
var infoRow = document.createElement('tr');
var infoRowEmptyCell = document.createElement('td');
infoRowEmptyCell.className = 'romcell';
var infoRowDataCell = document.createElement('td');
infoRowDataCell.className = 'romcell';
infoRowDataCell.setAttribute('colspan', 3);
infoRowDataCell.innerHTML = '<strong>Calling process:</strong> ' + result[i].callingProcess;
infoRow.appendChild(infoRowEmptyCell);
infoRow.appendChild(infoRowDataCell);
surroundingRow.appendChild(infoRow);
// initiated by user
if (result[i].callingUser) {
if (result[i].callingUser.length > 0) {
var infoRow3 = document.createElement('tr');
var infoRowEmptyCell3 = document.createElement('td');
infoRowEmptyCell3.className = 'romcell';
var infoRowDataCell3 = document.createElement('td');
infoRowDataCell3.className = 'romcell';
infoRowDataCell3.setAttribute('colspan', 3);
infoRowDataCell3.innerHTML = '<strong>User:</strong> ' + result[i].callingUser + "</a>";
infoRow3.appendChild(infoRowEmptyCell3);
infoRow3.appendChild(infoRowDataCell3);
surroundingRow.appendChild(infoRow3);
}
}
// correlation id
var infoRow2 = document.createElement('tr');
var infoRowEmptyCell2 = document.createElement('td');
infoRowEmptyCell2.className = 'romcell';
var infoRowDataCell2 = document.createElement('td');
infoRowDataCell2.className = 'romcell';
infoRowDataCell2.setAttribute('colspan', 3);
infoRowDataCell2.innerHTML = '<strong>Correlation Id:</strong> <a class="romlink" href="/index.html?page=settings&sub=logs&correlationid=' + result[i].correlationId + '">' + result[i].correlationId + "</a>";
infoRow2.appendChild(infoRowEmptyCell2);
infoRow2.appendChild(infoRowDataCell2);
surroundingRow.appendChild(infoRow2);
newTable.appendChild(surroundingRow);
}
},
function (error) {
},
JSON.stringify(model)
);
}
// load the logs
initLogs();
loadLogs();
</script>

View File

@@ -0,0 +1,181 @@
let lastStartIndex = 0;
let currentPage = 1;
let searchModel = {};
function initLogs() {
let correlationIdParam = getQueryString('correlationid', 'string');
if (correlationIdParam) {
if (correlationIdParam.length > 0) {
document.getElementById('logs_correlationid').value = correlationIdParam;
}
}
}
function resetFilters() {
document.getElementById('logs_startdate').value = '';
document.getElementById('logs_enddate').value = '';
document.getElementById('logs_type_info').checked = false;
document.getElementById('logs_type_warning').checked = false;
document.getElementById('logs_type_critical').checked = false;
document.getElementById('logs_textsearch').value = '';
document.getElementById('logs_correlationid').value = '';
loadLogs();
}
function loadLogs(StartIndex, PageNumber) {
let model = {}
if (StartIndex && PageNumber) {
currentPage += 1;
// get saved search model
model = searchModel;
model.StartIndex = StartIndex;
model.PageNumber = PageNumber;
} else {
currentPage = 1;
// create search model
let statusList = [];
if (document.getElementById('logs_type_info').checked == true) { statusList.push(0); }
if (document.getElementById('logs_type_warning').checked == true) { statusList.push(2); }
if (document.getElementById('logs_type_critical').checked == true) { statusList.push(3); }
let startDate = null;
let startDateObj = document.getElementById('logs_startdate');
if (startDateObj.value != null) { startDate = new Date(startDateObj.value); }
let endDate = null;
let endDateObj = document.getElementById('logs_enddate');
if (endDateObj.value != null) { endDate = new Date(endDateObj.value); }
let searchText = null;
let searchTextObj = document.getElementById('logs_textsearch');
if (searchTextObj.value != null) { searchText = searchTextObj.value; }
let correlationId = null;
let correlationIdTextObj = document.getElementById('logs_correlationid');
if (correlationIdTextObj.value != null) { correlationId = correlationIdTextObj.value; }
model = {
"StartIndex": StartIndex,
"PageNumber": PageNumber,
"PageSize": 100,
"Status": statusList,
"StartDateTime": startDate,
"EndDateTime": endDate,
"SearchText": searchText,
"CorrelationId": correlationId
}
searchModel = model;
}
ajaxCall(
'/api/v1.1/Logs',
'POST',
function (result) {
let newTable = document.getElementById('settings_events_table');
if (currentPage == 1) {
newTable.innerHTML = '';
newTable.appendChild(
createTableRow(
true,
[
//'Id',
['Event Time', 'logs_table_cell_150px'],
['Severity', 'logs_table_cell_150px'],
'Process',
'Message'
],
'',
''
)
);
}
for (let i = 0; i < result.length; i++) {
lastStartIndex = result[i].id;
let surroundingRow = document.createElement('tbody');
surroundingRow.setAttribute('colspan', 4);
surroundingRow.className = 'logs_table_row_' + result[i].eventType;
let newRow = [
moment(result[i].eventTime).format("YYYY-MM-DD h:mm:ss a"),
result[i].eventType,
result[i].process,
result[i].message.replaceAll("\n", "<br />")
];
surroundingRow.appendChild(createTableRow(false, newRow, '', 'romcell logs_table_cell'));
// exception
let exceptionString = '';
if (result[i].exceptionValue) {
exceptionString = "<strong>Exception</strong><pre class='logs_table_exception' style='width: 795px; word-wrap: break-word; overflow-wrap: break-word; overflow-y: scroll;'>" + syntaxHighlight(JSON.stringify(result[i].exceptionValue, null, 2)).replace(/\\n/g, "<br /> ") + "</pre>";
let exRow = document.createElement('tr');
let leadCell = document.createElement('td');
exRow.appendChild(leadCell);
let exCell = document.createElement('td');
exCell.colSpan = '3';
exCell.innerHTML = exceptionString;
exRow.appendChild(exCell);
surroundingRow.appendChild(exRow);
}
// calling process
let infoRow = document.createElement('tr');
let infoRowEmptyCell = document.createElement('td');
infoRowEmptyCell.className = 'romcell';
let infoRowDataCell = document.createElement('td');
infoRowDataCell.className = 'romcell';
infoRowDataCell.setAttribute('colspan', 3);
infoRowDataCell.innerHTML = '<strong>Calling process:</strong> ' + result[i].callingProcess;
infoRow.appendChild(infoRowEmptyCell);
infoRow.appendChild(infoRowDataCell);
surroundingRow.appendChild(infoRow);
// initiated by user
if (result[i].callingUser) {
if (result[i].callingUser.length > 0) {
let infoRow3 = document.createElement('tr');
let infoRowEmptyCell3 = document.createElement('td');
infoRowEmptyCell3.className = 'romcell';
let infoRowDataCell3 = document.createElement('td');
infoRowDataCell3.className = 'romcell';
infoRowDataCell3.setAttribute('colspan', 3);
infoRowDataCell3.innerHTML = '<strong>User:</strong> ' + result[i].callingUser + "</a>";
infoRow3.appendChild(infoRowEmptyCell3);
infoRow3.appendChild(infoRowDataCell3);
surroundingRow.appendChild(infoRow3);
}
}
// correlation id
let infoRow2 = document.createElement('tr');
let infoRowEmptyCell2 = document.createElement('td');
infoRowEmptyCell2.className = 'romcell';
let infoRowDataCell2 = document.createElement('td');
infoRowDataCell2.className = 'romcell';
infoRowDataCell2.setAttribute('colspan', 3);
infoRowDataCell2.innerHTML = '<strong>Correlation Id:</strong> <a class="romlink" href="/index.html?page=settings&sub=logs&correlationid=' + result[i].correlationId + '">' + result[i].correlationId + "</a>";
infoRow2.appendChild(infoRowEmptyCell2);
infoRow2.appendChild(infoRowDataCell2);
surroundingRow.appendChild(infoRow2);
newTable.appendChild(surroundingRow);
}
},
function (error) {
},
JSON.stringify(model)
);
}

View File

@@ -1,98 +1,37 @@
<div id="gametitle">
<h1 id="gametitle_label">Platform Mapping</h1>
<h1 id="gametitle_label">Platforms</h1>
</div>
<p>When determining the platform of a ROM or image (which is later used when determining the game title), only the "Unique File Extensions" are used. All other extensions are ignored as they will limit the ability of Gaseous to determine the game title (see <a href="https://github.com/gaseous-project/gaseous-server#game-image-title-matching" class="romlink">https://github.com/gaseous-project/gaseous-server#game-image-title-matching</a> for more information on how matching works).</p>
<div class="section">
<div class="section-body">
<p>When determining the platform of a ROM or image (which is later used when determining the game title), only
the "Unique File Extensions" are used. All other extensions are ignored as they will limit the ability of
Gaseous to determine the game title (see <a
href="https://github.com/gaseous-project/gaseous-server/wiki/ROM-Metadata-Matching" class="romlink"
target="_blank"
rel="noopener noreferrer">https://github.com/gaseous-project/gaseous-server/wiki/ROM-Metadata-Matching</a>
for
more
information on how matching works).</p>
<p>This list is pre-populated with some of the more common platforms. New platforms will appear in this list as titles are added.</p>
<p>This list is pre-populated with some of the more common platforms. New platforms will appear in this list as
titles are added.</p>
<p id="settings_mapping_import" style="display: none;"><button value="Export to JSON" onclick="DownloadJSON();">Export to JSON</button><button id="importjson" value="Import JSON">Import JSON</button><button value="Reset to Default" onclick="loadPlatformMapping(true);">Reset to Default</button></p>
<p id="settings_mapping_import" style="display: none;"><button value="Export to JSON"
onclick="DownloadJSON();">Export to JSON</button><button id="importjson" value="Import JSON">Import
JSON</button><button value="Reset to Default" onclick="loadPlatformMapping(true);">Reset to
Default</button></p>
<input id='uploadjson' type='file' name='files' hidden/>
<input id='uploadjson' type='file' name='files' hidden />
<table id="settings_mapping_table" style="width: 100%;" cellspacing="0">
</table>
<table id="settings_mapping_table" style="width: 100%;" cellspacing="0">
</table>
</div>
</div>
<script type="text/javascript">
if (userProfile.roles.includes("Admin")) {
document.getElementById('settings_mapping_import').style.display = '';
}
function loadPlatformMapping(Overwrite) {
var queryString = '';
if (Overwrite == true) {
queryString = '?ResetToDefault=true';
}
ajaxCall(
'/api/v1.1/PlatformMaps' + queryString,
'GET',
function (result) {
var newTable = document.getElementById('settings_mapping_table');
newTable.innerHTML = '';
newTable.appendChild(
createTableRow(
true,
[
'Platform',
'Supported File Extensions',
'Unique File Extensions',
'Has Web Emulator'
],
'',
''
)
);
for (var i = 0; i < result.length; i++) {
var hasWebEmulator = '';
if (result[i].webEmulator.type.length > 0) {
hasWebEmulator = 'Yes';
}
var platformLink = '';
if (userProfile.roles.includes("Admin")) {
platformLink = '<a href="#/" onclick="ShowPlatformMappingDialog(' + result[i].igdbId + ');" class="romlink">' + result[i].igdbName + '</a>';
} else {
platformLink = result[i].igdbName;
}
var newRow = [
platformLink,
result[i].extensions.supportedFileExtensions.join(', '),
result[i].extensions.uniqueFileExtensions.join(', '),
hasWebEmulator
];
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell logs_table_cell'));
}
}
);
}
function DownloadJSON() {
window.location = '/api/v1.1/PlatformMaps/PlatformMap.json';
}
document.getElementById('importjson').addEventListener('click', openDialog);
function openDialog() {
document.getElementById('uploadjson').click();
}
$('#uploadjson').change(function () {
$(this).simpleUpload("/api/v1.1/PlatformMaps", {
start: function (file) {
//upload started
console.log("JSON upload started");
},
success: function(data){
//upload successful
window.location.reload();
}
});
});
// Load the platform mapping
SetupButtons();
loadPlatformMapping();
</script>

View File

@@ -0,0 +1,448 @@
function loadPlatformMapping(Overwrite) {
let queryString = '';
if (Overwrite == true) {
console.log('Overwriting PlatformMap.json');
queryString = '?ResetToDefault=true';
}
ajaxCall(
'/api/v1.1/PlatformMaps' + queryString,
'GET',
function (result) {
let newTable = document.getElementById('settings_mapping_table');
newTable.innerHTML = '';
newTable.appendChild(
createTableRow(
true,
[
'Platform',
'Supported File Extensions',
'Unique File Extensions',
'Has Web Emulator',
''
],
'',
''
)
);
for (let i = 0; i < result.length; i++) {
let hasWebEmulator = '';
if (result[i].webEmulator.type.length > 0) {
hasWebEmulator = 'Yes';
}
let platformEditButton = null;
if (userProfile.roles.includes("Admin")) {
platformEditButton = document.createElement('div');
platformEditButton.classList.add('romlink');
platformEditButton.onclick = function () {
let mappingModal = new Mapping(result[i].igdbId, loadPlatformMapping);
mappingModal.open();
};
let editButtonImage = document.createElement('img');
editButtonImage.src = '/images/edit.svg';
editButtonImage.alt = 'Edit';
editButtonImage.title = 'Edit';
editButtonImage.classList.add('banner_button_image');
platformEditButton.appendChild(editButtonImage);
}
let newRow = [
result[i].igdbName,
result[i].extensions.supportedFileExtensions.join(', '),
result[i].extensions.uniqueFileExtensions.join(', '),
hasWebEmulator,
platformEditButton
];
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell logs_table_cell'));
}
}
);
}
function DownloadJSON() {
window.location = '/api/v1.1/PlatformMaps/PlatformMap.json';
}
function SetupButtons() {
if (userProfile.roles.includes("Admin")) {
document.getElementById('settings_mapping_import').style.display = '';
document.getElementById('uploadjson').addEventListener('change', function () {
$(this).simpleUpload("/api/v1.1/PlatformMaps", {
start: function (file) {
//upload started
console.log("JSON upload started");
},
success: function (data) {
//upload successful
window.location.reload();
}
});
});
document.getElementById('importjson').addEventListener('click', openDialog);
}
}
function openDialog() {
document.getElementById('uploadjson').click();
}
class Mapping {
constructor(PlatformId, OKCallback, CancelCallback) {
this.PlatformId = PlatformId;
this.OKCallback = OKCallback;
this.CancelCallback = CancelCallback;
}
async open() {
// Create the modal
this.dialog = await new Modal("mappings");
await this.dialog.BuildModal();
// Get the platform data
await fetch('/api/v1.1/PlatformMaps/' + this.PlatformId, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
}).then(async response => {
if (response.ok) {
let result = await response.json();
this.PlatformData = result;
} else {
let warningDialog = new MessageBox("Error", "Failed to load platform data", "OK");
warningDialog.open();
}
});
// setup the dialog
this.dialog.modalElement.querySelector('#modal-header-text').innerHTML = this.PlatformData.igdbName;
// setup general page
this.alternateNames = this.dialog.modalElement.querySelector('#mapping_edit_alternativenames');
$(this.alternateNames).select2({
tags: true,
tokenSeparators: [',']
});
this.#AddTokensFromList(this.alternateNames, this.PlatformData.alternateNames);
this.supportedFileExtensions = this.dialog.modalElement.querySelector('#mapping_edit_supportedfileextensions');
$(this.supportedFileExtensions).select2({
tags: true,
tokenSeparators: [','],
createTag: function (params) {
if (params.term.indexOf('.') === -1) {
// Return null to disable tag creation
return null;
}
return {
id: params.term.toUpperCase(),
text: params.term.toUpperCase()
}
}
});
this.#AddTokensFromList(this.supportedFileExtensions, this.PlatformData.extensions.supportedFileExtensions);
this.dialog.modalElement.querySelector('#mapping_edit_igdbslug').value = this.PlatformData.igdbSlug;
this.dialog.modalElement.querySelector('#mapping_edit_retropie').value = this.PlatformData.retroPieDirectoryName;
// setup the emulator page
this.webEmulatorConfiguration = new WebEmulatorConfiguration(this.PlatformData);
await this.webEmulatorConfiguration.open();
this.dialog.modalElement.querySelector('#mapping_edit_webemulator').appendChild(this.webEmulatorConfiguration.panel);
// setup the buttons
let okButton = new ModalButton("OK", 1, this, async function (callingObject) {
callingObject.PlatformData.alternateNames = $(callingObject.alternateNames).val();
callingObject.PlatformData.extensions.supportedFileExtensions = $(callingObject.supportedFileExtensions).val();
callingObject.PlatformData.retroPieDirectoryName = callingObject.dialog.modalElement.querySelector('#mapping_edit_retropie').value;
callingObject.PlatformData.webEmulator.type = callingObject.webEmulatorConfiguration.PlatformMap.webEmulator.type;
callingObject.PlatformData.webEmulator.core = callingObject.webEmulatorConfiguration.PlatformMap.webEmulator.core;
callingObject.PlatformData.enabledBIOSHashes = callingObject.webEmulatorConfiguration.PlatformMap.enabledBIOSHashes;
await fetch('/api/v1.1/PlatformMaps/' + callingObject.PlatformId, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(callingObject.PlatformData)
}).then(async response => {
if (response.ok) {
let result = await response.json();
if (callingObject.OKCallback) {
callingObject.OKCallback();
}
callingObject.dialog.close();
} else {
let warningDialog = new Dialog("Error", "Failed to save platform data", "OK");
warningDialog.open();
}
});
});
this.dialog.addButton(okButton);
// create the cancel button
let cancelButton = new ModalButton("Cancel", 0, this, function (callingObject) {
if (callingObject.CancelCallback) {
callingObject.CancelCallback();
}
callingObject.dialog.close();
});
this.dialog.addButton(cancelButton);
this.dialog.open();
}
#AddTokensFromList(selectObj, tagList) {
for (let i = 0; i < tagList.length; i++) {
let data = {
id: tagList[i],
text: tagList[i]
}
let newOption = new Option(data.text, data.id, true, true);
$(selectObj).append(newOption).trigger('change');
}
}
}
class WebEmulatorConfiguration {
constructor(PlatformMap) {
this.PlatformMap = PlatformMap;
if (this.PlatformMap.bios.length > 0) {
this.PlatformMap.bios.sort((a, b) => (a.description > b.description) ? 1 : ((b.description > a.description) ? -1 : 0))
}
}
async open() {
// create the panel
this.panel = document.createElement('div');
const templateResponse = await fetch('/pages/modals/webemulator.html');
const templateContent = await templateResponse.text();
this.panel.innerHTML = templateContent;
// load the emulator list
this.#LoadEmulatorList();
// select the emulator and core
if (this.PlatformMap.webEmulator.type.length === 0) {
this.PlatformMap.webEmulator.type = 'none';
}
let emulatorSelect = this.panel.querySelector('#webemulator_select_' + this.PlatformMap.webEmulator.type);
if (emulatorSelect != null) {
emulatorSelect.checked = true;
this.#LoadCoreList(this.PlatformMap.webEmulator.type);
let coreSelect = this.panel.querySelector('#webemulator_core_select_' + this.PlatformMap.webEmulator.core);
if (coreSelect != null) {
coreSelect.checked = true;
}
}
this.#EmulatorInfoPanels();
// load the bios list
this.#LoadBiosList();
}
#LoadEmulatorList() {
let emulatorSelect = this.panel.querySelector('#webemulator_select');
let emulatorSelectTable = document.createElement('table');
// create radio button list of available web emulators
let emulatorSelectTableRow = document.createElement('tr');
let emulatorSelectTableCell = document.createElement('td');
let newOption = document.createElement('input');
newOption.id = 'webemulator_select_none';
newOption.name = 'webemulator_select';
newOption.type = 'radio';
newOption.value = '';
newOption.addEventListener('change', () => {
this.#LoadCoreList('');
this.PlatformMap.webEmulator.type = '';
this.#EmulatorInfoPanels();
});
emulatorSelectTableCell.appendChild(newOption);
let newLabel = document.createElement('label');
newLabel.htmlFor = 'webemulator_select_none';
newLabel.innerHTML = '&nbsp;None';
emulatorSelectTableCell.appendChild(newLabel);
emulatorSelectTableRow.appendChild(emulatorSelectTableCell);
emulatorSelectTable.appendChild(emulatorSelectTableRow);
if (this.PlatformMap.webEmulator.availableWebEmulators) {
if (this.PlatformMap.webEmulator.availableWebEmulators.length > 0) {
for (let i = 0; i < this.PlatformMap.webEmulator.availableWebEmulators.length; i++) {
let emulatorSelectTableRow = document.createElement('tr');
let emulatorSelectTableCell = document.createElement('td');
let newOption = document.createElement('input');
newOption.id = 'webemulator_select_' + this.PlatformMap.webEmulator.availableWebEmulators[i].emulatorType;
newOption.name = 'webemulator_select';
newOption.type = 'radio';
newOption.value = this.PlatformMap.webEmulator.availableWebEmulators[i].emulatorType;
newOption.addEventListener('change', () => {
this.#LoadCoreList(this.PlatformMap.webEmulator.availableWebEmulators[i].emulatorType);
this.PlatformMap.webEmulator.type = this.PlatformMap.webEmulator.availableWebEmulators[i].emulatorType;
this.#EmulatorInfoPanels();
});
emulatorSelectTableCell.appendChild(newOption);
let newLabel = document.createElement('label');
newLabel.htmlFor = 'webemulator_select_' + this.PlatformMap.webEmulator.availableWebEmulators[i].emulatorType;
newLabel.innerHTML = "&nbsp;" + this.PlatformMap.webEmulator.availableWebEmulators[i].emulatorType;
emulatorSelectTableCell.appendChild(newLabel);
emulatorSelectTableRow.appendChild(emulatorSelectTableCell);
emulatorSelectTable.appendChild(emulatorSelectTableRow);
}
}
}
emulatorSelect.appendChild(emulatorSelectTable);
}
#EmulatorInfoPanels() {
// show appropriate emulator info panel
switch (this.PlatformMap.webEmulator.type) {
case 'EmulatorJS':
this.panel.querySelector('#webemulator_info_emulatorjs').style.display = '';
break;
default:
this.panel.querySelector('#webemulator_info_emulatorjs').style.display = 'none';
break;
}
}
#LoadCoreList(EmulatorType) {
let coreSelectSection = this.panel.querySelector('#webemulator_core_select-section');
coreSelectSection.style.display = 'none';
// show core help (if available)
switch (EmulatorType) {
case 'EmulatorJS':
this.panel.querySelector('#webemulator_core_info_emulatorjs').style.display = '';
break;
}
let coreSelect = this.panel.querySelector('#webemulator_core_select');
coreSelect.innerHTML = '';
let coreSelectTable = document.createElement('table');
if (this.PlatformMap.webEmulator.availableWebEmulators) {
if (this.PlatformMap.webEmulator.availableWebEmulators.length > 0) {
for (let i = 0; i < this.PlatformMap.webEmulator.availableWebEmulators.length; i++) {
if (this.PlatformMap.webEmulator.availableWebEmulators[i].emulatorType == EmulatorType) {
for (let j = 0; j < this.PlatformMap.webEmulator.availableWebEmulators[i].availableWebEmulatorCores.length; j++) {
coreSelectSection.style.display = '';
let coreSelectTableRow = document.createElement('tr');
let coreSelectTableCell = document.createElement('td');
let newOption = document.createElement('input');
newOption.id = 'webemulator_core_select_' + this.PlatformMap.webEmulator.availableWebEmulators[i].availableWebEmulatorCores[j].core;
newOption.name = 'webemulator_core_select';
newOption.type = 'radio';
newOption.value = this.PlatformMap.webEmulator.availableWebEmulators[i].availableWebEmulatorCores[j].core;
newOption.text = this.PlatformMap.webEmulator.availableWebEmulators[i].availableWebEmulatorCores[j].core;
if (this.PlatformMap.webEmulator.availableWebEmulators[i].availableWebEmulatorCores[j].default == true) {
newOption.checked = true;
}
newOption.addEventListener('change', () => {
this.PlatformMap.webEmulator.core = this.PlatformMap.webEmulator.availableWebEmulators[i].availableWebEmulatorCores[j].core;
});
coreSelectTableCell.appendChild(newOption);
let newLabel = document.createElement('label');
newLabel.htmlFor = 'webemulator_core_select_' + this.PlatformMap.webEmulator.availableWebEmulators[i].availableWebEmulatorCores[j].core;
let labelText = "";
if (this.PlatformMap.webEmulator.availableWebEmulators[i].availableWebEmulatorCores[j].alternateCoreName.length > 0) {
labelText = "&nbsp;" + this.PlatformMap.webEmulator.availableWebEmulators[i].availableWebEmulatorCores[j].core + " (maps to core: " + this.PlatformMap.webEmulator.availableWebEmulators[i].availableWebEmulatorCores[j].alternateCoreName + ")";
} else {
labelText = "&nbsp;" + this.PlatformMap.webEmulator.availableWebEmulators[i].availableWebEmulatorCores[j].core;
}
if (this.PlatformMap.webEmulator.availableWebEmulators[i].availableWebEmulatorCores[j].default == true) {
labelText += " (Default)";
}
newLabel.innerHTML = labelText;
coreSelectTableCell.appendChild(newLabel);
coreSelectTableRow.appendChild(coreSelectTableCell);
coreSelectTable.appendChild(coreSelectTableRow);
}
}
}
}
}
coreSelect.appendChild(coreSelectTable);
}
#LoadBiosList() {
if (this.PlatformMap.bios.length > 0) {
let biosSelect = this.panel.querySelector('#webemulator_bios_select');
biosSelect.innerHTML = '';
let biosSelectTable = document.createElement('table');
biosSelectTable.style.width = '100%';
for (let i = 0; i < this.PlatformMap.bios.length; i++) {
let biosSelectTableRow = document.createElement('tr');
biosSelectTableRow.classList.add('romrow');
let biosSelectTableCell = document.createElement('td');
biosSelectTableCell.classList.add('romcell');
let newOption = document.createElement('input');
newOption.id = 'webemulator_bios_select_' + this.PlatformMap.bios[i].hash;
newOption.name = 'webemulator_bios_select';
newOption.type = 'checkbox';
newOption.value = this.PlatformMap.bios[i].hash;
if (this.PlatformMap.enabledBIOSHashes.includes(this.PlatformMap.bios[i].hash)) {
newOption.checked = true;
}
newOption.addEventListener('change', () => {
if (newOption.checked) {
this.PlatformMap.enabledBIOSHashes.push(this.PlatformMap.bios[i].hash);
} else {
let index = this.PlatformMap.enabledBIOSHashes.indexOf(this.PlatformMap.bios[i].hash);
if (index > -1) {
this.PlatformMap.enabledBIOSHashes.splice(index, 1);
}
}
});
biosSelectTableCell.appendChild(newOption);
let newLabel = document.createElement('label');
newLabel.htmlFor = 'webemulator_bios_select_' + this.PlatformMap.bios[i].hash;
let labelText = "";
if (this.PlatformMap.bios[i].description.length > 0) {
labelText = this.PlatformMap.bios[i].description + " (" + this.PlatformMap.bios[i].filename + ")";
} else {
labelText = this.PlatformMap.bios[i].filename;
}
newLabel.innerHTML = "&nbsp;" + labelText;
biosSelectTableCell.appendChild(newLabel);
biosSelectTableRow.appendChild(biosSelectTableCell);
biosSelectTable.appendChild(biosSelectTableRow);
}
biosSelect.appendChild(biosSelectTable);
} else {
this.panel.querySelector('#webemulator_bios_select-section').style.display = 'none';
}
}
}

View File

@@ -1,290 +1,16 @@
<div id="gametitle">
<h1 id="gametitle_label">Services</h1>
</div>
<table id="settings_tasktimers" class="romtable" style="width: 100%;" cellspacing="0">
</table>
<div style="text-align: right;"><button id="settings_tasktimers_default" onclick="defaultTaskTimers();">Reset to
Default</button><button id="settings_tasktimers_new" onclick="saveTaskTimers();">Save</button></div>
<div class="section">
<div id="settings_tasktimers" style="width: 100%;">
</div>
<div style="text-align: right;"><button id="settings_tasktimers_default" onclick="defaultTaskTimers();">Reset to
Default</button><button id="settings_tasktimers_new" onclick="saveTaskTimers();">Save</button></div>
</div>
<script type="text/javascript">
function getBackgroundTaskTimers() {
ajaxCall(
'/api/v1/System/Settings/BackgroundTasks/Configuration',
'GET',
function (result) {
var targetTable = document.getElementById('settings_tasktimers');
targetTable.innerHTML = '';
for (const [key, value] of Object.entries(result)) {
var newTableRowBody = document.createElement('tbody');
newTableRowBody.className = 'romrow';
var enabledString = "";
if (value.enabled == true) {
enabledString = 'checked="checked"';
}
var newTableIntervalRow = createTableRow(
false,
[
GetTaskFriendlyName(value.task),
'Enabled',
'<input id="settings_enabled_' + value.task + '" name="settings_tasktimers_enabled" type="checkbox" ' + enabledString + '/>',
],
'',
'romcell'
);
newTableRowBody.appendChild(newTableIntervalRow);
var newTableRow = createTableRow(
false,
[
'',
'Minimum Interval (Minutes):',
'<input id="settings_tasktimers_' + value.task + '" name="settings_tasktimers_values" data-name="' + value.task + '" data-default="' + value.defaultInterval + '" type="number" placeholder="' + value.defaultInterval + '" min="' + value.minimumAllowedInterval + '" value="' + value.interval + '" />'
],
'',
'romcell'
);
newTableRowBody.appendChild(newTableRow);
// allowed time periods row
var newTableRowTime = document.createElement('tr');
var rowTimeSpace = document.createElement('td');
newTableRowTime.appendChild(rowTimeSpace);
var rowTimeContentTitle = document.createElement('td');
rowTimeContentTitle.className = 'romcell';
rowTimeContentTitle.innerHTML = "Allowed Days:";
newTableRowTime.appendChild(rowTimeContentTitle);
var rowTimeContent = document.createElement('td');
// rowTimeContent.setAttribute('colspan', 2);
rowTimeContent.className = 'romcell';
var daySelector = document.createElement('select');
daySelector.id = 'settings_alloweddays_' + value.task;
daySelector.name = 'settings_alloweddays';
daySelector.multiple = 'multiple';
daySelector.setAttribute('data-default', value.defaultAllowedDays.join(","));
daySelector.style.width = '95%';
var days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
for (var d = 0; d < days.length; d++) {
var dayOpt = document.createElement('option');
dayOpt.value = days[d];
dayOpt.innerHTML = days[d];
if (value.allowedDays.includes(days[d])) {
dayOpt.selected = 'selected';
}
daySelector.appendChild(dayOpt);
}
rowTimeContent.appendChild(daySelector);
$(daySelector).select2({
tags: false
});
newTableRowTime.appendChild(rowTimeContent);
newTableRowBody.appendChild(newTableRowTime);
// add start and end times
var newTableRowClock = document.createElement('tr');
var rowClockSpace = document.createElement('td');
newTableRowClock.appendChild(rowClockSpace);
var rowClockContentTitle = document.createElement('td');
rowClockContentTitle.className = 'romcell';
rowClockContentTitle.innerHTML = "Time Range:";
newTableRowClock.appendChild(rowClockContentTitle);
var rowClockContent = document.createElement('td');
rowClockContent.className = 'romcell';
// rowClockContent.setAttribute('colspan', 2);
rowClockContent.appendChild(generateTimeDropDowns(value.task, 'Start', value.defaultAllowedStartHours, value.defaultAllowedStartMinutes, value.allowedStartHours, value.allowedStartMinutes));
rowClockContentSeparator = document.createElement('span');
rowClockContentSeparator.innerHTML = '&nbsp;-&nbsp;';
rowClockContent.appendChild(rowClockContentSeparator);
rowClockContent.appendChild(generateTimeDropDowns(value.task, 'End', value.defaultAllowedEndHours, value.defaultAllowedEndMinutes, value.allowedEndHours, value.allowedEndMinutes));
newTableRowClock.appendChild(rowClockContent);
newTableRowBody.appendChild(newTableRowClock);
// blocks tasks
var newTableRowBlocks = document.createElement('tr');
var rowBlocksSpace = document.createElement('td');
newTableRowBlocks.appendChild(rowBlocksSpace);
var rowBlocksContentTitle = document.createElement('td');
rowBlocksContentTitle.className = 'romcell';
rowBlocksContentTitle.innerHTML = "Blocks:";
newTableRowBlocks.appendChild(rowBlocksContentTitle);
var rowBlocksContent = document.createElement('td');
rowBlocksContent.className = 'romcell';
// rowBlocksContent.setAttribute('colspan', 2);
var blocksString = "";
for (var i = 0; i < value.blocks.length; i++) {
if (blocksString.length > 0) { blocksString += ", "; }
blocksString += GetTaskFriendlyName(value.blocks[i]);
}
if (blocksString.length == 0) { blocksString = 'None'; }
rowBlocksContent.innerHTML = blocksString;
newTableRowBlocks.appendChild(rowBlocksContent);
newTableRowBody.appendChild(newTableRowBlocks);
// blocked by tasks
var newTableRowBlockedBy = document.createElement('tr');
var rowBlockedBySpace = document.createElement('td');
newTableRowBlockedBy.appendChild(rowBlockedBySpace);
var rowBlockedByContentTitle = document.createElement('td');
rowBlockedByContentTitle.className = 'romcell';
rowBlockedByContentTitle.innerHTML = "Blocked By:";
newTableRowBlockedBy.appendChild(rowBlockedByContentTitle);
var rowBlockedByContent = document.createElement('td');
rowBlockedByContent.className = 'romcell';
// rowBlockedByContent.setAttribute('colspan', 2);
var BlockedByString = "";
for (var i = 0; i < value.blockedBy.length; i++) {
if (BlockedByString.length > 0) { BlockedByString += ", "; }
BlockedByString += GetTaskFriendlyName(value.blockedBy[i]);
}
if (BlockedByString.length == 0) { BlockedByString = 'None'; }
rowBlockedByContent.innerHTML = BlockedByString;
newTableRowBlockedBy.appendChild(rowBlockedByContent);
newTableRowBody.appendChild(newTableRowBlockedBy);
// complete row
targetTable.appendChild(newTableRowBody);
}
}
);
}
function generateTimeDropDowns(taskName, rangeName, defaultHour, defaultMinute, valueHour, valueMinute) {
var container = document.createElement('div');
container.style.display = 'inline';
var elementName = 'settings_tasktimers_time';
var hourSelector = document.createElement('input');
hourSelector.id = 'settings_tasktimers_' + taskName + '_' + rangeName + '_Hour';
hourSelector.name = elementName;
hourSelector.setAttribute('data-name', taskName);
hourSelector.setAttribute('type', 'number');
hourSelector.setAttribute('min', '0');
hourSelector.setAttribute('max', '23');
hourSelector.setAttribute('placeholder', defaultHour);
hourSelector.value = valueHour;
container.appendChild(hourSelector);
var separator = document.createElement('span');
separator.innerHTML = " : ";
container.appendChild(separator);
var minSelector = document.createElement('input');
minSelector.id = 'settings_tasktimers_' + taskName + '_' + rangeName + '_Minute';
minSelector.name = elementName;
minSelector.setAttribute('type', 'number');
minSelector.setAttribute('min', '0');
minSelector.setAttribute('max', '59');
minSelector.setAttribute('placeholder', defaultMinute);
minSelector.value = valueMinute;
container.appendChild(minSelector);
return container;
}
function saveTaskTimers() {
var timerValues = document.getElementsByName('settings_tasktimers_values');
var model = [];
for (var i = 0; i < timerValues.length; i++) {
var taskName = timerValues[i].getAttribute('data-name');
var taskEnabled = document.getElementById('settings_enabled_' + taskName).checked;
var taskIntervalObj = document.getElementById('settings_tasktimers_' + taskName);
var taskInterval = function () { if (taskIntervalObj.value) { return taskIntervalObj.value; } else { return taskIntervalObj.getAttribute('placeholder'); } };
var taskDaysRaw = $('#settings_alloweddays_' + taskName).select2('data');
var taskDays = [];
if (taskDaysRaw.length > 0) {
for (var d = 0; d < taskDaysRaw.length; d++) {
taskDays.push(taskDaysRaw[d].id);
}
} else {
taskDays.push("Monday");
}
var taskStartHourObj = document.getElementById('settings_tasktimers_' + taskName + '_Start_Hour');
var taskStartMinuteObj = document.getElementById('settings_tasktimers_' + taskName + '_Start_Minute');
var taskEndHourObj = document.getElementById('settings_tasktimers_' + taskName + '_End_Hour');
var taskEndMinuteObj = document.getElementById('settings_tasktimers_' + taskName + '_End_Minute');
var taskStartHour = function () { if (taskStartHourObj.value) { return taskStartHourObj.value; } else { return taskStartHourObj.getAttribute('placeholder'); } };
var taskStartMinute = function () { if (taskStartMinuteObj.value) { return taskStartMinuteObj.value; } else { return taskStartMinuteObj.getAttribute('placeholder'); } };
var taskEndHour = function () { if (taskEndHourObj.value) { return taskEndHourObj.value; } else { return taskEndHourObj.getAttribute('placeholder'); } };
var taskEndMinute = function () { if (taskEndMinuteObj.value) { return taskEndMinuteObj.value; } else { return taskEndMinuteObj.getAttribute('placeholder'); } };
model.push(
{
"task": taskName,
"enabled": taskEnabled,
"interval": taskInterval(),
"allowedDays": taskDays,
"allowedStartHours": taskStartHour(),
"allowedStartMinutes": taskStartMinute(),
"allowedEndHours": taskEndHour(),
"allowedEndMinutes": taskEndMinute()
}
);
}
ajaxCall(
'/api/v1/System/Settings/BackgroundTasks/Configuration',
'POST',
function (result) {
getBackgroundTaskTimers();
},
function (error) {
getBackgroundTaskTimers();
},
JSON.stringify(model)
);
}
function defaultTaskTimers() {
var timerValues = document.getElementsByName('settings_tasktimers_enabled');
for (var i = 0; i < timerValues.length; i++) {
timerValues[i].checked = true;
}
var timerValues = document.getElementsByName('settings_tasktimers_values');
for (var i = 0; i < timerValues.length; i++) {
timerValues[i].value = timerValues[i].getAttribute('data-default');
}
var timerValues = document.getElementsByName('settings_alloweddays');
for (var i = 0; i < timerValues.length; i++) {
var defaultSelections = timerValues[i].getAttribute('data-default').split(',');
$(timerValues[i]).val(defaultSelections);
$(timerValues[i]).trigger('change');
}
var timerValues = document.getElementsByName('settings_tasktimers_time');
for (var i = 0; i < timerValues.length; i++) {
timerValues[i].value = timerValues[i].getAttribute('placeholder');
}
saveTaskTimers();
}
// populate the page
getBackgroundTaskTimers();
</script>

View File

@@ -0,0 +1,297 @@
function getBackgroundTaskTimers() {
ajaxCall(
'/api/v1/System/Settings/BackgroundTasks/Configuration',
'GET',
function (result) {
let targetTable = document.getElementById('settings_tasktimers');
targetTable.innerHTML = '';
for (const [key, value] of Object.entries(result)) {
let enabledString = "";
if (value.enabled == true) {
enabledString = 'checked="checked"';
}
// add heading
let serviceHeader = document.createElement('div');
serviceHeader.className = 'section-header';
serviceHeader.innerHTML = GetTaskFriendlyName(value.task);
targetTable.appendChild(serviceHeader);
// create table for each service
let serviceTable = document.createElement('table');
serviceTable.style.width = '100%';
serviceTable.classList.add('section-body');
// add enabled
let newEnabledRow = document.createElement('tr');
let newEnabledTitle = document.createElement('td');
newEnabledTitle.className = 'romcell romcell-headercell';
newEnabledTitle.innerHTML = "Enabled:";
newEnabledRow.appendChild(newEnabledTitle);
let newEnabledContent = document.createElement('td');
newEnabledContent.className = 'romcell';
let newEnabledCheckbox = document.createElement('input');
newEnabledCheckbox.id = 'settings_enabled_' + value.task;
newEnabledCheckbox.name = 'settings_tasktimers_enabled';
newEnabledCheckbox.type = 'checkbox';
newEnabledCheckbox.checked = value.enabled;
newEnabledContent.appendChild(newEnabledCheckbox);
newEnabledRow.appendChild(newEnabledContent);
serviceTable.appendChild(newEnabledRow);
// add interval
let newIntervalRow = document.createElement('tr');
let newIntervalTitle = document.createElement('td');
newIntervalTitle.className = 'romcell romcell-headercell';
newIntervalTitle.innerHTML = "Minimum Interval (Minutes):";
newIntervalRow.appendChild(newIntervalTitle);
let newIntervalContent = document.createElement('td');
newIntervalContent.className = 'romcell';
let newIntervalInput = document.createElement('input');
newIntervalInput.id = 'settings_tasktimers_' + value.task;
newIntervalInput.name = 'settings_tasktimers_values';
newIntervalInput.setAttribute('data-name', value.task);
newIntervalInput.setAttribute('data-default', value.defaultInterval);
newIntervalInput.type = 'number';
newIntervalInput.placeholder = value.defaultInterval;
newIntervalInput.min = value.minimumAllowedInterval;
newIntervalInput.value = value.interval;
newIntervalContent.appendChild(newIntervalInput);
newIntervalRow.appendChild(newIntervalContent);
serviceTable.appendChild(newIntervalRow);
// allowed time periods row
let newTableRowTime = document.createElement('tr');
let rowTimeContentTitle = document.createElement('td');
rowTimeContentTitle.className = 'romcell romcell-headercell';
rowTimeContentTitle.innerHTML = "Allowed Days:";
newTableRowTime.appendChild(rowTimeContentTitle);
let rowTimeContent = document.createElement('td');
// rowTimeContent.setAttribute('colspan', 2);
rowTimeContent.className = 'romcell';
let daySelector = document.createElement('select');
daySelector.id = 'settings_alloweddays_' + value.task;
daySelector.name = 'settings_alloweddays';
daySelector.multiple = 'multiple';
daySelector.setAttribute('data-default', value.defaultAllowedDays.join(","));
daySelector.style.width = '95%';
let days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
for (let d = 0; d < days.length; d++) {
let dayOpt = document.createElement('option');
dayOpt.value = days[d];
dayOpt.innerHTML = days[d];
if (value.allowedDays.includes(days[d])) {
dayOpt.selected = 'selected';
}
daySelector.appendChild(dayOpt);
}
rowTimeContent.appendChild(daySelector);
$(daySelector).select2({
tags: false
});
newTableRowTime.appendChild(rowTimeContent);
serviceTable.appendChild(newTableRowTime);
// add start and end times
let newTableRowClock = document.createElement('tr');
let rowClockContentTitle = document.createElement('td');
rowClockContentTitle.className = 'romcell romcell-headercell';
rowClockContentTitle.innerHTML = "Time Range:";
newTableRowClock.appendChild(rowClockContentTitle);
let rowClockContent = document.createElement('td');
rowClockContent.className = 'romcell';
// rowClockContent.setAttribute('colspan', 2);
rowClockContent.appendChild(generateTimeDropDowns(value.task, 'Start', value.defaultAllowedStartHours, value.defaultAllowedStartMinutes, value.allowedStartHours, value.allowedStartMinutes));
rowClockContentSeparator = document.createElement('span');
rowClockContentSeparator.innerHTML = '&nbsp;-&nbsp;';
rowClockContent.appendChild(rowClockContentSeparator);
rowClockContent.appendChild(generateTimeDropDowns(value.task, 'End', value.defaultAllowedEndHours, value.defaultAllowedEndMinutes, value.allowedEndHours, value.allowedEndMinutes));
newTableRowClock.appendChild(rowClockContent);
serviceTable.appendChild(newTableRowClock);
// blocks tasks
let newTableRowBlocks = document.createElement('tr');
let rowBlocksContentTitle = document.createElement('td');
rowBlocksContentTitle.className = 'romcell romcell-headercell';
rowBlocksContentTitle.innerHTML = "Blocks:";
newTableRowBlocks.appendChild(rowBlocksContentTitle);
let rowBlocksContent = document.createElement('td');
rowBlocksContent.className = 'romcell';
// rowBlocksContent.setAttribute('colspan', 2);
let blocksString = "";
for (let i = 0; i < value.blocks.length; i++) {
if (blocksString.length > 0) { blocksString += ", "; }
blocksString += GetTaskFriendlyName(value.blocks[i]);
}
if (blocksString.length == 0) { blocksString = 'None'; }
rowBlocksContent.innerHTML = blocksString;
newTableRowBlocks.appendChild(rowBlocksContent);
serviceTable.appendChild(newTableRowBlocks);
// blocked by tasks
let newTableRowBlockedBy = document.createElement('tr');
let rowBlockedByContentTitle = document.createElement('td');
rowBlockedByContentTitle.className = 'romcell romcell-headercell';
rowBlockedByContentTitle.innerHTML = "Blocked By:";
newTableRowBlockedBy.appendChild(rowBlockedByContentTitle);
let rowBlockedByContent = document.createElement('td');
rowBlockedByContent.className = 'romcell';
// rowBlockedByContent.setAttribute('colspan', 2);
let BlockedByString = "";
for (let i = 0; i < value.blockedBy.length; i++) {
if (BlockedByString.length > 0) { BlockedByString += ", "; }
BlockedByString += GetTaskFriendlyName(value.blockedBy[i]);
}
if (BlockedByString.length == 0) { BlockedByString = 'None'; }
rowBlockedByContent.innerHTML = BlockedByString;
newTableRowBlockedBy.appendChild(rowBlockedByContent);
serviceTable.appendChild(newTableRowBlockedBy);
// complete row
targetTable.appendChild(serviceTable);
}
}
);
}
function generateTimeDropDowns(taskName, rangeName, defaultHour, defaultMinute, valueHour, valueMinute) {
let container = document.createElement('div');
container.style.display = 'inline';
let elementName = 'settings_tasktimers_time';
let hourSelector = document.createElement('input');
hourSelector.id = 'settings_tasktimers_' + taskName + '_' + rangeName + '_Hour';
hourSelector.name = elementName;
hourSelector.setAttribute('data-name', taskName);
hourSelector.setAttribute('type', 'number');
hourSelector.setAttribute('min', '0');
hourSelector.setAttribute('max', '23');
hourSelector.setAttribute('placeholder', defaultHour);
hourSelector.value = valueHour;
container.appendChild(hourSelector);
let separator = document.createElement('span');
separator.innerHTML = " : ";
container.appendChild(separator);
let minSelector = document.createElement('input');
minSelector.id = 'settings_tasktimers_' + taskName + '_' + rangeName + '_Minute';
minSelector.name = elementName;
minSelector.setAttribute('type', 'number');
minSelector.setAttribute('min', '0');
minSelector.setAttribute('max', '59');
minSelector.setAttribute('placeholder', defaultMinute);
minSelector.value = valueMinute;
container.appendChild(minSelector);
return container;
}
function saveTaskTimers() {
let timerValues = document.getElementsByName('settings_tasktimers_values');
let model = [];
for (let i = 0; i < timerValues.length; i++) {
let taskName = timerValues[i].getAttribute('data-name');
let taskEnabled = document.getElementById('settings_enabled_' + taskName).checked;
let taskIntervalObj = document.getElementById('settings_tasktimers_' + taskName);
let taskInterval = function () { if (taskIntervalObj.value) { return taskIntervalObj.value; } else { return taskIntervalObj.getAttribute('placeholder'); } };
let taskDaysRaw = $('#settings_alloweddays_' + taskName).select2('data');
let taskDays = [];
if (taskDaysRaw.length > 0) {
for (let d = 0; d < taskDaysRaw.length; d++) {
taskDays.push(taskDaysRaw[d].id);
}
} else {
taskDays.push("Monday");
}
let taskStartHourObj = document.getElementById('settings_tasktimers_' + taskName + '_Start_Hour');
let taskStartMinuteObj = document.getElementById('settings_tasktimers_' + taskName + '_Start_Minute');
let taskEndHourObj = document.getElementById('settings_tasktimers_' + taskName + '_End_Hour');
let taskEndMinuteObj = document.getElementById('settings_tasktimers_' + taskName + '_End_Minute');
let taskStartHour = function () { if (taskStartHourObj.value) { return taskStartHourObj.value; } else { return taskStartHourObj.getAttribute('placeholder'); } };
let taskStartMinute = function () { if (taskStartMinuteObj.value) { return taskStartMinuteObj.value; } else { return taskStartMinuteObj.getAttribute('placeholder'); } };
let taskEndHour = function () { if (taskEndHourObj.value) { return taskEndHourObj.value; } else { return taskEndHourObj.getAttribute('placeholder'); } };
let taskEndMinute = function () { if (taskEndMinuteObj.value) { return taskEndMinuteObj.value; } else { return taskEndMinuteObj.getAttribute('placeholder'); } };
model.push(
{
"task": taskName,
"enabled": taskEnabled,
"interval": taskInterval(),
"allowedDays": taskDays,
"allowedStartHours": taskStartHour(),
"allowedStartMinutes": taskStartMinute(),
"allowedEndHours": taskEndHour(),
"allowedEndMinutes": taskEndMinute()
}
);
}
ajaxCall(
'/api/v1/System/Settings/BackgroundTasks/Configuration',
'POST',
function (result) {
getBackgroundTaskTimers();
},
function (error) {
getBackgroundTaskTimers();
},
JSON.stringify(model)
);
}
function defaultTaskTimers() {
let taskEnabled = document.getElementsByName('settings_tasktimers_enabled');
for (let i = 0; i < taskEnabled.length; i++) {
taskEnabled[i].checked = true;
}
let taskTimerValues = document.getElementsByName('settings_tasktimers_values');
for (let i = 0; i < taskTimerValues.length; i++) {
taskTimerValues[i].value = taskTimerValues[i].getAttribute('data-default');
}
let taskAllowedDays = document.getElementsByName('settings_alloweddays');
for (let i = 0; i < taskAllowedDays.length; i++) {
let defaultSelections = taskAllowedDays[i].getAttribute('data-default').split(',');
$(taskAllowedDays[i]).val(defaultSelections);
$(taskAllowedDays[i]).trigger('change');
}
let taskTimes = document.getElementsByName('settings_tasktimers_time');
for (let i = 0; i < taskTimes.length; i++) {
taskTimes[i].value = taskTimes[i].getAttribute('placeholder');
}
saveTaskTimers();
}

View File

@@ -2,190 +2,105 @@
<h1 id="gametitle_label">Settings</h1>
</div>
<table cellspacing="0" style="width: 100%; vertical-align: top;">
<tr>
<th colspan="2">
<h3>Metadata Sources</h3>
</th>
</tr>
<tr>
<th style="width: 25%;">
Signature Source
</th>
<td>
<input type="radio" name="settings_signaturesource" id="settings_signaturesource_local" value="LocalOnly"
onclick="document.getElementById('settings_hasheoushost_row').style.display = 'none';">
<label for="settings_signaturesource_local">Local Only</label>
</td>
</tr>
<tr>
<td></td>
<td>
<input type="radio" name="settings_signaturesource" id="settings_signaturesource_hasheous" value="Hasheous"
onclick="document.getElementById('settings_hasheoushost_row').style.display = '';">
<label for="settings_signaturesource_hasheous">Hasheous</label>
</td>
</tr>
<tr id="settings_hasheoushost_row" style="display: none;">
<th>
Hasheous Host
</th>
<td>
<input type="url" id="settings_signaturesource_hasheoushost" style="width: 90%;">
</td>
</tr>
<tr>
<th>
<label for="settings_hasheoussubmit">Submit updates to Hasheous when fixing ROM matches</label>
</th>
<td>
<input type="checkbox" id="settings_hasheoussubmit" onchange="toggleHasheousAPIKey(this);">
</td>
</tr>
<tr id="settings_hasheousapikey_row" style="display: none;">
<th>
Hasheous API key
</th>
<td>
<textarea id="settings_hasheousapikey" rows="2" style="width: 90%;"></textarea>
</td>
</tr>
<tr>
<th colspan="2">
<h3>Logging</h3>
</th>
</tr>
<tr>
<th>
Write logs
</th>
<td>
<input type="radio" name="settings_logs_write" id="settings_logs_write_db" value="false"
checked="checked"><label for="settings_logs_write_db"> To database only
(default)</label>
</td>
</tr>
<tr>
<td></td>
<td>
<input type="radio" name="settings_logs_write" id="settings_logs_write_fs" value="true"><label
for="settings_logs_write_fs"> To database and disk</label>
</td>
</tr>
<tr>
<td colspan="2">&nbsp;</td>
</tr>
<tr>
<th>
Minimum log retention (days):
</th>
<td>
<input type="number" min="1" id="settings_logs_retention" />
</td>
</tr>
<tr>
<th colspan="2">
<h3>Emulator</h3>
</th>
</tr>
<tr>
<th><label for="settings_emulator_debug">Enable debug mode</label></th>
<td><input type="checkbox" name="settings_emulator" id="settings_emulator_debug" checked="checked" /></td>
</tr>
<tr>
<td colspan="2" style="text-align: right;">
<button id="settings_tasktimers_new" onclick="setSystemSettings();">Save</button>
</td>
</tr>
</table>
<script type="text/javascript">
function getSystemSettings() {
ajaxCall(
'/api/v1/System/Settings/System',
'GET',
function (result) {
var optionToSelect = 'settings_logs_write_db';
if (result.alwaysLogToDisk == true) {
optionToSelect = 'settings_logs_write_fs';
}
document.getElementById(optionToSelect).checked = true;
document.getElementById('settings_logs_retention').value = result.minimumLogRetentionPeriod;
document.getElementById('settings_emulator_debug').checked = result.emulatorDebugMode;
switch (result.signatureSource.source) {
case "LocalOnly":
document.getElementById('settings_signaturesource_local').checked = true;
break;
case "Hasheous":
document.getElementById('settings_signaturesource_hasheous').checked = true;
document.getElementById('settings_hasheoushost_row').style.display = '';
break;
}
document.getElementById('settings_signaturesource_hasheoushost').value = result.signatureSource.hasheousHost;
let hasheousSubmitCheck = document.getElementById('settings_hasheoussubmit');
if (result.signatureSource.hasheousSubmitFixes == true) {
hasheousSubmitCheck.checked = true;
}
document.getElementById('settings_hasheousapikey').innerHTML = result.signatureSource.hasheousAPIKey;
toggleHasheousAPIKey(hasheousSubmitCheck);
}
);
}
function setSystemSettings() {
var alwaysLogToDisk = false;
if ($("input[type='radio'][name='settings_logs_write']:checked").val() == "true") {
alwaysLogToDisk = true;
}
var retention = document.getElementById('settings_logs_retention');
var retentionValue = 0;
if (retention.value) {
retentionValue = retention.value;
} else {
retentionValue = 7;
}
var model = {
"alwaysLogToDisk": alwaysLogToDisk,
"minimumLogRetentionPeriod": Number(retentionValue),
"emulatorDebugMode": document.getElementById('settings_emulator_debug').checked,
"signatureSource": {
"Source": $("input[type='radio'][name='settings_signaturesource']:checked").val(),
"HasheousHost": document.getElementById('settings_signaturesource_hasheoushost').value,
"HasheousAPIKey": document.getElementById('settings_hasheousapikey').innerHTML,
"HasheousSubmitFixes": document.getElementById('settings_hasheoussubmit').checked
}
};
ajaxCall(
'/api/v1/System/Settings/System',
'POST',
function (result) {
getSystemSettings();
},
function (error) {
getSystemSettings();
},
JSON.stringify(model)
);
}
function toggleHasheousAPIKey(checkbox) {
let settings_hasheousapikey_row = document.getElementById('settings_hasheousapikey_row');
if (checkbox.checked == true) {
settings_hasheousapikey_row.style.display = '';
} else {
settings_hasheousapikey_row.style.display = 'none';
}
}
<div class="section">
<div class="section-header">Metadata Sources</div>
<div class="section-body">
<table>
<tr>
<td style="width: 25%;">
Signature Source
</td>
<td>
<input type="radio" name="settings_signaturesource" id="settings_signaturesource_local"
value="LocalOnly"
onclick="document.getElementById('settings_hasheoushost_row').style.display = 'none';">
<label for="settings_signaturesource_local">Local Only</label>
</td>
</tr>
<tr>
<td></td>
<td>
<input type="radio" name="settings_signaturesource" id="settings_signaturesource_hasheous"
value="Hasheous"
onclick="document.getElementById('settings_hasheoushost_row').style.display = '';">
<label for="settings_signaturesource_hasheous">Hasheous</label>
</td>
</tr>
<tr id="settings_hasheoushost_row" style="display: none;">
<td>
Hasheous Host
</td>
<td>
<input type="url" id="settings_signaturesource_hasheoushost" style="width: 90%;">
</td>
</tr>
<tr>
<td>
<label for="settings_hasheoussubmit">Submit updates to Hasheous when fixing ROM matches</label>
</td>
<td>
<input type="checkbox" id="settings_hasheoussubmit" onchange="toggleHasheousAPIKey(this);">
</td>
</tr>
<tr id="settings_hasheousapikey_row" style="display: none;">
<td>
Hasheous API key
</td>
<td>
<input type="text" id="settings_hasheousapikey" style="width: 90%;">
</td>
</tr>
</table>
</div>
<div class="section-header">Logging</div>
<div class="section-body">
<table>
<tr>
<td style="width: 25%;">
Write logs
</td>
<td>
<input type="radio" name="settings_logs_write" id="settings_logs_write_db" value="false"
checked="checked"><label for="settings_logs_write_db"> To database only
(default)</label>
</td>
</tr>
<tr>
<td></td>
<td>
<input type="radio" name="settings_logs_write" id="settings_logs_write_fs" value="true"><label
for="settings_logs_write_fs"> To database and disk</label>
</td>
</tr>
<tr>
<td colspan="2">&nbsp;</td>
</tr>
<tr>
<td style="width: 25%;">
Minimum log retention (days):
</td>
<td>
<input type="number" min="1" id="settings_logs_retention" />
</td>
</tr>
</table>
</div>
<div class="section-header">Emulator</div>
<div class="section-body">
<table>
<tr>
<td style="width: 25%;"><label for="settings_emulator_debug">Enable debug mode</label></td>
<td><input type="checkbox" name="settings_emulator" id="settings_emulator_debug" checked="checked" />
</td>
</tr>
</table>
</div>
<div style="text-align: right;">
<button id="settings_tasktimers_new" onclick="setSystemSettings();">Save</button>
</div>
</div>
<script>
// kick of page data load
getSystemSettings();
</script>

View File

@@ -0,0 +1,88 @@
function getSystemSettings() {
ajaxCall(
'/api/v1/System/Settings/System',
'GET',
function (result) {
console.log(result);
let optionToSelect = 'settings_logs_write_db';
if (result.alwaysLogToDisk == true) {
optionToSelect = 'settings_logs_write_fs';
}
document.getElementById(optionToSelect).checked = true;
document.getElementById('settings_logs_retention').value = result.minimumLogRetentionPeriod;
document.getElementById('settings_emulator_debug').checked = result.emulatorDebugMode;
switch (result.signatureSource.source) {
case "LocalOnly":
document.getElementById('settings_signaturesource_local').checked = true;
break;
case "Hasheous":
document.getElementById('settings_signaturesource_hasheous').checked = true;
document.getElementById('settings_hasheoushost_row').style.display = '';
break;
}
document.getElementById('settings_signaturesource_hasheoushost').value = result.signatureSource.hasheousHost;
let hasheousSubmitCheck = document.getElementById('settings_hasheoussubmit');
if (result.signatureSource.hasheousSubmitFixes == true) {
hasheousSubmitCheck.checked = true;
}
document.getElementById('settings_hasheousapikey').value = result.signatureSource.hasheousAPIKey;
toggleHasheousAPIKey(hasheousSubmitCheck);
}
);
}
function setSystemSettings() {
let alwaysLogToDisk = false;
if ($("input[type='radio'][name='settings_logs_write']:checked").val() == "true") {
alwaysLogToDisk = true;
}
let retention = document.getElementById('settings_logs_retention');
let retentionValue = 0;
if (retention.value) {
retentionValue = retention.value;
} else {
retentionValue = 7;
}
let model = {
"alwaysLogToDisk": alwaysLogToDisk,
"minimumLogRetentionPeriod": Number(retentionValue),
"emulatorDebugMode": document.getElementById('settings_emulator_debug').checked,
"signatureSource": {
"Source": $("input[type='radio'][name='settings_signaturesource']:checked").val(),
"HasheousHost": document.getElementById('settings_signaturesource_hasheoushost').value,
"HasheousAPIKey": document.getElementById('settings_hasheousapikey').value,
"HasheousSubmitFixes": document.getElementById('settings_hasheoussubmit').checked
}
};
console.log(model);
ajaxCall(
'/api/v1/System/Settings/System',
'POST',
function (result) {
getSystemSettings();
},
function (error) {
getSystemSettings();
},
JSON.stringify(model)
);
}
function toggleHasheousAPIKey(checkbox) {
let settings_hasheousapikey_row = document.getElementById('settings_hasheousapikey_row');
if (checkbox.checked == true) {
settings_hasheousapikey_row.style.display = '';
} else {
settings_hasheousapikey_row.style.display = 'none';
}
}

View File

@@ -2,271 +2,50 @@
<h1 id="gametitle_label">System</h1>
</div>
<h3>Background Tasks</h3>
<div id="system_tasks"></div>
<h3>Usage</h3>
<p><strong>Disk</strong></p>
<div id="system_disks"></div>
<p><strong>Library</strong></p>
<div>
<table cellspacing="0" style="width: 100%;">
<tr>
<td id="system_platforms"></td>
</tr>
<tr>
<td id="system_platforms_legend"></td>
</tr>
</table>
<div class="section">
<div class="section-header">Background Tasks</div>
<div id="system_tasks" class="section-body"></div>
</div>
<p><strong>Database</strong></p>
<div id="system_database"></div>
<h3>Local Database Signatures</h3>
<div id="system_signatures"></div>
<div class="section">
<div class="section-header">Disk Usage</div>
<div class="section-body">
<div id="system_disks"></div>
</div>
</div>
<div class="section">
<div class="section-header">Library</div>
<div class="section-body">
<table cellspacing="0" style="width: 100%;">
<tr>
<td id="system_platforms"></td>
</tr>
<tr>
<td id="system_platforms_legend"></td>
</tr>
</table>
</div>
</div>
<div class="section">
<div class="section-header">Database</div>
<div class="section-body">
<div id="system_database"></div>
</div>
</div>
<div class="section">
<div class="section-header">Local Database Signatures</div>
<div class="section-body">
<div id="system_signatures"></div>
</div>
</div>
<script type="text/javascript">
function SystemLoadStatus() {
ajaxCall('/api/v1.1/BackgroundTasks', 'GET', function (result) {
var newTable = document.createElement('table');
newTable.className = 'romtable';
newTable.setAttribute('cellspacing', 0);
newTable.appendChild(createTableRow(true, ['Task', 'Status', 'Interval<br/>(minutes)', 'Last Run Duration<br />(hh:mm:ss)', '', 'Last Run Start', 'Next Run Start', '']));
if (result) {
for (var i = 0; i < result.length; i++) {
if (result[i].itemState != "Disabled") {
var itemTypeName = GetTaskFriendlyName(result[i].itemType, result[i].options);
var itemStateName;
var itemLastStart;
var hasError = "";
if (result[i].hasErrors) {
if (result[i].hasErrors.errorType != null) {
hasError = " (" + result[i].hasErrors.errorType + ")";
}
}
if (result[i].isBlocked == false) {
switch (result[i].itemState) {
case 'NeverStarted':
itemStateName = "Never started";
itemLastStart = '-';
break;
case 'Stopped':
itemStateName = "Stopped";
itemLastStart = moment(result[i].lastRunTime).format("YYYY-MM-DD h:mm:ss a");
break;
case 'Running':
var progressPercent = "";
if (result[i].currentStateProgress) {
progressPercent = " (" + result[i].currentStateProgress + ")";
}
itemStateName = "Running" + progressPercent;
itemLastStart = moment(result[i].lastRunTime).format("YYYY-MM-DD h:mm:ss a");
break;
default:
itemStateName = "Unknown status";
itemLastStart = moment(result[i].lastRunTime).format("YYYY-MM-DD h:mm:ss a");
break;
}
} else {
itemStateName = "Blocked";
itemLastStart = moment(result[i].lastRunTime).format("YYYY-MM-DD h:mm:ss a");
}
itemStateName += hasError;
var itemInterval = result[i].interval;
var nextRunTime = moment(result[i].nextRunTime).format("YYYY-MM-DD h:mm:ss a");
var startButton = '';
if (userProfile.roles.includes("Admin")) {
if (result[i].allowManualStart == true && !["Running"].includes(result[i].itemState) && result[i].isBlocked == false) {
startButton = "<span id='startProcess' class='romstart' onclick='StartProcess(\"" + result[i].itemType + "\");'>Start</span>";
}
}
if (result[i].allowManualStart == false && result[i].removeWhenStopped == true) {
itemInterval = '';
nextRunTime = '';
}
var logLink = '';
if (result[i].correlationId) {
logLink = '<a href="/index.html?page=settings&sub=logs&correlationid=' + result[i].correlationId + '" class="romlink">View Log</a>';
}
var newRow = [
itemTypeName,
itemStateName,
itemInterval,
new Date(result[i].lastRunDuration * 1000).toISOString().slice(11, 19),
logLink,
itemLastStart,
nextRunTime,
startButton
];
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell'));
}
}
}
var targetDiv = document.getElementById('system_tasks');
targetDiv.innerHTML = '';
targetDiv.appendChild(newTable);
});
}
function SystemLoadSystemStatus() {
ajaxCall('/api/v1.1/System', 'GET', function (result) {
if (result) {
var totalLibrarySpace = 0;
// disks
var newTable = document.createElement('table');
newTable.className = 'romtable';
newTable.setAttribute('cellspacing', 0);
newTable.appendChild(createTableRow(true, ['Path', 'Library Size <div id="disk_LibSize" style="width: 10px; height: 10px; background-color: green;"></div>', 'Other <div id="disk_OtherSize" style="width: 10px; height: 10px; background-color: lightgreen;"></div>', 'Total Size <div id="disk_FreeSize" style="width: 10px; height: 10px; background-color: lightgray;"></div>']));
for (var i = 0; i < result.paths.length; i++) {
var spaceUsedByLibrary = result.paths[i].spaceUsed;
totalLibrarySpace += spaceUsedByLibrary;
var spaceUsedByOthers = result.paths[i].totalSpace - result.paths[i].spaceAvailable;
var newRow = [
result.paths[i].libraryPath,
formatBytes(spaceUsedByLibrary),
formatBytes(spaceUsedByOthers),
formatBytes(result.paths[i].totalSpace)
];
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell'));
var spaceRow = document.createElement('tr');
var spaceCell = document.createElement('td');
spaceCell.setAttribute('colspan', 4);
spaceCell.appendChild(BuildSpaceBar(spaceUsedByLibrary, spaceUsedByOthers, result.paths[i].totalSpace));
spaceRow.appendChild(spaceCell);
newTable.appendChild(spaceRow);
}
var targetDiv = document.getElementById('system_disks');
targetDiv.innerHTML = '';
targetDiv.appendChild(newTable);
BuildLibraryStatisticsBar(document.getElementById('system_platforms'), document.getElementById('system_platforms_legend'), result.platformStatistics, totalLibrarySpace);
// database
var newDbTable = document.createElement('table');
newDbTable.className = 'romtable';
newDbTable.setAttribute('cellspacing', 0);
newDbTable.appendChild(createTableRow(false, ['Database Size', formatBytes(result.databaseSize)]));
var targetDbDiv = document.getElementById('system_database');
targetDbDiv.innerHTML = '';
targetDbDiv.appendChild(newDbTable);
}
});
}
function BuildSpaceBar(LibrarySize, OtherSize, TotalSize) {
var newTable = document.createElement('table');
newTable.setAttribute('cellspacing', 0);
newTable.setAttribute('style', 'width: 100%; height: 10px;');
var newRow = document.createElement('tr');
var LibrarySizePercent = Math.floor(LibrarySize / TotalSize * 100);
var OtherSizePercent = Math.floor(OtherSize / TotalSize * 100);
var FreeSizePercent = Math.floor((LibrarySize + OtherSize) / TotalSize * 100);
var LibraryCell = document.createElement('td');
LibraryCell.setAttribute('style', 'width: ' + LibrarySizePercent + '%; background-color: green;');
var OtherCell = document.createElement('td');
OtherCell.setAttribute('style', 'width: ' + OtherSizePercent + '%; background-color: lightgreen;');
var FreeCell = document.createElement('td');
FreeCell.setAttribute('style', 'width: ' + FreeSizePercent + '%; background-color: lightgray;');
newRow.appendChild(LibraryCell);
newRow.appendChild(OtherCell);
newRow.appendChild(FreeCell);
newTable.appendChild(newRow);
return newTable;
}
function BuildLibraryStatisticsBar(TargetObject, TargetObjectLegend, LibraryStatistics, LibrarySize) {
TargetObject.innerHTML = '';
TargetObjectLegend.innerHTML = '';
var newTable = document.createElement('table');
newTable.setAttribute('cellspacing', 0);
newTable.setAttribute('style', 'width: 100%; height: 10px;');
var newRow = document.createElement('tr');
for (var i = 0; i < LibraryStatistics.length; i++) {
var platformSizePercent = LibraryStatistics[i].totalSize / LibrarySize * 100;
var platformSizeColour = intToRGB(hashCode(LibraryStatistics[i].platform));
var newCell = document.createElement('td');
newCell.setAttribute('style', 'min-width: 2px; width: ' + platformSizePercent + '%; background-color: #' + platformSizeColour);
newRow.appendChild(newCell);
var legend = document.createElement('div');
legend.className = 'legend_box';
var legendColour = document.createElement('div');
legendColour.className = 'legend_colour';
legendColour.setAttribute('style', 'background-color: #' + platformSizeColour + ';');
var legendLabel = document.createElement('div');
legendLabel.className = 'legend_label';
legendLabel.innerHTML = LibraryStatistics[i].platform + '<br />' + formatBytes(LibraryStatistics[i].totalSize) + '<br />Images: ' + LibraryStatistics[i].romCount;
legend.appendChild(legendColour);
legend.appendChild(legendLabel);
TargetObjectLegend.appendChild(legend);
}
newTable.appendChild(newRow);
TargetObject.appendChild(newTable);
}
function SystemSignaturesStatus() {
ajaxCall('/api/v1.1/Signatures/Status', 'GET', function (result) {
var newTable = document.createElement('table');
newTable.className = 'romtable';
newTable.setAttribute('cellspacing', 0);
newTable.appendChild(createTableRow(true, ['Sources', 'Platforms', 'Games', 'ROMs']));
if (result) {
var newRow = [
result.sources,
result.platforms,
result.games,
result.roms
];
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell'));
}
var targetDiv = document.getElementById('system_signatures');
targetDiv.innerHTML = '';
targetDiv.appendChild(newTable);
});
}
function StartProcess(itemType) {
ajaxCall('/api/v1.1/BackgroundTasks/' + itemType + '?ForceRun=true', 'GET', function (result) {
SystemLoadStatus();
});
}
// Load the system status
SystemLoadStatus();
setInterval(SystemLoadStatus, 3000);
setInterval(SystemLoadStatus, 2000);
SystemLoadSystemStatus();
setInterval(SystemLoadSystemStatus, 60000);
SystemSignaturesStatus();

View File

@@ -0,0 +1,297 @@
function SystemLoadStatus() {
ajaxCall('/api/v1.1/BackgroundTasks', 'GET', function (result) {
let newTable = document.createElement('table');
newTable.className = 'romtable';
newTable.setAttribute('cellspacing', 0);
newTable.appendChild(createTableRow(true, ['Task', 'Status', '', '', 'Interval<br/>(minutes)', 'Last Run Duration<br />(hh:mm:ss)', 'Last Run Start', 'Next Run Start', '']));
if (result) {
for (let i = 0; i < result.length; i++) {
if (result[i].itemState != "Disabled") {
let itemTypeName = GetTaskFriendlyName(result[i].itemType, result[i].options);
let itemStateName;
let itemLastStart;
let hasError = "";
if (result[i].hasErrors) {
if (result[i].hasErrors.errorType != null) {
// hasError = " (" + result[i].hasErrors.errorType + ")";
hasError = "<img src='/images/" + result[i].hasErrors.errorType + ".svg' class='banner_button_image' style='padding-top: 5px;' title='" + result[i].hasErrors.errorType + "'>";
}
}
if (result[i].isBlocked == false) {
if (result[i].force == true && result[i].itemState != "Running") {
itemStateName = "<div>Pending </div><div><progress></progress></div>";
itemLastStart = '-';
} else {
switch (result[i].itemState) {
case 'NeverStarted':
itemStateName = "Never started";
itemLastStart = moment(result[i].lastRunTime).format("YYYY-MM-DD h:mm:ss a");
break;
case 'Stopped':
itemStateName = "Stopped";
itemLastStart = moment(result[i].lastRunTime).format("YYYY-MM-DD h:mm:ss a");
break;
case 'Running':
itemStateName = "Running";
if (result[i].currentStateProgress) {
if (result[i].currentStateProgress.includes(" of ")) {
let progressParts = result[i].currentStateProgress.split(" of ");
itemStateName = "<div>Running " + result[i].currentStateProgress + "</div><div><progress value=\"" + progressParts[0] + "\" max=\"" + progressParts[1] + "\">" + result[i].currentStateProgress + "</progress></div>";
} else {
itemStateName = "Running (" + result[i].currentStateProgress + ")";
}
}
itemLastStart = moment(result[i].lastRunTime).format("YYYY-MM-DD h:mm:ss a");
break;
default:
itemStateName = "Unknown status";
itemLastStart = moment(result[i].lastRunTime).format("YYYY-MM-DD h:mm:ss a");
break;
}
}
} else {
itemStateName = "Blocked";
itemLastStart = moment(result[i].lastRunTime).format("YYYY-MM-DD h:mm:ss a");
}
let itemInterval = result[i].interval;
let nextRunTime = moment(result[i].nextRunTime).format("YYYY-MM-DD h:mm:ss a");
let startButton = '';
if (userProfile.roles.includes("Admin")) {
if (result[i].force == false) {
if (result[i].allowManualStart == true && !["Running"].includes(result[i].itemState) && result[i].isBlocked == false) {
startButton = "<img id='startProcess' class='taskstart' src='/images/start-task.svg' onclick='StartProcess(\"" + result[i].itemType + "\");' title='Start'>";
}
}
}
if (result[i].allowManualStart == false && result[i].removeWhenStopped == true) {
itemInterval = '';
nextRunTime = '';
}
let logLink = '';
if (result[i].correlationId) {
logLink = '<a href="/index.html?page=settings&sub=logs&correlationid=' + result[i].correlationId + '" class="romlink">Logs</a>';
}
let newRow = [
itemTypeName,
itemStateName,
hasError,
logLink,
itemInterval,
new Date(result[i].lastRunDuration * 1000).toISOString().slice(11, 19),
itemLastStart,
nextRunTime,
startButton
];
newTable.appendChild(createTableRow(false, newRow, 'romrow taskrow', 'romcell'));
}
}
}
let targetDiv = document.getElementById('system_tasks');
targetDiv.innerHTML = '';
targetDiv.appendChild(newTable);
});
}
function SystemLoadSystemStatus() {
ajaxCall('/api/v1.1/System', 'GET', function (result) {
if (result) {
let totalLibrarySpace = 0;
// disks
let newTable = document.createElement('table');
newTable.className = 'romtable';
newTable.setAttribute('cellspacing', 0);
newTable.appendChild(createTableRow(true, ['Path', 'Library Size <div id="disk_LibSize" style="width: 10px; height: 10px; background-color: green;"></div>', 'Other <div id="disk_OtherSize" style="width: 10px; height: 10px; background-color: lightgreen;"></div>', 'Total Size <div id="disk_FreeSize" style="width: 10px; height: 10px; background-color: lightgray;"></div>']));
for (let i = 0; i < result.paths.length; i++) {
let spaceUsedByLibrary = result.paths[i].spaceUsed;
totalLibrarySpace += spaceUsedByLibrary;
let spaceUsedByOthers = result.paths[i].totalSpace - result.paths[i].spaceAvailable;
let libraryRow = document.createElement('tbody');
libraryRow.className = 'romrow';
let titleRow = document.createElement('tr');
let titleCell = document.createElement('td');
titleCell.setAttribute('colspan', 4);
titleCell.innerHTML = '<strong>' + result.paths[i].name + '</strong>';
titleCell.className = 'romcell';
titleRow.appendChild(titleCell);
libraryRow.appendChild(titleRow);
let newRow = [
result.paths[i].libraryPath,
formatBytes(spaceUsedByLibrary),
formatBytes(spaceUsedByOthers),
formatBytes(result.paths[i].totalSpace)
];
libraryRow.appendChild(createTableRow(false, newRow, '', 'romcell'));
let spaceRow = document.createElement('tr');
let spaceCell = document.createElement('td');
spaceCell.setAttribute('colspan', 4);
spaceCell.appendChild(BuildSpaceBar(spaceUsedByLibrary, spaceUsedByOthers, result.paths[i].totalSpace));
spaceRow.appendChild(spaceCell);
libraryRow.appendChild(spaceRow);
newTable.appendChild(libraryRow);
}
let targetDiv = document.getElementById('system_disks');
targetDiv.innerHTML = '';
targetDiv.appendChild(newTable);
BuildLibraryStatisticsBar(document.getElementById('system_platforms'), document.getElementById('system_platforms_legend'), result.platformStatistics, totalLibrarySpace);
// database
let newDbTable = document.createElement('table');
newDbTable.className = 'romtable';
newDbTable.setAttribute('cellspacing', 0);
newDbTable.appendChild(createTableRow(false, ['Database Size', formatBytes(result.databaseSize)]));
let targetDbDiv = document.getElementById('system_database');
targetDbDiv.innerHTML = '';
targetDbDiv.appendChild(newDbTable);
}
});
}
function BuildSpaceBar(LibrarySize, OtherSize, TotalSize) {
let newTable = document.createElement('table');
newTable.setAttribute('cellspacing', 0);
newTable.setAttribute('style', 'width: 100%; height: 10px;');
let newRow = document.createElement('tr');
let LibrarySizePercent = Math.floor(LibrarySize / TotalSize * 100);
let OtherSizePercent = Math.floor(OtherSize / TotalSize * 100);
let FreeSizePercent = Math.floor((LibrarySize + OtherSize) / TotalSize * 100);
let LibraryCell = document.createElement('td');
LibraryCell.setAttribute('style', 'width: ' + LibrarySizePercent + '%; background-color: green;');
let OtherCell = document.createElement('td');
OtherCell.setAttribute('style', 'width: ' + OtherSizePercent + '%; background-color: lightgreen;');
let FreeCell = document.createElement('td');
FreeCell.setAttribute('style', 'width: ' + FreeSizePercent + '%; background-color: lightgray;');
newRow.appendChild(LibraryCell);
newRow.appendChild(OtherCell);
newRow.appendChild(FreeCell);
newTable.appendChild(newRow);
return newTable;
}
function BuildLibraryStatisticsBar(TargetObject, TargetObjectLegend, LibraryStatistics, LibrarySize) {
TargetObject.innerHTML = '';
TargetObjectLegend.innerHTML = '';
let newTable = document.createElement('div');
newTable.setAttribute('cellspacing', 0);
newTable.setAttribute('style', 'width: 100%; height: 10px;');
let newRow = document.createElement('div');
newRow.setAttribute('style', 'display: flex; width: 100%;');
for (let i = 0; i < LibraryStatistics.length; i++) {
let platformSizePercent = LibraryStatistics[i].totalSize / LibrarySize * 100;
let platformSizeColour = intToRGB(hashCode(LibraryStatistics[i].platform));
let newCell = document.createElement('div');
let segmentId = 'platform_' + LibraryStatistics[i].platform;
newCell.id = segmentId;
newCell.setAttribute('style', 'display: inline; height: 10px; min-width: 1px; width: ' + platformSizePercent + '%; background-color: #' + platformSizeColour);
// newCell.innerHTML = '&nbsp;';
newRow.appendChild(newCell);
let legend = document.createElement('div');
legend.id = 'legend_' + LibraryStatistics[i].platform;
legend.className = 'legend_box';
let legendColour = document.createElement('div');
let colourId = 'colour_' + LibraryStatistics[i].platform;
legendColour.id = colourId;
legendColour.className = 'legend_colour';
legendColour.setAttribute('style', 'background-color: #' + platformSizeColour + ';');
let legendLabel = document.createElement('div');
legendLabel.className = 'legend_label';
legendLabel.innerHTML = '<strong>' + LibraryStatistics[i].platform + '</strong><br />' + formatBytes(LibraryStatistics[i].totalSize) + '<br />ROMs: ' + LibraryStatistics[i].romCount;
// event listeners
legend.addEventListener('mouseenter', function () {
let segment = document.getElementById(segmentId);
segment.style.outline = '2px solid #' + platformSizeColour;
segment.style.outlineOffset = '0px';
segment.style.zIndex = '1';
segment.style.boxShadow = '0px 0px 10px 0px #' + platformSizeColour;
let legendColour = document.getElementById(colourId);
legendColour.style.outline = '2px solid #' + platformSizeColour;
legendColour.style.outlineOffset = '0px';
legendColour.style.zIndex = '1';
legendColour.style.boxShadow = '0px 0px 10px 0px #' + platformSizeColour;
});
legend.addEventListener('mouseleave', function () {
let segment = document.getElementById(segmentId);
segment.style.outline = 'none';
segment.style.outlineOffset = '0px';
segment.style.zIndex = '0';
segment.style.boxShadow = 'none';
let legendColour = document.getElementById(colourId);
legendColour.style.outline = 'none';
legendColour.style.outlineOffset = '0px';
legendColour.style.zIndex = '0';
legendColour.style.boxShadow = 'none';
});
legend.appendChild(legendColour);
legend.appendChild(legendLabel);
TargetObjectLegend.appendChild(legend);
}
newTable.appendChild(newRow);
TargetObject.appendChild(newTable);
}
function SystemSignaturesStatus() {
ajaxCall('/api/v1.1/Signatures/Status', 'GET', function (result) {
let newTable = document.createElement('table');
newTable.className = 'romtable';
newTable.setAttribute('cellspacing', 0);
newTable.appendChild(createTableRow(true, ['Sources', 'Platforms', 'Games', 'ROMs']));
if (result) {
let newRow = [
result.sources,
result.platforms,
result.games,
result.roms
];
newTable.appendChild(createTableRow(false, newRow, 'romrow', 'romcell'));
}
let targetDiv = document.getElementById('system_signatures');
targetDiv.innerHTML = '';
targetDiv.appendChild(newTable);
});
}
function StartProcess(itemType) {
ajaxCall('/api/v1.1/BackgroundTasks/' + itemType + '?ForceRun=true', 'GET', function (result) {
SystemLoadStatus();
});
}

View File

@@ -2,100 +2,19 @@
<h1 id="gametitle_label">Users</h1>
</div>
<button id="settings_users_new" value="New User" style="float: right;" onclick="showSubDialog('settingsusernew');">New User</button>
<div id="settings_users_table_container">
<div class="section">
<div class="section-body">
<div id="settings_users_table_container">
</div>
<div style="text-align: right;"><button id="settings_users_new" value="New User">New
User</button>
</div>
</div>
</div>
<script type="text/javascript">
function GetUsers() {
var targetDiv = document.getElementById('settings_users_table_container');
targetDiv.innerHTML = '';
ajaxCall(
'/api/v1.1/Account/Users',
'GET',
function(result) {
var newTable = document.createElement('table');
newTable.className = 'romtable';
newTable.style.width = '100%';
newTable.cellSpacing = 0;
newTable.appendChild(
createTableRow(
true,
[
'',
'Email',
'Role',
'Age Restriction',
''
],
'',
''
)
);
for (var i = 0; i < result.length; i++) {
var userAvatar = document.createElement('img');
userAvatar.className = "user_list_icon";
if (result[i].avatar != "00000000-0000-0000-0000-000000000000") {
userAvatar.setAttribute("src", "/api/v1.1/Account/Avatar/" + result[i].avatar + ".jpg");
} else {
userAvatar.setAttribute("src", "/images/user.svg");
userAvatar.classList.add("user_list_icon_reversed");
}
var roleDiv = document.createElement('div');
var roleItem = CreateBadge(result[i].highestRole);
roleDiv.appendChild(roleItem);
var ageRestrictionPolicyDescription = document.createElement('div');
if (result[i].securityProfile != null) {
if (result[i].securityProfile.ageRestrictionPolicy != null) {
var IncludeUnratedText = '';
if (result[i].securityProfile.ageRestrictionPolicy.includeUnrated == true) {
IncludeUnratedText = " &#43; Unclassified titles";
}
var restrictionText = result[i].securityProfile.ageRestrictionPolicy.maximumAgeRestriction + IncludeUnratedText;
ageRestrictionPolicyDescription = CreateBadge(restrictionText);
}
}
var editButton = '';
var deleteButton = '';
if (userProfile.userId != result[i].id) {
editButton = '<a href="#" onclick="showDialog(\'settingsuseredit\', \'' + result[i].id + '\');" class="romlink"><img src="/images/edit.svg" class="banner_button_image" alt="Edit" title="Edit" /></a>';
deleteButton = '<a href="#" onclick="showSubDialog(\'settingsuserdelete\', \'' + result[i].id + '\');" class="romlink"><img src="/images/delete.svg" class="banner_button_image" alt="Delete" title="Delete" /></a>';
}
newTable.appendChild(
createTableRow(
false,
[
userAvatar,
result[i].emailAddress,
roleDiv,
ageRestrictionPolicyDescription,
'<div style="text-align: right;">' + editButton + deleteButton + '</div>'
],
'romrow',
'romcell'
)
);
}
targetDiv.appendChild(newTable);
}
);
}
// Load the users table
SetupPage();
GetUsers();
</script>

View File

@@ -0,0 +1,590 @@
function SetupPage() {
// set up new user button
let newUserButton = document.getElementById('settings_users_new');
newUserButton.addEventListener('click', function () {
let userNew = new UserNew();
userNew.open();
});
}
function GetUsers() {
console.log("Loading users...");
let targetDiv = document.getElementById('settings_users_table_container');
targetDiv.innerHTML = '';
ajaxCall(
'/api/v1.1/Account/Users',
'GET',
function (result) {
let newTable = document.createElement('table');
newTable.className = 'romtable';
newTable.style.width = '100%';
newTable.cellSpacing = 0;
newTable.appendChild(
createTableRow(
true,
[
'',
'Email',
'Role',
'Age Restriction',
''
],
'',
''
)
);
for (let i = 0; i < result.length; i++) {
let userAvatar = new Avatar(result[i].profileId, 32, 32, true);
userAvatar.classList.add("user_list_icon");
let roleDiv = document.createElement('div');
let roleItem = CreateBadge(result[i].highestRole);
roleDiv.appendChild(roleItem);
let ageRestrictionPolicyDescription = document.createElement('div');
if (result[i].securityProfile != null) {
if (result[i].securityProfile.ageRestrictionPolicy != null) {
let IncludeUnratedText = '';
if (result[i].securityProfile.ageRestrictionPolicy.includeUnrated == true) {
IncludeUnratedText = " &#43; Unclassified titles";
}
let restrictionText = result[i].securityProfile.ageRestrictionPolicy.maximumAgeRestriction + IncludeUnratedText;
ageRestrictionPolicyDescription = CreateBadge(restrictionText);
}
}
let controls = document.createElement('div');
controls.style.textAlign = 'right';
let editButton = '';
let deleteButton = '';
if (userProfile.userId != result[i].id) {
editButton = document.createElement('a');
editButton.href = '#';
editButton.addEventListener('click', () => {
// showDialog('settingsuseredit', result[i].id);
let userEdit = new UserEdit(result[i].id, GetUsers);
userEdit.open();
});
editButton.classList.add('romlink');
let editButtonImage = document.createElement('img');
editButtonImage.src = '/images/edit.svg';
editButtonImage.classList.add('banner_button_image');
editButtonImage.alt = 'Edit';
editButtonImage.title = 'Edit';
editButton.appendChild(editButtonImage);
controls.appendChild(editButton);
deleteButton = document.createElement('a');
deleteButton.href = '#';
deleteButton.addEventListener('click', () => {
let warningDialog = new MessageBox("Delete User", "Are you sure you want to delete this user?<br /><br /><strong>Warning</strong>: This cannot be undone!");
warningDialog.addButton(new ModalButton("OK", 2, warningDialog, async (callingObject) => {
fetch("/api/v1.1/Account/Users/" + result[i].id, {
method: 'DELETE'
}).then(async response => {
if (response.ok) {
GetUsers();
callingObject.msgDialog.close();
} else {
let result = await response.json();
let warningDialog = new MessageBox("Delete User Error", "An error occurred while deleting the user.");
warningDialog.open();
}
});
}));
warningDialog.addButton(new ModalButton("Cancel", 0, warningDialog, async (callingObject) => {
callingObject.msgDialog.close();
}));
warningDialog.open();
});
deleteButton.classList.add('romlink');
let deleteButtonImage = document.createElement('img');
deleteButtonImage.src = '/images/delete.svg';
deleteButtonImage.classList.add('banner_button_image');
deleteButtonImage.alt = 'Delete';
deleteButtonImage.title = 'Delete';
deleteButton.appendChild(deleteButtonImage);
controls.appendChild(deleteButton);
}
newTable.appendChild(
createTableRow(
false,
[
userAvatar,
result[i].emailAddress,
roleDiv,
ageRestrictionPolicyDescription,
controls
],
'romrow',
'romcell'
)
);
}
targetDiv.appendChild(newTable);
}
);
}
class UserNew {
constructor() {
}
async open() {
// Create the modal
this.dialog = await new Modal("usernew");
await this.dialog.BuildModal();
// setup the dialog
this.dialog.modalElement.querySelector('#modal-header-text').innerHTML = "New User";
this.dialog.modalElement.style = 'width: 550px; height: 380px; min-width: unset; min-height: unset; max-width: unset; max-height: unset;';
// setup email check
this.email = this.dialog.modalElement.querySelector('#email-address');
this.email_error = this.dialog.modalElement.querySelector('#email-error');
this.EmailCheck = new EmailCheck(this.email, this.email_error);
// setup password check
this.password_new = this.dialog.modalElement.querySelector('#new-password');
this.password_confirm = this.dialog.modalElement.querySelector('#confirm-new-password');
this.password_error = this.dialog.modalElement.querySelector('#password-error');
this.PasswordCheck = new PasswordCheck(this.password_new, this.password_confirm, this.password_error);
// add the ok button
let okButton = new ModalButton("OK", 1, this, async function (callingObject) {
if (!await EmailCheck.CheckEmail(callingObject.EmailCheck, callingObject.email)) {
// display an error
let warningDialog = new MessageBox("New User Error", "Invalid email address. Please correct the errors before continuing.");
warningDialog.open();
return;
}
if (!PasswordCheck.CheckPasswords(callingObject.PasswordCheck, callingObject.password_new, callingObject.password_confirm)) {
// display an error
let warningDialog = new MessageBox("New User Error", "The password doesn't meet the requirements. Please correct the errors before continuing.");
warningDialog.open();
return;
}
// create the new user
var model = {
"userName": callingObject.email.value,
"email": callingObject.email.value,
"password": callingObject.password_new.value,
"confirmPassword": callingObject.password_confirm.value
}
fetch("/api/v1.1/Account/Users", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(model)
}).then(async response => {
if (response.ok) {
let result = await response.json();
GetUsers();
callingObject.dialog.close();
} else {
let result = await response.json();
let warningDialog = new MessageBox("New User Error", "An error occurred while creating the user. Check that the email address is valid and the password meets the requirements.");
warningDialog.open();
}
});
});
this.dialog.addButton(okButton);
// add the cancel button
let cancelButton = new ModalButton("Cancel", 0, this, async function (callingObject) {
callingObject.dialog.close();
});
this.dialog.addButton(cancelButton);
// show the dialog
await this.dialog.open();
}
}
class UserEdit {
constructor(UserId, OkCallback, CancelCallback) {
this.userId = UserId;
this.okCallback = OkCallback;
this.cancelCallback = CancelCallback;
}
async open() {
// Create the modal
this.dialog = await new Modal("useredit");
await this.dialog.BuildModal();
await fetch("/api/v1.1/Account/Users/" + this.userId, {
method: 'GET'
}).then(async response => {
if (response.ok) {
let result = await response.json();
this.user = result;
} else {
let result = await response.json();
let warningDialog = new MessageBox("Edit User Error", "An error occurred while retrieving the user.");
warningDialog.open();
}
});
// setup the dialog
if (this.user.profileId == "00000000-0000-0000-0000-000000000000") {
this.dialog.modalElement.querySelector('#modal-header-text').innerHTML = this.user.emailAddress;
} else {
await fetch("/api/v1.1/UserProfile/" + this.user.profileId, {
method: 'GET'
}).then(async response => {
if (response.ok) {
let result = await response.json();
this.profile = result;
this.dialog.modalElement.querySelector('#modal-header-text').innerHTML = this.profile.displayName + ' (' + this.user.emailAddress + ')';
} else {
this.dialog.modalElement.querySelector('#modal-header-text').innerHTML = this.user.emailAddress;
}
});
}
// setup general page
this.dialog.modalElement.querySelector('#user-id').innerHTML = this.user.id;
let userProfileCard = new ProfileCard(this.user.profileId, true);
if (this.user.lockoutEnabled === true) {
this.dialog.modalElement.querySelector('#user-lockedout').innerHTML = 'Locked';
this.dialog.modalElement.querySelector('#user-lockedout').style.backgroundColor = 'red';
this.dialog.modalElement.querySelector('#user-lockedout-end').innerHTML = 'until ' + new Date(this.user.lockoutEnd).toLocaleString();
} else {
this.dialog.modalElement.querySelector('#user-lockedout').innerHTML = 'Unlocked';
this.dialog.modalElement.querySelector('#user-lockedout').style.backgroundColor = '';
this.dialog.modalElement.querySelector('#user-lockedout-end').innerHTML = '';
}
this.dialog.modalElement.querySelector('#user-profile-card').appendChild(userProfileCard);
// set user role
this.role_Player = this.dialog.modalElement.querySelector('#settings_user_role_player');
this.role_Player.addEventListener('change', () => {
this.UpdateRolePermissionsDisplay();
});
this.role_Gamer = this.dialog.modalElement.querySelector('#settings_user_role_gamer');
this.role_Gamer.addEventListener('change', () => {
this.UpdateRolePermissionsDisplay();
});
this.role_Admin = this.dialog.modalElement.querySelector('#settings_user_role_admin');
this.role_Admin.addEventListener('change', () => {
this.UpdateRolePermissionsDisplay();
});
this.dialog.modalElement.querySelector('#settings_user_role_' + this.user.highestRole.toLowerCase()).checked = true;
this.UpdateRolePermissionsDisplay();
this.rolePermTable = this.dialog.modalElement.querySelector('#role-permissions-table');
this.rolePermCover = this.dialog.modalElement.querySelector('#role-permissions-expand');
this.rolePermLink = this.dialog.modalElement.querySelector('#role-permissions-expand-link');
this.rolePermLink.addEventListener('click', () => {
if (Array.from(this.rolePermTable.classList).includes('collapsed')) {
this.rolePermTable.classList.remove('collapsed');
this.rolePermTable.classList.add('expanded');
this.rolePermCover.classList.remove('collapsed');
this.rolePermCover.classList.add('expanded');
this.rolePermLink.innerHTML = 'Hide details...';
} else {
this.rolePermTable.classList.remove('expanded');
this.rolePermTable.classList.add('collapsed');
this.rolePermCover.classList.remove('expanded');
this.rolePermCover.classList.add('collapsed');
this.rolePermLink.innerHTML = 'Show details...';
}
});
// setup age restriction tab
let ageRestrictionPolicyBox = this.dialog.modalElement.querySelector('#settings_user_agerestrictions');
let ageRestrictionPolicyTable = document.createElement('table');
for (let ageGroup in AgeRatingGroups) {
let tRow = document.createElement('tr');
let tCell = document.createElement('td');
let ageGroupRadio = document.createElement('input');
ageGroupRadio.type = 'radio';
ageGroupRadio.name = 'ageGroup';
ageGroupRadio.value = ageGroup;
ageGroupRadio.id = 'ageGroup_' + ageGroup;
ageGroupRadio.addEventListener('change', () => {
this.UpdateAssignedAgeGroupDisplay();
});
tCell.appendChild(ageGroupRadio);
let ageGroupLabel = document.createElement('label');
ageGroupLabel.htmlFor = 'ageGroup_' + ageGroup;
ageGroupLabel.innerHTML = ageGroup;
tCell.appendChild(ageGroupLabel);
tRow.appendChild(tCell);
ageRestrictionPolicyTable.appendChild(tRow);
}
// add allow unclassified titles checkbox
let tRow = document.createElement('tr');
let tCell = document.createElement('td');
let includeUnratedCheckbox = document.createElement('input');
includeUnratedCheckbox.type = 'checkbox';
includeUnratedCheckbox.id = 'includeUnrated';
includeUnratedCheckbox.addEventListener('change', () => {
this.UpdateAssignedAgeGroupDisplay();
});
tCell.appendChild(includeUnratedCheckbox);
let includeUnratedLabel = document.createElement('label');
includeUnratedLabel.htmlFor = 'includeUnrated';
includeUnratedLabel.innerHTML = 'Include unrated titles';
tCell.appendChild(includeUnratedLabel);
tRow.appendChild(tCell);
ageRestrictionPolicyTable.appendChild(tRow);
ageRestrictionPolicyBox.appendChild(ageRestrictionPolicyTable);
this.dialog.modalElement.querySelector('#ageGroup_' + this.user.securityProfile.ageRestrictionPolicy.maximumAgeRestriction).checked = true;
if (this.user.securityProfile.ageRestrictionPolicy.includeUnrated === true) {
this.dialog.modalElement.querySelector('#includeUnrated').checked = true;
}
this.UpdateAssignedAgeGroupDisplay();
this.agePermTable = this.dialog.modalElement.querySelector('#settings_user_agerestrictions_preview');
this.agePermCover = this.dialog.modalElement.querySelector('#settings_user_agerestrictions_expand');
this.agePermLink = this.dialog.modalElement.querySelector('#settings_user_agerestrictions_expand-link');
this.agePermLink.addEventListener('click', () => {
if (Array.from(this.agePermTable.classList).includes('collapsed')) {
this.agePermTable.classList.remove('collapsed');
this.agePermTable.classList.add('expanded');
this.agePermCover.classList.remove('collapsed');
this.agePermCover.classList.add('expanded');
this.agePermLink.innerHTML = 'Hide details...';
} else {
this.agePermTable.classList.remove('expanded');
this.agePermTable.classList.add('collapsed');
this.agePermCover.classList.remove('expanded');
this.agePermCover.classList.add('collapsed');
this.agePermLink.innerHTML = 'Show details...';
}
});
// set up the password change form
this.password_new = this.dialog.modalElement.querySelector('#new-password');
this.password_confirm = this.dialog.modalElement.querySelector('#confirm-new-password');
this.password_error = this.dialog.modalElement.querySelector('#password-error');
this.PasswordCheck = new PasswordCheck(this.password_new, this.password_confirm, this.password_error);
// create the ok button
let okButton = new ModalButton("OK", 1, this, async function (callingObject) {
// check if a new password has been entered
if (callingObject.password_new.value.length > 0 && callingObject.password_confirm.value.length > 0) {
// check if the new password meets the rules
if (!PasswordCheck.CheckPasswords(callingObject.PasswordCheck, callingObject.password_new, callingObject.password_confirm)) {
// display an error
let warningDialog = new MessageBox("Password Reset Error", "The new password does not meet the requirements.");
warningDialog.open();
return;
}
// requirements met, reset the password
let model = {
newPassword: callingObject.password_new.value,
confirmPassword: callingObject.password_confirm.value
};
let changeSuccessfull = false;
await fetch("/api/v1.1/Account/Users/" + callingObject.userId + "/Password", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(model)
}).then(async response => {
if (!response.ok) {
// handle the error
console.error("Error updating password:");
console.error(response);
let warningDialog = new MessageBox("Password Reset Error", "The password reset failed. Check the current password and try again.");
warningDialog.open();
changeSuccessfull = false;
return;
} else {
// clear the password fields
callingObject.password_new.value = "";
callingObject.password_confirm.value = "";
callingObject.password_error.innerHTML = "";
changeSuccessfull = true;
}
});
if (changeSuccessfull == false) {
return;
}
}
// set the role
let selectedRole = callingObject.dialog.modalElement.querySelector('input[name="settings_user_role"]:checked').value.toLowerCase();
await fetch("/api/v1.1/Account/Users/" + callingObject.userId + "/Roles?RoleName=" + selectedRole, {
method: 'POST'
}).then(async response => {
if (!response.ok) {
// handle the error
console.error("Error updating role:");
console.error(response);
let warningDialog = new MessageBox("Role Update Error", "The role update failed. Check the role and try again.");
warningDialog.open();
return;
}
});
// set the security profile
let securityProfile = {
"ageRestrictionPolicy": {
"maximumAgeRestriction": callingObject.dialog.modalElement.querySelector('input[name="ageGroup"]:checked').value,
"includeUnrated": callingObject.dialog.modalElement.querySelector('#includeUnrated').checked
}
};
await fetch("/api/v1.1/Account/Users/" + callingObject.userId + "/SecurityProfile", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(securityProfile)
}).then(async response => {
if (!response.ok) {
// handle the error
console.error("Error updating security profile:");
console.error(response);
let warningDialog = new MessageBox("Security Profile Update Error", "The security profile update failed. Check the settings and try again.");
warningDialog.open();
return;
}
});
if (callingObject.okCallback) {
callingObject.okCallback();
}
callingObject.dialog.close();
});
this.dialog.addButton(okButton);
// create the cancel button
let cancelButton = new ModalButton("Cancel", 0, this, function (callingObject) {
if (callingObject.cancelCallback) {
callingObject.cancelCallback();
}
callingObject.dialog.close();
});
this.dialog.addButton(cancelButton);
// show the dialog
this.dialog.open();
}
UpdateRolePermissionsDisplay() {
// get selected role
let selectedRole = this.dialog.modalElement.querySelector('input[name="settings_user_role"]:checked').value.toLowerCase();
// get the player role icons
let playerPermssions = this.dialog.modalElement.querySelectorAll('td[name="role-player"]');
playerPermssions.forEach(element => {
if (selectedRole == 'player') {
element.style.display = '';
} else {
element.style.display = 'none';
}
});
// get the gamer role icons
let gamerPermssions = this.dialog.modalElement.querySelectorAll('td[name="role-gamer"]');
gamerPermssions.forEach(element => {
if (selectedRole == 'gamer') {
element.style.display = '';
} else {
element.style.display = 'none';
}
});
// get the admin role icons
let adminPermssions = this.dialog.modalElement.querySelectorAll('td[name="role-admin"]');
adminPermssions.forEach(element => {
if (selectedRole == 'admin') {
element.style.display = '';
} else {
element.style.display = 'none';
}
});
}
UpdateAssignedAgeGroupDisplay() {
// get the selected age group
let selectedAgeGroup = this.dialog.modalElement.querySelector('input[name="ageGroup"]:checked').value;
let ageGroupList = [];
switch (selectedAgeGroup) {
case "Adult":
ageGroupList = ["Child", "Teen", "Mature", "Adult"];
break;
case "Mature":
ageGroupList = ["Child", "Teen", "Mature"];
break;
case "Teen":
ageGroupList = ["Child", "Teen"];
break;
case "Child":
ageGroupList = ["Child"];
break;
default:
break;
}
// get target div
let assignedAgeGroup = this.dialog.modalElement.querySelector('#settings_user_agerestrictions_preview');
assignedAgeGroup.innerHTML = '';
// generate restrictions table
let ageRestrictionPolicyTable = document.createElement('table');
ageRestrictionPolicyTable.classList.add('romtable');
ageRestrictionPolicyTable.setAttribute('cellspacing', '0');
for (const [key, value] of Object.entries(ClassificationBoards)) {
let thRow = document.createElement('tr');
let thCell = document.createElement('th');
thCell.innerHTML = value;
thRow.appendChild(thCell);
ageRestrictionPolicyTable.appendChild(thRow);
// add age rating icons
let trRow = document.createElement('tr');
let tdCell = document.createElement('td');
for (let i = 0; i < ageGroupList.length; i++) {
let ageRatingBadgeIndexes = AgeRatingGroups[ageGroupList[i]][key];
for (let j = 0; j < ageRatingBadgeIndexes.length; j++) {
let ageRatingBatch = document.createElement('img');
ageRatingBatch.src = '/images/Ratings/' + key + '/' + AgeRatingStrings[ageRatingBadgeIndexes[j]] + '.svg';
ageRatingBatch.classList.add('rating_image_mini');
ageRatingBatch.setAttribute('title', ClassificationRatings[AgeRatingStrings[ageRatingBadgeIndexes[j]]]);
tdCell.appendChild(ageRatingBatch);
}
ageRestrictionPolicyTable.appendChild(trRow);
}
trRow.appendChild(tdCell);
ageRestrictionPolicyTable.appendChild(trRow);
}
assignedAgeGroup.appendChild(ageRestrictionPolicyTable);
}
}