mirror of
https://github.com/unraid/webgui.git
synced 2026-02-19 23:49:35 -06:00
Changes to support array optional feature.
This commit is contained in:
@@ -19,27 +19,32 @@ $width = [123,300];
|
||||
|
||||
if ($name == "") {
|
||||
/* default values when adding new share. */
|
||||
$share = ["nameOrig" => "",
|
||||
"name" => "",
|
||||
"comment" => "",
|
||||
"allocator" => "highwater",
|
||||
"floor" => "",
|
||||
"splitLevel" => "",
|
||||
"include" => "",
|
||||
"exclude" => "",
|
||||
"useCache" => "no",
|
||||
"cachePool" => "",
|
||||
"cow" => "auto"
|
||||
];
|
||||
$share = [
|
||||
"nameOrig" => "",
|
||||
"name" => "",
|
||||
"comment" => "",
|
||||
"allocator" => "highwater",
|
||||
"floor" => "",
|
||||
"splitLevel" => "",
|
||||
"include" => "",
|
||||
"exclude" => "",
|
||||
"useCache" => "no",
|
||||
"cachePool" => "",
|
||||
"cachePool2" => "",
|
||||
"cow" => "auto"
|
||||
];
|
||||
} elseif (array_key_exists($name, $shares)) {
|
||||
/* edit existing share. */
|
||||
$share = $shares[$name];
|
||||
/* edit existing share. */
|
||||
$share = $shares[$name];
|
||||
} else {
|
||||
/* handle share deleted case. */
|
||||
echo "<p class='notice'>"._('Share')." '".htmlspecialchars($name)."' "._('has been deleted').".</p><input type='button' value=\""._('Done')."\" onclick='done()'>";
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the configuration is pools only, then no array disks are available. */
|
||||
$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";
|
||||
|
||||
@@ -75,14 +80,18 @@ function presetSpace($val) {
|
||||
$large[] = _var($disk, 'fsSize');
|
||||
}
|
||||
|
||||
/* Get the maximum value from the large array, filtering out non-numeric values */
|
||||
$fsSize[""] = max(array_filter($large, 'is_numeric'));
|
||||
|
||||
/* Prepare the fsSize array for each pool */
|
||||
foreach ($pools as $pool) {
|
||||
$fsSize[$pool] = _var($disks[$pool], 'fsSize', 0);
|
||||
}
|
||||
|
||||
/* Get the maximum value from the large array, filtering out non-numeric values */
|
||||
if (!empty($large)) {
|
||||
$fsSize[''] = max(array_filter($large, 'is_numeric'));
|
||||
} else {
|
||||
$fsSize[''] = $fsSize[$pool];
|
||||
}
|
||||
|
||||
/* Get the cache pool size */
|
||||
$pool = _var($shares[$name], 'cachePool');
|
||||
$size = _var($fsSize, $pool, 0);
|
||||
@@ -149,46 +158,78 @@ function enabledDisks() {
|
||||
function fsSize() {
|
||||
global $disks, $pools, $share;
|
||||
|
||||
/* Initialize an array to hold filesystem sizes */
|
||||
$fsSize = [];
|
||||
|
||||
/* Initialize an array to hold sizes of enabled disks */
|
||||
$small = [];
|
||||
|
||||
$enabledDisks = enabledDisks();
|
||||
/* Get a list of enabled disks */
|
||||
$enabledDisks = enabledDisks();
|
||||
|
||||
/* Iterate over the filtered disk data */
|
||||
foreach (data_filter($disks) as $key => $disk) {
|
||||
/* Check if the disk is in the list of enabled disks */
|
||||
if (in_array($key, $enabledDisks)) {
|
||||
/* Add the filesystem size of the enabled disk to the array */
|
||||
$small[] = _var($disk, 'fsSize');
|
||||
}
|
||||
}
|
||||
|
||||
$fsSize[''] = min(array_filter($small));
|
||||
/* Set the minimum filesystem size from the array of enabled disks */
|
||||
if (!empty($small)) {
|
||||
$fsSize[''] = min(array_filter($small));
|
||||
} else {
|
||||
$fsSize[''] = 0;
|
||||
}
|
||||
|
||||
/* Iterate over the pool names and add their filesystem sizes */
|
||||
foreach ($pools as $pool) {
|
||||
/* Set the filesystem size for each pool, defaulting to 0 if not set */
|
||||
$fsSize[$pool] = _var($disks[$pool], 'fsSize', 0);
|
||||
}
|
||||
|
||||
/* Return the filesystem sizes as a JSON encoded string */
|
||||
return json_encode($fsSize);
|
||||
}
|
||||
|
||||
function fsFree() {
|
||||
global $disks, $pools;
|
||||
|
||||
/* Initialize an array to hold free filesystem space */
|
||||
$fsFree = [];
|
||||
|
||||
/* Initialize an array to hold free space of enabled disks */
|
||||
$large = [];
|
||||
|
||||
$enabledDisks = enabledDisks();
|
||||
/* Get a list of enabled disks */
|
||||
$enabledDisks = enabledDisks();
|
||||
|
||||
/* Iterate over the filtered disk data */
|
||||
foreach (data_filter($disks) as $key => $disk) {
|
||||
/* Check if the disk is in the list of enabled disks */
|
||||
if (in_array($key, $enabledDisks)) {
|
||||
/* Add the free filesystem space of the enabled disk to the array */
|
||||
$large[] = _var($disk, 'fsFree');
|
||||
}
|
||||
}
|
||||
|
||||
$fsFree[''] = max(array_filter($large));
|
||||
|
||||
/* Iterate over the pool names and add their free filesystem space */
|
||||
foreach ($pools as $pool) {
|
||||
/* Set the free filesystem space for each pool, defaulting to 0 if not set */
|
||||
$fsFree[$pool] = _var($disks[$pool], 'fsFree', 0);
|
||||
}
|
||||
|
||||
/* Determine the free filesystem space based on the poolsOnly flag */
|
||||
if (!empty($large)) {
|
||||
/* Set the maximum free filesystem space from the array of enabled disks */
|
||||
$fsFree[''] = max(array_filter($large));
|
||||
} else {
|
||||
/* Set the minimum free filesystem space from the pool array */
|
||||
$fsFree[''] = min(array_filter($fsFree));
|
||||
}
|
||||
|
||||
/* Return the free filesystem space as a JSON encoded string */
|
||||
return json_encode($fsFree);
|
||||
}
|
||||
|
||||
@@ -205,13 +246,18 @@ function fsType() {
|
||||
}
|
||||
|
||||
function primary() {
|
||||
global $share;
|
||||
return $share['useCache']=='no' ? '' : $share['cachePool'];
|
||||
global $share;
|
||||
|
||||
return $share['useCache']=='no' ? '' : $share['cachePool'];
|
||||
}
|
||||
|
||||
function secondary() {
|
||||
global $share;
|
||||
return in_array($share['useCache'],['no','only']) ? '0' : '1';
|
||||
global $share;
|
||||
|
||||
|
||||
$rc = in_array($share['useCache'],['no','only']) ? '0' : '1';
|
||||
|
||||
return $rc;
|
||||
}
|
||||
|
||||
function direction() {
|
||||
@@ -227,6 +273,7 @@ $myDisks = array_filter(array_diff(array_keys(array_filter($disks,'my_disks')),
|
||||
:share_edit_global2_help:
|
||||
<?endif;?>
|
||||
|
||||
<br />
|
||||
<div class="clone1">
|
||||
<span class="clone">_(Read settings from)_</span><i class="fa fa-arrow-left fa-fw"></i>
|
||||
<span class="wrap"><select name="readshare" class="clone" onchange="toggleButton('readshare',false)">
|
||||
@@ -236,6 +283,7 @@ foreach ($shares as $list) if ($list['name']!=$name || !$name) echo mk_option(""
|
||||
?>
|
||||
</select></span><input type="button" id="readshare" value="_(Read)_" class="clone" onclick="readShare()" disabled>
|
||||
</div>
|
||||
|
||||
<?if ($name):?>
|
||||
<div class="clone2">
|
||||
<span class="clone">_(Write settings to)_</span><i class="fa fa-arrow-right fa-fw"></i>
|
||||
@@ -253,6 +301,7 @@ foreach ($rows as $row) echo $row;
|
||||
<form markdown="1" name="share_edit" method="POST" action="/update.htm" target="progressFrame" onsubmit="return prepareEdit()"<?=$name?" onchange=\"toggleButton('writeshare',true);$('#s5').dropdownchecklist('disable')\">":">"?>
|
||||
<input type="hidden" name="shareNameOrig" value="<?=htmlspecialchars($share['nameOrig'])?>">
|
||||
<input type="hidden" name="shareUseCache" value="<?=$share['useCache']?>">
|
||||
<input type="hidden" name="shareCachePool2" value="<?=$share['cachePool2']?>">
|
||||
<input type="hidden" name="shareAllocator" value="">
|
||||
<input type="hidden" name="shareSplitLevel" value="">
|
||||
<input type="hidden" name="shareInclude" value="">
|
||||
@@ -271,7 +320,7 @@ _(Comments)_:
|
||||
|
||||
<div markdown="1">
|
||||
_(Minimum free space)_:
|
||||
: <span class="input"><input type="text" name="shareFloor" maxlength="16" autocomplete="off" spellcheck="false" class="narrow" value="<?=presetSpace($share['floor'])?>" placeholder="0"></span><span id="autosize"><i class="fa fa-info i"></i>_(Calculated free space value)_</span>
|
||||
: <span class="input"><input type="text" name="shareFloor" maxlength="16" autocomplete="off" spellcheck="false" class="wide" value="<?=presetSpace($share['floor'])?>" placeholder="_(Free Space will be calculated)_">
|
||||
|
||||
:share_edit_free_space_help:
|
||||
|
||||
@@ -284,6 +333,7 @@ _(Share status)_:
|
||||
:share_edit_status_help:
|
||||
|
||||
</div>
|
||||
|
||||
<div markdown="1" class="full">
|
||||
_(Share status)_:
|
||||
: <span class="full1"> </span><span class="full2">_(Share contains data)_</span>
|
||||
@@ -291,6 +341,7 @@ _(Share status)_:
|
||||
:share_edit_delete_help:
|
||||
|
||||
</div>
|
||||
|
||||
<?if (_var($share,'exclusive')=="yes"):?>
|
||||
_(Exclusive access)_:
|
||||
: _(Yes)_
|
||||
@@ -306,10 +357,11 @@ _(Exclusive access)_:
|
||||
<?endif;?>
|
||||
<?endif;?>
|
||||
</div>
|
||||
|
||||
<div markdown="1" class="shade-<?=$display['theme']?>">
|
||||
_(Primary storage (for new files and folders))_:
|
||||
: <select id="primary" name="shareCachePool" onchange="form.shareFloor.value='';updateScreen(z(4),'slow')">
|
||||
<?=mk_option(primary(),'',_('Array'))?>
|
||||
<?=mk_option(primary(), '', _('Array'), $poolsOnly ? 'disabled' : '')?>
|
||||
<?foreach ($pools as $pool):?>
|
||||
<?if ($disks[$pool]['devices']) echo mk_option(primary(),$pool,my_disk($pool),$disks[$pool]['shareEnabled']=='yes'?"":"disabled")?>
|
||||
<?endforeach;?>
|
||||
@@ -327,6 +379,7 @@ _(Enable Copy-on-write)_:
|
||||
:share_edit_copy_on_write_help:
|
||||
|
||||
</div>
|
||||
|
||||
<div markdown="1" id="moreSettings1">
|
||||
_(Allocation method)_:
|
||||
: <select name="shareAllocator1">
|
||||
@@ -369,12 +422,16 @@ _(Excluded disk(s))_:
|
||||
:share_edit_excluded_disks_help:
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div markdown="1" class="shade-<?=$display['theme']?>">
|
||||
_(Secondary storage)_:
|
||||
: <select id="secondary" onchange="updateScreen(z(4),'slow')">
|
||||
<?=mk_option(secondary(),'0',_('None'))?>
|
||||
<?=mk_option(secondary(),'1',_('Array'))?>
|
||||
<?=mk_option(secondary(),'1',_('Array'), $poolsOnly ? 'disabled' : '')?>
|
||||
<?foreach ($pools as $pool):?>
|
||||
<?if ($disks[$pool]['devices']) echo mk_option(secondary(),$pool,my_disk($pool),$disks[$pool]['shareEnabled']=='yes'?"":"disabled")?>
|
||||
<?endforeach;?>
|
||||
</select>
|
||||
|
||||
:share_edit_secondary_storage_help:
|
||||
@@ -450,7 +507,7 @@ _(Mover action)_:
|
||||
<?else:?>
|
||||
<div markdown="1" class="empty">
|
||||
_(Delete)_<input type="checkbox" name="confirmDelete" onchange="chkDelete(this.form, document.getElementById('cmdEditShare'));">
|
||||
: <input type="submit" id="cmdEditShare" name="cmdEditShare" value="_(Apply)_" onclick="if (this.value=='_(Delete)_') this.value='Delete'; else this.value='Apply'" disabled><input type="button" value="_(Done)_" onclick="done()">
|
||||
: <input type="submit" id="cmdEditShare" name="cmdEditShare" value="<?= _('Apply') ?>" onclick="return handleDeleteClick(this)" disabled><input type="button" value="<?= _('Done') ?>" onclick="done()">
|
||||
</div>
|
||||
<div markdown="1" class="full">
|
||||
|
||||
@@ -462,130 +519,208 @@ _(Delete)_<input type="checkbox" name="confirmDelete" onchange="chkDelete(this.f
|
||||
<script>
|
||||
var form = document.share_edit;
|
||||
|
||||
$(function() {
|
||||
<?if ($name):?>
|
||||
$.post('/webGui/include/ShareList.php',{scan:"<?=$name?>"},function(e){
|
||||
if (e==1) {$('.empty').show(); $('.full').hide();} else {$('.full1').hide(); $('.full2').show();}
|
||||
});
|
||||
<?endif;?>
|
||||
initDropdown(false,true);
|
||||
<?if ($tabbed):?>
|
||||
$('#tab1').bind({click:function(){initDropdown(true,true);}});
|
||||
<?endif;?>
|
||||
updateScreen(form.shareUseCache.value);
|
||||
if ($.cookie('autosize-'+$('#shareName').val())) $('#autosize').show();
|
||||
checkName($('#shareName').val());
|
||||
});
|
||||
function initDropdown(forceInit) {
|
||||
if (forceInit) {
|
||||
destroyDropdownIfExists('#s1');
|
||||
destroyDropdownIfExists('#s2');
|
||||
destroyDropdownIfExists('#s3');
|
||||
destroyDropdownIfExists('#s4');
|
||||
<?if ($name):?>
|
||||
destroyDropdownIfExists('#s5');
|
||||
<?endif;?>
|
||||
}
|
||||
initializeDropdown('#s1', "_(All)_", <?=$width[1]?>);
|
||||
initializeDropdown('#s2', "_(None)_", <?=$width[1]?>);
|
||||
initializeDropdown('#s3', "_(All)_", <?=$width[1]?>);
|
||||
initializeDropdown('#s4', "_(None)_", <?=$width[1]?>);
|
||||
<?if ($name):?>
|
||||
initializeDropdown("#s5", "_(select)_...", <?=$width[0]?>, true);
|
||||
<?endif;?>
|
||||
}
|
||||
|
||||
function initDropdown(remove,create) {
|
||||
if (remove) {
|
||||
$('#s1').dropdownchecklist('destroy');
|
||||
$('#s2').dropdownchecklist('destroy');
|
||||
$('#s3').dropdownchecklist('destroy');
|
||||
$('#s4').dropdownchecklist('destroy');
|
||||
<?if ($name):?>
|
||||
$('#s5').dropdownchecklist('destroy');
|
||||
<?endif;?>
|
||||
}
|
||||
if (create) {
|
||||
$('#s1').dropdownchecklist({emptyText:"_(All)_", width:<?=$width[1]?>, explicitClose:"..._(close)_"});
|
||||
$('#s2').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[1]?>, explicitClose:"..._(close)_"});
|
||||
$('#s3').dropdownchecklist({emptyText:"_(All)_", width:<?=$width[1]?>, explicitClose:"..._(close)_"});
|
||||
$('#s4').dropdownchecklist({emptyText:"_(None)_", width:<?=$width[1]?>, explicitClose:"..._(close)_"});
|
||||
<?if ($name):?>
|
||||
$("#s5").dropdownchecklist({firstItemChecksAll:true, emptyText:"_(select)_...", width:<?=$width[0]?>, explicitClose:"..._(close)_"});
|
||||
<?endif;?>
|
||||
}
|
||||
function initializeDropdown(selector, emptyText, width, firstItemChecksAll = false) {
|
||||
try {
|
||||
$(selector).dropdownchecklist({
|
||||
emptyText: emptyText,
|
||||
width: width,
|
||||
explicitClose: "..._(close)_",
|
||||
firstItemChecksAll: firstItemChecksAll
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`Error initializing ${selector}: ` + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
function destroyDropdownIfExists(selector) {
|
||||
try {
|
||||
$(selector).dropdownchecklist('destroy');
|
||||
} catch (e) {
|
||||
if (e.message.includes('prior to initialization')) {
|
||||
console.log(`${selector} not initialized, skipping destroy.`);
|
||||
} else {
|
||||
console.error(`Error destroying ${selector}: ` + e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function z(i) {
|
||||
switch (i) {
|
||||
case 0: return $('#primary').prop('selectedIndex');
|
||||
case 1: return $('#secondary').prop('selectedIndex');
|
||||
case 2: return $('#direction').prop('selectedIndex');
|
||||
case 3: return z(2)==0 ? 'yes' : 'prefer';
|
||||
case 4: return z(0)==0 ? 'no' : (z(1)==0 ? 'only' : z(3));
|
||||
}
|
||||
switch (i) {
|
||||
case 0:
|
||||
return $('#primary').prop('selectedIndex');
|
||||
case 1:
|
||||
return $('#secondary').prop('selectedIndex');
|
||||
case 2:
|
||||
return $('#direction').prop('selectedIndex');
|
||||
case 3:
|
||||
return z(2) == 0 ? 'yes' : 'prefer';
|
||||
case 4:
|
||||
return z(0) == 0 ? 'no' : (z(1) == 0 ? 'only' : z(3));
|
||||
}
|
||||
}
|
||||
|
||||
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' ?>;
|
||||
|
||||
/* Update the Copy-on-Write (COW) setting visibility based on the filesystem type */
|
||||
function updateCOW(i, slow) {
|
||||
switch (cache) {
|
||||
case 'no':
|
||||
$('#primary option:eq(' + z(0) + ')').prop('selected', true);
|
||||
$('#primary option:eq(0)').prop('disabled', poolsOnly);
|
||||
secondaryDropdown.selectedIndex = 0;
|
||||
$('#moverDirection1').hide();
|
||||
if (poolsOnly) {
|
||||
$('#moverDirection2').hide();
|
||||
$('#moreSettings1').hide();
|
||||
} else {
|
||||
$('#moverDirection2').show();
|
||||
$('#moreSettings1').show(slow);
|
||||
}
|
||||
$('#moreSettings2').hide(slow);
|
||||
$('#cow-setting').hide(slow);
|
||||
form.shareAllocator.disabled = false;
|
||||
form.shareSplitLevel.disabled = false;
|
||||
enableDropdownIfExists('#s1');
|
||||
enableDropdownIfExists('#s2');
|
||||
$('#moverAction2').html("<i class='fa fa-info i'></i>_(Mover takes no action)_");
|
||||
break;
|
||||
case 'yes':
|
||||
$('#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)) {
|
||||
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;
|
||||
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") {
|
||||
$('#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)_");
|
||||
}
|
||||
$('#moreSettings1').hide(slow);
|
||||
$('#cow-setting').hide(slow);
|
||||
form.shareAllocator.disabled = false;
|
||||
form.shareSplitLevel.disabled = false;
|
||||
enableDropdownIfExists('#s3');
|
||||
enableDropdownIfExists('#s4');
|
||||
break;
|
||||
case 'only':
|
||||
$('#primary option:eq(' + z(0) + ')').prop('selected', true);
|
||||
$('#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)) {
|
||||
secondaryDropdown.options[i].disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
$('#moverDirection1').hide();
|
||||
$('#moverDirection2').show();
|
||||
$('#moreSettings1').hide(slow);
|
||||
$('#moreSettings2').hide(slow);
|
||||
updateCOW(form.shareCachePool.value, slow);
|
||||
form.shareAllocator.disabled = true;
|
||||
form.shareSplitLevel.disabled = true;
|
||||
disableDropdownIfExists('#s1');
|
||||
disableDropdownIfExists('#s2');
|
||||
$('#moverAction2').html("<i class='fa fa-info i'></i>_(Mover takes no action)_");
|
||||
break;
|
||||
case 'prefer':
|
||||
$('#primary option:eq(' + z(0) + ')').prop('selected', true);
|
||||
$('#secondary option:eq(' + z(1) + ')').prop('selected', true);
|
||||
$('#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());
|
||||
$('#moverDirection1').val('1').show();
|
||||
$('#moverDirection2').hide();
|
||||
$('#moreSettings1').hide(slow);
|
||||
$('#cow-setting').hide(slow);
|
||||
form.shareAllocator.disabled = false;
|
||||
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)_");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check secondary dropdown index and show/hide moreSettings2 */
|
||||
if (secondaryDropdown.selectedIndex === 1) {
|
||||
$('#moreSettings2').show('slow');
|
||||
} else {
|
||||
$('#moreSettings2').hide(slow);
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to update Copy-on-Write (COW) setting */
|
||||
function updateCOW(pool, slow) {
|
||||
const fsType = {<?=fsType()?>};
|
||||
if (fsType[i] === 'btrfs') {
|
||||
|
||||
if (fsType[pool] === 'btrfs') {
|
||||
$('#cow-setting').show(slow);
|
||||
} else {
|
||||
$('#cow-setting').hide(slow);
|
||||
}
|
||||
}
|
||||
|
||||
function updateScreen(cache,slow) {
|
||||
switch (cache) {
|
||||
case 'no':
|
||||
$('#primary option:eq('+z(0)+')').prop('selected',true);
|
||||
$('#secondary option:eq(0)').prop('selected',true);
|
||||
$('#secondary option:eq(1)').prop('disabled',true);
|
||||
$('#moverDirection1').hide();
|
||||
$('#moverDirection2').show();
|
||||
$('#moreSettings1').show(slow);
|
||||
$('#moreSettings2').hide(slow);
|
||||
$('#cow-setting').hide(slow);
|
||||
form.shareAllocator.disabled = false;
|
||||
form.shareSplitLevel.disabled = false;
|
||||
$('#s1').dropdownchecklist('enable');
|
||||
$('#s2').dropdownchecklist('enable');
|
||||
$('#moverAction2').html("<i class='fa fa-info i'></i>_(Mover takes no action)_");
|
||||
break;
|
||||
case 'yes':
|
||||
$('#primary option:eq('+z(0)+')').prop('selected',true);
|
||||
$('#secondary option:eq('+z(1)+')').prop('selected',true);
|
||||
$('#secondary option:eq(1)').prop('disabled',false);
|
||||
$('#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();
|
||||
$('#moreSettings1').hide(slow);
|
||||
$('#moreSettings2').show(slow);
|
||||
updateCOW(form.shareCachePool.value,slow);
|
||||
form.shareAllocator.disabled = false;
|
||||
form.shareSplitLevel.disabled = false;
|
||||
$('#s3').dropdownchecklist('enable');
|
||||
$('#s4').dropdownchecklist('enable');
|
||||
$('#moverAction1').html("<i class='fa fa-info i'></i>_(Mover transfers files from Primary storage to Secondary storage)_");
|
||||
break;
|
||||
case 'only':
|
||||
$('#primary option:eq('+z(0)+')').prop('selected',true);
|
||||
$('#secondary option:eq('+z(1)+')').prop('selected',true);
|
||||
$('#secondary option:eq(1)').prop('disabled',false);
|
||||
$('#moverDirection1').hide();
|
||||
$('#moverDirection2').show();
|
||||
$('#moreSettings1').hide(slow);
|
||||
$('#moreSettings2').hide(slow);
|
||||
updateCOW(form.shareCachePool.value,slow);
|
||||
form.shareAllocator.disabled = true;
|
||||
form.shareSplitLevel.disabled = true;
|
||||
$('#s1').dropdownchecklist('disable');
|
||||
$('#s2').dropdownchecklist('disable');
|
||||
$('#moverAction2').html("<i class='fa fa-info i'></i>_(Mover takes no action)_");
|
||||
break;
|
||||
case 'prefer':
|
||||
$('#primary option:eq('+z(0)+')').prop('selected',true);
|
||||
$('#secondary option:eq('+z(1)+')').prop('selected',true);
|
||||
$('#secondary option:eq(1)').prop('disabled',false);
|
||||
$('#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('1').show();
|
||||
$('#moverDirection2').hide();
|
||||
$('#moreSettings1').hide(slow);
|
||||
$('#moreSettings2').show(slow);
|
||||
updateCOW(form.shareCachePool.value,slow);
|
||||
form.shareAllocator.disabled = false;
|
||||
form.shareSplitLevel.disabled = false;
|
||||
$('#s3').dropdownchecklist('enable');
|
||||
$('#s4').dropdownchecklist('enable');
|
||||
$('#moverAction1').html("<i class='fa fa-info i'></i>_(Mover transfers files from Secondary storage to Primary storage)_");
|
||||
break;
|
||||
}
|
||||
function enableDropdownIfExists(selector) {
|
||||
try {
|
||||
$(selector).dropdownchecklist('enable');
|
||||
} catch (e) {
|
||||
console.log(`${selector} not initialized, cannot enable.`);
|
||||
}
|
||||
}
|
||||
|
||||
function disableDropdownIfExists(selector) {
|
||||
try {
|
||||
$(selector).dropdownchecklist('disable');
|
||||
} catch (e) {
|
||||
console.log(`${selector} not initialized, cannot disable.`);
|
||||
}
|
||||
}
|
||||
|
||||
/* Unite selected options into a comma-separated string */
|
||||
@@ -610,7 +745,7 @@ function setFloor(val) {
|
||||
const full = fsSize[primaryValue];
|
||||
const free = fsFree[primaryValue];
|
||||
|
||||
/* This is the disk with the largest free space. */
|
||||
/* This is the disk with the largest free space or current pool. */
|
||||
const arrayFree = fsFree[''];
|
||||
|
||||
/* Calculate 10% of available size as default */
|
||||
@@ -697,8 +832,11 @@ function parseDiskSize(sizeStr) {
|
||||
|
||||
/* Compose input fields. */
|
||||
function prepareEdit() {
|
||||
/* Declare variables at the function scope */
|
||||
var share, reserved, pools;
|
||||
|
||||
/* Test share name validity. */
|
||||
var share = form.shareName.value.trim();
|
||||
share = form.shareName.value.trim();
|
||||
|
||||
if (share.length == 0) {
|
||||
swal({
|
||||
@@ -711,7 +849,7 @@ function prepareEdit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
var reserved = [<?=implode(',',array_map('escapestring',explode(',',$var['reservedNames'])))?>];
|
||||
reserved = [<?=implode(',',array_map('escapestring',explode(',',$var['reservedNames'])))?>];
|
||||
if (reserved.includes(share)) {
|
||||
swal({
|
||||
title: "Invalid share name",
|
||||
@@ -723,7 +861,7 @@ function prepareEdit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
var pools = [<?=implode(',',array_map('escapestring',$pools))?>];
|
||||
pools = [<?=implode(',',array_map('escapestring',$pools))?>];
|
||||
if (pools.includes(share)) {
|
||||
swal({
|
||||
title: "Invalid share name",
|
||||
@@ -743,6 +881,14 @@ function prepareEdit() {
|
||||
form.shareUseCache.value = z(4);
|
||||
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") {
|
||||
form.shareCachePool2.value = "";
|
||||
} else {
|
||||
form.shareCachePool2.value = form.secondary.value;
|
||||
}
|
||||
|
||||
switch (form.shareUseCache.value) {
|
||||
case 'no':
|
||||
form.shareAllocator.value = form.shareAllocator1.value;
|
||||
@@ -763,62 +909,207 @@ function prepareEdit() {
|
||||
}
|
||||
|
||||
function readShare() {
|
||||
var name = $('select[name="readshare"]').val();
|
||||
initDropdown(true,false);
|
||||
$.get('/webGui/include/ShareData.php',{name:name},function(json) {
|
||||
var data = $.parseJSON(json);
|
||||
form.shareAllocator.value = data.allocator;
|
||||
form.shareFloor.value = data.floor;
|
||||
form.shareSplitLevel.value = data.splitLevel;
|
||||
form.shareInclude.value = data.include;
|
||||
form.shareExclude.value = data.exclude;
|
||||
form.shareUseCache.value = data.useCache;
|
||||
form.shareCOW.value = data.cow;
|
||||
for (var i=0,disk; disk=data.include.split(',')[i]; i++) for (var j=0,include; include=form.shareInclude.options[j]; j++) if (include.value==disk) include.selected=true;
|
||||
for (var i=0,disk; disk=data.exclude.split(',')[i]; i++) for (var j=0,exclude; exclude=form.shareExclude.options[j]; j++) if (exclude.value==disk) exclude.selected=true;
|
||||
initDropdown(false,true);
|
||||
});
|
||||
$(form).find('select').trigger('change');
|
||||
/* Declare variables at the function scope */
|
||||
var name, data, disk, include, exclude, i, j;
|
||||
|
||||
name = $('select[name="readshare"]').val();
|
||||
initDropdown(true);
|
||||
|
||||
$.get('/webGui/include/ShareData.php', { name: name }, function(json) {
|
||||
data = $.parseJSON(json);
|
||||
form.shareAllocator.value = data.allocator;
|
||||
form.shareFloor.value = data.floor;
|
||||
form.shareSplitLevel.value = data.splitLevel;
|
||||
form.shareInclude.value = data.include;
|
||||
form.shareExclude.value = data.exclude;
|
||||
form.shareUseCache.value = data.useCache;
|
||||
form.shareCOW.value = data.cow;
|
||||
|
||||
for (i = 0; (disk = data.include.split(',')[i]); i++) {
|
||||
for (j = 0; (include = form.shareInclude.options[j]); j++) {
|
||||
if (include.value == disk) include.selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; (disk = data.exclude.split(',')[i]); i++) {
|
||||
for (j = 0; (exclude = form.shareExclude.options[j]); j++) {
|
||||
if (exclude.value == disk) exclude.selected = true;
|
||||
}
|
||||
}
|
||||
|
||||
initDropdown(false);
|
||||
});
|
||||
|
||||
$(form).find('select').trigger('change');
|
||||
}
|
||||
|
||||
function writeShare(data,n,i) {
|
||||
if (data) {
|
||||
if (n<i) {
|
||||
$.post('/update.htm',data[n], function(){setTimeout(function(){writeShare(data,++n,i);},3000);});
|
||||
} else {
|
||||
toggleButton('writeshare',false);
|
||||
$('div.spinner.fixed').hide();
|
||||
}
|
||||
} else {
|
||||
var data = [], i = 0;
|
||||
$('select#s5 option').map(function() {
|
||||
if ($(this).prop('selected')==true && $(this).val()!='(All)') {
|
||||
data[i] = {};
|
||||
data[i]['shareName'] = $(this).val();
|
||||
data[i]['shareNameOrig'] = $(this).val();
|
||||
data[i]['shareAllocator'] = '<?=addslashes(htmlspecialchars($share['allocator']))?>';
|
||||
data[i]['shareFloor'] = '<?=addslashes(htmlspecialchars($share['floor']))?>';
|
||||
data[i]['shareSplitLevel'] = '<?=addslashes(htmlspecialchars($share['splitLevel']))?>';
|
||||
data[i]['shareInclude'] = '<?=addslashes(htmlspecialchars($share['include']))?>';
|
||||
data[i]['shareExclude'] = '<?=addslashes(htmlspecialchars($share['exclude']))?>';
|
||||
data[i]['shareUseCache'] = '<?=addslashes(htmlspecialchars($share['useCache']))?>';
|
||||
data[i]['cmdEditShare'] = 'Apply';
|
||||
i++;
|
||||
}
|
||||
});
|
||||
toggleButton('writeshare',true);
|
||||
$('div.spinner.fixed').show('slow');
|
||||
writeShare(data,0,i);
|
||||
}
|
||||
function writeShare(data, n, i) {
|
||||
/* Declare variables at the function scope */
|
||||
var newData, i;
|
||||
|
||||
if (data) {
|
||||
if (n < i) {
|
||||
$.post('/update.htm', data[n], function() {
|
||||
setTimeout(function() {
|
||||
writeShare(data, ++n, i);
|
||||
}, 3000);
|
||||
});
|
||||
} else {
|
||||
toggleButton('writeshare', false);
|
||||
$('div.spinner.fixed').hide();
|
||||
}
|
||||
} else {
|
||||
newData = [];
|
||||
i = 0;
|
||||
$('select#s5 option').map(function() {
|
||||
if ($(this).prop('selected') == true && $(this).val() != '(All)') {
|
||||
newData[i] = {};
|
||||
newData[i]['shareName'] = $(this).val();
|
||||
newData[i]['shareNameOrig'] = $(this).val();
|
||||
newData[i]['shareAllocator'] = '<?=addslashes(htmlspecialchars($share['allocator']))?>';
|
||||
newData[i]['shareFloor'] = '<?=addslashes(htmlspecialchars($share['floor']))?>';
|
||||
newData[i]['shareSplitLevel'] = '<?=addslashes(htmlspecialchars($share['splitLevel']))?>';
|
||||
newData[i]['shareInclude'] = '<?=addslashes(htmlspecialchars($share['include']))?>';
|
||||
newData[i]['shareExclude'] = '<?=addslashes(htmlspecialchars($share['exclude']))?>';
|
||||
newData[i]['shareUseCache'] = '<?=addslashes(htmlspecialchars($share['useCache']))?>';
|
||||
newData[i]['cmdEditShare'] = 'Apply';
|
||||
i++;
|
||||
}
|
||||
});
|
||||
toggleButton('writeshare', true);
|
||||
$('div.spinner.fixed').show('slow');
|
||||
writeShare(newData, 0, i);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
/* Declare variables at the function scope */
|
||||
let primaryDefaultValue, primaryDropdown, i;
|
||||
let secondaryDefaultValue, secondaryDropdown;
|
||||
let poolsOnly = <?= $poolsOnly ? 'true' : 'false' ?>;
|
||||
let useCache = "<?= $share['useCache'] ?>";
|
||||
|
||||
/* Handle the primary dropdown */
|
||||
primaryDefaultValue = document.forms['share_edit'].elements['shareCachePool'].value;
|
||||
primaryDropdown = document.getElementById('primary');
|
||||
|
||||
/* 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. */
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 (secodaryDropdown.selectedIndex !== 1) {
|
||||
secondaryDropdown.selectedIndex = 0;
|
||||
}
|
||||
} else if (firstEnabledOption !== null) {
|
||||
firstEnabledOption.selected = true;
|
||||
} else {
|
||||
/* If no enabled option found, reset the selection */
|
||||
secondaryDropdown.selectedIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
secondaryDropdown.dispatchEvent(new Event('change'));
|
||||
});
|
||||
|
||||
/* Clean up the share name by removing invalid characters. */
|
||||
function safeName(name) {
|
||||
/* Define the allowed characters regex */
|
||||
/* Declare variables at the function scope */
|
||||
const validChars = /^[A-Za-z0-9-_.: ]*$/;
|
||||
|
||||
let isValidName, sanitizedString, i;
|
||||
|
||||
/* Check if the name contains only valid characters */
|
||||
const isValidName = validChars.test(name);
|
||||
isValidName = validChars.test(name);
|
||||
|
||||
/* If valid, return the name as it is */
|
||||
if (isValidName) {
|
||||
@@ -826,8 +1117,8 @@ function safeName(name) {
|
||||
}
|
||||
|
||||
/* If not valid, sanitize the name by removing invalid characters */
|
||||
let sanitizedString = '';
|
||||
for (let i = 0; i < name.length; i++) {
|
||||
sanitizedString = '';
|
||||
for (i = 0; i < name.length; i++) {
|
||||
if (validChars.test(name[i])) {
|
||||
sanitizedString += name[i];
|
||||
}
|
||||
@@ -837,12 +1128,56 @@ function safeName(name) {
|
||||
return sanitizedString;
|
||||
}
|
||||
|
||||
/* Remove characters not allowed in share name. */
|
||||
function checkName(name) {
|
||||
var isValidName = /^[A-Za-z0-9-_.: ]*$/.test(name);
|
||||
/* Declare variables at the function scope */
|
||||
var isValidName;
|
||||
|
||||
isValidName = /^[A-Za-z0-9-_.: ]*$/.test(name);
|
||||
|
||||
if (isValidName) {
|
||||
$('#zfs-name').hide();
|
||||
} else {
|
||||
$('#zfs-name').show();
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove hidden '.DS_Store' files from share before deleting the share. */
|
||||
function handleDeleteClick(button) {
|
||||
const deleteLabel = "<?= _('Delete') ?>";
|
||||
if (button.value === deleteLabel) {
|
||||
$.post('/webGui/include/ShareList.php', { delete: "<?=$name?>" }, function(response) {
|
||||
if (response === 'success') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$(function() {
|
||||
<?if ($name):?>
|
||||
$.post('/webGui/include/ShareList.php', { scan: "<?=$name?>" }, function(e) {
|
||||
if (e == 1) {
|
||||
$('.empty').show();
|
||||
$('.full').hide();
|
||||
} else {
|
||||
$('.full1').hide();
|
||||
$('.full2').show();
|
||||
}
|
||||
});
|
||||
<?endif;?>
|
||||
initDropdown(true);
|
||||
<?if ($tabbed):?>
|
||||
$('#tab1').bind({
|
||||
click: function() {
|
||||
initDropdown(true);
|
||||
}
|
||||
});
|
||||
<?endif;?>
|
||||
updateScreen(form.shareUseCache.value);
|
||||
if ($.cookie('autosize-' + $('#shareName').val())) $('#autosize').show();
|
||||
checkName($('#shareName').val());
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -18,15 +18,70 @@ require_once "$docroot/webGui/include/Helpers.php";
|
||||
$_SERVER['REQUEST_URI'] = 'shares';
|
||||
require_once "$docroot/webGui/include/Translations.php";
|
||||
|
||||
/* If the configuration is pools only, then no array disks are available. */
|
||||
$poolsOnly = ((int)$var['SYS_ARRAY_SLOTS'] <= 2) ? true : false;
|
||||
|
||||
/* Check for any files in the share. */
|
||||
if (isset($_POST['scan'])) {
|
||||
die((new FilesystemIterator("/mnt/user/{$_POST['scan']}"))->valid() ? '0' : '1');
|
||||
$dirPath = "/mnt/user/{$_POST['scan']}";
|
||||
|
||||
/* Check if the directory exists. */
|
||||
if (!is_dir($dirPath)) {
|
||||
die('1'); // Directory does not exist
|
||||
}
|
||||
|
||||
$iterator = new FilesystemIterator($dirPath);
|
||||
$hasNonDSStoreFiles = false;
|
||||
|
||||
/* Iterate over the directory contents. */
|
||||
foreach ($iterator as $fileinfo) {
|
||||
if ($fileinfo->isFile() && $fileinfo->getFilename() !== '.DS_Store') {
|
||||
$hasNonDSStoreFiles = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
die($hasNonDSStoreFiles ? '0' : '1');
|
||||
}
|
||||
|
||||
/* Remove all '.DS_Store' files from a directory recursively and delete empty directories. */
|
||||
if (isset($_POST['delete'])) {
|
||||
$nameToDelete = $_POST['delete'];
|
||||
$dirPath = "/mnt/user/{$nameToDelete}";
|
||||
|
||||
if (is_dir($dirPath)) {
|
||||
removeDSStoreFilesAndEmptyDirs($dirPath);
|
||||
}
|
||||
|
||||
die("success");
|
||||
}
|
||||
|
||||
/* Function to remove '.DS_Store' files and empty directories from a share. */
|
||||
function removeDSStoreFilesAndEmptyDirs($dir) {
|
||||
$iterator = new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
|
||||
RecursiveIteratorIterator::CHILD_FIRST
|
||||
);
|
||||
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->isFile() && $file->getFilename() === '.DS_Store') {
|
||||
unlink($file->getRealPath());
|
||||
}
|
||||
}
|
||||
|
||||
/* Second pass to remove empty directories */
|
||||
foreach ($iterator as $file) {
|
||||
if ($file->isDir() && !(new \FilesystemIterator($file->getRealPath()))->valid()) {
|
||||
rmdir($file->getRealPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['cleanup'])) {
|
||||
$n = 0;
|
||||
// active shares
|
||||
$shares = array_map('strtolower',array_keys(parse_ini_file('state/shares.ini',true)));
|
||||
|
||||
// stored shares
|
||||
foreach (glob("/boot/config/shares/*.cfg",GLOB_NOSORT) as $name) {
|
||||
if (!in_array(strtolower(basename($name,'.cfg')),$shares)) {
|
||||
@@ -48,13 +103,11 @@ $var = parse_ini_file('state/var.ini');
|
||||
$sec = parse_ini_file('state/sec.ini',true);
|
||||
$sec_nfs = parse_ini_file('state/sec_nfs.ini',true);
|
||||
|
||||
|
||||
/* Get the pools from the disks.ini. */
|
||||
$pools_check = pools_filter(cache_filter($disks));
|
||||
$pools = implode(',', $pools_check);
|
||||
|
||||
/* If the configuration is pools only, then no array disks are available. */
|
||||
$poolsOnly = ((int)$var['sbNumDisks'] == 2) ? true : false;
|
||||
|
||||
// exit when no mountable array disks
|
||||
$nodisks = "<tr><td class='empty' colspan='7'><strong>"._('There are no mountable array or pool disks - cannot add shares').".</strong></td></tr>";
|
||||
if (!checkDisks($disks)) die($nodisks);
|
||||
@@ -126,6 +179,15 @@ else
|
||||
// Build table
|
||||
$row = 0;
|
||||
foreach ($shares as $name => $share) {
|
||||
/* Check if poolsOnly is true */
|
||||
$array = $share['cachePool2'] ? ucfirst($share['cachePool2']) : "<i class='fa fa-database fa-fw'></i>"._('Array');
|
||||
if ($poolsOnly) {
|
||||
/* If the shareUseCache is set to 'yes', change it to 'only' */
|
||||
if ((($share['useCache'] == 'yes') || ($share['useCache'] == 'prefer')) && (!$share['cachePool2'])) {
|
||||
$share['useCache'] = 'only';
|
||||
}
|
||||
}
|
||||
|
||||
$row++;
|
||||
$color = $share['color'];
|
||||
switch ($color) {
|
||||
@@ -153,10 +215,10 @@ foreach ($shares as $name => $share) {
|
||||
$cache = "<a class='hand info none' onclick='return false'><i class='fa fa-database fa-fw'></i>"._('Array')."<span>".sprintf(_('Primary storage %s'),_('Array'))."</span></a>";
|
||||
break;
|
||||
case 'yes':
|
||||
$cache = "<a class='hand info none' onclick='return false'><i class='fa fa-bullseye fa-fw'></i>".compress(my_disk($share['cachePool'],$display['raw']))." <i class='fa fa-long-arrow-right fa-fw'></i><i class='fa fa-database fa-fw'></i>"._('Array')."<span>"._('Primary storage to Secondary storage')."</span></a>";
|
||||
$cache = "<a class='hand info none' onclick='return false'><i class='fa fa-bullseye fa-fw'></i>".compress(my_disk($share['cachePool'],$display['raw']))." <i class='fa fa-long-arrow-right fa-fw'></i>".$array."<span>"._('Primary storage to Secondary storage')."</span></a>";
|
||||
break;
|
||||
case 'prefer':
|
||||
$cache = "<a class='hand info none' onclick='return false'><i class='fa fa-bullseye fa-fw'></i>".compress(my_disk($share['cachePool'],$display['raw']))." <i class='fa fa-long-arrow-left fa-fw'></i><i class='fa fa-database fa-fw'></i>"._('Array')."<span>"._('Secondary storage to Primary storage')."</span></a>";
|
||||
$cache = "<a class='hand info none' onclick='return false'><i class='fa fa-bullseye fa-fw'></i>".compress(my_disk($share['cachePool'],$display['raw']))." <i class='fa fa-long-arrow-left fa-fw'></i>".$array."<span>"._('Secondary storage to Primary storage')."</span></a>";
|
||||
break;
|
||||
case 'only':
|
||||
$exclusive = isset($share['exclusive']) && $share['exclusive']=='yes' ? "<i class='fa fa-caret-right '></i> " : "";
|
||||
|
||||
Reference in New Issue
Block a user