Fixes from extensive testing.

This commit is contained in:
dlandon
2024-05-26 08:39:31 -05:00
parent b14922734a
commit 32c769e6bd
+247 -136
View File
@@ -28,7 +28,7 @@ if ($name == "") {
"splitLevel" => "",
"include" => "",
"exclude" => "",
"useCache" => "no",
"useCache" => "",
"cachePool" => "",
"cachePool2" => "",
"cow" => "auto"
@@ -46,7 +46,26 @@ if ($name == "") {
$poolsOnly = ((int)$var['SYS_ARRAY_SLOTS'] <= 2) ? true : false;
/* Check for non existent pool device. */
if ($share['cachePool'] && !in_array($share['cachePool'],$pools)) $share['useCache'] = "no";
if ($share['cachePool'] && !in_array($share['cachePool'], $pools)) {
$poolDefined = false;
$share['useCache'] = $share['cachePool2'] ? "yes" : ($poolsOnly ? "no" : "yes");
} else {
$share['useCache'] = $share['useCache'] ?: ($poolsOnly ? "only" : "no");
$poolDefined = true;
}
/* Check for pool 2 (or array) being defined. */
if ((($share['useCache'] == "yes") || ($share['useCache'] == "prefer")) && ($poolsOnly) && (!$share['cachePool2'])) {
$poolDefined2 = false;
$share['useCache'] = "yes";
} else if ($share['cachePool2']) {
$poolDefined2 = in_array($share['cachePool2'], $pools);
} else {
$poolDefined2 = true;
}
$cachePoolCapitalized = ucfirst($share['cachePool']);
$cachePoolCapitalized2 = $share['cachePool2'] ? ucfirst($share['cachePool2']) : _("Array");
function globalInclude($name) {
global $var;
@@ -189,8 +208,6 @@ function fsSize() {
$fsSize[$pool] = _var($disks[$pool], 'fsSize', 0);
}
@file_put_contents("/tmp/fsSize", json_encode($fsSize, JSON_PRETTY_PRINT));
/* Return the filesystem sizes as a JSON encoded string */
return json_encode($fsSize);
}
@@ -367,7 +384,10 @@ _(Primary storage (for new files and folders))_:
<?foreach ($pools as $pool):?>
<?if ($disks[$pool]['devices']) echo mk_option(primary(),$pool,my_disk($pool),$disks[$pool]['shareEnabled']=='yes'?"":"disabled")?>
<?endforeach;?>
</select>
<?if ($share['cachePool']):?>
<option id="cachePoolOption" value="<?= $share['cachePool'] ?>" disabled><?= $cachePoolCapitalized ?></option>
<?endif;?>
</select><span id="cachePoolMessage" style="display: none; color: red;"></span>
:share_edit_primary_storage_help:
@@ -434,7 +454,10 @@ _(Secondary storage)_:
<?foreach ($pools as $pool):?>
<?if ($disks[$pool]['devices']) echo mk_option(secondary(),$pool,my_disk($pool),$disks[$pool]['shareEnabled']=='yes'?"":"disabled")?>
<?endforeach;?>
</select>
<?if ($share['cachePool2']):?>
<option id="cachePoolOption2" value="<?= $share['cachePool2'] ?>" disabled><?= $cachePoolCapitalized2 ?></option>
<?endif;?>
</select><span id="cachePoolMessage2" style="display: none; color: red;"></span>
:share_edit_secondary_storage_help:
@@ -521,6 +544,14 @@ _(Delete)_<input type="checkbox" name="confirmDelete" onchange="chkDelete(this.f
<script>
var form = document.share_edit;
/* Primary variables to check for valid selection of missing pool. */
var changeMadePrimary = false;
var checkRequiredPrimary = false;
/* Secondary variables to check for valid selection of missing pool. */
var changeMadeSecondary = false;
var checkRequiredSecondary = false;
function initDropdown(forceInit) {
if (forceInit) {
destroyDropdownIfExists('#s1');
@@ -582,17 +613,22 @@ function z(i) {
function updateScreen(cache, slow) {
const secondaryDropdown = document.getElementById('secondary');
const secondaryValue = secondaryDropdown.value;
const primaryDropdown = document.getElementById('primary');
const primaryValue = primaryDropdown.value;
const poolsOnly = <?= $poolsOnly ? 'true' : 'false' ?>;
let secondaryValue = secondaryDropdown.value;
switch (cache) {
case 'no':
$('#primary option:eq(' + z(0) + ')').prop('selected', true);
$('#primary option:eq(0)').prop('disabled', poolsOnly);
secondaryDropdown.selectedIndex = 0;
$('#moverDirection1').hide();
for (let i = 0; i < secondaryDropdown.options.length; i++) {
secondaryDropdown.options[i].disabled = true;
}
secondaryDropdown.selectedIndex = 0;
if (poolsOnly) {
$('#moverDirection2').hide();
$('#moreSettings1').hide();
@@ -612,9 +648,8 @@ function updateScreen(cache, slow) {
$('#primary option:eq(' + z(0) + ')').prop('selected', true);
$('#secondary option:eq(' + z(1) + ')').prop('selected', true);
/* Disable the secondary option that matches the primary selection and always disable option 1 */
for (let i = 0; i < secondaryDropdown.options.length; i++) {
if (secondaryDropdown.options[i].value === primaryValue || (i === 1 && poolsOnly)) {
if (secondaryDropdown.options[i].value === primaryValue || (i === 1 && poolsOnly) || secondaryDropdown.options[i].id === 'cachePoolOption2') {
secondaryDropdown.options[i].disabled = true;
} else {
secondaryDropdown.options[i].disabled = false;
@@ -624,23 +659,19 @@ function updateScreen(cache, slow) {
/* If the primary value equals the current secondary value, change secondary selection to index 0 or 1 based on poolsOnly */
if (secondaryValue === primaryValue) {
secondaryDropdown.selectedIndex = poolsOnly ? 0 : 1;
if (poolsOnly) {
$('#moverAction2').html("<i class='fa fa-info i'></i>_(Mover takes no action)_");
$('#moverDirection1').hide();
$('#moverDirection2').show();
} else {
$('#moverDirection1 option:eq(0)').text($('#primary option:eq(' + z(0) + ')').text() + ' → ' + $('#secondary option:eq(' + z(1) + ')').text());
$('#moverDirection1 option:eq(1)').text($('#secondary option:eq(' + z(1) + ')').text() + ' → ' + $('#primary option:eq(' + z(0) + ')').text());
$('#moverDirection1').val('0').show();
$('#moverDirection2').hide();
$('#moverAction1').html("<i class='fa fa-info i'></i>_(Mover transfers files from Primary storage to Secondary storage)_");
}
} else if (secondaryValue !== "0") {
secondaryValue = poolsOnly ? "0" : "1";
}
if ((secondaryValue !== "0") && (secondaryValue !== primaryValue)) {
$('#moverDirection1 option:eq(0)').text($('#primary option:eq(' + z(0) + ')').text() + ' → ' + $('#secondary option:eq(' + z(1) + ')').text());
$('#moverDirection1 option:eq(1)').text($('#secondary option:eq(' + z(1) + ')').text() + ' → ' + $('#primary option:eq(' + z(0) + ')').text());
$('#moverDirection1').val('0').show();
$('#moverDirection2').hide();
$('#moverAction1').html("<i class='fa fa-info i'></i>_(Mover transfers files from Primary storage to Secondary storage)_");
} else {
$('#moverAction2').html("<i class='fa fa-info i'></i>_(Mover takes no action)_");
$('#moverDirection1').hide();
$('#moverDirection2').show();
}
$('#moreSettings1').hide(slow);
$('#cow-setting').hide(slow);
@@ -654,10 +685,11 @@ function updateScreen(cache, slow) {
$('#primary option:eq(0)').prop('disabled', poolsOnly);
$('#secondary option:eq(' + z(1) + ')').prop('selected', true);
/* Enable all secondary options except option 1 if poolsOnly is true */
for (let i = 0; i < secondaryDropdown.options.length; i++) {
if (secondaryDropdown.options[i].value === primaryValue || (i === 1 && poolsOnly)) {
if (secondaryDropdown.options[i].value === primaryValue || (i === 1 && poolsOnly) || secondaryDropdown.options[i].id === 'cachePoolOption2') {
secondaryDropdown.options[i].disabled = true;
} else {
secondaryDropdown.options[i].disabled = false;
}
}
@@ -678,10 +710,30 @@ function updateScreen(cache, slow) {
$('#secondary option:eq(1)').prop('disabled', poolsOnly);
$('#moverDirection1 option:eq(0)').text($('#primary option:eq(' + z(0) + ')').text() + ' → ' + $('#secondary option:eq(' + z(1) + ')').text());
$('#moverDirection1 option:eq(1)').text($('#secondary option:eq(' + z(1) + ')').text() + ' → ' + $('#primary option:eq(' + z(0) + ')').text());
if (secondaryValue !== "0") {
$('#moverDirection1').val('1').show();
for (let i = 0; i < secondaryDropdown.options.length; i++) {
if (secondaryDropdown.options[i].value === primaryValue || (i === 1 && poolsOnly) || secondaryDropdown.options[i].id === 'cachePoolOption2') {
secondaryDropdown.options[i].disabled = true;
} else {
secondaryDropdown.options[i].disabled = false;
}
}
/* If the primary value equals the current secondary value, change secondary selection to index 0 or 1 based on poolsOnly */
if (secondaryValue === primaryValue) {
secondaryDropdown.selectedIndex = poolsOnly ? 0 : 1;
secondaryValue = poolsOnly ? "0" : "1";
}
if ((secondaryValue !== "0") && (secondaryValue !== primaryValue)) {
$('#moverDirection1 option:eq(0)').text($('#primary option:eq(' + z(0) + ')').text() + ' → ' + $('#secondary option:eq(' + z(1) + ')').text());
$('#moverDirection1 option:eq(1)').text($('#secondary option:eq(' + z(1) + ')').text() + ' → ' + $('#primary option:eq(' + z(0) + ')').text());
$('#moverDirection1').val('0').show();
$('#moverDirection2').hide();
$('#moverAction1').html("<i class='fa fa-info i'></i>_(Mover transfers files from Primary storage to Secondary storage)_");
} else {
$('#moverAction2').html("<i class='fa fa-info i'></i>_(Mover takes no action)_");
$('#moverDirection1').hide();
$('#moverDirection2').show();
}
$('#moreSettings1').hide(slow);
@@ -690,8 +742,7 @@ function updateScreen(cache, slow) {
form.shareSplitLevel.disabled = false;
enableDropdownIfExists('#s3');
enableDropdownIfExists('#s4');
$('#moverAction1').html("<i class='fa fa-info i'></i>_(Mover transfers files from Secondary storage to Primary storage)_");
$('#moverAction2').html("<i class='fa fa-info i'></i>_(Mover takes no action)_");
$('#moverAction2').html("<i class='fa fa-info i'></i>_(Mover takes no action)_");
break;
}
@@ -748,16 +799,18 @@ function setFloor(val) {
const fsFree = JSON.parse('<?= fsFree() ?>');
/* Retrieve size and free space based on selected primary value */
const primaryValue = $('#primary').val();
const secondaryValue = $('#secondary').val();
const primaryDropdown = document.getElementById('primary');
const primaryValue = primaryDropdown.value;
const secondaryDropdown = document.getElementById('secondary');
const secondaryValue = secondaryDropdown.value;
/* Secondary selection is array and array disks are accounted for. */
let full;
let free;
if (secondaryValue === "0" || secondaryValue === "1") {
/* Size of the primary pool, or smallest array disk. */
full = fsSize[primaryValue];
free = fsFree[primaryValue];
full = fsSize[''];
free = fsFree[''];
} else {
/* Size of the secondary pool. */
full = fsSize[secondaryValue];
@@ -844,6 +897,29 @@ function prepareEdit() {
/* Declare variables at the function scope */
var share, reserved, pools;
/* Check if a change was required and not made for primary dropdown */
if (checkRequiredPrimary && !changeMadePrimary) {
swal({
title: "Primary Storage",
text: "Selected Pool is not available and cannot be used.",
type: 'error',
html: true,
confirmButtonText: "Ok"
});
return false;
}
/* Check if a change was required and not made for secondary dropdown */
if (checkRequiredSecondary && !changeMadeSecondary) {
swal({
title: "Secondary Storage",
text: "Selected Pool is not available and cannot be used.",
type: 'error',
html: true,
confirmButtonText: "Ok"
});
return false;
}
/* Test share name validity. */
share = form.shareName.value.trim();
@@ -864,7 +940,6 @@ function prepareEdit() {
title: "Invalid share name",
text: "Do not use reserved names",
type: 'error',
html: true,
confirmButtonText: "Ok"
});
return false;
@@ -876,7 +951,6 @@ function prepareEdit() {
title: "Invalid share name",
text: "Do not use pool names",
type: 'error',
html: true,
confirmButtonText: "Ok"
});
return false;
@@ -891,8 +965,10 @@ function prepareEdit() {
form.shareFloor.value = setFloor(form.shareFloor.value);
/* shareCachePool2 is not used when none or array is secondary. */
secondaryValue = $('#secondary').val();
if (secondaryValue == "0" || secondaryValue == "1") {
const secondaryDropdown = document.getElementById('secondary');
const secondaryValue = secondaryDropdown.value;
if (secondaryValue === "0" || secondaryValue === "1") {
form.shareCachePool2.value = "";
} else {
form.shareCachePool2.value = form.secondary.value;
@@ -991,126 +1067,161 @@ function writeShare(data, n, i) {
}
}
/*
* This script handles the initialization and dynamic updates for the
* primary and secondary cache pool dropdowns in the form. It sets
* default values, detects changes made by the user, and ensures the
* dropdowns reflect the current configuration status.
*
* Key functionalities include:
* - Setting the default selection for each dropdown based on the defined
* configuration.
* - Displaying warnings if the configured pool is missing.
* - Disabling or enabling dropdown options as necessary.
* - Preventing form submission if required changes are not made.
*/
document.addEventListener('DOMContentLoaded', function() {
/* Declare variables at the function scope */
let primaryDefaultValue, primaryDropdown, i;
let secondaryDefaultValue, secondaryDropdown;
let poolsOnly = <?= $poolsOnly ? 'true' : 'false' ?>;
/* Define primary dropdown variables */
let primaryDropdown = document.getElementById('primary');
let primaryDefaultValue = "<?= $share['cachePool'] ?>";
let cachePool = "<?= $share['cachePool'] ?>";
let useCache = "<?= $share['useCache'] ?>";
let cachePoolCapitalized = "<?= $cachePoolCapitalized ?>";
let poolsOnly = <?= $poolsOnly ? 'true' : 'false' ?>;
let poolDefined = <?= $poolDefined ? 'true' : 'false' ?>;
/* Handle the primary dropdown */
primaryDefaultValue = document.forms['share_edit'].elements['shareCachePool'].value;
primaryDropdown = document.getElementById('primary');
/* Define secondary dropdown variables */
let secondaryDropdown = document.getElementById('secondary');
let secondaryDefaultValue = "<?= $share['cachePool2'] ?>";
let cachePool2 = "<?= $share['cachePool2'] ?>";
let cachePoolCapitalized2 = "<?= $cachePoolCapitalized2 ?>";
let poolDefined2 = <?= $poolDefined2 ? 'true' : 'false' ?>;
/* Select the correct pool or the first one if no pool is defined. */
if (primaryDefaultValue === "") {
/* Set the default to the first selection - Array or first pool. */
/* Flag to differentiate between user-initiated and programmatic changes */
let programmaticChange = false;
/* Add event listener to detect changes in the primary dropdown */
primaryDropdown.addEventListener('change', function() {
/* Check if the change was made programmatically */
if (!programmaticChange) {
/* Mark that a user-initiated change was made */
changeMadePrimary = true;
}
});
/* Handle the primary dropdown selection */
if (!poolDefined) {
checkRequiredPrimary = true; // Set flag to indicate that a check is required
let cachePoolOption = document.getElementById('cachePoolOption');
let messageSpan = document.getElementById('cachePoolMessage');
messageSpan.textContent = `Warning: Configured Pool '${cachePoolCapitalized}' is missing.`;
messageSpan.style.display = 'inline';
cachePoolOption.selected = true;
// Ensure the option is part of the dropdown
if (!cachePoolOption.parentNode) {
primaryDropdown.appendChild(cachePoolOption);
}
// Select the cachePoolOption
programmaticChange = true;
primaryDropdown.value = cachePoolOption.value;
programmaticChange = false;
} else {
let cachePoolOption = document.getElementById('cachePoolOption');
let messageSpan = document.getElementById('cachePoolMessage');
messageSpan.style.display = 'none';
// Remove the option from the dropdown
if (cachePoolOption && cachePoolOption.parentNode) {
cachePoolOption.parentNode.removeChild(cachePoolOption);
}
/* Set the default to the first selection - Array or first pool */
if (poolsOnly) {
primaryDropdown.selectedIndex = 1;
} else {
primaryDropdown.selectedIndex = 0;
}
} else {
/* Loop through the options and set the selected value */
for (i = 0; i < primaryDropdown.options.length; i++) {
if (primaryDropdown.options[i].value == primaryDefaultValue) {
primaryDropdown.selectedIndex = i;
break;
}
}
}
/* Handle the secondary dropdown */
secondaryDefaultValue = "<?= $share['cachePool2'] ?>";
secondaryDropdown = document.getElementById('secondary');
if (!secondaryDropdown) {
/* Exit if the element is not found. */
return;
}
/* Function to disable matching pool option in secondary dropdown. */
function disableMatchingOption() {
let primaryValue = primaryDropdown.value;
let firstEnabledOption = null;
let matchFound = false;
for (let i = 1; i < secondaryDropdown.options.length; i++) {
if (i === 1 && poolsOnly) {
secondaryDropdown.options[i].disabled = true;
continue;
}
if (secondaryDropdown.options[i].value === primaryValue) {
secondaryDropdown.options[i].disabled = true;
matchFound = true;
} else {
secondaryDropdown.options[i].disabled = false;
if (firstEnabledOption === null) {
firstEnabledOption = secondaryDropdown.options[i];
if (primaryDefaultValue !== "") {
for (let i = 0; i < primaryDropdown.options.length; i++) {
if (primaryDropdown.options[i].value == primaryDefaultValue) {
primaryDropdown.selectedIndex = i;
break;
}
}
}
/* Disable all secondary options if primary is array (index 0). */
if (primaryDropdown.selectedIndex === 0) {
for (let i = 1; i < secondaryDropdown.options.length; i++) {
secondaryDropdown.options[i].disabled = true;
}
secondaryDropdown.selectedIndex = 0;
/* Skip further processing as we already set the selection. */
return;
}
/* Enable and select secondary selection 1 if useCache is "yes" and poolsOnly is false */
if (useCache === "yes" && !poolsOnly) {
secondaryDropdown.options[1].disabled = false;
/* Skip further processing as we already set the selection. */
return;
}
/* Select the first enabled option in the secondary dropdown */
if (matchFound || primaryValue === secondaryDefaultValue) {
if (secondaryDropdown.selectedIndex !== 1) {
secondaryDropdown.selectedIndex = 0;
} else if (poolsOnly) {
secondaryDropdown.selectedIndex = 0;
}
} else if (firstEnabledOption !== null) {
firstEnabledOption.selected = true;
} else if (poolsOnly) {
/* Select the first pool option. */
primaryDropdown.selectedIndex = 1;
} else {
/* If no enabled option found, reset the selection */
secondaryDropdown.selectedIndex = -1;
/* Select the array option. */
primaryDropdown.selectedIndex = 0;
}
}
/* Call the function initially */
disableMatchingOption();
/* Select the appropriate pool from the dropdown. */
let matchFound = false;
/* Loop through the options and set the selected value */
for (let i = 0; i < secondaryDropdown.options.length; i++) {
if (secondaryDropdown.options[i].value == secondaryDefaultValue) {
secondaryDropdown.selectedIndex = i;
matchFound = true;
break;
/* Add event listener to detect changes in the secondary dropdown */
secondaryDropdown.addEventListener('change', function() {
/* Check if the change was made programmatically */
if (!programmaticChange) {
/* Mark that a user-initiated change was made */
changeMadeSecondary = true;
}
}
/* If no match is found or secondary default matches primary, default to the first selection */
if ((!matchFound || primaryDefaultValue === secondaryDefaultValue) && (secondaryDefaultValue != "")) {
secondaryDropdown.selectedIndex = 0;
}
/* Add event listener to primary dropdown to handle change event */
primaryDropdown.addEventListener('change', function() {
disableMatchingOption();
});
/* Trigger the onchange event if needed */
/* Handle the secondary dropdown selection */
if (!poolDefined2) {
checkRequiredSecondary = true; // Set flag to indicate that a check is required
let cachePoolOption2 = document.getElementById('cachePoolOption2');
let messageSpan2 = document.getElementById('cachePoolMessage2');
messageSpan2.textContent = `Warning: Configured Pool '${cachePoolCapitalized2}' is missing.`;
messageSpan2.style.display = 'inline';
cachePoolOption2.selected = true;
cachePoolOption2.disabled = true;
// Ensure the option is part of the dropdown
if (!cachePoolOption2.parentNode) {
secondaryDropdown.appendChild(cachePoolOption2);
}
// Select the cachePoolOption2
programmaticChange = true;
secondaryDropdown.value = cachePoolOption2.value;
programmaticChange = false;
} else {
let cachePoolOption2 = document.getElementById('cachePoolOption2');
let messageSpan2 = document.getElementById('cachePoolMessage2');
messageSpan2.style.display = 'none';
// Remove the option from the dropdown
if (cachePoolOption2 && cachePoolOption2.parentNode) {
cachePoolOption2.parentNode.removeChild(cachePoolOption2);
}
/* Loop through the options and set the selected value */
if (secondaryDefaultValue !== "") {
for (let i = 0; i < secondaryDropdown.options.length; i++) {
if (secondaryDropdown.options[i].value == secondaryDefaultValue) {
secondaryDropdown.selectedIndex = i;
break;
}
}
} else if (useCache !== "only") {
/* Select the array option. */
secondaryDropdown.selectedIndex = 1;
} else {
/* Select the none option. */
secondaryDropdown.selectedIndex = 0;
}
}
/* Trigger the onchange event if needed for the secondary dropdown */
programmaticChange = true;
secondaryDropdown.dispatchEvent(new Event('change'));
programmaticChange = false;
});
/* Clean up the share name by removing invalid characters. */