diff --git a/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php b/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php index f92a53e8f..4f54ad238 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php +++ b/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php @@ -1177,18 +1177,19 @@ _(Use Tailscale)_:
-Warning: +_(Warning)_: : Exit Node not yet approved. Navigate to the Tailscale website and approve it.
-_(Warning)_: invert):?> -: Tailscale Key expired! Renew/Disable key expiry for ''. +_(Warning)_: +: Tailscale Key expired! Renew/Disable key expiry for ''. -: Tailscale Key will expire in days?> days! Disable Key Expiry for ''. +_(Warning)_: +: Tailscale Key will expire in days?> days! Disable Key Expiry for ''.
@@ -1197,7 +1198,7 @@ _(Use Tailscale)_:
_(Warning)_: -: The following route(s) are not approved: +: The following route(s) are not approved:
diff --git a/emhttp/plugins/dynamix.vm.manager/VMSettings.page b/emhttp/plugins/dynamix.vm.manager/VMSettings.page index fa80e80ed..5832f35f7 100644 --- a/emhttp/plugins/dynamix.vm.manager/VMSettings.page +++ b/emhttp/plugins/dynamix.vm.manager/VMSettings.page @@ -119,7 +119,7 @@ $libvirt_log = file_exists("/var/log/libvirt/libvirtd.log");   : -
+ @@ -180,7 +180,7 @@ _(Libvirt storage location)_: _(Default VM storage path)_: -: +: _(Modify with caution: unable to validate path until Array is Started)_ @@ -188,7 +188,7 @@ _(Default VM storage path)_: :vms_libvirt_storage_help: _(Default ISO storage path)_: -: +: _(Modify with caution: unable to validate path until Array is Started)_ @@ -364,6 +364,64 @@ function btrfsScrub(path) { } }); } + +function validatePath(input) { + if (input.value.includes("'")) { + input.setCustomValidity(_("Single quote ' is not allowed in the path.")_); + } else { + input.setCustomValidity(""); + } + input.reportValidity(); +} + +// Validate both domaindir and mediadir on submit +function validateFormOnSubmit() { + const domaindir = document.getElementById('domaindir'); + const mediadir = document.getElementById('mediadir'); + + // Run validation + validatePath(domaindir); + validatePath(mediadir); + + // Check validity in order, and focus the first invalid field + if (!domaindir.checkValidity()) { + domaindir.reportValidity(); + domaindir.focus(); + return false; + } + + if (!mediadir.checkValidity()) { + mediadir.reportValidity(); + mediadir.focus(); + return false; + } + + // Both valid + return true; +} + +document.getElementById('settingsForm').addEventListener('submit', function(e) { + if (!validateFormOnSubmit()) { + e.preventDefault(); + } +}); + +// Attach validation on input events +['domaindir', 'mediadir'].forEach(id => { + const input = document.getElementById(id); + input.addEventListener('input', () => validatePath(input)); +}); + +// Hook into Unraid fileTreeAttach for both fields +$('.filepicker').each(function() { + const input = this; + $(input).fileTreeAttach(null, null, function(folder) { + $(input).val(folder); + validatePath(input); + $(document).trigger('close.fileTree'); + }); +}); + $(function(){ $.post("/plugins/dynamix.vm.manager/include/Fedora-virtio-isos.php",{},function(isos) { $('#winvirtio_select').html(isos).prop('disabled',false).change().each(function(){$(this).on('change',function() { diff --git a/emhttp/plugins/dynamix/Browse.page b/emhttp/plugins/dynamix/Browse.page index a745e1b96..d67495468 100644 --- a/emhttp/plugins/dynamix/Browse.page +++ b/emhttp/plugins/dynamix/Browse.page @@ -271,6 +271,8 @@ function fileEdit(id) { } function fullWindow() { + // this class is used to determine if the dialog is sized via the default CSS in default-dynamix.css or by JS when the user clicks the "expand" button. + $('.ui-dialog').toggleClass('ui-dialog-content-full'); if ($('.ui-dfm .ui-dialog-titlebar-close').html().indexOf('expand')>=0) { dfm.window.dialog('option','height',window.innerHeight-40); dfm.window.dialog('option','width',window.innerWidth); @@ -999,7 +1001,8 @@ $(function(){ } else { url.push(''); } - $('span.left').html(url.join('')).append(''); + $('.title .left').html(url.join('')); + $('.title .right').append(''); table = $('table.indexer'); thead = table.find('thead'); table.bind('sortEnd',function(e,t){ diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index c6eccfd38..cc5e088a4 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -62,23 +62,18 @@ foreach ($allPages as $page) { if (count($pages)) { $running = file_exists($nchan_pid) ? file($nchan_pid, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) : []; $start = array_diff($nchan, $running); // returns any new scripts to be started - $stop = array_diff($running, $nchan); // returns any old scripts to be stopped $running = array_merge($start, $running); // update list of current running nchan scripts - // start nchan scripts which are new - foreach ($start as $row) { - $script = explode(':', $row)[0]; - exec("$docroot/$script &>/dev/null &"); - } - // stop nchan scripts with the :stop option - foreach ($stop as $row) { - [$script, $opt] = my_explode(':', $row); - if ($opt == 'stop') { - exec('pkill --ns $$ -f '.escapeshellarg($docroot.'/'.$script).' &>/dev/null &'); - array_splice($running, array_search($row, $running), 1); - } - } + // start nchan scripts which are new or have been terminated but still should be running if (count($running)) { - file_put_contents($nchan_pid, implode("\n", $running) . "\n"); + file_put_contents_atomic($nchan_pid, implode("\n", $running) . "\n"); + foreach ($running as $row) { + $script = explode(':', $row, 2)[0]; + $output = []; + exec('pgrep --ns $$ -f ' . escapeshellarg("$docroot/$script"),$output,$retval); + if ($retval !== 0) { // 0=found; 1=none; 2=error + exec(escapeshellarg("$docroot/$script") . ' >/dev/null 2>&1 &'); + } + } } else { @unlink($nchan_pid); } diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php index badde52c6..322e81ca4 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php @@ -494,4 +494,20 @@ function fillAvailableHeight(params = { // default params // Add the new listener window.addEventListener('resize', window.fillAvailableHeightResizeHandler); } + +/** + * For every a.info element, we see if it has an inner span element. + * While the CSS will determine visibility, we still need to use JS to set the position of the "tooltip" span. + * Using the a.info element's offset position, we can calculate the top and left position needed for the span. + */ +$(document).on('mouseenter', 'a.info', function() { + const tooltip = $(this).find('span'); + if (tooltip.length) { + const aInfoPosition = $(this).offset(); + const addtionalOffset = 16; + const top = aInfoPosition.top + addtionalOffset; + const left = aInfoPosition.left + addtionalOffset; + tooltip.css({ top, left }); + } +}); diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/Footer.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/Footer.php index 59712c806..e7efc1c7f 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout/Footer.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/Footer.php @@ -56,6 +56,7 @@ function getArrayStatus($var) { +