From 34f7d4968d5b6a26fa5aa1b8b24283ac6e04650c Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Sat, 15 Mar 2025 16:22:37 +0000 Subject: [PATCH 01/85] Save PCI Data. --- etc/rc.d/rc.6 | 4 ++++ sbin/savepcidata | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 sbin/savepcidata diff --git a/etc/rc.d/rc.6 b/etc/rc.d/rc.6 index 8368d0f93..27022117c 100755 --- a/etc/rc.d/rc.6 +++ b/etc/rc.d/rc.6 @@ -219,6 +219,10 @@ if [[ ! -f /boot/logs/syslog && -z $MIRROR && -z $COPY ]]; then fi fi +# Save PCI data to validate system changes at system start. + +/usr/sbin/savepcidata + # Before unmounting file systems write a reboot or halt record to wtmp. /sbin/$SHUTDOWN_COMMAND -w diff --git a/sbin/savepcidata b/sbin/savepcidata new file mode 100644 index 000000000..01d24ae46 --- /dev/null +++ b/sbin/savepcidata @@ -0,0 +1,31 @@ +#!/usr/bin/php + $parts[0], // Full PCI address + 'class' => trim($parts[1], '"'), + 'vendor_id' => trim($parts[2], '"'), + 'device_id' => trim($parts[3], '"'), + 'revision' => (strpos($parts[4], '-r') === 0) ? substr($parts[4], 2) : null, + ]; + + // Determine correct indices for subsystem vendor/device IDs + $subsys_vendor_index = (isset($device['revision']) ? 5 : 4); + $subsys_device_index = $subsys_vendor_index + 1; + + $device['subsystem_vendor_id'] = trim($parts[$subsys_vendor_index], '"'); + $device['subsystem_device_id'] = trim($parts[$subsys_device_index], '"'); + + $devices[] = $device; + } + + file_put_contents("/boot/config/savedpcidata.json",json_encode($devices,JSON_PRETTY_PRINT)); +?> \ No newline at end of file From d1dd42246c5af2032ff2f110059a4843ee98dd8c Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Sat, 15 Mar 2025 16:33:39 +0000 Subject: [PATCH 02/85] Set executable permission for savepcidata --- sbin/savepcidata | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 sbin/savepcidata diff --git a/sbin/savepcidata b/sbin/savepcidata old mode 100644 new mode 100755 From cfdd4c487d92eb02750b69b1adb79c5c982b0904 Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Fri, 4 Apr 2025 10:20:26 +0100 Subject: [PATCH 03/85] Initial commit --- .../dynamix.vm.manager/VMMachines.page | 11 ++-- .../templates/Custom.form.php | 9 ++- emhttp/plugins/dynamix/CPUvms.page | 15 ++++- emhttp/plugins/dynamix/DashStats.page | 24 +++----- emhttp/plugins/dynamix/include/CPUset.php | 13 +++-- emhttp/plugins/dynamix/include/Helpers.php | 58 +++++++++++++++++++ emhttp/plugins/dynamix/include/SysDevs.php | 11 +++- 7 files changed, 111 insertions(+), 30 deletions(-) diff --git a/emhttp/plugins/dynamix.vm.manager/VMMachines.page b/emhttp/plugins/dynamix.vm.manager/VMMachines.page index 19b64eee3..713cf4198 100644 --- a/emhttp/plugins/dynamix.vm.manager/VMMachines.page +++ b/emhttp/plugins/dynamix.vm.manager/VMMachines.page @@ -20,6 +20,8 @@ Markdown="false" 0) $core_type = "$core_types[$cpu1]"; else $core_type = ""; if (!$cpu2) { - echo ""; + echo ""; } else { - echo ""; + echo ""; $check = ($vcpu && in_array($cpu2, $vcpu)) ? 'fa-circle orange-text':'fa-circle-o'; - echo ""; + echo ""; } } echo "
vCPUs: {$vm['domain']['vcpus']} $nopining"; diff --git a/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php b/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php index ef782b506..fa8e5118e 100644 --- a/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php +++ b/emhttp/plugins/dynamix.vm.manager/templates/Custom.form.php @@ -555,16 +555,19 @@ if ($snapshots!=null && count($snapshots) && !$boolNew) {
1 ? 'checked' : 'checked disabled') : ''; + if ($is_intel_cpu && count($core_types) > 0) $core_type = "{$core_types[$cpu1]}"; else $core_type = ""; if (!$cpu2) { - echo ""; + echo ""; } else { - echo ""; + echo ""; $extra = ($arrConfig['domain']['vcpu'] && in_array($cpu2, $arrConfig['domain']['vcpu'])) ? ($arrConfig['domain']['vcpus'] > 1 ? 'checked' : 'checked disabled') : ''; - echo ""; + echo ""; } } ?> diff --git a/emhttp/plugins/dynamix/CPUvms.page b/emhttp/plugins/dynamix/CPUvms.page index 89e6e6f25..297ab883c 100644 --- a/emhttp/plugins/dynamix/CPUvms.page +++ b/emhttp/plugins/dynamix/CPUvms.page @@ -22,10 +22,12 @@ $cpus = cpu_list(); $total = count($cpus); $spinner = "
"; $cpuset = implode(';',$cpus); +$is_intel_cpu = is_intel_cpu(); +$core_types = $is_intel_cpu ? get_intel_core_types() : []; function create($type = "") { // create the table header. Make multiple rows when CPU cores are many ;) - global $total, $cpus; + global $total, $cpus, $is_intel_cpu, $core_types; $loop = floor(($total-1)/32) + 1; $text = []; for ($c = 0; $c < $loop; $c++) { @@ -39,8 +41,12 @@ function create($type = "") { } $label = implode('
', array_fill(0, $loop, 'CORES:' . ($cpu2 ? '
CORES:' : ''))); if ($type == "vm") echo "VCPUS"; + echo "$label" . implode(array_map(function($t) { - return "$t"; + global $is_intel_cpu, $core_types; + [$cpu1, $cpu2] = my_preg_split('/[,
]/',$t); + if ($is_intel_cpu && count($core_types) > 0) $core_type = "$core_types[$cpu1]"; else $core_type = ""; + return "$t"; }, $text)); } ?> @@ -175,7 +181,10 @@ function ct() { /* Inject thread to containers toggles */ if ($('a[onclick^="thread2containers"]').length === 0) { $('form[name=ct]').find('thead tr th:gt(1)').each((i, elem) => { - elem.innerHTML = elem.innerHTML.replace(/(\d+)/g, '$1'); + // Preserve the existing title if available + let existingTitle = elem.title || ""; + let newTitle = existingTitle ? existingTitle + " _(Toggle thread to containers)_" : "_(Toggle thread to containers)_"; + elem.innerHTML = elem.innerHTML.replace(/(\d+)/g, '$1'); }); } }); diff --git a/emhttp/plugins/dynamix/DashStats.page b/emhttp/plugins/dynamix/DashStats.page index 5f2e59ad0..1e418c080 100644 --- a/emhttp/plugins/dynamix/DashStats.page +++ b/emhttp/plugins/dynamix/DashStats.page @@ -14,19 +14,6 @@ Nchan="wg_poller,update_1,update_2,update_3,ups_status:stop,vm_dashusage" */ ?>

+
_(Processor)_
@@ -265,14 +257,16 @@ switch ($theme) { + "; + if ($is_intel_cpu && count($core_types) > 0) $core_type = "({$core_types[$cpu1]})"; else $core_type = ""; if ($cpu2) - echo "CPU $cpu1 - HT $cpu20%
0%
"; + echo "CPU $cpu1 $core_type - HT $cpu2 0%
0%
"; else - echo "CPU $cpu10%
"; + echo "CPU $cpu1 $core_type0%
"; echo ""; } ?> diff --git a/emhttp/plugins/dynamix/include/CPUset.php b/emhttp/plugins/dynamix/include/CPUset.php index bca85c112..e87409e10 100644 --- a/emhttp/plugins/dynamix/include/CPUset.php +++ b/emhttp/plugins/dynamix/include/CPUset.php @@ -17,7 +17,8 @@ require_once "$docroot/webGui/include/Helpers.php"; // add translations $_SERVER['REQUEST_URI'] = 'settings'; require_once "$docroot/webGui/include/Translations.php"; - +$is_intel_cpu = is_intel_cpu(); +$core_types = $is_intel_cpu ? get_intel_core_types() : []; $cpus = explode(';',$_POST['cpus']??''); $corecount = 0; foreach ($cpus as $pair) { @@ -32,7 +33,7 @@ function scan($area, $text) { function create($id, $name, $vcpu) { // create the list of checkboxes. Make multiple rows when CPU cores are many ;) - global $cpus; + global $cpus,$is_intel_cpu,$core_types; $total = count($cpus); $loop = floor(($total-1)/32)+1; $text = []; @@ -48,8 +49,12 @@ function create($id, $name, $vcpu) { $check1 = ($vcpu && in_array($cpu1, $vcpu)) ? 'checked':''; $check2 = $cpu2 ? ($vcpu && (in_array($cpu2, $vcpu)) ? 'checked':''):''; if (empty($text[$n])) $text[$n] = ''; - $text[$n] .="
"; - if ($cpu2) $text[$n] .= "
"; + if ($is_intel_cpu && count($core_types) > 0) $core_type = "{$core_types[$cpu1]}"; else $core_type = ""; + $text[$n] .="
"; + if ($cpu2) { + if ($is_intel_cpu && count($core_types) > 0) $core_type = "{$core_types[$cpu2]}"; else $core_type = ""; + $text[$n] .= "
"; + } } } echo implode(array_map(function($t){return "$t";},$text)); diff --git a/emhttp/plugins/dynamix/include/Helpers.php b/emhttp/plugins/dynamix/include/Helpers.php index 68474afcf..d21633c64 100644 --- a/emhttp/plugins/dynamix/include/Helpers.php +++ b/emhttp/plugins/dynamix/include/Helpers.php @@ -416,4 +416,62 @@ function device_exists($name) global $disks,$devs; return (array_key_exists($name, $disks) && !str_contains(_var($disks[$name],'status'),'_NP')) || (array_key_exists($name, $devs)); } + + +# Check for process Core Types. +function parse_cpu_ranges($file) { + if (!is_file($file)) return null; + $ranges = file_get_contents($file); + $ranges = trim($ranges); + $cores = []; + foreach (explode(',', $ranges) as $range) { + if (strpos($range, '-') !== false) { + list($start, $end) = explode('-', $range); + $cores = array_merge($cores, range((int)$start, (int)$end)); + } else { + $cores[] = (int)$range; + } + } + return $cores; +} + +function get_intel_core_types() { + $core_types = array(); + $cpu_core_file = "/sys/devices/cpu_core/cpus"; + $cpu_atom_file = "/sys/devices/cpu_atom/cpus"; + $p_cores = parse_cpu_ranges($cpu_core_file); + $e_cores = parse_cpu_ranges($cpu_atom_file); + if ($p_cores) { + foreach ($p_cores as $core) { + $core_types[$core] = _("P-Core"); + } + } + if ($e_cores) { + foreach ($e_cores as $core) { + $core_types[$core] = _("E-Core"); + } + } + return $core_types; +} + +function dmidecode($key,$n,$all=true) { + $entries = array_filter(explode($key,shell_exec("dmidecode -qt$n")??"")); + $properties = []; + foreach ($entries as $entry) { + $property = []; + foreach (explode("\n",$entry) as $line) if (strpos($line,': ')!==false) { + [$key,$value] = my_explode(': ',trim($line)); + $property[$key] = $value; + } + $properties[] = $property; + } + return $all ? $properties : $properties[0]??null; +} + +function is_intel_cpu() { + $cpu = dmidecode('Processor Information','4',0); + $cpu_vendor = $cpu['Manufacturer'] ?? ""; + $is_intel_cpu = stripos($cpu_vendor, "intel") !== false ? true : false; + return $is_intel_cpu; +} ?> diff --git a/emhttp/plugins/dynamix/include/SysDevs.php b/emhttp/plugins/dynamix/include/SysDevs.php index 32fbddb22..73b9e09aa 100644 --- a/emhttp/plugins/dynamix/include/SysDevs.php +++ b/emhttp/plugins/dynamix/include/SysDevs.php @@ -211,11 +211,20 @@ EOT; } break; case 't2': + $is_intel_cpu = is_intel_cpu(); + $core_types = $is_intel_cpu ? get_intel_core_types() : []; + var_dump($is_intel_cpu,$core_types); exec('cat /sys/devices/system/cpu/*/topology/thread_siblings_list|sort -nu',$pairs); $i = 1; foreach ($pairs as $line) { + $line2 = $line; $line = preg_replace(['/(\d+)[-,](\d+)/','/(\d+)\b/'],['$1 / $2','cpu $1'],$line); - echo "".(strpos($line,'/')===false?"Single":"Pair ".$i++).":$line"; + if ($is_intel_cpu && count($core_types) > 0) { + [$cpu1, $cpu2] = my_preg_split('/[,-]/',$line2); + $core = $cpu1; + $core_type = "({$core_types[$core]})"; + } else $core_type = ""; + echo "".(strpos($line,'/')===false?"Single":"Pair ".$i++).":$line $core_type"; } break; case 't3': From f1bb7124f313e3a49dda03e7cac108a8c8f51b21 Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Fri, 4 Apr 2025 12:11:34 +0100 Subject: [PATCH 04/85] Add helper functions --- emhttp/plugins/dynamix/include/Helpers.php | 87 ++++++++++++++++++++++ sbin/savepcidata | 11 +-- 2 files changed, 88 insertions(+), 10 deletions(-) diff --git a/emhttp/plugins/dynamix/include/Helpers.php b/emhttp/plugins/dynamix/include/Helpers.php index 68474afcf..9185a532d 100644 --- a/emhttp/plugins/dynamix/include/Helpers.php +++ b/emhttp/plugins/dynamix/include/Helpers.php @@ -416,4 +416,91 @@ function device_exists($name) global $disks,$devs; return (array_key_exists($name, $disks) && !str_contains(_var($disks[$name],'status'),'_NP')) || (array_key_exists($name, $devs)); } + +// Load saved PCI data +function loadSavedData($filename) { + if (!file_exists($filename)) { + die("File not found: $filename\n"); + } + + return json_decode(file_get_contents($filename), true); +} + +// Run lspci -Dmn to get the current devices +function loadCurrentPCIData() { + $output = shell_exec('lspci -Dmn'); + $devices = []; + + foreach (explode("\n", trim($output)) as $line) { + $parts = explode(" ", $line); + + if (count($parts) < 6) continue; // Skip malformed lines + + $device = [ + 'class' => trim($parts[1], '"'), + 'vendor_id' => trim($parts[2], '"'), + 'device_id' => trim($parts[3], '"'), + ]; + + $devices[$parts[0]] = $device; + } + return $devices; +} + +// Compare the saved and current data +function comparePCIData() { + + $changes = []; + $saved = loadSavedData("/boot/config/savedpcidata.json"); + $current = loadCurrentPCIData(); + #$current = loadSavedData("/boot/config/current.json"); + + // Compare saved devices with current devices + foreach ($saved as $pci_id => $saved_device) { + if (!isset($current[$pci_id])) { + // Device has been removed + $changes[$pci_id] = [ + 'status' => 'removed', + 'device' => $saved_device + ]; + } else { + // Device exists in both, check for modifications + $current_device = $current[$pci_id]; + $differences = []; + + // Compare fields + foreach (['vendor_id', 'device_id', 'class'] as $field) { + if (isset($saved_device[$field]) && isset($current_device[$field]) && $saved_device[$field] !== $current_device[$field]) { + $differences[$field] = [ + 'old' => $saved_device[$field], + 'new' => $current_device[$field] + ]; + } + } + + if (!empty($differences)) { + $changes[$pci_id] = [ + 'status' => 'changed', + 'device' => $current_device, + 'differences' => $differences + ]; + } + } + } + + // Check for added devices + foreach ($current as $pci_id => $current_device) { + if (!isset($saved[$pci_id])) { + // Device has been added + $changes[$pci_id] = [ + 'status' => 'added', + 'device' => $current_device + ]; + } + } + return $changes; +} + + + ?> diff --git a/sbin/savepcidata b/sbin/savepcidata index 01d24ae46..50ef0b56f 100755 --- a/sbin/savepcidata +++ b/sbin/savepcidata @@ -10,21 +10,12 @@ if (count($parts) < 6) continue; // Skip malformed lines $device = [ - 'pci_address' => $parts[0], // Full PCI address 'class' => trim($parts[1], '"'), 'vendor_id' => trim($parts[2], '"'), 'device_id' => trim($parts[3], '"'), - 'revision' => (strpos($parts[4], '-r') === 0) ? substr($parts[4], 2) : null, ]; - // Determine correct indices for subsystem vendor/device IDs - $subsys_vendor_index = (isset($device['revision']) ? 5 : 4); - $subsys_device_index = $subsys_vendor_index + 1; - - $device['subsystem_vendor_id'] = trim($parts[$subsys_vendor_index], '"'); - $device['subsystem_device_id'] = trim($parts[$subsys_device_index], '"'); - - $devices[] = $device; + $devices[$parts[0]] = $device; } file_put_contents("/boot/config/savedpcidata.json",json_encode($devices,JSON_PRETTY_PRINT)); From 37e03531deee29d274820ee68e5ce7250132a9a0 Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Sat, 5 Apr 2025 22:08:43 +0100 Subject: [PATCH 05/85] VM Functions and System devices. --- .../dynamix.vm.manager/include/VMMachines.php | 17 ++++++++- .../dynamix.vm.manager/include/libvirt.php | 12 ++++++ .../javascript/vmmanager.js | 38 +++++++++++-------- emhttp/plugins/dynamix/SysDevs.page | 21 ++++++++++ emhttp/plugins/dynamix/include/Helpers.php | 13 +++++-- emhttp/plugins/dynamix/include/PCIUpdate.php | 34 +++++++++++++++++ emhttp/plugins/dynamix/include/SysDevs.php | 30 +++++++++++++++ sbin/savepcidata | 4 ++ 8 files changed, 147 insertions(+), 22 deletions(-) create mode 100644 emhttp/plugins/dynamix/include/PCIUpdate.php diff --git a/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php b/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php index 549fdb9f0..eb1bd6187 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php +++ b/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php @@ -39,6 +39,7 @@ $i = 0; $kvm = ['var kvm=[];']; $show = explode(',',unscript(_var($_GET,'show'))); $path = _var($domain_cfg,'MEDIADIR'); +$pci_device_changes = comparePCIData(); foreach ($vms as $vm) { $res = $lv->get_domain_by_name($vm); @@ -52,6 +53,14 @@ foreach ($vms as $vm) { $image = substr($icon,-4)=='.png' ? "" : (substr($icon,0,5)=='icon-' ? "" : ""); $arrConfig = domain_to_config($uuid); $snapshots = getvmsnapshots($vm) ; + $vmpciids = $lv->domain_get_vm_pciids($vm); + $pcierror = false; + foreach($vmpciids as $pciid => $pcidetail) { + if (isset($pci_device_changes["0000:".$pciid])) { + $pcierror = true; + $image = ''; + } + } $cdroms = $lv->get_cdrom_stats($res,true,true) ; if ($state == 'running') { $mem = $dom['memory']/1024; @@ -117,7 +126,7 @@ foreach ($vms as $vm) { unset($dom); if (!isset($domain_cfg["CONSOLE"])) $vmrcconsole = "web" ; else $vmrcconsole = $domain_cfg["CONSOLE"] ; if (!isset($domain_cfg["RDPOPT"])) $vmrcconsole .= ";no" ; else $vmrcconsole .= ";".$domain_cfg["RDPOPT"] ; - $menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s', '%s')\"", addslashes($vm),addslashes($uuid),addslashes($template),$state,addslashes($vmrcurl),strtoupper($vmrcprotocol),addslashes($log),addslashes($fstype), $vmrcconsole,false,addslashes(str_replace('"',"'",$WebUI))); + $menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s', '%s', %s)\"", addslashes($vm),addslashes($uuid),addslashes($template),$state,addslashes($vmrcurl),strtoupper($vmrcprotocol),addslashes($log),addslashes($fstype), $vmrcconsole,false,addslashes(str_replace('"',"'",$WebUI)),$pcierror); $kvm[] = "kvm.push({id:'$uuid',state:'$state'});"; switch ($state) { case 'running': @@ -196,7 +205,11 @@ foreach ($vms as $vm) { $title = _('Select ISO image'); $cdstr = $cdromcount." / 2"; echo ""; - echo "$image$vm
"._($status)."
"; + echo "$image"; + echo "$vm"; + #var_dump($pcierror,$vmpciids); + if ($pcierror) echo ""; + echo "
"._($status)."
"; echo "$desc"; echo "$vcpu"; echo "$mem"; diff --git a/emhttp/plugins/dynamix.vm.manager/include/libvirt.php b/emhttp/plugins/dynamix.vm.manager/include/libvirt.php index 69f77f5c5..018f469dc 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/libvirt.php +++ b/emhttp/plugins/dynamix.vm.manager/include/libvirt.php @@ -2257,6 +2257,18 @@ class Libvirt { return ['pci' => $devs_pci, 'usb' => $devs_usb]; } + function domain_get_vm_pciids($domain) { + $hostdevs=$this->domain_get_host_devices_pci($domain); + $vmpcidevs=[]; + foreach($hostdevs as $key => $dev) { + $vmpcidevs[$dev['id']] = [ + 'vendor_id' => ltrim($dev['vendor_id'], '0x'), + 'device_id' => ltrim($dev['product_id'], '0x'), + ]; + } + return $vmpcidevs; + } + function get_nic_info($domain) { $macs = $this->get_xpath($domain, "//domain/devices/interface/mac/@address", false); if (!$macs) return $this->_set_last_error(); diff --git a/emhttp/plugins/dynamix.vm.manager/javascript/vmmanager.js b/emhttp/plugins/dynamix.vm.manager/javascript/vmmanager.js index e7899cb32..71431b8ff 100644 --- a/emhttp/plugins/dynamix.vm.manager/javascript/vmmanager.js +++ b/emhttp/plugins/dynamix.vm.manager/javascript/vmmanager.js @@ -83,7 +83,7 @@ function ajaxVMDispatchWebUI(params, spin){ } },'json'); } -function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, fstype="QEMU",consolein="web;no",usage=false,webui=""){ +function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, fstype="QEMU",consolein="web;no",usage=false,webui="",pcierror=false){ var opts = []; var path = location.pathname; var x = path.indexOf("?"); @@ -172,22 +172,28 @@ function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, f ajaxVMDispatch({action:"domain-destroy", uuid:uuid}, "loadlist"); }}); } else { - opts.push({text:_("Start"), icon:"fa-play", action:function(e) { - e.preventDefault(); - ajaxVMDispatch({action:"domain-start", uuid:uuid}, "loadlist"); - }}); - if (vmrcprotocol == "VNC" || vmrcprotocol == "SPICE") { - if (console == "web" || console == "both") { - opts.push({text:_("Start with console")+ " (" + vmrcprotocol + ")" , icon:"fa-play", action:function(e) { - e.preventDefault(); - ajaxVMDispatchconsole({action:"domain-start-console", uuid:uuid, vmrcurl:vmrcurl}, "loadlist") ; - }});} - if (console == "remote" || console == "both") { - opts.push({text:_("Start with remote-viewer")+ " (" + vmrcprotocol + ")" , icon:"fa-play", action:function(e) { - e.preventDefault(); - ajaxVMDispatchconsoleRV({action:"domain-start-consoleRV", uuid:uuid, vmrcurl:vmrcurl}, "loadlist") ; - }}); + if (!pcierror) { + opts.push({text:_("Start"), icon:"fa-play", action:function(e) { + e.preventDefault(); + ajaxVMDispatch({action:"domain-start", uuid:uuid}, "loadlist"); + }}); + if (vmrcprotocol == "VNC" || vmrcprotocol == "SPICE") { + if (console == "web" || console == "both") { + opts.push({text:_("Start with console")+ " (" + vmrcprotocol + ")" , icon:"fa-play", action:function(e) { + e.preventDefault(); + ajaxVMDispatchconsole({action:"domain-start-console", uuid:uuid, vmrcurl:vmrcurl}, "loadlist") ; + }});} + if (console == "remote" || console == "both") { + opts.push({text:_("Start with remote-viewer")+ " (" + vmrcprotocol + ")" , icon:"fa-play", action:function(e) { + e.preventDefault(); + ajaxVMDispatchconsoleRV({action:"domain-start-consoleRV", uuid:uuid, vmrcurl:vmrcurl}, "loadlist") ; + }}); + } } + } else { + opts.push({text:_("Start disabled due to PCI Changes"), icon:"fa fa-minus-circle orb red-orb", action:function(e) { + e.preventDefault(); + }}); } } opts.push({divider:true}); diff --git a/emhttp/plugins/dynamix/SysDevs.page b/emhttp/plugins/dynamix/SysDevs.page index dce5eb649..02ed63cf8 100644 --- a/emhttp/plugins/dynamix/SysDevs.page +++ b/emhttp/plugins/dynamix/SysDevs.page @@ -46,6 +46,27 @@ function applyCfg() { $("#applycfg").attr("disabled",true); }); } +function ackPCI(pcidevice,action) { + switch(action) { + case 'removed': + // Remove entry from saved. + swaltext = "_(Acknowledge removal of PCI Address)_: "+pcidevice; + break; + case 'changed': + // Update saved with current + swaltext = "_(Acknowledge update of PCI Address)_: "+pcidevice; + break; + case 'added': + // Add to saved. + swaltext = "_(Acknowledge addition of PCI Address)_: "+pcidevice; + break; + } + swal({title:"Are you sure?",text:swaltext,type:"warning",html:true,showCancelButton:true},function(){ + $.post('/webGui/include/PCIUpdate.php',{action:action,pciid:pcidevice}) + $('#t1').load('/webGui/include/SysDevs.php',{table:'t1'}); + }); +} + diff --git a/emhttp/plugins/dynamix/include/Helpers.php b/emhttp/plugins/dynamix/include/Helpers.php index 9185a532d..1a24d1a21 100644 --- a/emhttp/plugins/dynamix/include/Helpers.php +++ b/emhttp/plugins/dynamix/include/Helpers.php @@ -419,11 +419,11 @@ function device_exists($name) // Load saved PCI data function loadSavedData($filename) { - if (!file_exists($filename)) { - die("File not found: $filename\n"); - } + if (file_exists($filename)) { + $saveddata = file_get_contents($filename); + } else $saveddata = ""; - return json_decode(file_get_contents($filename), true); + return json_decode($saveddata, true); } // Run lspci -Dmn to get the current devices @@ -436,10 +436,14 @@ function loadCurrentPCIData() { if (count($parts) < 6) continue; // Skip malformed lines + $description_str = shell_exec(("lspci -s ".$parts[0])); + $description = preg_replace('/^\S+\s+/', '', $description_str); + $device = [ 'class' => trim($parts[1], '"'), 'vendor_id' => trim($parts[2], '"'), 'device_id' => trim($parts[3], '"'), + 'description' => trim($description,'"'), ]; $devices[$parts[0]] = $device; @@ -452,6 +456,7 @@ function comparePCIData() { $changes = []; $saved = loadSavedData("/boot/config/savedpcidata.json"); + if (!$saved) return []; $current = loadCurrentPCIData(); #$current = loadSavedData("/boot/config/current.json"); diff --git a/emhttp/plugins/dynamix/include/PCIUpdate.php b/emhttp/plugins/dynamix/include/PCIUpdate.php new file mode 100644 index 000000000..70c85d6f2 --- /dev/null +++ b/emhttp/plugins/dynamix/include/PCIUpdate.php @@ -0,0 +1,34 @@ + + diff --git a/emhttp/plugins/dynamix/include/SysDevs.php b/emhttp/plugins/dynamix/include/SysDevs.php index 32fbddb22..1027c3a7f 100644 --- a/emhttp/plugins/dynamix/include/SysDevs.php +++ b/emhttp/plugins/dynamix/include/SysDevs.php @@ -18,6 +18,8 @@ require_once "$docroot/webGui/include/Helpers.php"; $_SERVER['REQUEST_URI'] = 'tools'; require_once "$docroot/webGui/include/Translations.php"; +$pci_device_diffs = comparePCIData(); + function usb_physical_port($usbbusdev) { if (preg_match('/^Bus (?P\S+) Device (?P\S+): ID (?P\S+)(?P.*)$/', $usbbusdev, $usbMatch)) { //udevadm info -a --name=/dev/bus/usb/003/002 | grep KERNEL== @@ -115,6 +117,14 @@ case 't1': $iommuinuse[] = (strpos($string,'/')) ? strstr($string, '/', true) : $string; } exec('lsscsi -s',$lsscsi); + // Filter for 'removed' devices + $removedArr = array_filter($pci_device_diffs, function($entry) { + return isset($entry['status']) && $entry['status'] === 'removed'; + }); + foreach ($removedArr as $removedpci => $removeddata) { + $groups[] = "IOMMU "._("Removed"); + $groups[] = "\tR[{$removeddata['device']['vendor_id']}:{$removeddata['device']['device_id']}] ".str_replace("0000:","",$removedpci)." ".trim($removeddata['device']['description'],"\n"); + } foreach ($groups as $line) { if (!$line) continue; if ($line[0]=='I') { @@ -126,6 +136,8 @@ case 't1': $line = preg_replace("/^\t/","",$line); $vd = trim(explode(" ", $line)[0], "[]"); $pciaddress = explode(" ", $line)[1]; + $removed = $line[0]=='R' ? true : false; + if ($removed) $line=preg_replace('/R/', '', $line, 1); if (preg_match($BDF_REGEX, $pciaddress)) { // By default lspci does not output the when the only domain in the system is 0000. Add it back. $pciaddress = "0000:".$pciaddress; @@ -140,13 +152,31 @@ case 't1': if ((strpos($line, 'Host bridge') === false) && (strpos($line, 'PCI bridge') === false)) { if (file_exists('/sys/kernel/iommu_groups/'.$iommu.'/devices/'.$pciaddress.'/reset')) echo ""; echo ""; + if (!$removed) { echo in_array($iommu, $iommuinuse) ? '| or just echo (in_array($pciaddress."|".$vd, $vfio_cfg_devices) || in_array($pciaddress, $vfio_cfg_devices)) ? " checked>" : ">"; + } } else { echo ""; } echo '',$line,''; + if (array_key_exists($pciaddress,$pci_device_diffs)) { + echo ""; + echo ""; + echo _("PCI Device change"); + echo " "._("Action").":".ucfirst(_($pci_device_diffs[$pciaddress]['status']))." "; + if ($pci_device_diffs[$pciaddress]['status']!="removed") echo $pci_device_diffs[$pciaddress]['device']['description']; + echo ""; + if ($pci_device_diffs[$pciaddress]['status']=="changed") { + echo ""; + echo _("Differences"); + foreach($pci_device_diffs[$pciaddress]['differences'] as $key => $changes){ + echo " $key "._("before").":{$changes['old']} "._("after").":{$changes['new']} "; + } + echo ""; + } + } unset($outputvfio); switch (true) { case (strpos($line, 'USB controller') !== false): diff --git a/sbin/savepcidata b/sbin/savepcidata index 50ef0b56f..23b2a918a 100755 --- a/sbin/savepcidata +++ b/sbin/savepcidata @@ -9,10 +9,14 @@ if (count($parts) < 6) continue; // Skip malformed lines + $description_str = shell_exec(("lspci -s ".$parts[0])); + $description = preg_replace('/^\S+\s+/', '', $description_str); + $device = [ 'class' => trim($parts[1], '"'), 'vendor_id' => trim($parts[2], '"'), 'device_id' => trim($parts[3], '"'), + 'description' => trim($description,'"'), ]; $devices[$parts[0]] = $device; From c2e9450e903fe6e57fa8a71b9478f3c08514af8c Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Sat, 5 Apr 2025 22:26:02 +0100 Subject: [PATCH 06/85] Add dashboard update. --- emhttp/plugins/dynamix/include/DashboardApps.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix/include/DashboardApps.php b/emhttp/plugins/dynamix/include/DashboardApps.php index aa49190a6..781863d14 100644 --- a/emhttp/plugins/dynamix/include/DashboardApps.php +++ b/emhttp/plugins/dynamix/include/DashboardApps.php @@ -115,6 +115,7 @@ if ($_POST['vms']) { } echo ""; $running = 0; + $pci_device_changes = comparePCIData(); foreach ($vms as $vm) { $res = $lv->get_domain_by_name($vm); $uuid = libvirt_domain_get_uuid_string($res); @@ -156,7 +157,15 @@ if ($_POST['vms']) { if (!isset($domain_cfg["CONSOLE"])) $vmrcconsole = "web"; else $vmrcconsole = $domain_cfg["CONSOLE"]; if (!isset($domain_cfg["RDPOPT"])) $vmrcconsole .= ";no"; else $vmrcconsole .= ";".$domain_cfg["RDPOPT"]; $WebUI = html_entity_decode($arrConfig["template"]["webui"]); - $menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm), addslashes($uuid), addslashes($template), $state, addslashes($vmrcurl), strtoupper($vmrcprotocol), addslashes($log),addslashes($fstype), $vmrcconsole,false,addslashes(str_replace('"',"'",$WebUI))); + $vmpciids = $lv->domain_get_vm_pciids($vm); + $pcierror = false; + foreach($vmpciids as $pciid => $pcidetail) { + if (isset($pci_device_changes["0000:".$pciid])) { + $pcierror = true; + $image = ''; + } + } + $menu = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm), addslashes($uuid), addslashes($template), $state, addslashes($vmrcurl), strtoupper($vmrcprotocol), addslashes($log),addslashes($fstype), $vmrcconsole,false,addslashes(str_replace('"',"'",$WebUI)),$pcierror); $icon = $lv->domain_get_icon_url($res); switch ($state) { case 'running': From 002b857b2265ea2ea8a4bd2e0de8671515d10342 Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Sun, 6 Apr 2025 09:27:46 +0100 Subject: [PATCH 07/85] Add acknowledge all button --- emhttp/plugins/dynamix/SysDevs.page | 20 +++++++++-- emhttp/plugins/dynamix/include/PCIUpdate.php | 38 ++++++++++++++------ emhttp/plugins/dynamix/include/SysDevs.php | 4 +++ 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/emhttp/plugins/dynamix/SysDevs.page b/emhttp/plugins/dynamix/SysDevs.page index 02ed63cf8..675c0d07d 100644 --- a/emhttp/plugins/dynamix/SysDevs.page +++ b/emhttp/plugins/dynamix/SysDevs.page @@ -46,6 +46,17 @@ function applyCfg() { $("#applycfg").attr("disabled",true); }); } +function formatFullInput(input) { + return input + .split(';') + .filter(Boolean) // remove empty trailing entry + .map(entry => { + let [pci, status] = entry.split(','); + status = status.charAt(0).toUpperCase() + status.slice(1).toLowerCase(); + return `${pci} _(${status})_`; + }) + .join('
'); +} function ackPCI(pcidevice,action) { switch(action) { case 'removed': @@ -60,10 +71,15 @@ function ackPCI(pcidevice,action) { // Add to saved. swaltext = "_(Acknowledge addition of PCI Address)_: "+pcidevice; break; + case 'all': + // Add to saved. + swaltext = "_(Acknowledge all PCI Address modifications)_:
"+formatFullInput(pcidevice); + break; } swal({title:"Are you sure?",text:swaltext,type:"warning",html:true,showCancelButton:true},function(){ - $.post('/webGui/include/PCIUpdate.php',{action:action,pciid:pcidevice}) - $('#t1').load('/webGui/include/SysDevs.php',{table:'t1'}); + $.post('/webGui/include/PCIUpdate.php',{action:action,pciid:pcidevice}).done(function(d) { + if (d == "OK") $('#t1').load('/webGui/include/SysDevs.php',{table:'t1'}); + }); }); } diff --git a/emhttp/plugins/dynamix/include/PCIUpdate.php b/emhttp/plugins/dynamix/include/PCIUpdate.php index 70c85d6f2..ae19c8fab 100644 --- a/emhttp/plugins/dynamix/include/PCIUpdate.php +++ b/emhttp/plugins/dynamix/include/PCIUpdate.php @@ -14,20 +14,38 @@ "; echo _("PCI Device change"); echo " "._("Action").":".ucfirst(_($pci_device_diffs[$pciaddress]['status']))." "; + $ackparm .= $pciaddress.",".$pci_device_diffs[$pciaddress]['status'].";"; if ($pci_device_diffs[$pciaddress]['status']!="removed") echo $pci_device_diffs[$pciaddress]['device']['description']; echo ""; if ($pci_device_diffs[$pciaddress]['status']=="changed") { @@ -224,8 +226,10 @@ case 't1': if (file_exists("/var/log/vfio-pci") && filesize("/var/log/vfio-pci")) { echo ''; } + if ($ackparm == "") $ackdisable =" disabled "; else $ackdisable = ""; echo ''; echo ''; + echo ''; echo ''; echo << From 9f1d5e6b3ba9f838852915a7820b509ad214592b Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Mon, 7 Apr 2025 11:13:12 +0100 Subject: [PATCH 08/85] PHP Fixes and code updates --- .../dynamix.vm.manager/include/VMMachines.php | 8 ++--- .../dynamix.vm.manager/include/libvirt.php | 4 +-- .../plugins/dynamix/include/DashboardApps.php | 6 ++-- emhttp/plugins/dynamix/include/Helpers.php | 31 ++++++++++--------- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php b/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php index eb1bd6187..f1e9bcb3b 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php +++ b/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php @@ -56,10 +56,7 @@ foreach ($vms as $vm) { $vmpciids = $lv->domain_get_vm_pciids($vm); $pcierror = false; foreach($vmpciids as $pciid => $pcidetail) { - if (isset($pci_device_changes["0000:".$pciid])) { - $pcierror = true; - $image = ''; - } + if (isset($pci_device_changes["0000:".$pciid])) $pcierror = true; } $cdroms = $lv->get_cdrom_stats($res,true,true) ; if ($state == 'running') { @@ -207,8 +204,7 @@ foreach ($vms as $vm) { echo ""; echo "$image"; echo "$vm"; - #var_dump($pcierror,$vmpciids); - if ($pcierror) echo ""; + if ($pcierror) echo ""; echo "
"._($status)."
"; echo "$desc"; echo "$vcpu"; diff --git a/emhttp/plugins/dynamix.vm.manager/include/libvirt.php b/emhttp/plugins/dynamix.vm.manager/include/libvirt.php index 018f469dc..49345df28 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/libvirt.php +++ b/emhttp/plugins/dynamix.vm.manager/include/libvirt.php @@ -2262,8 +2262,8 @@ class Libvirt { $vmpcidevs=[]; foreach($hostdevs as $key => $dev) { $vmpcidevs[$dev['id']] = [ - 'vendor_id' => ltrim($dev['vendor_id'], '0x'), - 'device_id' => ltrim($dev['product_id'], '0x'), + 'vendor_id' => ltrim($dev['vendor_id'] ?? "", '0x'), + 'device_id' => ltrim($dev['product_id'] ?? "", '0x'), ]; } return $vmpcidevs; diff --git a/emhttp/plugins/dynamix/include/DashboardApps.php b/emhttp/plugins/dynamix/include/DashboardApps.php index 781863d14..d569250c0 100644 --- a/emhttp/plugins/dynamix/include/DashboardApps.php +++ b/emhttp/plugins/dynamix/include/DashboardApps.php @@ -156,7 +156,7 @@ if ($_POST['vms']) { $log = (is_file("/var/log/libvirt/qemu/$vm.log") ? "libvirt/qemu/$vm.log" : ''); if (!isset($domain_cfg["CONSOLE"])) $vmrcconsole = "web"; else $vmrcconsole = $domain_cfg["CONSOLE"]; if (!isset($domain_cfg["RDPOPT"])) $vmrcconsole .= ";no"; else $vmrcconsole .= ";".$domain_cfg["RDPOPT"]; - $WebUI = html_entity_decode($arrConfig["template"]["webui"]); + $WebUI = html_entity_decode($arrConfig["template"]["webui"]??""); $vmpciids = $lv->domain_get_vm_pciids($vm); $pcierror = false; foreach($vmpciids as $pciid => $pcidetail) { @@ -187,7 +187,9 @@ if ($_POST['vms']) { break; } $image = substr($icon,-4)=='.png' ? "" : (substr($icon,0,5)=='icon-' ? "" : ""); - echo "$image$vm
"._($status)."
"; + echo "$image$vm"; + if ($pcierror) echo ""; + echo "
"._($status)."
"; if ($state == "running") { #Build VM Usage array. $menuusage = sprintf("onclick=\"addVMContext('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s')\"", addslashes($vm), addslashes($uuid), addslashes($template), $state, addslashes($vmrcurl), strtoupper($vmrcprotocol), addslashes($log),addslashes($fstype), $vmrcconsole,true,addslashes(str_replace('"',"'",$WebUI))); diff --git a/emhttp/plugins/dynamix/include/Helpers.php b/emhttp/plugins/dynamix/include/Helpers.php index 1a24d1a21..3fdac326f 100644 --- a/emhttp/plugins/dynamix/include/Helpers.php +++ b/emhttp/plugins/dynamix/include/Helpers.php @@ -431,22 +431,26 @@ function loadCurrentPCIData() { $output = shell_exec('lspci -Dmn'); $devices = []; - foreach (explode("\n", trim($output)) as $line) { - $parts = explode(" ", $line); + if (file_exists("/boot/config/current.json")){ + $devices = loadSavedData("/boot/config/current.json"); + } else { + foreach (explode("\n", trim($output)) as $line) { + $parts = explode(" ", $line); - if (count($parts) < 6) continue; // Skip malformed lines + if (count($parts) < 6) continue; // Skip malformed lines - $description_str = shell_exec(("lspci -s ".$parts[0])); - $description = preg_replace('/^\S+\s+/', '', $description_str); + $description_str = shell_exec(("lspci -s ".$parts[0])); + $description = preg_replace('/^\S+\s+/', '', $description_str); - $device = [ - 'class' => trim($parts[1], '"'), - 'vendor_id' => trim($parts[2], '"'), - 'device_id' => trim($parts[3], '"'), - 'description' => trim($description,'"'), - ]; + $device = [ + 'class' => trim($parts[1], '"'), + 'vendor_id' => trim($parts[2], '"'), + 'device_id' => trim($parts[3], '"'), + 'description' => trim($description,'"'), + ]; - $devices[$parts[0]] = $device; + $devices[$parts[0]] = $device; + } } return $devices; } @@ -458,8 +462,7 @@ function comparePCIData() { $saved = loadSavedData("/boot/config/savedpcidata.json"); if (!$saved) return []; $current = loadCurrentPCIData(); - #$current = loadSavedData("/boot/config/current.json"); - + // Compare saved devices with current devices foreach ($saved as $pci_id => $saved_device) { if (!isset($current[$pci_id])) { From f041c83a92b6a2c85f22e19792e41f30131e0ff2 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Thu, 3 Apr 2025 18:10:05 -0700 Subject: [PATCH 09/85] feat: implement ThemeHelper class to centralize theme management and improve color handling across various pages --- .../DockerSettings.page | 2 +- .../include/CreateDocker.php | 3 +- .../dynamix.vm.manager/VMMachines.page | 9 +- .../dynamix.vm.manager/VMSettings.page | 2 +- emhttp/plugins/dynamix/DashStats.page | 3 +- emhttp/plugins/dynamix/DisplaySettings.page | 9 +- emhttp/plugins/dynamix/include/.login.php | 13 +- .../plugins/dynamix/include/.set-password.php | 18 +- emhttp/plugins/dynamix/include/Boot.php | 13 +- .../dynamix/include/DefaultPageLayout.php | 23 ++- .../plugins/dynamix/include/ThemeHelper.php | 154 ++++++++++++++++++ 11 files changed, 204 insertions(+), 45 deletions(-) create mode 100644 emhttp/plugins/dynamix/include/ThemeHelper.php diff --git a/emhttp/plugins/dynamix.docker.manager/DockerSettings.page b/emhttp/plugins/dynamix.docker.manager/DockerSettings.page index 3102585b3..8ca6473b9 100644 --- a/emhttp/plugins/dynamix.docker.manager/DockerSettings.page +++ b/emhttp/plugins/dynamix.docker.manager/DockerSettings.page @@ -123,7 +123,7 @@ function hide_eth($network) { return in_array($network,$mgmt_port) && lan_port('wlan0',true)==1; } -$bgcolor = strstr('white,azure',$display['theme']) ? '#f2f2f2' : '#1c1c1c'; +$bgcolor = $themeHelper->isLightTheme() ? '#f2f2f2' : '#1c1c1c'; // $themeHelper set in DefaultPageLayout.php //Check if docker.cfg does exist $no_dockercfg = !is_file('/boot/config/docker.cfg'); diff --git a/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php b/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php index c47c50b16..0e77a6cb4 100644 --- a/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php +++ b/emhttp/plugins/dynamix.docker.manager/include/CreateDocker.php @@ -318,7 +318,8 @@ $authoringMode = $dockercfg['DOCKER_AUTHORING_MODE'] == "yes" ? true : false; $authoring = $authoringMode ? 'advanced' : 'noshow'; $disableEdit = $authoringMode ? 'false' : 'true'; $showAdditionalInfo = ''; -$bgcolor = strstr('white,azure',$display['theme']) ? '#f2f2f2' : '#1c1c1c'; + +$bgcolor = $themeHelper->isLightTheme() ? '#f2f2f2' : '#1c1c1c'; // $themeHelper set in DefaultPageLayout.php # Search for existing TAILSCALE_ entries in the Docker template $TS_existing_vars = false; diff --git a/emhttp/plugins/dynamix.vm.manager/VMMachines.page b/emhttp/plugins/dynamix.vm.manager/VMMachines.page index 9e4ef09e2..dd9adc55c 100644 --- a/emhttp/plugins/dynamix.vm.manager/VMMachines.page +++ b/emhttp/plugins/dynamix.vm.manager/VMMachines.page @@ -20,12 +20,13 @@ Markdown="false" getThemeName(); $cpus = cpu_list(); -$hover = in_array($theme,['white','azure']) ? 'rgba(0,0,0,0.1)' : 'rgba(255,255,255,0.1)'; -$bgcolor = in_array($theme,['white','azure']) ? '#f2f2f2' : '#1c1c1c'; -$fgcolor = in_array($theme,['white','azure']) ? '#1c1c1c' : '#f2f2f2'; -$incolor = $theme!='gray' ? $bgcolor : '#121510'; +$hover = $themeHelper->isLightTheme() ? 'rgba(0,0,0,0.1)' : 'rgba(255,255,255,0.1)'; +$bgcolor = $themeHelper->isLightTheme() ? '#f2f2f2' : '#1c1c1c'; +$fgcolor = $themeHelper->isLightTheme() ? '#1c1c1c' : '#f2f2f2'; +$incolor = $themeName !== 'gray' ? $bgcolor : '#121510'; function showCPUs($uuid) { global $cpus; diff --git a/emhttp/plugins/dynamix.vm.manager/VMSettings.page b/emhttp/plugins/dynamix.vm.manager/VMSettings.page index 12337f911..d6c5e29e7 100644 --- a/emhttp/plugins/dynamix.vm.manager/VMSettings.page +++ b/emhttp/plugins/dynamix.vm.manager/VMSettings.page @@ -92,7 +92,7 @@ if (is_file('/boot/syslinux/syslinux.cfg')) { $arrValidNetworks = getValidNetworks(); $pcie_acs_override = detect($bootcfg, $bootenv, 'pcie_acs_override'); $vfio_allow_unsafe = detect($bootcfg, $bootenv, 'allow_unsafe_interrupts'); -$bgcolor = strstr('white,azure',$display['theme']) ? '#f2f2f2' : '#1c1c1c'; +$bgcolor = $themeHelper->isLightTheme() ? '#f2f2f2' : '#1c1c1c'; $started = $var['fsState']=='Started'; $libvirt_up = $libvirt_running=='yes'; $libvirt_log = file_exists("/var/log/libvirt/libvirtd.log"); diff --git a/emhttp/plugins/dynamix/DashStats.page b/emhttp/plugins/dynamix/DashStats.page index 6cf9e30ed..26df08ff3 100644 --- a/emhttp/plugins/dynamix/DashStats.page +++ b/emhttp/plugins/dynamix/DashStats.page @@ -50,8 +50,7 @@ function customTiles($column) { } // adjust the text color in log window -$fgcolor = in_array($theme,['white','azure']) ? '#1c1c1c' : '#f2f2f2'; -exec("sed -ri 's/^\.logLine\{color:#......;/.logLine{color:$fgcolor;/' $docroot/plugins/dynamix.docker.manager/log.htm >/dev/null &"); +$themeHelper->updateDockerLogColor($docroot); // $themeHelper set in DefaultPageLayout.php exec("/etc/rc.d/rc.docker status >/dev/null",$dummy,$dockerd); exec("/etc/rc.d/rc.libvirt status >/dev/null",$dummy,$libvirtd); diff --git a/emhttp/plugins/dynamix/DisplaySettings.page b/emhttp/plugins/dynamix/DisplaySettings.page index e15b0bb31..2c8f93f4d 100644 --- a/emhttp/plugins/dynamix/DisplaySettings.page +++ b/emhttp/plugins/dynamix/DisplaySettings.page @@ -249,11 +249,14 @@ _(Temperature unit)_: :display_temperature_unit_help: +getThemeName(); // $themeHelper set in DefaultPageLayout.php + $themes = $themeHelper->getThemesFromFileSystem($docroot); +?> _(Dynamix color theme)_: : diff --git a/emhttp/plugins/dynamix/include/.login.php b/emhttp/plugins/dynamix/include/.login.php index 73b6b554b..dc789afbe 100644 --- a/emhttp/plugins/dynamix/include/.login.php +++ b/emhttp/plugins/dynamix/include/.login.php @@ -236,7 +236,10 @@ $myFile = "case-model.cfg"; $myCase = file_exists("$boot/$myFile") ? file_get_contents("$boot/$myFile") : false; extract(parse_plugin_cfg('dynamix', true)); -$theme_dark = in_array($display['theme'], ['black', 'gray']); + +require_once "$docroot/plugins/dynamix/include/ThemeHelper.php"; +$themeHelper = new ThemeHelper($display['theme']); +$isDarkTheme = $themeHelper->isDarkTheme(); ?> @@ -274,8 +277,8 @@ $theme_dark = in_array($display['theme'], ['black', 'gray']); / /************************/ body { - background: ; - color: ; + background: ; + color: ; font-family: clear-sans, sans-serif; font-size: .875rem; padding: 0; @@ -359,7 +362,7 @@ $theme_dark = in_array($display['theme'], ['black', 'gray']); width: 500px; margin: 6rem auto; border-radius: 10px; - background: ; + background: ; } #login::after { content: ""; @@ -451,7 +454,7 @@ $theme_dark = in_array($display['theme'], ['black', 'gray']); /************************/ @media (max-width: 500px) { body { - background: ; + background: ; } [type=email], [type=number], [type=password], [type=search], [type=tel], [type=text], [type=url], textarea { font-size: 16px; /* This prevents the mobile browser from zooming in on the input-field. */ diff --git a/emhttp/plugins/dynamix/include/.set-password.php b/emhttp/plugins/dynamix/include/.set-password.php index 091f31be3..67c8a1a1d 100644 --- a/emhttp/plugins/dynamix/include/.set-password.php +++ b/emhttp/plugins/dynamix/include/.set-password.php @@ -40,7 +40,9 @@ if (!empty($_POST['password']) && !empty($_POST['confirmPassword'])) { return $POST_ERROR = $VALIDATION_MESSAGES['saveError']; } -$THEME_DARK = in_array($display['theme'],['black','gray']); +require_once "$docroot/plugins/dynamix/include/ThemeHelper.php"; +$themeHelper = new ThemeHelper($display['theme']); +$isDarkTheme = $themeHelper->isDarkTheme(); ?> @@ -78,13 +80,13 @@ $THEME_DARK = in_array($display['theme'],['black','gray']); / /************************/ :root { - --body-bg: ; - --body-text-color: ; - --section-bg: ; - --shadow: ; - --form-text-color: ; - --form-bg-color: ; - --form-border-color: ; + --body-bg: ; + --body-text-color: ; + --section-bg: ; + --shadow: ; + --form-text-color: ; + --form-bg-color: ; + --form-border-color: ; } body { background: var(--body-bg); diff --git a/emhttp/plugins/dynamix/include/Boot.php b/emhttp/plugins/dynamix/include/Boot.php index 278f9928d..9d1423c1a 100644 --- a/emhttp/plugins/dynamix/include/Boot.php +++ b/emhttp/plugins/dynamix/include/Boot.php @@ -24,13 +24,10 @@ $var = parse_ini_file("/var/local/emhttp/var.ini"); /** * Just like DefaultPageLayout.php */ -$theme = strtok($display['theme'],'-'); -$themes1 = in_array($theme,['black','white']); -$themes2 = in_array($theme,['gray','azure']); -$themeHtmlClass = "Theme--$theme"; -if ($themes2) { - $themeHtmlClass .= " Theme--sidebar"; -} +require_once "$docroot/plugins/dynamix/include/ThemeHelper.php"; +$themeHelper = new ThemeHelper($display['theme']); +$themeName = $themeHelper->getThemeName(); +$themeHtmlClass = $themeHelper->getThemeHtmlClass(); ?> lang="" class=""> @@ -46,7 +43,7 @@ if ($themes2) { "> "> -"> +"> From ac13bb701766f11c0c964a2604f485810d9fdb11 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Fri, 4 Apr 2025 20:50:21 -0700 Subject: [PATCH 24/85] refactor: implement generate_sidebar_icon_css function and update DefaultPageLayout.php to utilize it for sidebar icon CSS generation --- .../dynamix/include/DefaultPageLayout.php | 20 ++++++------- .../plugins/dynamix/include/PageBuilder.php | 30 +++++++++++++++++++ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index fc3a09484..783199677 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -37,6 +37,9 @@ $banner = "$config/plugins/dynamix/banner.png"; $notes = '/var/tmp/unRAIDServer.txt'; if (!file_exists($notes)) file_put_contents($notes,shell_exec("$docroot/plugins/dynamix.plugin.manager/scripts/plugin changes $docroot/plugins/unRAIDServer/unRAIDServer.plg")); +$taskPages = find_pages('Tasks'); +$buttonPages = find_pages('Buttons'); + function annotate($text) {echo "\n\n";} ?> @@ -79,12 +82,9 @@ function annotate($text) {echo "\n\n";} ?> -lang="" class=""> +lang="" class="getThemeHtmlClass() ?>"> <?=_var($var,'NAME')?>/<?=_var($myPage,'name')?> From 101644b46b93503ac8e15df529e525a9ce089b45 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 7 Apr 2025 15:40:01 -0700 Subject: [PATCH 29/85] chore: comment for VMSettings nitpick suggestion --- emhttp/plugins/dynamix.vm.manager/VMSettings.page | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix.vm.manager/VMSettings.page b/emhttp/plugins/dynamix.vm.manager/VMSettings.page index d6c5e29e7..8609b79ac 100644 --- a/emhttp/plugins/dynamix.vm.manager/VMSettings.page +++ b/emhttp/plugins/dynamix.vm.manager/VMSettings.page @@ -92,7 +92,7 @@ if (is_file('/boot/syslinux/syslinux.cfg')) { $arrValidNetworks = getValidNetworks(); $pcie_acs_override = detect($bootcfg, $bootenv, 'pcie_acs_override'); $vfio_allow_unsafe = detect($bootcfg, $bootenv, 'allow_unsafe_interrupts'); -$bgcolor = $themeHelper->isLightTheme() ? '#f2f2f2' : '#1c1c1c'; +$bgcolor = $themeHelper->isLightTheme() ? '#f2f2f2' : '#1c1c1c'; // $themeHelper set in DefaultPageLayout.php $started = $var['fsState']=='Started'; $libvirt_up = $libvirt_running=='yes'; $libvirt_log = file_exists("/var/log/libvirt/libvirtd.log"); From ee489bfe5f4887977afc5b8b2b34b6bcc9ab82e3 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 7 Apr 2025 15:42:00 -0700 Subject: [PATCH 30/85] refactor: add error handling for missing theme directory in ThemeHelper.php --- emhttp/plugins/dynamix/include/ThemeHelper.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix/include/ThemeHelper.php b/emhttp/plugins/dynamix/include/ThemeHelper.php index 195353f09..13bd5ad1f 100644 --- a/emhttp/plugins/dynamix/include/ThemeHelper.php +++ b/emhttp/plugins/dynamix/include/ThemeHelper.php @@ -135,7 +135,13 @@ class ThemeHelper { */ public static function getThemesFromFileSystem(string $docroot): array { $themes = []; - $themeFiles = glob("$docroot/webGui/styles/themes/*.css"); + $themePath = "$docroot/webGui/styles/themes"; + if (!is_dir($themePath)) { + error_log("Theme directory not found: $themePath"); + return $themes; + } + + $themeFiles = glob("$themePath/*.css"); foreach ($themeFiles as $themeFile) { $themeName = basename($themeFile, '.css'); From a973866514921152fe255a2037bb17c0b117926e Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 7 Apr 2025 16:34:54 -0700 Subject: [PATCH 31/85] refactor: $buttonPages output of styles and scripts location --- .../dynamix/include/DefaultPageLayout.php | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index db6964eeb..f6effd4cb 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -675,6 +675,21 @@ $.ajaxPrefilter(function(s, orig, xhr){ } }); + +',"\n"; + if (is_file($docroot.$css_theme)) echo '',"\n"; + // create page content + eval('?>'.parse_text($button['text'])); +} +?> + @@ -735,17 +750,7 @@ echo "
"; unset($buttonPages,$button); // Build page content -// Reload page every X minutes during extended viewing? -if (isset($myPage['Load']) && $myPage['Load'] > 0) echo "\n\n"; echo "
"; $tab = 1; $pages = []; From 060fb2eb197f7217a2ae611454c793c2f2969e6f Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 7 Apr 2025 16:54:15 -0700 Subject: [PATCH 33/85] refactor: move inline JavaScript from DefaultPageLayout.php to HeadInlineJS.php for improved maintainability --- .../dynamix/include/DefaultPageLayout.php | 581 +---------------- .../DefaultPageLayout/HeadInlineJS.php | 588 ++++++++++++++++++ 2 files changed, 589 insertions(+), 580 deletions(-) create mode 100644 emhttp/plugins/dynamix/include/DefaultPageLayout/HeadInlineJS.php diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index a61255f2d..4d12b54f9 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -100,587 +100,8 @@ if ($themeHelper->isSidebarTheme()) { - + + From f8d13b8b0941d0b52fc8da697724490a96b136fd Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 7 Apr 2025 17:01:23 -0700 Subject: [PATCH 34/85] refactor: move inline JavaScript from of DefaultPageLayout.php to BodyInlineJS.php for improved maintainability --- .../dynamix/include/DefaultPageLayout.php | 477 +---------------- .../DefaultPageLayout/BodyInlineJS.php | 479 ++++++++++++++++++ 2 files changed, 480 insertions(+), 476 deletions(-) create mode 100644 emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index 4d12b54f9..432d143a5 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -275,481 +275,6 @@ unset($pages,$page,$pgs,$pg,$icon,$nchan,$running,$start,$stop,$row,$script,$opt - - + diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php new file mode 100644 index 000000000..f0143b1e1 --- /dev/null +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php @@ -0,0 +1,479 @@ + + From 7d763f3f312df90408d88e81d3f1c6fee93a0e0f Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 7 Apr 2025 18:02:31 -0700 Subject: [PATCH 35/85] refactor: consolidate nchan script creation in DefaultPageLayout.php for found pages --- .../dynamix/include/DefaultPageLayout.php | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index 432d143a5..85c310661 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -38,6 +38,20 @@ if (!file_exists($notes)) file_put_contents($notes,shell_exec("$docroot/plugins/ $taskPages = find_pages('Tasks'); $buttonPages = find_pages('Buttons'); +$pages = []; // finds subpages +if (!empty($myPage['text'])) $pages[$myPage['name']] = $myPage; +if (_var($myPage,'Type')=='xmenu') $pages = array_merge($pages, find_pages($myPage['name'])); + +// build nchan scripts from found pages +foreach ($taskPages as $button) { + if (isset($button['Nchan'])) nchan_merge($button['root'], $button['Nchan']); +} +foreach ($buttonPages as $button) { + if (isset($button['Nchan'])) nchan_merge($button['root'], $button['Nchan']); +} +foreach ($pages as $page) { + if (isset($page['Nchan'])) nchan_merge($page['root'], $page['Nchan']); +} function annotate($text) {echo "\n\n";} @@ -146,8 +160,6 @@ foreach ($taskPages as $button) { $play = $task==$page ? " active" : ""; echo ""; - // create list of nchan scripts to be started - if (isset($button['Nchan'])) nchan_merge($button['root'], $button['Nchan']); } unset($taskPages); echo "
"; @@ -174,8 +186,6 @@ foreach ($buttonPages as $button) { } else { echo "
"; } - // create list of nchan scripts to be started - if (isset($button['Nchan'])) nchan_merge($button['root'], $button['Nchan']); } echo ""; @@ -188,9 +198,6 @@ unset($buttonPages,$button); // Build page content echo "
"; $tab = 1; -$pages = []; -if (!empty($myPage['text'])) $pages[$myPage['name']] = $myPage; -if (_var($myPage,'Type')=='xmenu') $pages = array_merge($pages, find_pages($myPage['name'])); if (isset($myPage['Tabs'])) $display['tabs'] = strtolower($myPage['Tabs'])=='true' ? 0 : 1; $tabbed = $display['tabs']==0 && count($pages)>1; @@ -234,8 +241,6 @@ foreach ($pages as $page) { echo ""; } } - // create list of nchan scripts to be started - if (isset($page['Nchan'])) nchan_merge($page['root'], $page['Nchan']); annotate($page['file']); // include page specific stylesheets (if existing) $css = "/{$page['root']}/sheets/{$page['name']}"; From 350aceea7f7a1de9f50e70fe7a76dfcf0081bd38 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 7 Apr 2025 18:35:09 -0700 Subject: [PATCH 36/85] refactor: enhance nchan script management in DefaultPageLayout.php by consolidating logic and improving clarity --- .../dynamix/include/DefaultPageLayout.php | 55 +++++++++---------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index 85c310661..a9a031fe0 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -28,8 +28,6 @@ $entity = $notify['entity'] & 1 == 1; $alerts = '/tmp/plugins/my_alerts.txt'; $wlan0 = file_exists('/sys/class/net/wlan0'); -$nchan = ['webGui/nchan/notify_poller','webGui/nchan/session_check']; -if ($wlan0) $nchan[] = 'webGui/nchan/wlan0'; $safemode = _var($var,'safeMode')=='yes'; $banner = "$config/plugins/dynamix/banner.png"; @@ -42,16 +40,35 @@ $pages = []; // finds subpages if (!empty($myPage['text'])) $pages[$myPage['name']] = $myPage; if (_var($myPage,'Type')=='xmenu') $pages = array_merge($pages, find_pages($myPage['name'])); +// nchan related actions +$nchan = ['webGui/nchan/notify_poller','webGui/nchan/session_check']; +if ($wlan0) $nchan[] = 'webGui/nchan/wlan0'; // build nchan scripts from found pages -foreach ($taskPages as $button) { - if (isset($button['Nchan'])) nchan_merge($button['root'], $button['Nchan']); -} -foreach ($buttonPages as $button) { - if (isset($button['Nchan'])) nchan_merge($button['root'], $button['Nchan']); -} -foreach ($pages as $page) { +$allPages = array_merge($taskPages, $buttonPages, $pages); +foreach ($allPages as $page) { if (isset($page['Nchan'])) nchan_merge($page['root'], $page['Nchan']); } +// act on nchan scripts +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 -f $docroot/$script &>/dev/null &"); + array_splice($running,array_search($row,$running),1); + } + } + if (count($running)) file_put_contents($nchan_pid,implode("\n",$running)."\n"); else @unlink($nchan_pid); +} function annotate($text) {echo "\n\n";} @@ -252,26 +269,6 @@ foreach ($pages as $page) { empty($page['Markdown']) || $page['Markdown']=='true' ? eval('?>'.Markdown(parse_text($page['text']))) : eval('?>'.parse_text($page['text'])); if ($close) echo "
"; } -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 -f $docroot/$script &>/dev/null &"); - array_splice($running,array_search($row,$running),1); - } - } - if (count($running)) file_put_contents($nchan_pid,implode("\n",$running)."\n"); else @unlink($nchan_pid); -} unset($pages,$page,$pgs,$pg,$icon,$nchan,$running,$start,$stop,$row,$script,$opt,$nchan_run); ?> From 17b3424ad251312bdb3967b5d2a0cec931fa1d0e Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 7 Apr 2025 18:49:36 -0700 Subject: [PATCH 37/85] refactor: restructure DefaultPageLayout.php by extracting header and navigation into separate files for improved organization and maintainability --- .../dynamix/include/DefaultPageLayout.php | 59 +++---------------- .../include/DefaultPageLayout/Header.php | 13 ++++ .../DefaultPageLayout/Navigation/Main.php | 44 ++++++++++++++ 3 files changed, 64 insertions(+), 52 deletions(-) create mode 100644 emhttp/plugins/dynamix/include/DefaultPageLayout/Header.php create mode 100644 emhttp/plugins/dynamix/include/DefaultPageLayout/Navigation/Main.php diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index a9a031fe0..ef0ceccf3 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -156,62 +156,17 @@ if (isset($myPage['Load'])) { -
+
- + + + + + + "; -if ($themeHelper->isSidebarTheme()) echo "
"; - -unset($buttonPages,$button); - // Build page content echo "
"; $tab = 1; diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/Header.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/Header.php new file mode 100644 index 000000000..4a33aef78 --- /dev/null +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/Header.php @@ -0,0 +1,13 @@ + diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/Navigation/Main.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/Navigation/Main.php new file mode 100644 index 000000000..762c6c653 --- /dev/null +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/Navigation/Main.php @@ -0,0 +1,44 @@ +"; +if ($themeHelper->isSidebarTheme()) echo "
"; + +unset($buttonPages,$button); From 19fe88d6330af59d69887f359747bf45c2d57f6e Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Tue, 8 Apr 2025 17:14:33 +0100 Subject: [PATCH 38/85] Update savepcidata in rc.6 --- etc/rc.d/rc.6 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/etc/rc.d/rc.6 b/etc/rc.d/rc.6 index 27022117c..be06262b1 100755 --- a/etc/rc.d/rc.6 +++ b/etc/rc.d/rc.6 @@ -76,6 +76,10 @@ if [[ -x /sbin/hwclock ]]; then fi fi +# Save PCI data to validate system changes at system start. +log "Save PCI Configuration." +/usr/local/sbin/savepcidata + # Run any local shutdown scripts: if [[ -x /etc/rc.d/rc.local_shutdown ]]; then /etc/rc.d/rc.local_shutdown stop @@ -219,10 +223,6 @@ if [[ ! -f /boot/logs/syslog && -z $MIRROR && -z $COPY ]]; then fi fi -# Save PCI data to validate system changes at system start. - -/usr/sbin/savepcidata - # Before unmounting file systems write a reboot or halt record to wtmp. /sbin/$SHUTDOWN_COMMAND -w From 469b499db1ab1b699043390e91f0452b08057841 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Tue, 8 Apr 2025 09:40:35 -0700 Subject: [PATCH 39/85] refactor: enhance navigation structure in Main.php by improving template usage and updating CSS for better layout and alignment --- .../DefaultPageLayout/Navigation/Main.php | 118 ++++++++++++------ .../plugins/dynamix/styles/default-base.css | 6 +- 2 files changed, 83 insertions(+), 41 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/Navigation/Main.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/Navigation/Main.php index 762c6c653..2b248b534 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout/Navigation/Main.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/Navigation/Main.php @@ -1,44 +1,84 @@ "; -if ($themeHelper->isSidebarTheme()) echo "
+
diff --git a/emhttp/plugins/dynamix/styles/default-base.css b/emhttp/plugins/dynamix/styles/default-base.css index 263d71659..2b8c91faf 100644 --- a/emhttp/plugins/dynamix/styles/default-base.css +++ b/emhttp/plugins/dynamix/styles/default-base.css @@ -447,7 +447,7 @@ div.title.shift { .nav-tile { height: 4rem; line-height: 4rem; - display: block; + display: flex; padding: 0; margin: 0; font-size: 1.2rem; @@ -463,11 +463,13 @@ div.title.shift { } .nav-tile.right { text-align: right; + justify-content: flex-end; } .nav-item, .nav-user { position: relative; - display: inline-block; + display: flex; + align-items: center; text-align: center; margin: 0; } From 293e1e1e12f09774f08742beabe6dd8b2de61292 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Tue, 8 Apr 2025 10:07:13 -0700 Subject: [PATCH 40/85] refactor: extract global elements from DefaultPageLayout.php into MiscElements.php for improved organization and maintainability --- .../dynamix/include/DefaultPageLayout.php | 14 ++++------- .../DefaultPageLayout/MiscElements.php | 24 +++++++++++++++++++ 2 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 emhttp/plugins/dynamix/include/DefaultPageLayout/MiscElements.php diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index ef0ceccf3..4733b9737 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -157,13 +157,9 @@ if (isset($myPage['Load'])) {
- + - - - -
-
-
- - - + + + diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/MiscElements.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/MiscElements.php new file mode 100644 index 000000000..099e87f50 --- /dev/null +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/MiscElements.php @@ -0,0 +1,24 @@ + + + + + + + +
+ +
+ + \ No newline at end of file From 4d4266ff76d29d64d031dbbc86d62a1d05a24480 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Tue, 8 Apr 2025 12:33:17 -0700 Subject: [PATCH 41/85] refactor: extract main content logic from DefaultPageLayout.php into MainContent.php for improved organization and maintainability --- .../dynamix/include/DefaultPageLayout.php | 80 ++----------------- .../include/DefaultPageLayout/MainContent.php | 61 ++++++++++++++ 2 files changed, 69 insertions(+), 72 deletions(-) create mode 100644 emhttp/plugins/dynamix/include/DefaultPageLayout/MainContent.php diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index 4733b9737..c6d32366a 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -156,76 +156,12 @@ if (isset($myPage['Load'])) { -
- - - - - -"; -$tab = 1; -if (isset($myPage['Tabs'])) $display['tabs'] = strtolower($myPage['Tabs'])=='true' ? 0 : 1; -$tabbed = $display['tabs']==0 && count($pages)>1; - -foreach ($pages as $page) { - $close = false; - if (isset($page['Title'])) { - eval("\$title=\"".htmlspecialchars($page['Title'])."\";"); - if ($tabbed) { - echo "
"; - $close = true; - } else { - if ($tab==1) echo "
"; - echo "
"; - echo tab_title($title,$page['root'],_var($page,'Tag',false)); - echo "
"; - } - $tab++; - } - if (isset($page['Type']) && $page['Type']=='menu') { - $pgs = find_pages($page['name']); - foreach ($pgs as $pg) { - @eval("\$title=\"".htmlspecialchars($pg['Title'])."\";"); - $icon = _var($pg,'Icon',""); - if (substr($icon,-4)=='.png') { - $root = $pg['root']; - if (file_exists("$docroot/$root/images/$icon")) { - $icon = ""; - } elseif (file_exists("$docroot/$root/$icon")) { - $icon = ""; - } else { - $icon = ""; - } - } elseif (substr($icon,0,5)=='icon-') { - $icon = ""; - } elseif ($icon[0]!='<') { - if (substr($icon,0,3)!='fa-') $icon = "fa-$icon"; - $icon = ""; - } - echo ""; - } - } - annotate($page['file']); - // include page specific stylesheets (if existing) - $css = "/{$page['root']}/sheets/{$page['name']}"; - $css_stock = "$css.css"; - $css_theme = "$css-$theme.css"; - if (is_file($docroot.$css_stock)) echo '',"\n"; - if (is_file($docroot.$css_theme)) echo '',"\n"; - // create page content - empty($page['Markdown']) || $page['Markdown']=='true' ? eval('?>'.Markdown(parse_text($page['text']))) : eval('?>'.parse_text($page['text'])); - if ($close) echo "
"; -} -unset($pages,$page,$pgs,$pg,$icon,$nchan,$running,$start,$stop,$row,$script,$opt,$nchan_run); -?> -
- - - - - +
+ + + + + + + diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/MainContent.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/MainContent.php new file mode 100644 index 000000000..a0da8c741 --- /dev/null +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/MainContent.php @@ -0,0 +1,61 @@ +"; +$tab = 1; +if (isset($myPage['Tabs'])) $display['tabs'] = strtolower($myPage['Tabs'])=='true' ? 0 : 1; +$tabbed = $display['tabs']==0 && count($pages)>1; + +foreach ($pages as $page) { + $close = false; + if (isset($page['Title'])) { + eval("\$title=\"".htmlspecialchars($page['Title'])."\";"); + if ($tabbed) { + echo "
"; + $close = true; + } else { + if ($tab==1) echo "
"; + echo "
"; + echo tab_title($title,$page['root'],_var($page,'Tag',false)); + echo "
"; + } + $tab++; + } + if (isset($page['Type']) && $page['Type']=='menu') { + $pgs = find_pages($page['name']); + foreach ($pgs as $pg) { + @eval("\$title=\"".htmlspecialchars($pg['Title'])."\";"); + $icon = _var($pg,'Icon',""); + if (substr($icon,-4)=='.png') { + $root = $pg['root']; + if (file_exists("$docroot/$root/images/$icon")) { + $icon = ""; + } elseif (file_exists("$docroot/$root/$icon")) { + $icon = ""; + } else { + $icon = ""; + } + } elseif (substr($icon,0,5)=='icon-') { + $icon = ""; + } elseif ($icon[0]!='<') { + if (substr($icon,0,3)!='fa-') $icon = "fa-$icon"; + $icon = ""; + } + echo ""; + } + } + annotate($page['file']); + // include page specific stylesheets (if existing) + $css = "/{$page['root']}/sheets/{$page['name']}"; + $css_stock = "$css.css"; + $css_theme = "$css-$theme.css"; + if (is_file($docroot.$css_stock)) echo '',"\n"; + if (is_file($docroot.$css_theme)) echo '',"\n"; + // create page content + empty($page['Markdown']) || $page['Markdown']=='true' ? eval('?>'.Markdown(parse_text($page['text']))) : eval('?>'.parse_text($page['text'])); + if ($close) echo "
"; +} +unset($pages,$page,$pgs,$pg,$icon,$nchan,$running,$start,$stop,$row,$script,$opt,$nchan_run); +?> +
\ No newline at end of file From 270f0735cf500615553ce5499598a549f0aca99a Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Tue, 8 Apr 2025 13:06:49 -0700 Subject: [PATCH 42/85] refactor: centralize stylesheet inclusion logic in DefaultPageLayout.php by creating includePageStylesheets function for improved code reuse and maintainability --- .../dynamix/include/DefaultPageLayout.php | 18 +++++++++++++----- .../include/DefaultPageLayout/MainContent.php | 6 ------ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index c6d32366a..feef9707b 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -135,18 +135,26 @@ if ($themeHelper->isSidebarTheme()) { ',"\n"; if (is_file($docroot.$css_theme)) echo '',"\n"; - // create page content +} + +foreach ($buttonPages as $button) { + annotate($button['file']); + includePageStylesheets($button); eval('?>'.parse_text($button['text'])); } +foreach ($pages as $page) { + annotate($page['file']); + includePageStylesheets($page); +} + // Reload page every X minutes during extended viewing? if (isset($myPage['Load'])) { echo generateReloadScript($myPage['Load']); diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/MainContent.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/MainContent.php index a0da8c741..20e32b70f 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout/MainContent.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/MainContent.php @@ -46,12 +46,6 @@ foreach ($pages as $page) { } } annotate($page['file']); - // include page specific stylesheets (if existing) - $css = "/{$page['root']}/sheets/{$page['name']}"; - $css_stock = "$css.css"; - $css_theme = "$css-$theme.css"; - if (is_file($docroot.$css_stock)) echo '',"\n"; - if (is_file($docroot.$css_theme)) echo '',"\n"; // create page content empty($page['Markdown']) || $page['Markdown']=='true' ? eval('?>'.Markdown(parse_text($page['text']))) : eval('?>'.parse_text($page['text'])); if ($close) echo "
"; From e8a84ca42841c0204469efcc0a7c20d4b64dec24 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Tue, 8 Apr 2025 13:17:09 -0700 Subject: [PATCH 43/85] refactor: reorganize HTML structure in DefaultPageLayout.php and MainContent.php for improved readability and maintainability --- .../dynamix/include/DefaultPageLayout.php | 15 ++- .../include/DefaultPageLayout/MainContent.php | 101 +++++++++--------- 2 files changed, 59 insertions(+), 57 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index feef9707b..b8dc82c4a 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -164,12 +164,11 @@ if (isset($myPage['Load'])) { -
- - - - - - - + + + + + + + diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/MainContent.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/MainContent.php index 20e32b70f..f76c4605a 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout/MainContent.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/MainContent.php @@ -1,55 +1,58 @@ "; $tab = 1; if (isset($myPage['Tabs'])) $display['tabs'] = strtolower($myPage['Tabs'])=='true' ? 0 : 1; $tabbed = $display['tabs']==0 && count($pages)>1; - -foreach ($pages as $page) { - $close = false; - if (isset($page['Title'])) { - eval("\$title=\"".htmlspecialchars($page['Title'])."\";"); - if ($tabbed) { - echo "
"; - $close = true; - } else { - if ($tab==1) echo "
"; - echo "
"; - echo tab_title($title,$page['root'],_var($page,'Tag',false)); - echo "
"; - } - $tab++; - } - if (isset($page['Type']) && $page['Type']=='menu') { - $pgs = find_pages($page['name']); - foreach ($pgs as $pg) { - @eval("\$title=\"".htmlspecialchars($pg['Title'])."\";"); - $icon = _var($pg,'Icon',""); - if (substr($icon,-4)=='.png') { - $root = $pg['root']; - if (file_exists("$docroot/$root/images/$icon")) { - $icon = ""; - } elseif (file_exists("$docroot/$root/$icon")) { - $icon = ""; - } else { - $icon = ""; - } - } elseif (substr($icon,0,5)=='icon-') { - $icon = ""; - } elseif ($icon[0]!='<') { - if (substr($icon,0,3)!='fa-') $icon = "fa-$icon"; - $icon = ""; - } - echo ""; - } - } - annotate($page['file']); - // create page content - empty($page['Markdown']) || $page['Markdown']=='true' ? eval('?>'.Markdown(parse_text($page['text']))) : eval('?>'.parse_text($page['text'])); - if ($close) echo "
"; -} -unset($pages,$page,$pgs,$pg,$icon,$nchan,$running,$start,$stop,$row,$script,$opt,$nchan_run); ?> -
\ No newline at end of file +
+
+
"; + $close = true; + } else { + if ($tab==1) echo "
"; + echo "
"; + echo tab_title($title,$page['root'],_var($page,'Tag',false)); + echo "
"; + } + $tab++; + } + if (isset($page['Type']) && $page['Type']=='menu') { + $pgs = find_pages($page['name']); + foreach ($pgs as $pg) { + @eval("\$title=\"".htmlspecialchars($pg['Title'])."\";"); + $icon = _var($pg,'Icon',""); + if (substr($icon,-4)=='.png') { + $root = $pg['root']; + if (file_exists("$docroot/$root/images/$icon")) { + $icon = ""; + } elseif (file_exists("$docroot/$root/$icon")) { + $icon = ""; + } else { + $icon = ""; + } + } elseif (substr($icon,0,5)=='icon-') { + $icon = ""; + } elseif ($icon[0]!='<') { + if (substr($icon,0,3)!='fa-') $icon = "fa-$icon"; + $icon = ""; + } + echo ""; + } + } + annotate($page['file']); + // create page content + empty($page['Markdown']) || $page['Markdown']=='true' ? eval('?>'.Markdown(parse_text($page['text']))) : eval('?>'.parse_text($page['text'])); + if ($close) echo "
"; + } + unset($pages,$page,$pgs,$pg,$icon,$nchan,$running,$start,$stop,$row,$script,$opt,$nchan_run); + ?> +
+
\ No newline at end of file From 6e1564b9d88402b2f56f030c22ad8018cae688ed Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Tue, 8 Apr 2025 13:20:36 -0700 Subject: [PATCH 44/85] refactor: use webGui symlink in DefaultPageLayout.php where possible --- emhttp/plugins/dynamix/include/DefaultPageLayout.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index b8dc82c4a..73822551b 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -11,7 +11,7 @@ */ ?> getThemeName(); // keep $theme, $themes1, $themes2 vars for plugin backwards compatibility for the time being $themes1 = $themeHelper->isTopNavTheme(); @@ -29,7 +29,7 @@ $alerts = '/tmp/plugins/my_alerts.txt'; $wlan0 = file_exists('/sys/class/net/wlan0'); $safemode = _var($var,'safeMode')=='yes'; -$banner = "$config/plugins/dynamix/banner.png"; +$banner = "$config/webGui/banner.png"; $notes = '/var/tmp/unRAIDServer.txt'; if (!file_exists($notes)) file_put_contents($notes,shell_exec("$docroot/plugins/dynamix.plugin.manager/scripts/plugin changes $docroot/plugins/unRAIDServer/unRAIDServer.plg")); @@ -100,7 +100,7 @@ function generateReloadScript($loadMinutes) { "> "> "> -"> +"> "> From 1054592adbb6739107c14273889592fa74e929ff Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Fri, 4 Apr 2025 20:50:21 -0700 Subject: [PATCH 67/85] refactor: implement generate_sidebar_icon_css function and update DefaultPageLayout.php to utilize it for sidebar icon CSS generation --- .../dynamix/include/DefaultPageLayout.php | 20 ++++++------- .../plugins/dynamix/include/PageBuilder.php | 30 +++++++++++++++++++ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index 011bcaf33..5e84ea02c 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -37,6 +37,9 @@ $banner = "$config/plugins/dynamix/banner.png"; $notes = '/var/tmp/unRAIDServer.txt'; if (!file_exists($notes)) file_put_contents($notes,shell_exec("$docroot/plugins/dynamix.plugin.manager/scripts/plugin changes $docroot/plugins/unRAIDServer/unRAIDServer.plg")); +$taskPages = find_pages('Tasks'); +$buttonPages = find_pages('Buttons'); + function annotate($text) {echo "\n\n";} ?> @@ -79,12 +82,9 @@ function annotate($text) {echo "\n\n";} ?> -lang="" class=""> +lang="" class="getThemeHtmlClass() ?>"> <?=_var($var,'NAME')?>/<?=_var($myPage,'name')?> From 503b2c9fa1f9ffde41c0d290edc49cf22eaf6355 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 7 Apr 2025 15:40:01 -0700 Subject: [PATCH 72/85] chore: comment for VMSettings nitpick suggestion --- emhttp/plugins/dynamix.vm.manager/VMSettings.page | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix.vm.manager/VMSettings.page b/emhttp/plugins/dynamix.vm.manager/VMSettings.page index 5b2a7fca3..01b809ba1 100644 --- a/emhttp/plugins/dynamix.vm.manager/VMSettings.page +++ b/emhttp/plugins/dynamix.vm.manager/VMSettings.page @@ -92,7 +92,7 @@ if (is_file('/boot/syslinux/syslinux.cfg')) { $arrValidNetworks = getValidNetworks(); $pcie_acs_override = detect($bootcfg, $bootenv, 'pcie_acs_override'); $vfio_allow_unsafe = detect($bootcfg, $bootenv, 'allow_unsafe_interrupts'); -$bgcolor = $themeHelper->isLightTheme() ? '#f2f2f2' : '#1c1c1c'; +$bgcolor = $themeHelper->isLightTheme() ? '#f2f2f2' : '#1c1c1c'; // $themeHelper set in DefaultPageLayout.php $started = $var['fsState']=='Started'; $libvirt_up = $libvirt_running=='yes'; $libvirt_log = file_exists("/var/log/libvirt/libvirtd.log"); From b8b666990c42e243445766919da6bf923a1287fe Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 7 Apr 2025 15:42:00 -0700 Subject: [PATCH 73/85] refactor: add error handling for missing theme directory in ThemeHelper.php --- emhttp/plugins/dynamix/include/ThemeHelper.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix/include/ThemeHelper.php b/emhttp/plugins/dynamix/include/ThemeHelper.php index 195353f09..13bd5ad1f 100644 --- a/emhttp/plugins/dynamix/include/ThemeHelper.php +++ b/emhttp/plugins/dynamix/include/ThemeHelper.php @@ -135,7 +135,13 @@ class ThemeHelper { */ public static function getThemesFromFileSystem(string $docroot): array { $themes = []; - $themeFiles = glob("$docroot/webGui/styles/themes/*.css"); + $themePath = "$docroot/webGui/styles/themes"; + if (!is_dir($themePath)) { + error_log("Theme directory not found: $themePath"); + return $themes; + } + + $themeFiles = glob("$themePath/*.css"); foreach ($themeFiles as $themeFile) { $themeName = basename($themeFile, '.css'); From b6428a5f2ff22c8d6583f220404dc5845b2ba763 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 5 May 2025 12:44:30 -0700 Subject: [PATCH 74/85] refactor: Reload Dash/Main pages when visibility becomes visible --- .../dynamix/include/DefaultPageLayout/BodyInlineJS.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php index f0143b1e1..3b15fe7f7 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php @@ -433,7 +433,13 @@ document.addEventListener("visibilitychange", (event) => { if (document.hidden) { nchanFocusStop(); } else { - nchanFocusStart(); + 0):?> + $(function(){ + setTimeout(function(){window.location.reload();},1000); + }); + + nchanFocusStart(); + } }); From 6edb1c6ea1518faa91fde601314f19378ebb944c Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 5 May 2025 12:45:15 -0700 Subject: [PATCH 75/85] Remove 1 second delay --- .../dynamix/include/DefaultPageLayout/BodyInlineJS.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php index 3b15fe7f7..1412956a3 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php @@ -434,9 +434,7 @@ document.addEventListener("visibilitychange", (event) => { nchanFocusStop(); } else { 0):?> - $(function(){ - setTimeout(function(){window.location.reload();},1000); - }); + window.location.reload(); nchanFocusStart(); From 3b982b8399f761126fb7e6280b5d4b41032f57f9 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 5 May 2025 12:53:01 -0700 Subject: [PATCH 76/85] Fix: Don't reload page if modal is open --- .../dynamix/include/DefaultPageLayout.php | 316 +++++++++++------- .../DefaultPageLayout/BodyInlineJS.php | 8 +- 2 files changed, 198 insertions(+), 126 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index 432d143a5..d4886b654 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -1,4 +1,4 @@ - -getThemeName(); // keep $theme, $themes1, $themes2 vars for plugin backwards compatibility for the time being @@ -18,7 +18,7 @@ $themes1 = $themeHelper->isTopNavTheme(); $themes2 = $themeHelper->isSidebarTheme(); $themeHelper->updateDockerLogColor($docroot); -$display['font'] = filter_var($_COOKIE['fontSize'] ?? $display['font'] ?? '',FILTER_SANITIZE_NUMBER_FLOAT,FILTER_FLAG_ALLOW_FRACTION); +$display['font'] = filter_var($_COOKIE['fontSize'] ?? $display['font'] ?? '', FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION); $header = $display['header']; // keep $header, $backgnd vars for plugin backwards compatibility for the time being $backgnd = $display['background']; @@ -29,28 +29,38 @@ $alerts = '/tmp/plugins/my_alerts.txt'; $wlan0 = file_exists('/sys/class/net/wlan0'); $nchan = ['webGui/nchan/notify_poller','webGui/nchan/session_check']; -if ($wlan0) $nchan[] = 'webGui/nchan/wlan0'; -$safemode = _var($var,'safeMode')=='yes'; +if ($wlan0) { + $nchan[] = 'webGui/nchan/wlan0'; +} +$safemode = _var($var, 'safeMode') == 'yes'; $banner = "$config/plugins/dynamix/banner.png"; $notes = '/var/tmp/unRAIDServer.txt'; -if (!file_exists($notes)) file_put_contents($notes,shell_exec("$docroot/plugins/dynamix.plugin.manager/scripts/plugin changes $docroot/plugins/unRAIDServer/unRAIDServer.plg")); +if (!file_exists($notes)) { + file_put_contents($notes, shell_exec("$docroot/plugins/dynamix.plugin.manager/scripts/plugin changes $docroot/plugins/unRAIDServer/unRAIDServer.plg")); +} $taskPages = find_pages('Tasks'); $buttonPages = find_pages('Buttons'); -function annotate($text) {echo "\n\n";} +function annotate($text) +{ + echo "\n\n"; +} -function generateReloadScript($loadMinutes) { - if ($loadMinutes <= 0) return ''; +function generateReloadScript($loadMinutes) +{ + if ($loadMinutes <= 0) { + return ''; + } $interval = $loadMinutes * 60000; return "\n\n"; } ?> -lang="" class="getThemeHtmlClass() ?>"> +lang="" class="getThemeHtmlClass() ?>"> -<?=_var($var,'NAME')?>/<?=_var($myPage,'name')?> +<?=_var($var, 'NAME')?>/<?=_var($myPage, 'name')?> @@ -58,7 +68,7 @@ function generateReloadScript($loadMinutes) { - + "> "> "> @@ -86,10 +96,10 @@ function generateReloadScript($loadMinutes) { } -isSidebarTheme()) { - echo generate_sidebar_icon_css($taskPages, $buttonPages); + echo generate_sidebar_icon_css($taskPages, $buttonPages); } ?> @@ -101,24 +111,46 @@ if ($themeHelper->isSidebarTheme()) { - + -',"\n"; - if (is_file($docroot.$css_theme)) echo '',"\n"; - // create page content - eval('?>'.parse_text($button['text'])); + annotate($button['file']); + // include page specific stylesheets (if existing) + $css = "/{$button['root']}/sheets/{$button['name']}"; + $css_stock = "$css.css"; + $css_theme = "$css-$theme.css"; // @todo add syslog for deprecation notice + if (is_file($docroot.$css_stock)) { + echo '',"\n"; + } + if (is_file($docroot.$css_theme)) { + echo '',"\n"; + } + // create page content + eval('?>'.parse_text($button['text'])); } // Reload page every X minutes during extended viewing? -if (isset($myPage['Load'])) { - echo generateReloadScript($myPage['Load']); +if (isset($myPage['Load']) && $myPage['Load'] > 0) { + ?> + + @@ -136,51 +168,63 @@ if (isset($myPage['Load'])) {
-"; -if ($themeHelper->isSidebarTheme()) echo "
"; unset($buttonPages,$button); @@ -189,83 +233,105 @@ unset($buttonPages,$button); echo "
"; $tab = 1; $pages = []; -if (!empty($myPage['text'])) $pages[$myPage['name']] = $myPage; -if (_var($myPage,'Type')=='xmenu') $pages = array_merge($pages, find_pages($myPage['name'])); -if (isset($myPage['Tabs'])) $display['tabs'] = strtolower($myPage['Tabs'])=='true' ? 0 : 1; -$tabbed = $display['tabs']==0 && count($pages)>1; +if (!empty($myPage['text'])) { + $pages[$myPage['name']] = $myPage; +} +if (_var($myPage, 'Type') == 'xmenu') { + $pages = array_merge($pages, find_pages($myPage['name'])); +} +if (isset($myPage['Tabs'])) { + $display['tabs'] = strtolower($myPage['Tabs']) == 'true' ? 0 : 1; +} +$tabbed = $display['tabs'] == 0 && count($pages) > 1; foreach ($pages as $page) { - $close = false; - if (isset($page['Title'])) { - eval("\$title=\"".htmlspecialchars($page['Title'])."\";"); - if ($tabbed) { - echo "
"; - $close = true; - } else { - if ($tab==1) echo "
"; - echo "
"; - echo tab_title($title,$page['root'],_var($page,'Tag',false)); - echo "
"; - } - $tab++; - } - if (isset($page['Type']) && $page['Type']=='menu') { - $pgs = find_pages($page['name']); - foreach ($pgs as $pg) { - @eval("\$title=\"".htmlspecialchars($pg['Title'])."\";"); - $icon = _var($pg,'Icon',""); - if (substr($icon,-4)=='.png') { - $root = $pg['root']; - if (file_exists("$docroot/$root/images/$icon")) { - $icon = ""; - } elseif (file_exists("$docroot/$root/$icon")) { - $icon = ""; + $close = false; + if (isset($page['Title'])) { + eval("\$title=\"".htmlspecialchars($page['Title'])."\";"); + if ($tabbed) { + echo "
"; + $close = true; } else { - $icon = ""; + if ($tab == 1) { + echo "
"; + } + echo "
"; + echo tab_title($title, $page['root'], _var($page, 'Tag', false)); + echo "
"; } - } elseif (substr($icon,0,5)=='icon-') { - $icon = ""; - } elseif ($icon[0]!='<') { - if (substr($icon,0,3)!='fa-') $icon = "fa-$icon"; - $icon = ""; - } - echo ""; + $tab++; + } + if (isset($page['Type']) && $page['Type'] == 'menu') { + $pgs = find_pages($page['name']); + foreach ($pgs as $pg) { + @eval("\$title=\"".htmlspecialchars($pg['Title'])."\";"); + $icon = _var($pg, 'Icon', ""); + if (substr($icon, -4) == '.png') { + $root = $pg['root']; + if (file_exists("$docroot/$root/images/$icon")) { + $icon = ""; + } elseif (file_exists("$docroot/$root/$icon")) { + $icon = ""; + } else { + $icon = ""; + } + } elseif (substr($icon, 0, 5) == 'icon-') { + $icon = ""; + } elseif ($icon[0] != '<') { + if (substr($icon, 0, 3) != 'fa-') { + $icon = "fa-$icon"; + } + $icon = ""; + } + echo ""; + } + } + // create list of nchan scripts to be started + if (isset($page['Nchan'])) { + nchan_merge($page['root'], $page['Nchan']); + } + annotate($page['file']); + // include page specific stylesheets (if existing) + $css = "/{$page['root']}/sheets/{$page['name']}"; + $css_stock = "$css.css"; + $css_theme = "$css-$theme.css"; + if (is_file($docroot.$css_stock)) { + echo '',"\n"; + } + if (is_file($docroot.$css_theme)) { + echo '',"\n"; + } + // create page content + empty($page['Markdown']) || $page['Markdown'] == 'true' ? eval('?>'.Markdown(parse_text($page['text']))) : eval('?>'.parse_text($page['text'])); + if ($close) { + echo "
"; } - } - // create list of nchan scripts to be started - if (isset($page['Nchan'])) nchan_merge($page['root'], $page['Nchan']); - annotate($page['file']); - // include page specific stylesheets (if existing) - $css = "/{$page['root']}/sheets/{$page['name']}"; - $css_stock = "$css.css"; - $css_theme = "$css-$theme.css"; - if (is_file($docroot.$css_stock)) echo '',"\n"; - if (is_file($docroot.$css_theme)) echo '',"\n"; - // create page content - empty($page['Markdown']) || $page['Markdown']=='true' ? eval('?>'.Markdown(parse_text($page['text']))) : eval('?>'.parse_text($page['text'])); - if ($close) echo "
"; } 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 -f $docroot/$script &>/dev/null &"); - array_splice($running,array_search($row,$running),1); + $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 -f $docroot/$script &>/dev/null &"); + array_splice($running, array_search($row, $running), 1); + } + } + if (count($running)) { + file_put_contents($nchan_pid, implode("\n", $running)."\n"); + } else { + @unlink($nchan_pid); } - } - if (count($running)) file_put_contents($nchan_pid,implode("\n",$running)."\n"); else @unlink($nchan_pid); } unset($pages,$page,$pgs,$pg,$icon,$nchan,$running,$start,$stop,$row,$script,$opt,$nchan_run); ?> @@ -274,7 +340,7 @@ unset($pages,$page,$pgs,$pg,$icon,$nchan,$running,$start,$stop,$row,$script,$opt
- - + + diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php index 1412956a3..4ec20cfc3 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php @@ -434,7 +434,13 @@ document.addEventListener("visibilitychange", (event) => { nchanFocusStop(); } else { 0):?> - window.location.reload(); + if ( dialogOpen() ) { + clearInterval(timers.reload); + setTimerReload(); + nchanFocusStart(); + } else { + window.location.reload(); + } nchanFocusStart(); From 2edd2b4e5198cf22f6f363d00c0ba90d29b55aae Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 5 May 2025 12:57:39 -0700 Subject: [PATCH 77/85] Refactor: Only reload Main/Dash on visibility if Live Updates disabled --- .../dynamix/include/DefaultPageLayout/BodyInlineJS.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php index 4ec20cfc3..45cb99b95 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php @@ -411,25 +411,19 @@ $('body').on('click','a,.ca_href', function(e) { var nchanPaused = false; var blurTimer = false; + $(window).focus(function() { nchanFocusStart(); }); // Stop nchan on loss of focus - $(window).blur(function() { blurTimer = setTimeout(function(){ nchanFocusStop(); },30000); }); - document.addEventListener("visibilitychange", (event) => { - - if (document.hidden) { - nchanFocusStop(); - } - if (document.hidden) { nchanFocusStop(); } else { @@ -445,7 +439,6 @@ document.addEventListener("visibilitychange", (event) => { nchanFocusStart(); } - }); function nchanFocusStart() { @@ -486,4 +479,5 @@ function nchanFocusStop(banner=true) { } } } + From f5bbc6c0670d6fb122ad7e2da405656e2e18b42f Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 5 May 2025 13:06:44 -0700 Subject: [PATCH 78/85] refactor: move reload page during extended viewing in abstracted HeadInlineJS --- .../dynamix/include/DefaultPageLayout.php | 23 ------------------- .../DefaultPageLayout/HeadInlineJS.php | 19 +++++++++++++++ 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index d4886b654..0f64731e9 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -129,29 +129,6 @@ foreach ($buttonPages as $button) { // create page content eval('?>'.parse_text($button['text'])); } - -// Reload page every X minutes during extended viewing? -if (isset($myPage['Load']) && $myPage['Load'] > 0) { - ?> - - diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/HeadInlineJS.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/HeadInlineJS.php index 77b95e280..f191553d6 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout/HeadInlineJS.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/HeadInlineJS.php @@ -585,4 +585,23 @@ $.ajaxPrefilter(function(s, orig, xhr){ s.data += "csrf_token="+csrf_token; } }); + + 0):?> + // Reload page every X minutes during extended viewing? + function setTimerReload() { + timers.reload = setInterval(function(){ + if (nchanPaused === false && ! dialogOpen() ) { + location.reload(); + } + },); + } + $(document).click(function(e) { + clearInterval(timers.reload); + setTimerReload(); + }); + function dialogOpen() { + return ($('.sweet-alert').is(':visible') || $('.swal-overlay--show-modal').is(':visible') ); + } + setTimerReload(); + From 727b0c625b9fee91d84181f99825d7ec26c86742 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 5 May 2025 13:09:15 -0700 Subject: [PATCH 79/85] chore: nitpick comment for liveUpdate JS --- .../dynamix/include/DefaultPageLayout/BodyInlineJS.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php index 45cb99b95..5b9359601 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/BodyInlineJS.php @@ -407,7 +407,9 @@ $('body').on('click','a,.ca_href', function(e) { } }); -// Start & stop live updates when window loses focus +// Only include window focus/blur event handlers when live updates are disabled +// to prevent unnecessary page reloads when live updates are already handling data refreshes +// nchanPaused / blurTimer used elsewhere so need to always be defined var nchanPaused = false; var blurTimer = false; From 3d755ea0fe43b132d2ed20607b66fde101a4fb0e Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 5 May 2025 14:47:57 -0700 Subject: [PATCH 80/85] refactor: clean up whitespace and formatting in DefaultPageLayout.php --- .../dynamix/include/DefaultPageLayout.php | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index 15c6461b1..203567f04 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -212,7 +212,7 @@ foreach ($buttonPages as $button) { $icon = ""; } $title = $themeHelper->isSidebarTheme() ? "" : " title=\""._($button['Title'])."\""; - echo ""; + echo ""; } else { echo "
"; } @@ -222,9 +222,6 @@ foreach ($buttonPages as $button) { } $title = $themeHelper->isSidebarTheme() ? "" : " title=\""._($button['Title'])."\""; echo ""; - } else { - echo "
"; - } } echo ""; @@ -286,17 +283,16 @@ foreach ($pages as $page) { echo ""; } } - } - annotate($page['file']); - // include page specific stylesheets (if existing) - $css = "/{$page['root']}/sheets/{$page['name']}"; - $css_stock = "$css.css"; - $css_theme = "$css-$theme.css"; - if (is_file($docroot.$css_stock)) echo '',"\n"; - if (is_file($docroot.$css_theme)) echo '',"\n"; - // create page content - empty($page['Markdown']) || $page['Markdown']=='true' ? eval('?>'.Markdown(parse_text($page['text']))) : eval('?>'.parse_text($page['text'])); - if ($close) echo "
"; + annotate($page['file']); + // include page specific stylesheets (if existing) + $css = "/{$page['root']}/sheets/{$page['name']}"; + $css_stock = "$css.css"; + $css_theme = "$css-$theme.css"; + if (is_file($docroot.$css_stock)) echo '',"\n"; + if (is_file($docroot.$css_theme)) echo '',"\n"; + // create page content + empty($page['Markdown']) || $page['Markdown']=='true' ? eval('?>'.Markdown(parse_text($page['text']))) : eval('?>'.parse_text($page['text'])); + if ($close) echo "
"; } unset($pages,$page,$pgs,$pg,$icon,$nchan,$running,$start,$stop,$row,$script,$opt,$nchan_run); ?> From a2f013803f86ad8734c752243ee7636f7927a268 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 5 May 2025 15:59:14 -0700 Subject: [PATCH 81/85] chore: force install checkbox title attr on plugin install page --- emhttp/plugins/dynamix.plugin.manager/PluginInstall.page | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix.plugin.manager/PluginInstall.page b/emhttp/plugins/dynamix.plugin.manager/PluginInstall.page index 83f503ffc..e647c82be 100644 --- a/emhttp/plugins/dynamix.plugin.manager/PluginInstall.page +++ b/emhttp/plugins/dynamix.plugin.manager/PluginInstall.page @@ -54,7 +54,7 @@ Tag="download"
- +
From 04d5d3d2388e26832ec08168710fe7d4bcbe8315 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 5 May 2025 16:01:18 -0700 Subject: [PATCH 82/85] chore: format force install checkbox label for better readability on plugin install page --- emhttp/plugins/dynamix.plugin.manager/PluginInstall.page | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/emhttp/plugins/dynamix.plugin.manager/PluginInstall.page b/emhttp/plugins/dynamix.plugin.manager/PluginInstall.page index e647c82be..f3e30735c 100644 --- a/emhttp/plugins/dynamix.plugin.manager/PluginInstall.page +++ b/emhttp/plugins/dynamix.plugin.manager/PluginInstall.page @@ -54,7 +54,10 @@ Tag="download"
- +
From 1ba0b6691614e68db8edbca6c266ab9bfc6c6a82 Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 5 May 2025 16:40:39 -0700 Subject: [PATCH 83/85] refactor: centralize reload script logic in HeadInlineJS.php and update DefaultPageLayout.php for improved maintainability --- .../dynamix/include/DefaultPageLayout.php | 29 ++++++------------- .../DefaultPageLayout/HeadInlineJS.php | 11 +++++++ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index 73822551b..04cabf208 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -70,13 +70,16 @@ if (count($pages)) { if (count($running)) file_put_contents($nchan_pid,implode("\n",$running)."\n"); else @unlink($nchan_pid); } -function annotate($text) {echo "\n\n";} - -function generateReloadScript($loadMinutes) { - if ($loadMinutes <= 0) return ''; - $interval = $loadMinutes * 60000; - return "\n\n"; +function includePageStylesheets($page) { + global $docroot, $theme; + $css = "/{$page['root']}/sheets/{$page['name']}"; + $css_stock = "$css.css"; + $css_theme = "$css-$theme.css"; // @todo add syslog for deprecation notice + if (is_file($docroot.$css_stock)) echo '',"\n"; + if (is_file($docroot.$css_theme)) echo '',"\n"; } + +function annotate($text) {echo "\n\n";} ?> lang="" class="getThemeHtmlClass() ?>"> @@ -135,15 +138,6 @@ if ($themeHelper->isSidebarTheme()) { ',"\n"; - if (is_file($docroot.$css_theme)) echo '',"\n"; -} - foreach ($buttonPages as $button) { annotate($button['file']); includePageStylesheets($button); @@ -154,11 +148,6 @@ foreach ($pages as $page) { annotate($page['file']); includePageStylesheets($page); } - -// Reload page every X minutes during extended viewing? -if (isset($myPage['Load'])) { - echo generateReloadScript($myPage['Load']); -} ?> diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout/HeadInlineJS.php b/emhttp/plugins/dynamix/include/DefaultPageLayout/HeadInlineJS.php index 77b95e280..f7e384f40 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout/HeadInlineJS.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout/HeadInlineJS.php @@ -585,4 +585,15 @@ $.ajaxPrefilter(function(s, orig, xhr){ s.data += "csrf_token="+csrf_token; } }); + + 0): ?> + timers.reload = setInterval( + function(){ + if (nchanPaused === false) { + location.reload(); + } + }, + + ); + From 6d67c1774c61c408f42093de5c034d2c6c40984b Mon Sep 17 00:00:00 2001 From: Zack Spear Date: Mon, 5 May 2025 16:44:52 -0700 Subject: [PATCH 84/85] refactor: move includePageStylesheets and annotate functions from DefaultPageLayout.php to PageBuilder.php for improved code organization and maintainability --- .../plugins/dynamix/include/DefaultPageLayout.php | 11 ----------- emhttp/plugins/dynamix/include/PageBuilder.php | 13 +++++++++++++ 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/emhttp/plugins/dynamix/include/DefaultPageLayout.php b/emhttp/plugins/dynamix/include/DefaultPageLayout.php index 04cabf208..a17767c11 100644 --- a/emhttp/plugins/dynamix/include/DefaultPageLayout.php +++ b/emhttp/plugins/dynamix/include/DefaultPageLayout.php @@ -69,17 +69,6 @@ if (count($pages)) { } if (count($running)) file_put_contents($nchan_pid,implode("\n",$running)."\n"); else @unlink($nchan_pid); } - -function includePageStylesheets($page) { - global $docroot, $theme; - $css = "/{$page['root']}/sheets/{$page['name']}"; - $css_stock = "$css.css"; - $css_theme = "$css-$theme.css"; // @todo add syslog for deprecation notice - if (is_file($docroot.$css_stock)) echo '',"\n"; - if (is_file($docroot.$css_theme)) echo '',"\n"; -} - -function annotate($text) {echo "\n\n";} ?> lang="" class="getThemeHtmlClass() ?>"> diff --git a/emhttp/plugins/dynamix/include/PageBuilder.php b/emhttp/plugins/dynamix/include/PageBuilder.php index d084b0ca3..8218e4578 100644 --- a/emhttp/plugins/dynamix/include/PageBuilder.php +++ b/emhttp/plugins/dynamix/include/PageBuilder.php @@ -127,6 +127,19 @@ function generate_sidebar_icon_css($tasks, $buttons) { return $css; } +function includePageStylesheets($page) { + global $docroot, $theme; + $css = "/{$page['root']}/sheets/{$page['name']}"; + $css_stock = "$css.css"; + $css_theme = "$css-$theme.css"; // @todo add syslog for deprecation notice + if (is_file($docroot.$css_stock)) echo '',"\n"; + if (is_file($docroot.$css_theme)) echo '',"\n"; +} + +function annotate($text) { + echo "\n\n"; +} + // hack to embed function output in a quoted string (e.g., in a page Title) // see: http://stackoverflow.com/questions/6219972/why-embedding-functions-inside-of-strings-is-different-than-variables function _func($x) {return $x;} From 62eac91e47768cc3b181dfa83c6f3f830e264e4e Mon Sep 17 00:00:00 2001 From: SimonFair <39065407+SimonFair@users.noreply.github.com> Date: Sun, 20 Apr 2025 17:26:43 +0100 Subject: [PATCH 85/85] Update novnc --- .../.github/ISSUE_TEMPLATE/bug_report.md | 34 + .../novnc/.github/ISSUE_TEMPLATE/config.yml | 5 + .../.github/ISSUE_TEMPLATE/feature_request.md | 17 + .../novnc/.github/workflows/deploy.yml | 97 ++ .../novnc/.github/workflows/lint.yml | 19 + .../novnc/.github/workflows/test.yml | 28 + .../novnc/.github/workflows/translate.yml | 15 + .../dynamix.vm.manager/novnc/.gitignore | 12 + .../dynamix.vm.manager/novnc/.gitmodules | 0 .../dynamix.vm.manager/novnc/LICENSE.txt | 62 ++ .../novnc/app/error-handler.js | 2 +- .../novnc/app/locale/cs.json | 24 +- .../novnc/app/locale/de.json | 29 +- .../novnc/app/locale/el.json | 23 +- .../novnc/app/locale/es.json | 16 +- .../novnc/app/locale/fr.json | 50 +- .../novnc/app/locale/it.json | 6 +- .../novnc/app/locale/ja.json | 33 +- .../novnc/app/locale/ko.json | 22 +- .../novnc/app/locale/nl.json | 78 +- .../novnc/app/locale/pl.json | 25 +- .../novnc/app/locale/pt_BR.json | 26 +- .../novnc/app/locale/ru.json | 26 +- .../novnc/app/locale/sv.json | 34 +- .../novnc/app/locale/tr.json | 2 +- .../novnc/app/locale/zh_CN.json | 80 +- .../novnc/app/locale/zh_TW.json | 22 +- .../novnc/app/localization.js | 4 +- .../novnc/app/styles/base.css | 945 +++++++++--------- .../novnc/app/styles/constants.css | 30 + .../novnc/app/styles/input.css | 845 +++++++++++----- .../dynamix.vm.manager/novnc/app/ui.js | 170 ++-- .../dynamix.vm.manager/novnc/app/webutil.js | 4 +- .../novnc/core/crypto/md5.js | 2 +- .../novnc/core/decoders/copyrect.js | 2 +- .../novnc/core/decoders/h264.js | 321 ++++++ .../novnc/core/decoders/hextile.js | 2 +- .../novnc/core/decoders/jpeg.js | 2 +- .../novnc/core/decoders/raw.js | 2 +- .../novnc/core/decoders/rre.js | 2 +- .../novnc/core/decoders/tight.js | 2 +- .../novnc/core/decoders/tightpng.js | 2 +- .../novnc/core/decoders/zlib.js | 51 + .../novnc/core/decoders/zrle.js | 2 +- .../dynamix.vm.manager/novnc/core/deflator.js | 2 +- .../dynamix.vm.manager/novnc/core/display.js | 55 +- .../novnc/core/encodings.js | 7 +- .../dynamix.vm.manager/novnc/core/inflator.js | 2 +- .../novnc/core/input/domkeytable.js | 2 +- .../novnc/core/input/fixedkeys.js | 2 +- .../novnc/core/input/gesturehandler.js | 2 +- .../novnc/core/input/keyboard.js | 24 +- .../novnc/core/input/vkeys.js | 2 +- .../dynamix.vm.manager/novnc/core/rfb.js | 388 +++++-- .../novnc/core/util/browser.js | 85 +- .../novnc/core/util/cursor.js | 2 +- .../novnc/core/util/element.js | 2 +- .../novnc/core/util/events.js | 2 +- .../novnc/core/util/eventtarget.js | 2 +- .../dynamix.vm.manager/novnc/core/util/int.js | 2 +- .../novnc/core/util/logging.js | 2 +- .../novnc/core/util/strings.js | 2 +- .../dynamix.vm.manager/novnc/core/websock.js | 14 +- .../dynamix.vm.manager/novnc/package.json | 6 +- .../plugins/dynamix.vm.manager/novnc/vnc.html | 416 ++++++++ .../dynamix.vm.manager/novnc/vnc_lite.html | 180 ++++ emhttp/plugins/dynamix.vm.manager/vnc.html | 166 +-- 67 files changed, 3325 insertions(+), 1217 deletions(-) create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/.github/ISSUE_TEMPLATE/bug_report.md create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/.github/ISSUE_TEMPLATE/config.yml create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/.github/ISSUE_TEMPLATE/feature_request.md create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/deploy.yml create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/lint.yml create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/test.yml create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/translate.yml create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/.gitignore create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/.gitmodules create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/LICENSE.txt create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/app/styles/constants.css create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/core/decoders/h264.js create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/core/decoders/zlib.js create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/vnc.html create mode 100644 emhttp/plugins/dynamix.vm.manager/novnc/vnc_lite.html diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/.github/ISSUE_TEMPLATE/bug_report.md b/emhttp/plugins/dynamix.vm.manager/novnc/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..1b377d569 --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,34 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Client (please complete the following information):** + - OS: [e.g. iOS] + - Browser: [e.g. chrome, safari] + - Browser version: [e.g. 22] + +**Server (please complete the following information):** + - noVNC version: [e.g. 1.0.0 or git commit id] + - VNC server: [e.g. QEMU, TigerVNC] + - WebSocket proxy: [e.g. websockify] + +**Additional context** +Add any other context about the problem here. diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/.github/ISSUE_TEMPLATE/config.yml b/emhttp/plugins/dynamix.vm.manager/novnc/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..cbd35aa75 --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Question or discussion + url: https://groups.google.com/forum/?fromgroups#!forum/novnc + about: Ask a question or start a discussion diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/.github/ISSUE_TEMPLATE/feature_request.md b/emhttp/plugins/dynamix.vm.manager/novnc/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..066b2d920 --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/deploy.yml b/emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/deploy.yml new file mode 100644 index 000000000..a11d3d0a5 --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/deploy.yml @@ -0,0 +1,97 @@ +name: Publish + +on: + push: + pull_request: + release: + types: [published] + +jobs: + npm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: | + GITREV=$(git rev-parse --short HEAD) + echo $GITREV + sed -i "s/^\(.*\"version\".*\)\"\([^\"]\+\)\"\(.*\)\$/\1\"\2-g$GITREV\"\3/" package.json + if: github.event_name != 'release' + - uses: actions/setup-node@v4 + with: + # Needs to be explicitly specified for auth to work + registry-url: 'https://registry.npmjs.org' + - run: npm install + - uses: actions/upload-artifact@v4 + with: + name: npm + path: lib + - run: npm publish --access public + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + if: | + github.repository == 'novnc/noVNC' && + github.event_name == 'release' && + !github.event.release.prerelease + - run: npm publish --access public --tag beta + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + if: | + github.repository == 'novnc/noVNC' && + github.event_name == 'release' && + github.event.release.prerelease + - run: npm publish --access public --tag dev + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + if: | + github.repository == 'novnc/noVNC' && + github.event_name == 'push' && + github.event.ref == 'refs/heads/master' + snap: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: | + GITREV=$(git rev-parse --short HEAD) + echo $GITREV + sed -i "s/^\(.*\"version\".*\)\"\([^\"]\+\)\"\(.*\)\$/\1\"\2-g$GITREV\"\3/" package.json + if: github.event_name != 'release' + - run: | + VERSION=$(grep '"version"' package.json | cut -d '"' -f 4) + echo $VERSION + sed -i "s/^version:.*/version: '$VERSION'/" snap/snapcraft.yaml + - uses: snapcore/action-build@v1 + id: snapcraft + - uses: actions/upload-artifact@v4 + with: + name: snap + path: ${{ steps.snapcraft.outputs.snap }} + - uses: snapcore/action-publish@v1 + with: + snap: ${{ steps.snapcraft.outputs.snap }} + release: stable + env: + SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_LOGIN }} + if: | + github.repository == 'novnc/noVNC' && + github.event_name == 'release' && + !github.event.release.prerelease + - uses: snapcore/action-publish@v1 + with: + snap: ${{ steps.snapcraft.outputs.snap }} + release: beta + env: + SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_LOGIN }} + if: | + github.repository == 'novnc/noVNC' && + github.event_name == 'release' && + github.event.release.prerelease + - uses: snapcore/action-publish@v1 + with: + snap: ${{ steps.snapcraft.outputs.snap }} + release: edge + env: + SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_LOGIN }} + if: | + github.repository == 'novnc/noVNC' && + github.event_name == 'push' && + github.event.ref == 'refs/heads/master' diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/lint.yml b/emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/lint.yml new file mode 100644 index 000000000..540bb9907 --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/lint.yml @@ -0,0 +1,19 @@ +name: Lint + +on: [push, pull_request] + +jobs: + eslint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + - run: npm update + - run: npm run lint + html: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + - run: npm update + - run: git ls-tree --name-only -r HEAD | grep -E "[.](html|css)$" | xargs ./utils/validate diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/test.yml b/emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/test.yml new file mode 100644 index 000000000..b72195b52 --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/test.yml @@ -0,0 +1,28 @@ +name: Test + +on: [push, pull_request] + +jobs: + test: + strategy: + matrix: + os: + - ubuntu-latest + - windows-latest + browser: + - ChromeHeadless + - FirefoxHeadless + include: + - os: macos-latest + browser: Safari + - os: windows-latest + browser: EdgeHeadless + fail-fast: false + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + - run: npm update + - run: npm run test + env: + TEST_BROWSER_NAME: ${{ matrix.browser }} diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/translate.yml b/emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/translate.yml new file mode 100644 index 000000000..a4da9cbfa --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/.github/workflows/translate.yml @@ -0,0 +1,15 @@ +name: Translate + +on: [push, pull_request] + +jobs: + translate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + - run: npm update + - run: sudo apt-get install gettext + - run: make -C po update-pot + - run: make -C po update-po + - run: make -C po update-js diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/.gitignore b/emhttp/plugins/dynamix.vm.manager/novnc/.gitignore new file mode 100644 index 000000000..c178dbab4 --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/.gitignore @@ -0,0 +1,12 @@ +*.pyc +*.o +tests/data_*.js +utils/rebind.so +utils/websockify +/node_modules +/build +/lib +recordings +*.swp +*~ +noVNC-*.tgz diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/.gitmodules b/emhttp/plugins/dynamix.vm.manager/novnc/.gitmodules new file mode 100644 index 000000000..e69de29bb diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/LICENSE.txt b/emhttp/plugins/dynamix.vm.manager/novnc/LICENSE.txt new file mode 100644 index 000000000..0581c11ed --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/LICENSE.txt @@ -0,0 +1,62 @@ +noVNC is Copyright (C) 2022 The noVNC authors +(./AUTHORS) + +The noVNC core library files are licensed under the MPL 2.0 (Mozilla +Public License 2.0). The noVNC core library is composed of the +Javascript code necessary for full noVNC operation. This includes (but +is not limited to): + + core/**/*.js + app/*.js + test/playback.js + +The HTML, CSS, font and images files that included with the noVNC +source distibution (or repository) are not considered part of the +noVNC core library and are licensed under more permissive licenses. +The intent is to allow easy integration of noVNC into existing web +sites and web applications. + +The HTML, CSS, font and image files are licensed as follows: + + *.html : 2-Clause BSD license + + app/styles/*.css : 2-Clause BSD license + + app/styles/Orbitron* : SIL Open Font License 1.1 + (Copyright 2009 Matt McInerney) + + app/images/ : Creative Commons Attribution-ShareAlike + http://creativecommons.org/licenses/by-sa/3.0/ + +Some portions of noVNC are copyright to their individual authors. +Please refer to the individual source files and/or to the noVNC commit +history: https://github.com/novnc/noVNC/commits/master + +The are several files and projects that have been incorporated into +the noVNC core library. Here is a list of those files and the original +licenses (all MPL 2.0 compatible): + + core/base64.js : MPL 2.0 + + core/des.js : Various BSD style licenses + + vendor/pako/ : MIT + +Any other files not mentioned above are typically marked with +a copyright/license header at the top of the file. The default noVNC +license is MPL-2.0. + +The following license texts are included: + + docs/LICENSE.MPL-2.0 + docs/LICENSE.OFL-1.1 + docs/LICENSE.BSD-3-Clause (New BSD) + docs/LICENSE.BSD-2-Clause (Simplified BSD / FreeBSD) + vendor/pako/LICENSE (MIT) + +Or alternatively the license texts may be found here: + + http://www.mozilla.org/MPL/2.0/ + http://scripts.sil.org/OFL + http://en.wikipedia.org/wiki/BSD_licenses + https://opensource.org/licenses/MIT diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/error-handler.js b/emhttp/plugins/dynamix.vm.manager/novnc/app/error-handler.js index 67b63720c..5f6ffb674 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/error-handler.js +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/error-handler.js @@ -1,6 +1,6 @@ /* * noVNC: HTML5 VNC client - * Copyright (C) 2019 The noVNC Authors + * Copyright (C) 2019 The noVNC authors * Licensed under MPL 2.0 (see LICENSE.txt) * * See README.md for usage and integration instructions. diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/cs.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/cs.json index 589145ef3..dd31e6c18 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/cs.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/cs.json @@ -14,7 +14,7 @@ "Password is required": "Je vyžadováno heslo", "noVNC encountered an error:": "noVNC narazilo na chybu:", "Hide/Show the control bar": "Skrýt/zobrazit ovládací panel", - "Move/Drag Viewport": "Přesunout/přetáhnout výřez", + "Move/Drag viewport": "Přesunout/přetáhnout výřez", "viewport drag": "přesun výřezu", "Active Mouse Button": "Aktivní tlačítka myši", "No mousebutton": "Žádné", @@ -22,9 +22,9 @@ "Middle mousebutton": "Prostřední tlačítko myši", "Right mousebutton": "Pravé tlačítko myši", "Keyboard": "Klávesnice", - "Show Keyboard": "Zobrazit klávesnici", + "Show keyboard": "Zobrazit klávesnici", "Extra keys": "Extra klávesy", - "Show Extra Keys": "Zobrazit extra klávesy", + "Show extra keys": "Zobrazit extra klávesy", "Ctrl": "Ctrl", "Toggle Ctrl": "Přepnout Ctrl", "Alt": "Alt", @@ -45,13 +45,13 @@ "Clear": "Vymazat", "Fullscreen": "Celá obrazovka", "Settings": "Nastavení", - "Shared Mode": "Sdílený režim", - "View Only": "Pouze prohlížení", - "Clip to Window": "Přizpůsobit oknu", - "Scaling Mode:": "Přizpůsobení velikosti", + "Shared mode": "Sdílený režim", + "View only": "Pouze prohlížení", + "Clip to window": "Přizpůsobit oknu", + "Scaling mode:": "Přizpůsobení velikosti", "None": "Žádné", - "Local Scaling": "Místní", - "Remote Resizing": "Vzdálené", + "Local scaling": "Místní", + "Remote resizing": "Vzdálené", "Advanced": "Pokročilé", "Repeater ID:": "ID opakovače", "WebSocket": "WebSocket", @@ -59,9 +59,9 @@ "Host:": "Hostitel:", "Port:": "Port:", "Path:": "Cesta", - "Automatic Reconnect": "Automatická obnova připojení", - "Reconnect Delay (ms):": "Zpoždění připojení (ms)", - "Show Dot when No Cursor": "Tečka místo chybějícího kurzoru myši", + "Automatic reconnect": "Automatická obnova připojení", + "Reconnect delay (ms):": "Zpoždění připojení (ms)", + "Show dot when no cursor": "Tečka místo chybějícího kurzoru myši", "Logging:": "Logování:", "Disconnect": "Odpojit", "Connect": "Připojit", diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/de.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/de.json index 62e73360f..fa1546377 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/de.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/de.json @@ -13,7 +13,7 @@ "Password is required": "Passwort ist erforderlich", "noVNC encountered an error:": "Ein Fehler ist aufgetreten:", "Hide/Show the control bar": "Kontrollleiste verstecken/anzeigen", - "Move/Drag Viewport": "Ansichtsfenster verschieben/ziehen", + "Move/Drag viewport": "Ansichtsfenster verschieben/ziehen", "viewport drag": "Ansichtsfenster ziehen", "Active Mouse Button": "Aktive Maustaste", "No mousebutton": "Keine Maustaste", @@ -21,9 +21,9 @@ "Middle mousebutton": "Mittlere Maustaste", "Right mousebutton": "Rechte Maustaste", "Keyboard": "Tastatur", - "Show Keyboard": "Tastatur anzeigen", + "Show keyboard": "Tastatur anzeigen", "Extra keys": "Zusatztasten", - "Show Extra Keys": "Zusatztasten anzeigen", + "Show extra keys": "Zusatztasten anzeigen", "Ctrl": "Strg", "Toggle Ctrl": "Strg umschalten", "Alt": "Alt", @@ -44,13 +44,13 @@ "Clear": "Löschen", "Fullscreen": "Vollbild", "Settings": "Einstellungen", - "Shared Mode": "Geteilter Modus", - "View Only": "Nur betrachten", - "Clip to Window": "Auf Fenster begrenzen", - "Scaling Mode:": "Skalierungsmodus:", + "Shared mode": "Geteilter Modus", + "View only": "Nur betrachten", + "Clip to window": "Auf Fenster begrenzen", + "Scaling mode:": "Skalierungsmodus:", "None": "Keiner", - "Local Scaling": "Lokales skalieren", - "Remote Resizing": "Serverseitiges skalieren", + "Local scaling": "Lokales skalieren", + "Remote resizing": "Serverseitiges skalieren", "Advanced": "Erweitert", "Repeater ID:": "Repeater ID:", "WebSocket": "WebSocket", @@ -58,12 +58,17 @@ "Host:": "Server:", "Port:": "Port:", "Path:": "Pfad:", - "Automatic Reconnect": "Automatisch wiederverbinden", - "Reconnect Delay (ms):": "Wiederverbindungsverzögerung (ms):", + "Automatic reconnect": "Automatisch wiederverbinden", + "Reconnect delay (ms):": "Wiederverbindungsverzögerung (ms):", "Logging:": "Protokollierung:", "Disconnect": "Verbindung trennen", "Connect": "Verbinden", "Password:": "Passwort:", "Cancel": "Abbrechen", - "Canvas not supported.": "Canvas nicht unterstützt." + "Canvas not supported.": "Canvas nicht unterstützt.", + "Disconnect timeout": "Zeitüberschreitung beim Trennen", + "Local Downscaling": "Lokales herunterskalieren", + "Local Cursor": "Lokaler Mauszeiger", + "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "'Clipping-Modus' aktiviert, Scrollbalken in 'IE-Vollbildmodus' werden nicht unterstützt", + "True Color": "True Color" } \ No newline at end of file diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/el.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/el.json index 4df3e03c4..57d67316c 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/el.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/el.json @@ -41,6 +41,7 @@ "Reset": "Επαναφορά", "Clipboard": "Πρόχειρο", "Edit clipboard content in the textarea below.": "Επεξεργαστείτε το περιεχόμενο του πρόχειρου στην περιοχή κειμένου παρακάτω.", + "Full Screen": "Πλήρης Οθόνη", "Settings": "Ρυθμίσεις", "Shared Mode": "Κοινόχρηστη Λειτουργία", "View Only": "Μόνο Θέαση", @@ -75,5 +76,25 @@ "Username:": "Κωδικός Χρήστη:", "Password:": "Κωδικός Πρόσβασης:", "Send Credentials": "Αποστολή Διαπιστευτηρίων", - "Cancel": "Ακύρωση" + "Cancel": "Ακύρωση", + "Password is required": "Απαιτείται ο κωδικός πρόσβασης", + "viewport drag": "σύρσιμο θεατού πεδίου", + "Active Mouse Button": "Ενεργό Πλήκτρο Ποντικιού", + "No mousebutton": "Χωρίς Πλήκτρο Ποντικιού", + "Left mousebutton": "Αριστερό Πλήκτρο Ποντικιού", + "Middle mousebutton": "Μεσαίο Πλήκτρο Ποντικιού", + "Right mousebutton": "Δεξί Πλήκτρο Ποντικιού", + "Clear": "Καθάρισμα", + "Canvas not supported.": "Δεν υποστηρίζεται το στοιχείο Canvas", + "Disconnect timeout": "Παρέλευση χρονικού ορίου αποσύνδεσης", + "Local Downscaling": "Τοπική Συρρίκνωση", + "Local Cursor": "Τοπικός Δρομέας", + "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "Εφαρμογή λειτουργίας αποκοπής αφού δεν υποστηρίζονται οι λωρίδες κύλισης σε πλήρη οθόνη στον IE", + "True Color": "Πραγματικά Χρώματα", + "Style:": "Στυλ:", + "default": "προεπιλεγμένο", + "Apply": "Εφαρμογή", + "Connection": "Σύνδεση", + "Token:": "Διακριτικό:", + "Send Password": "Αποστολή Κωδικού Πρόσβασης" } \ No newline at end of file diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/es.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/es.json index b9e663a3d..bb088243c 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/es.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/es.json @@ -10,7 +10,7 @@ "Disconnect timeout": "Tiempo de desconexión agotado", "noVNC encountered an error:": "noVNC ha encontrado un error:", "Hide/Show the control bar": "Ocultar/Mostrar la barra de control", - "Move/Drag Viewport": "Mover/Arrastrar la ventana", + "Move/Drag viewport": "Mover/Arrastrar la ventana", "viewport drag": "Arrastrar la ventana", "Active Mouse Button": "Botón activo del ratón", "No mousebutton": "Ningún botón del ratón", @@ -18,7 +18,7 @@ "Middle mousebutton": "Botón central del ratón", "Right mousebutton": "Botón derecho del ratón", "Keyboard": "Teclado", - "Show Keyboard": "Mostrar teclado", + "Show keyboard": "Mostrar teclado", "Extra keys": "Teclas adicionales", "Show Extra Keys": "Mostrar Teclas Adicionales", "Ctrl": "Ctrl", @@ -43,13 +43,13 @@ "Settings": "Configuraciones", "Encrypt": "Encriptar", "Shared Mode": "Modo Compartido", - "View Only": "Solo visualización", - "Clip to Window": "Recortar al tamaño de la ventana", - "Scaling Mode:": "Modo de escalado:", + "View only": "Solo visualización", + "Clip to window": "Recortar al tamaño de la ventana", + "Scaling mode:": "Modo de escalado:", "None": "Ninguno", "Local Scaling": "Escalado Local", "Local Downscaling": "Reducción de escala local", - "Remote Resizing": "Cambio de tamaño remoto", + "Remote resizing": "Cambio de tamaño remoto", "Advanced": "Avanzado", "Local Cursor": "Cursor Local", "Repeater ID:": "ID del Repetidor:", @@ -57,8 +57,8 @@ "Host:": "Host:", "Port:": "Puerto:", "Path:": "Ruta:", - "Automatic Reconnect": "Reconexión automática", - "Reconnect Delay (ms):": "Retraso en la reconexión (ms):", + "Automatic reconnect": "Reconexión automática", + "Reconnect delay (ms):": "Retraso en la reconexión (ms):", "Logging:": "Registrando:", "Disconnect": "Desconectar", "Connect": "Conectar", diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/fr.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/fr.json index c0eeec7d3..c8607cebe 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/fr.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/fr.json @@ -1,9 +1,10 @@ { + "Running without HTTPS is not recommended, crashes or other issues are likely.": "Lancer sans HTTPS n'est pas recommandé, crashs ou autres problèmes en vue.", "Connecting...": "En cours de connexion...", "Disconnecting...": "Déconnexion en cours...", "Reconnecting...": "Reconnexion en cours...", "Internal error": "Erreur interne", - "Must set host": "Doit définir l'hôte", + "Failed to connect to server: ": "Échec de connexion au serveur ", "Connected (encrypted) to ": "Connecté (chiffré) à ", "Connected (unencrypted) to ": "Connecté (non chiffré) à ", "Something went wrong, connection is closed": "Quelque chose s'est mal passé, la connexion a été fermée", @@ -15,19 +16,19 @@ "noVNC encountered an error:": "noVNC a rencontré une erreur :", "Hide/Show the control bar": "Masquer/Afficher la barre de contrôle", "Drag": "Faire glisser", - "Move/Drag Viewport": "Déplacer/faire glisser le Viewport", + "Move/Drag viewport": "Déplacer la fenêtre de visualisation", "Keyboard": "Clavier", - "Show Keyboard": "Afficher le clavier", + "Show keyboard": "Afficher le clavier", "Extra keys": "Touches supplémentaires", - "Show Extra Keys": "Afficher les touches supplémentaires", + "Show extra keys": "Afficher les touches supplémentaires", "Ctrl": "Ctrl", "Toggle Ctrl": "Basculer Ctrl", "Alt": "Alt", "Toggle Alt": "Basculer Alt", "Toggle Windows": "Basculer Windows", - "Windows": "Windows", - "Send Tab": "Envoyer l'onglet", - "Tab": "l'onglet", + "Windows": "Fenêtre", + "Send Tab": "Envoyer Tab", + "Tab": "Tabulation", "Esc": "Esc", "Send Escape": "Envoyer Escape", "Ctrl+Alt+Del": "Ctrl+Alt+Del", @@ -39,16 +40,16 @@ "Reboot": "Redémarrer", "Reset": "Réinitialiser", "Clipboard": "Presse-papiers", - "Clear": "Effacer", - "Fullscreen": "Plein écran", + "Edit clipboard content in the textarea below.": "Editer le contenu du presse-papier dans la zone ci-dessous.", + "Full screen": "Plein écran", "Settings": "Paramètres", - "Shared Mode": "Mode partagé", - "View Only": "Afficher uniquement", - "Clip to Window": "Clip à fenêtre", - "Scaling Mode:": "Mode mise à l'échelle :", + "Shared mode": "Mode partagé", + "View only": "Afficher uniquement", + "Clip to window": "Ajuster à la fenêtre", + "Scaling mode:": "Mode mise à l'échelle :", "None": "Aucun", - "Local Scaling": "Mise à l'échelle locale", - "Remote Resizing": "Redimensionnement à distance", + "Local scaling": "Mise à l'échelle locale", + "Remote resizing": "Redimensionnement à distance", "Advanced": "Avancé", "Quality:": "Qualité :", "Compression level:": "Niveau de compression :", @@ -58,15 +59,24 @@ "Host:": "Hôte :", "Port:": "Port :", "Path:": "Chemin :", - "Automatic Reconnect": "Reconnecter automatiquemen", - "Reconnect Delay (ms):": "Délai de reconnexion (ms) :", - "Show Dot when No Cursor": "Afficher le point lorsqu'il n'y a pas de curseur", + "Automatic reconnect": "Reconnecter automatiquement", + "Reconnect delay (ms):": "Délai de reconnexion (ms) :", + "Show dot when no cursor": "Afficher le point lorsqu'il n'y a pas de curseur", "Logging:": "Se connecter :", "Version:": "Version :", "Disconnect": "Déconnecter", "Connect": "Connecter", + "Server identity": "Identité du serveur", + "The server has provided the following identifying information:": "Le serveur a fourni l'identification suivante :", + "Fingerprint:": "Empreinte digitale :", + "Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "SVP, verifiez que l'information est correcte et pressez \"Accepter\". Sinon pressez \"Refuser\".", + "Approve": "Accepter", + "Reject": "Refuser", + "Credentials": "Envoyer les identifiants", "Username:": "Nom d'utilisateur :", "Password:": "Mot de passe :", - "Send Credentials": "Envoyer les identifiants", - "Cancel": "Annuler" + "Send credentials": "Envoyer les identifiants", + "Cancel": "Annuler", + "Must set host": "Doit définir l'hôte", + "Clear": "Effacer" } \ No newline at end of file diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/it.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/it.json index 18a7f7447..28e6f721b 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/it.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/it.json @@ -15,7 +15,7 @@ "noVNC encountered an error:": "noVNC ha riscontrato un errore:", "Hide/Show the control bar": "Nascondi/Mostra la barra di controllo", "Keyboard": "Tastiera", - "Show Keyboard": "Mostra tastiera", + "Show keyboard": "Mostra tastiera", "Extra keys": "Tasti Aggiuntivi", "Show Extra Keys": "Mostra Tasti Aggiuntivi", "Ctrl": "Ctrl", @@ -40,9 +40,9 @@ "Clear": "Pulisci", "Fullscreen": "Schermo intero", "Settings": "Impostazioni", - "Shared Mode": "Modalità condivisa", + "Shared mode": "Modalità condivisa", "View Only": "Sola Visualizzazione", - "Scaling Mode:": "Modalità di ridimensionamento:", + "Scaling mode:": "Modalità di ridimensionamento:", "None": "Nessuna", "Local Scaling": "Ridimensionamento Locale", "Remote Resizing": "Ridimensionamento Remoto", diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ja.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ja.json index 70fd7a5d1..4fc9b8a9e 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ja.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ja.json @@ -1,13 +1,14 @@ { - "HTTPS is required for full functionality": "すべての機能を使用するにはHTTPS接続が必要です", + "Running without HTTPS is not recommended, crashes or other issues are likely.": "HTTPS接続なしで実行することは推奨されません。クラッシュしたりその他の問題が発生したりする可能性があります。", "Connecting...": "接続しています...", "Disconnecting...": "切断しています...", "Reconnecting...": "再接続しています...", "Internal error": "内部エラー", "Must set host": "ホストを設定する必要があります", + "Failed to connect to server: ": "サーバーへの接続に失敗しました: ", "Connected (encrypted) to ": "接続しました (暗号化済み): ", "Connected (unencrypted) to ": "接続しました (暗号化されていません): ", - "Something went wrong, connection is closed": "何らかの問題で、接続が閉じられました", + "Something went wrong, connection is closed": "問題が発生したため、接続が閉じられました", "Failed to connect to server": "サーバーへの接続に失敗しました", "Disconnected": "切断しました", "New connection has been rejected with reason: ": "新規接続は次の理由で拒否されました: ", @@ -16,11 +17,11 @@ "noVNC encountered an error:": "noVNC でエラーが発生しました:", "Hide/Show the control bar": "コントロールバーを隠す/表示する", "Drag": "ドラッグ", - "Move/Drag Viewport": "ビューポートを移動/ドラッグ", + "Move/Drag viewport": "ビューポートを移動/ドラッグ", "Keyboard": "キーボード", - "Show Keyboard": "キーボードを表示", + "Show keyboard": "キーボードを表示", "Extra keys": "追加キー", - "Show Extra Keys": "追加キーを表示", + "Show extra keys": "追加キーを表示", "Ctrl": "Ctrl", "Toggle Ctrl": "Ctrl キーをトグル", "Alt": "Alt", @@ -41,15 +42,15 @@ "Reset": "リセット", "Clipboard": "クリップボード", "Edit clipboard content in the textarea below.": "以下の入力欄からクリップボードの内容を編集できます。", - "Full Screen": "全画面表示", + "Full screen": "全画面表示", "Settings": "設定", - "Shared Mode": "共有モード", - "View Only": "表示専用", - "Clip to Window": "ウィンドウにクリップ", - "Scaling Mode:": "スケーリングモード:", + "Shared mode": "共有モード", + "View only": "表示専用", + "Clip to window": "ウィンドウにクリップ", + "Scaling mode:": "スケーリングモード:", "None": "なし", - "Local Scaling": "ローカルスケーリング", - "Remote Resizing": "リモートでリサイズ", + "Local scaling": "ローカルでスケーリング", + "Remote resizing": "リモートでリサイズ", "Advanced": "高度", "Quality:": "品質:", "Compression level:": "圧縮レベル:", @@ -59,9 +60,9 @@ "Host:": "ホスト:", "Port:": "ポート:", "Path:": "パス:", - "Automatic Reconnect": "自動再接続", - "Reconnect Delay (ms):": "再接続する遅延 (ミリ秒):", - "Show Dot when No Cursor": "カーソルがないときにドットを表示する", + "Automatic reconnect": "自動再接続", + "Reconnect delay (ms):": "再接続する遅延 (ミリ秒):", + "Show dot when no cursor": "カーソルがないときにドットを表示する", "Logging:": "ロギング:", "Version:": "バージョン:", "Disconnect": "切断", @@ -75,6 +76,6 @@ "Credentials": "資格情報", "Username:": "ユーザー名:", "Password:": "パスワード:", - "Send Credentials": "資格情報を送信", + "Send credentials": "資格情報を送信", "Cancel": "キャンセル" } \ No newline at end of file diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ko.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ko.json index e4ecddcfd..47b0805c9 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ko.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ko.json @@ -14,7 +14,7 @@ "Password is required": "비밀번호가 필요합니다.", "noVNC encountered an error:": "noVNC에 오류가 발생했습니다:", "Hide/Show the control bar": "컨트롤 바 숨기기/보이기", - "Move/Drag Viewport": "움직이기/드래그 뷰포트", + "Move/Drag viewport": "움직이기/드래그 뷰포트", "viewport drag": "뷰포트 드래그", "Active Mouse Button": "마우스 버튼 활성화", "No mousebutton": "마우스 버튼 없음", @@ -22,9 +22,9 @@ "Middle mousebutton": "중간 마우스 버튼", "Right mousebutton": "오른쪽 마우스 버튼", "Keyboard": "키보드", - "Show Keyboard": "키보드 보이기", + "Show keyboard": "키보드 보이기", "Extra keys": "기타 키들", - "Show Extra Keys": "기타 키들 보이기", + "Show extra keys": "기타 키들 보이기", "Ctrl": "Ctrl", "Toggle Ctrl": "Ctrl 켜기/끄기", "Alt": "Alt", @@ -45,13 +45,13 @@ "Clear": "지우기", "Fullscreen": "전체화면", "Settings": "설정", - "Shared Mode": "공유 모드", - "View Only": "보기 전용", - "Clip to Window": "창에 클립", - "Scaling Mode:": "스케일링 모드:", + "Shared mode": "공유 모드", + "View only": "보기 전용", + "Clip to window": "창에 클립", + "Scaling mode:": "스케일링 모드:", "None": "없음", - "Local Scaling": "로컬 스케일링", - "Remote Resizing": "원격 크기 조절", + "Local scaling": "로컬 스케일링", + "Remote resizing": "원격 크기 조절", "Advanced": "고급", "Repeater ID:": "중계 ID", "WebSocket": "웹소켓", @@ -59,8 +59,8 @@ "Host:": "호스트:", "Port:": "포트:", "Path:": "위치:", - "Automatic Reconnect": "자동 재연결", - "Reconnect Delay (ms):": "재연결 지연 시간 (ms)", + "Automatic reconnect": "자동 재연결", + "Reconnect delay (ms):": "재연결 지연 시간 (ms)", "Logging:": "로깅", "Disconnect": "연결 해제", "Connect": "연결", diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/nl.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/nl.json index 0cdcc92a9..61f2df3c7 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/nl.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/nl.json @@ -1,36 +1,32 @@ { - "Connecting...": "Verbinden...", - "Disconnecting...": "Verbinding verbreken...", + "Running without HTTPS is not recommended, crashes or other issues are likely.": "Het is niet aan te raden om zonder HTTPS te werken, crashes of andere problemen zijn dan waarschijnlijk.", + "Connecting...": "Aan het verbinden…", + "Disconnecting...": "Bezig om verbinding te verbreken...", "Reconnecting...": "Opnieuw verbinding maken...", "Internal error": "Interne fout", - "Must set host": "Host moeten worden ingesteld", + "Failed to connect to server: ": "Verbinding maken met server is mislukt", "Connected (encrypted) to ": "Verbonden (versleuteld) met ", "Connected (unencrypted) to ": "Verbonden (onversleuteld) met ", "Something went wrong, connection is closed": "Er iets fout gelopen, verbinding werd verbroken", "Failed to connect to server": "Verbinding maken met server is mislukt", "Disconnected": "Verbinding verbroken", - "New connection has been rejected with reason: ": "Nieuwe verbinding is geweigerd omwille van de volgende reden: ", + "New connection has been rejected with reason: ": "Nieuwe verbinding is geweigerd met de volgende reden: ", "New connection has been rejected": "Nieuwe verbinding is geweigerd", - "Password is required": "Wachtwoord is vereist", + "Credentials are required": "Inloggegevens zijn nodig", "noVNC encountered an error:": "noVNC heeft een fout bemerkt:", "Hide/Show the control bar": "Verberg/Toon de bedieningsbalk", - "Move/Drag Viewport": "Verplaats/Versleep Kijkvenster", - "viewport drag": "kijkvenster slepen", - "Active Mouse Button": "Actieve Muisknop", - "No mousebutton": "Geen muisknop", - "Left mousebutton": "Linker muisknop", - "Middle mousebutton": "Middelste muisknop", - "Right mousebutton": "Rechter muisknop", + "Drag": "Sleep", + "Move/Drag viewport": "Verplaats/Versleep Kijkvenster", "Keyboard": "Toetsenbord", - "Show Keyboard": "Toon Toetsenbord", + "Show keyboard": "Toon Toetsenbord", "Extra keys": "Extra toetsen", - "Show Extra Keys": "Toon Extra Toetsen", + "Show extra keys": "Toon Extra Toetsen", "Ctrl": "Ctrl", "Toggle Ctrl": "Ctrl omschakelen", "Alt": "Alt", "Toggle Alt": "Alt omschakelen", - "Toggle Windows": "Windows omschakelen", - "Windows": "Windows", + "Toggle Windows": "Vensters omschakelen", + "Windows": "Vensters", "Send Tab": "Tab Sturen", "Tab": "Tab", "Esc": "Esc", @@ -44,30 +40,56 @@ "Reboot": "Herstarten", "Reset": "Resetten", "Clipboard": "Klembord", - "Clear": "Wissen", - "Fullscreen": "Volledig Scherm", + "Edit clipboard content in the textarea below.": "Edit de inhoud van het klembord in het tekstveld hieronder", + "Full screen": "Volledig Scherm", "Settings": "Instellingen", - "Shared Mode": "Gedeelde Modus", - "View Only": "Alleen Kijken", - "Clip to Window": "Randen buiten venster afsnijden", - "Scaling Mode:": "Schaalmodus:", + "Shared mode": "Gedeelde Modus", + "View only": "Alleen Kijken", + "Clip to window": "Randen buiten venster afsnijden", + "Scaling mode:": "Schaalmodus:", "None": "Geen", - "Local Scaling": "Lokaal Schalen", - "Remote Resizing": "Op Afstand Formaat Wijzigen", + "Local scaling": "Lokaal Schalen", + "Remote resizing": "Op Afstand Formaat Wijzigen", "Advanced": "Geavanceerd", + "Quality:": "Kwaliteit:", + "Compression level:": "Compressieniveau:", "Repeater ID:": "Repeater ID:", "WebSocket": "WebSocket", "Encrypt": "Versleutelen", "Host:": "Host:", "Port:": "Poort:", "Path:": "Pad:", - "Automatic Reconnect": "Automatisch Opnieuw Verbinden", - "Reconnect Delay (ms):": "Vertraging voor Opnieuw Verbinden (ms):", - "Show Dot when No Cursor": "Geef stip weer indien geen cursor", + "Automatic reconnect": "Automatisch Opnieuw Verbinden", + "Reconnect delay (ms):": "Vertraging voor Opnieuw Verbinden (ms):", + "Show dot when no cursor": "Geef stip weer indien geen cursor", "Logging:": "Logmeldingen:", + "Version:": "Versie:", "Disconnect": "Verbinding verbreken", "Connect": "Verbinden", + "Server identity": "Serveridentiteit", + "The server has provided the following identifying information:": "De server geeft de volgende identificerende informatie:", + "Fingerprint:": "Vingerafdruk:", + "Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "Verifieer dat de informatie is correct en druk “OK”. Druk anders op “Afwijzen”.", + "Approve": "OK", + "Reject": "Afwijzen", + "Credentials": "Inloggegevens", + "Username:": "Gebruikersnaam:", "Password:": "Wachtwoord:", + "Send credentials": "Stuur inloggegevens", + "Cancel": "Annuleren", + "Must set host": "Host moeten worden ingesteld", + "Password is required": "Wachtwoord is vereist", + "viewport drag": "kijkvenster slepen", + "Active Mouse Button": "Actieve Muisknop", + "No mousebutton": "Geen muisknop", + "Left mousebutton": "Linker muisknop", + "Middle mousebutton": "Middelste muisknop", + "Right mousebutton": "Rechter muisknop", + "Clear": "Wissen", "Send Password": "Verzend Wachtwoord:", - "Cancel": "Annuleren" + "Disconnect timeout": "Timeout tijdens verbreken van verbinding", + "Local Downscaling": "Lokaal Neerschalen", + "Local Cursor": "Lokale Cursor", + "Canvas not supported.": "Canvas wordt niet ondersteund.", + "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "''Clipping mode' ingeschakeld, omdat schuifbalken in volledige-scherm-modus in IE niet worden ondersteund" } \ No newline at end of file diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/pl.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/pl.json index 006ac7a55..87c169056 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/pl.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/pl.json @@ -21,9 +21,9 @@ "Middle mousebutton": "Środkowy przycisk myszy", "Right mousebutton": "Prawy przycisk myszy", "Keyboard": "Klawiatura", - "Show Keyboard": "Pokaż klawiaturę", + "Show keyboard": "Pokaż klawiaturę", "Extra keys": "Przyciski dodatkowe", - "Show Extra Keys": "Pokaż przyciski dodatkowe", + "Show extra keys": "Pokaż przyciski dodatkowe", "Ctrl": "Ctrl", "Toggle Ctrl": "Przełącz Ctrl", "Alt": "Alt", @@ -49,8 +49,8 @@ "Clip to Window": "Przytnij do Okna", "Scaling Mode:": "Tryb Skalowania:", "None": "Brak", - "Local Scaling": "Skalowanie lokalne", - "Remote Resizing": "Skalowanie zdalne", + "Local scaling": "Skalowanie lokalne", + "Remote resizing": "Skalowanie zdalne", "Advanced": "Zaawansowane", "Repeater ID:": "ID Repeatera:", "WebSocket": "WebSocket", @@ -58,12 +58,23 @@ "Host:": "Host:", "Port:": "Port:", "Path:": "Ścieżka:", - "Automatic Reconnect": "Automatycznie wznawiaj połączenie", - "Reconnect Delay (ms):": "Opóźnienie wznawiania (ms):", + "Automatic reconnect": "Automatycznie wznawiaj połączenie", + "Reconnect delay (ms):": "Opóźnienie wznawiania (ms):", "Logging:": "Poziom logowania:", "Disconnect": "Rozłącz", "Connect": "Połącz", "Password:": "Hasło:", "Cancel": "Anuluj", - "Canvas not supported.": "Element Canvas nie jest wspierany." + "Canvas not supported.": "Element Canvas nie jest wspierany.", + "Disconnect timeout": "Timeout rozłączenia", + "Local Downscaling": "Downscaling lokalny", + "Local Cursor": "Lokalny kursor", + "Forcing clipping mode since scrollbars aren't supported by IE in fullscreen": "Wymuszam clipping mode ponieważ paski przewijania nie są wspierane przez IE w trybie pełnoekranowym", + "True Color": "True Color", + "Style:": "Styl:", + "default": "domyślny", + "Apply": "Zapisz", + "Connection": "Połączenie", + "Token:": "Token:", + "Send Password": "Wyślij Hasło" } \ No newline at end of file diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/pt_BR.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/pt_BR.json index aa130f764..224b86efd 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/pt_BR.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/pt_BR.json @@ -15,11 +15,11 @@ "noVNC encountered an error:": "O noVNC encontrou um erro:", "Hide/Show the control bar": "Esconder/mostrar a barra de controles", "Drag": "Arrastar", - "Move/Drag Viewport": "Mover/arrastar a janela", + "Move/Drag viewport": "Mover/arrastar a janela", "Keyboard": "Teclado", - "Show Keyboard": "Mostrar teclado", + "Show keyboard": "Mostrar teclado", "Extra keys": "Teclas adicionais", - "Show Extra Keys": "Mostar teclas adicionais", + "Show extra keys": "Mostar teclas adicionais", "Ctrl": "Ctrl", "Toggle Ctrl": "Pressionar/soltar Ctrl", "Alt": "Alt", @@ -42,13 +42,13 @@ "Clear": "Limpar", "Fullscreen": "Tela cheia", "Settings": "Configurações", - "Shared Mode": "Modo compartilhado", - "View Only": "Apenas visualizar", - "Clip to Window": "Recortar à janela", - "Scaling Mode:": "Modo de dimensionamento:", + "Shared mode": "Modo compartilhado", + "View only": "Apenas visualizar", + "Clip to window": "Recortar à janela", + "Scaling mode:": "Modo de dimensionamento:", "None": "Nenhum", - "Local Scaling": "Local", - "Remote Resizing": "Remoto", + "Local scaling": "Local", + "Remote resizing": "Remoto", "Advanced": "Avançado", "Quality:": "Qualidade:", "Compression level:": "Nível de compressão:", @@ -58,15 +58,15 @@ "Host:": "Host:", "Port:": "Porta:", "Path:": "Caminho:", - "Automatic Reconnect": "Reconexão automática", - "Reconnect Delay (ms):": "Atraso da reconexão (ms)", - "Show Dot when No Cursor": "Mostrar ponto quando não há cursor", + "Automatic reconnect": "Reconexão automática", + "Reconnect delay (ms):": "Atraso da reconexão (ms)", + "Show dot when no cursor": "Mostrar ponto quando não há cursor", "Logging:": "Registros:", "Version:": "Versão:", "Disconnect": "Desconectar", "Connect": "Conectar", "Username:": "Nome de usuário:", "Password:": "Senha:", - "Send Credentials": "Enviar credenciais", + "Send credentials": "Enviar credenciais", "Cancel": "Cancelar" } \ No newline at end of file diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ru.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ru.json index cab97396e..bd1bb534a 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ru.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ru.json @@ -15,16 +15,16 @@ "noVNC encountered an error:": "Ошибка noVNC: ", "Hide/Show the control bar": "Скрыть/Показать контрольную панель", "Drag": "Переместить", - "Move/Drag Viewport": "Переместить окно", + "Move/Drag viewport": "Переместить окно", "Keyboard": "Клавиатура", - "Show Keyboard": "Показать клавиатуру", + "Show keyboard": "Показать клавиатуру", "Extra keys": "Дополнительные Кнопки", "Show Extra Keys": "Показать Дополнительные Кнопки", "Ctrl": "Ctrl", - "Toggle Ctrl": "Переключение нажатия Ctrl", + "Toggle Ctrl": "Зажать Ctrl", "Alt": "Alt", - "Toggle Alt": "Переключение нажатия Alt", - "Toggle Windows": "Переключение вкладок", + "Toggle Alt": "Зажать Alt", + "Toggle Windows": "Зажать Windows", "Windows": "Вкладка", "Send Tab": "Передать нажатие Tab", "Tab": "Tab", @@ -42,13 +42,13 @@ "Clear": "Очистить", "Fullscreen": "Во весь экран", "Settings": "Настройки", - "Shared Mode": "Общий режим", + "Shared mode": "Общий режим", "View Only": "Только Просмотр", - "Clip to Window": "В окно", - "Scaling Mode:": "Масштаб:", + "Clip to window": "В окно", + "Scaling mode:": "Масштаб:", "None": "Нет", - "Local Scaling": "Локльный масштаб", - "Remote Resizing": "Удаленная перенастройка размера", + "Local scaling": "Локальный масштаб", + "Remote resizing": "Удаленная перенастройка размера", "Advanced": "Дополнительно", "Quality:": "Качество", "Compression level:": "Уровень Сжатия", @@ -58,9 +58,9 @@ "Host:": "Сервер:", "Port:": "Порт:", "Path:": "Путь:", - "Automatic Reconnect": "Автоматическое переподключение", - "Reconnect Delay (ms):": "Задержка переподключения (мс):", - "Show Dot when No Cursor": "Показать точку вместо курсора", + "Automatic reconnect": "Автоматическое переподключение", + "Reconnect delay (ms):": "Задержка переподключения (мс):", + "Show dot when no cursor": "Показать точку вместо курсора", "Logging:": "Лог:", "Version:": "Версия", "Disconnect": "Отключение", diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/sv.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/sv.json index 80a400bfa..67f6675aa 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/sv.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/sv.json @@ -4,7 +4,6 @@ "Disconnecting...": "Kopplar ner...", "Reconnecting...": "Återansluter...", "Internal error": "Internt fel", - "Must set host": "Du måste specifiera en värd", "Failed to connect to server: ": "Misslyckades att ansluta till servern: ", "Connected (encrypted) to ": "Ansluten (krypterat) till ", "Connected (unencrypted) to ": "Ansluten (okrypterat) till ", @@ -17,11 +16,11 @@ "noVNC encountered an error:": "noVNC stötte på ett problem:", "Hide/Show the control bar": "Göm/Visa kontrollbaren", "Drag": "Dra", - "Move/Drag Viewport": "Flytta/Dra Vyn", + "Move/Drag viewport": "Flytta/Dra vyn", "Keyboard": "Tangentbord", - "Show Keyboard": "Visa Tangentbord", + "Show keyboard": "Visa tangentbord", "Extra keys": "Extraknappar", - "Show Extra Keys": "Visa Extraknappar", + "Show extra keys": "Visa extraknappar", "Ctrl": "Ctrl", "Toggle Ctrl": "Växla Ctrl", "Alt": "Alt", @@ -42,15 +41,15 @@ "Reset": "Återställ", "Clipboard": "Urklipp", "Edit clipboard content in the textarea below.": "Redigera urklippets innehåll i fältet nedan.", - "Full Screen": "Fullskärm", + "Full screen": "Fullskärm", "Settings": "Inställningar", - "Shared Mode": "Delat Läge", - "View Only": "Endast Visning", - "Clip to Window": "Begränsa till Fönster", - "Scaling Mode:": "Skalningsläge:", + "Shared mode": "Delat läge", + "View only": "Endast visning", + "Clip to window": "Begränsa till fönster", + "Scaling mode:": "Skalningsläge:", "None": "Ingen", - "Local Scaling": "Lokal Skalning", - "Remote Resizing": "Ändra Storlek", + "Local scaling": "Lokal skalning", + "Remote resizing": "Ändra storlek", "Advanced": "Avancerat", "Quality:": "Kvalitet:", "Compression level:": "Kompressionsnivå:", @@ -60,9 +59,9 @@ "Host:": "Värd:", "Port:": "Port:", "Path:": "Sökväg:", - "Automatic Reconnect": "Automatisk Återanslutning", - "Reconnect Delay (ms):": "Fördröjning (ms):", - "Show Dot when No Cursor": "Visa prick när ingen muspekare finns", + "Automatic reconnect": "Automatisk återanslutning", + "Reconnect delay (ms):": "Fördröjning (ms):", + "Show dot when no cursor": "Visa prick när ingen muspekare finns", "Logging:": "Loggning:", "Version:": "Version:", "Disconnect": "Koppla från", @@ -76,6 +75,9 @@ "Credentials": "Användaruppgifter", "Username:": "Användarnamn:", "Password:": "Lösenord:", - "Send Credentials": "Skicka Användaruppgifter", - "Cancel": "Avbryt" + "Send credentials": "Skicka användaruppgifter", + "Cancel": "Avbryt", + "Must set host": "Du måste specifiera en värd", + "HTTPS is required for full functionality": "HTTPS krävs för full funktionalitet", + "Clear": "Rensa" } \ No newline at end of file diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/tr.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/tr.json index 451c1b8a6..90f816244 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/tr.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/tr.json @@ -23,7 +23,7 @@ "Keyboard": "Klavye", "Show Keyboard": "Klavye Düzenini Göster", "Extra keys": "Ekstra tuşlar", - "Show Extra Keys": "Ekstra tuşları göster", + "Show extra keys": "Ekstra tuşları göster", "Ctrl": "Ctrl", "Toggle Ctrl": "Ctrl Değiştir ", "Alt": "Alt", diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/zh_CN.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/zh_CN.json index 3679eaddd..2898d2c1d 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/zh_CN.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/zh_CN.json @@ -1,31 +1,33 @@ { + "Running without HTTPS is not recommended, crashes or other issues are likely.": "不建议在没有 HTTPS 的情况下运行,可能会出现崩溃或出现其他问题。", "Connecting...": "连接中...", + "Disconnecting...": "正在断开连接...", + "Reconnecting...": "重新连接中...", + "Internal error": "内部错误", + "Must set host": "必须设置主机", + "Failed to connect to server: ": "无法连接到服务器:", "Connected (encrypted) to ": "已连接(已加密)到", "Connected (unencrypted) to ": "已连接(未加密)到", - "Disconnecting...": "正在断开连接...", + "Something went wrong, connection is closed": "出了点问题,连接已关闭", + "Failed to connect to server": "无法连接到服务器", "Disconnected": "已断开连接", - "Must set host": "必须设置主机", - "Reconnecting...": "重新连接中...", - "Password is required": "请提供密码", - "Disconnect timeout": "超时断开", + "New connection has been rejected with reason: ": "新连接被拒绝,原因如下:", + "New connection has been rejected": "新连接已被拒绝", + "Credentials are required": "需要凭证", "noVNC encountered an error:": "noVNC 遇到一个错误:", "Hide/Show the control bar": "显示/隐藏控制栏", - "Move/Drag Viewport": "移动/拖动窗口", - "viewport drag": "窗口拖动", - "Active Mouse Button": "启动鼠标按键", - "No mousebutton": "禁用鼠标按键", - "Left mousebutton": "鼠标左键", - "Middle mousebutton": "鼠标中键", - "Right mousebutton": "鼠标右键", + "Drag": "拖动", + "Move/Drag viewport": "移动/拖动窗口", "Keyboard": "键盘", - "Show Keyboard": "显示键盘", + "Show keyboard": "显示键盘", "Extra keys": "额外按键", - "Show Extra Keys": "显示额外按键", + "Show extra keys": "显示额外按键", "Ctrl": "Ctrl", "Toggle Ctrl": "切换 Ctrl", - "Edit clipboard content in the textarea below.": "在下面的文本区域中编辑剪贴板内容。", "Alt": "Alt", "Toggle Alt": "切换 Alt", + "Toggle Windows": "切换窗口", + "Windows": "窗口", "Send Tab": "发送 Tab 键", "Tab": "Tab", "Esc": "Esc", @@ -39,31 +41,53 @@ "Reboot": "重启", "Reset": "重置", "Clipboard": "剪贴板", - "Clear": "清除", - "Fullscreen": "全屏", + "Edit clipboard content in the textarea below.": "在下面的文本区域中编辑剪贴板内容。", + "Full screen": "全屏", "Settings": "设置", - "Encrypt": "加密", - "Shared Mode": "分享模式", - "View Only": "仅查看", - "Clip to Window": "限制/裁切窗口大小", - "Scaling Mode:": "缩放模式:", + "Shared mode": "分享模式", + "View only": "仅查看", + "Clip to window": "限制/裁切窗口大小", + "Scaling mode:": "缩放模式:", "None": "无", - "Local Scaling": "本地缩放", - "Local Downscaling": "降低本地尺寸", - "Remote Resizing": "远程调整大小", + "Local scaling": "本地缩放", + "Remote resizing": "远程调整大小", "Advanced": "高级", - "Local Cursor": "本地光标", + "Quality:": "品质:", + "Compression level:": "压缩级别:", "Repeater ID:": "中继站 ID", "WebSocket": "WebSocket", + "Encrypt": "加密", "Host:": "主机:", "Port:": "端口:", "Path:": "路径:", - "Automatic Reconnect": "自动重新连接", - "Reconnect Delay (ms):": "重新连接间隔 (ms):", + "Automatic reconnect": "自动重新连接", + "Reconnect delay (ms):": "重新连接间隔 (ms):", + "Show dot when no cursor": "无光标时显示点", "Logging:": "日志级别:", + "Version:": "版本:", "Disconnect": "断开连接", "Connect": "连接", + "Server identity": "服务器身份", + "The server has provided the following identifying information:": "服务器提供了以下识别信息:", + "Fingerprint:": "指纹:", + "Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "请核实信息是否正确,并按 “同意”,否则按 “拒绝”。", + "Approve": "同意", + "Reject": "拒绝", + "Credentials": "凭证", + "Username:": "用户名:", "Password:": "密码:", + "Send credentials": "发送凭证", "Cancel": "取消", + "Password is required": "请提供密码", + "Disconnect timeout": "超时断开", + "viewport drag": "窗口拖动", + "Active Mouse Button": "启动鼠标按键", + "No mousebutton": "禁用鼠标按键", + "Left mousebutton": "鼠标左键", + "Middle mousebutton": "鼠标中键", + "Right mousebutton": "鼠标右键", + "Clear": "清除", + "Local Downscaling": "降低本地尺寸", + "Local Cursor": "本地光标", "Canvas not supported.": "不支持 Canvas。" } \ No newline at end of file diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/zh_TW.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/zh_TW.json index 8ddf813f0..9d292a315 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/zh_TW.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/zh_TW.json @@ -14,7 +14,7 @@ "Password is required": "請提供密碼", "noVNC encountered an error:": "noVNC 遇到一個錯誤:", "Hide/Show the control bar": "顯示/隱藏控制列", - "Move/Drag Viewport": "拖放顯示範圍", + "Move/Drag viewport": "拖放顯示範圍", "viewport drag": "顯示範圍拖放", "Active Mouse Button": "啟用滑鼠按鍵", "No mousebutton": "無滑鼠按鍵", @@ -22,9 +22,9 @@ "Middle mousebutton": "滑鼠中鍵", "Right mousebutton": "滑鼠右鍵", "Keyboard": "鍵盤", - "Show Keyboard": "顯示鍵盤", + "Show keyboard": "顯示鍵盤", "Extra keys": "額外按鍵", - "Show Extra Keys": "顯示額外按鍵", + "Show extra keys": "顯示額外按鍵", "Ctrl": "Ctrl", "Toggle Ctrl": "切換 Ctrl", "Alt": "Alt", @@ -45,13 +45,13 @@ "Clear": "清除", "Fullscreen": "全螢幕", "Settings": "設定", - "Shared Mode": "分享模式", - "View Only": "僅檢視", - "Clip to Window": "限制/裁切視窗大小", - "Scaling Mode:": "縮放模式:", + "Shared mode": "分享模式", + "View only": "僅檢視", + "Clip to window": "限制/裁切視窗大小", + "Scaling mode:": "縮放模式:", "None": "無", - "Local Scaling": "本機縮放", - "Remote Resizing": "遠端調整大小", + "Local scaling": "本機縮放", + "Remote resizing": "遠端調整大小", "Advanced": "進階", "Repeater ID:": "中繼站 ID", "WebSocket": "WebSocket", @@ -59,8 +59,8 @@ "Host:": "主機:", "Port:": "連接埠:", "Path:": "路徑:", - "Automatic Reconnect": "自動重新連線", - "Reconnect Delay (ms):": "重新連線間隔 (ms):", + "Automatic reconnect": "自動重新連線", + "Reconnect delay (ms):": "重新連線間隔 (ms):", "Logging:": "日誌級別:", "Disconnect": "中斷連線", "Connect": "連線", diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/localization.js b/emhttp/plugins/dynamix.vm.manager/novnc/app/localization.js index 7d7e6e6af..c8257fdbe 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/localization.js +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/localization.js @@ -1,13 +1,13 @@ /* * noVNC: HTML5 VNC client - * Copyright (C) 2018 The noVNC Authors + * Copyright (C) 2018 The noVNC authors * Licensed under MPL 2.0 (see LICENSE.txt) * * See README.md for usage and integration instructions. */ /* - * Localization Utilities + * Localization utilities */ export class Localizer { diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/base.css b/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/base.css index f83ad4b93..87bfb45c5 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/base.css +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/base.css @@ -1,6 +1,6 @@ /* * noVNC base CSS - * Copyright (C) 2019 The noVNC Authors + * Copyright (C) 2019 The noVNC authors * noVNC is licensed under the MPL 2.0 (see LICENSE.txt) * This file is licensed under the 2-Clause BSD license (see LICENSE.txt). */ @@ -30,30 +30,31 @@ */ :root { - font-family: sans-serif; + font-family: sans-serif; + line-height: 1.6; } body { - margin:0; - padding:0; - /*Background image with light grey curve.*/ - background-color:#494949; - background-repeat:no-repeat; - background-position:right bottom; - height:100%; - touch-action: none; + margin:0; + padding:0; + /*Background image with light grey curve.*/ + background-color:#494949; + background-repeat:no-repeat; + background-position:right bottom; + height:100%; + touch-action: none; } html { - height:100%; + height:100%; } .noVNC_only_touch.noVNC_hidden { - display: none; + display: none; } .noVNC_disabled { - color: rgb(128, 128, 128); + color: var(--novnc-grey); } /* ---------------------------------------- @@ -62,33 +63,33 @@ html { */ .noVNC_spinner { - position: relative; + position: relative; } .noVNC_spinner, .noVNC_spinner::before, .noVNC_spinner::after { - width: 10px; - height: 10px; - border-radius: 2px; - box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); - animation: noVNC_spinner 1.0s linear infinite; + width: 10px; + height: 10px; + border-radius: 2px; + box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); + animation: noVNC_spinner 1.0s linear infinite; } .noVNC_spinner::before { - content: ""; - position: absolute; - left: 0px; - top: 0px; - animation-delay: -0.1s; + content: ""; + position: absolute; + left: 0px; + top: 0px; + animation-delay: -0.1s; } .noVNC_spinner::after { - content: ""; - position: absolute; - top: 0px; - left: 0px; - animation-delay: 0.1s; + content: ""; + position: absolute; + top: 0px; + left: 0px; + animation-delay: 0.1s; } @keyframes noVNC_spinner { - 0% { box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); width: 20px; } - 25% { box-shadow: 20px 10px 0 rgba(255, 255, 255, 1); width: 10px; } - 50% { box-shadow: 60px 10px 0 rgba(255, 255, 255, 0); width: 10px; } + 0% { box-shadow: -60px 10px 0 rgba(255, 255, 255, 0); width: 20px; } + 25% { box-shadow: 20px 10px 0 rgba(255, 255, 255, 1); width: 10px; } + 50% { box-shadow: 60px 10px 0 rgba(255, 255, 255, 0); width: 10px; } } /* ---------------------------------------- @@ -97,39 +98,39 @@ html { */ .noVNC_center { - /* - * This is a workaround because webkit misrenders transforms and - * uses non-integer coordinates, resulting in blurry content. - * Ideally we'd use "top: 50%; transform: translateY(-50%);" on - * the objects instead. - */ - display: flex; - align-items: center; - justify-content: center; - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - pointer-events: none; + /* + * This is a workaround because webkit misrenders transforms and + * uses non-integer coordinates, resulting in blurry content. + * Ideally we'd use "top: 50%; transform: translateY(-50%);" on + * the objects instead. + */ + display: flex; + align-items: center; + justify-content: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; } .noVNC_center > * { - pointer-events: auto; + pointer-events: auto; } .noVNC_vcenter { - display: flex !important; - flex-direction: column; - justify-content: center; - position: fixed; - top: 0; - left: 0; - height: 100%; - margin: 0 !important; - padding: 0 !important; - pointer-events: none; + display: flex !important; + flex-direction: column; + justify-content: center; + position: fixed; + top: 0; + left: 0; + height: 100%; + margin: 0 !important; + padding: 0 !important; + pointer-events: none; } .noVNC_vcenter > * { - pointer-events: auto; + pointer-events: auto; } /* ---------------------------------------- @@ -138,7 +139,7 @@ html { */ .noVNC_connect_layer { - z-index: 60; + z-index: 60; } /* ---------------------------------------- @@ -147,396 +148,404 @@ html { */ #noVNC_fallback_error { - z-index: 1000; - visibility: hidden; - /* Put a dark background in front of everything but the error, - and don't let mouse events pass through */ - background: rgba(0, 0, 0, 0.8); - pointer-events: all; + z-index: 1000; + visibility: hidden; + /* Put a dark background in front of everything but the error, + and don't let mouse events pass through */ + background: rgba(0, 0, 0, 0.8); + pointer-events: all; } #noVNC_fallback_error.noVNC_open { - visibility: visible; + visibility: visible; } #noVNC_fallback_error > div { - max-width: calc(100vw - 30px - 30px); - max-height: calc(100vh - 30px - 30px); - overflow: auto; + max-width: calc(100vw - 30px - 30px); + max-height: calc(100vh - 30px - 30px); + overflow: auto; - padding: 15px; + padding: 15px; - transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; - transform: translateY(-50px); - opacity: 0; + transform: translateY(-50px); + opacity: 0; - text-align: center; - font-weight: bold; - color: #fff; + text-align: center; + font-weight: bold; + color: #fff; - border-radius: 10px; - box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); - background: rgba(200,55,55,0.8); + border-radius: 12px; + box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); + background: rgba(200,55,55,0.8); } #noVNC_fallback_error.noVNC_open > div { - transform: translateY(0); - opacity: 1; + transform: translateY(0); + opacity: 1; } #noVNC_fallback_errormsg { - font-weight: normal; + font-weight: normal; } #noVNC_fallback_errormsg .noVNC_message { - display: inline-block; - text-align: left; - font-family: monospace; - white-space: pre-wrap; + display: inline-block; + text-align: left; + font-family: monospace; + white-space: pre-wrap; } #noVNC_fallback_error .noVNC_location { - font-style: italic; - font-size: 0.8em; - color: rgba(255, 255, 255, 0.8); + font-style: italic; + font-size: 0.8em; + color: rgba(255, 255, 255, 0.8); } #noVNC_fallback_error .noVNC_stack { - padding: 10px; - margin: 10px; - font-size: 0.8em; - text-align: left; - font-family: monospace; - white-space: pre; - border: 1px solid rgba(0, 0, 0, 0.5); - background: rgba(0, 0, 0, 0.2); - overflow: auto; + padding: 10px; + margin: 10px; + font-size: 0.8em; + text-align: left; + font-family: monospace; + white-space: pre; + border: 1px solid rgba(0, 0, 0, 0.5); + background: rgba(0, 0, 0, 0.2); + overflow: auto; } /* ---------------------------------------- - * Control Bar + * Control bar * ---------------------------------------- */ #noVNC_control_bar_anchor { - /* The anchor is needed to get z-stacking to work */ - position: fixed; - z-index: 10; + /* The anchor is needed to get z-stacking to work */ + position: fixed; + z-index: 10; - transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; - /* Edge misrenders animations wihthout this */ - transform: translateX(0); + /* Edge misrenders animations wihthout this */ + transform: translateX(0); } :root.noVNC_connected #noVNC_control_bar_anchor.noVNC_idle { - opacity: 0.8; + opacity: 0.8; } #noVNC_control_bar_anchor.noVNC_right { - left: auto; - right: 0; + left: auto; + right: 0; } #noVNC_control_bar { - position: relative; - left: -100%; + position: relative; + left: -100%; - transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; - background-color: rgb(110, 132, 163); - border-radius: 0 10px 10px 0; + background-color: var(--novnc-blue); + border-radius: 0 12px 12px 0; - user-select: none; - -webkit-user-select: none; - -webkit-touch-callout: none; /* Disable iOS image long-press popup */ + user-select: none; + -webkit-user-select: none; + -webkit-touch-callout: none; /* Disable iOS image long-press popup */ } #noVNC_control_bar.noVNC_open { - box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); - left: 0; + box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); + left: 0; } #noVNC_control_bar::before { - /* This extra element is to get a proper shadow */ - content: ""; - position: absolute; - z-index: -1; - height: 100%; - width: 30px; - left: -30px; - transition: box-shadow 0.5s ease-in-out; + /* This extra element is to get a proper shadow */ + content: ""; + position: absolute; + z-index: -1; + height: 100%; + width: 30px; + left: -30px; + transition: box-shadow 0.5s ease-in-out; } #noVNC_control_bar.noVNC_open::before { - box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); + box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); } .noVNC_right #noVNC_control_bar { - left: 100%; - border-radius: 10px 0 0 10px; + left: 100%; + border-radius: 12px 0 0 12px; } .noVNC_right #noVNC_control_bar.noVNC_open { - left: 0; + left: 0; } .noVNC_right #noVNC_control_bar::before { - visibility: hidden; + visibility: hidden; } #noVNC_control_bar_handle { - position: absolute; - left: -15px; - top: 0; - transform: translateY(35px); - width: calc(100% + 30px); - height: 50px; - z-index: -1; - cursor: pointer; - border-radius: 5px; - background-color: rgb(83, 99, 122); - background-image: url("../images/handle_bg.svg"); - background-repeat: no-repeat; - background-position: right; - box-shadow: 3px 3px 0px rgba(0, 0, 0, 0.5); + position: absolute; + left: -15px; + top: 0; + transform: translateY(35px); + width: calc(100% + 30px); + height: 50px; + z-index: -1; + cursor: pointer; + border-radius: 6px; + background-color: var(--novnc-darkblue); + background-image: url("../images/handle_bg.svg"); + background-repeat: no-repeat; + background-position: right; + box-shadow: 3px 3px 0px rgba(0, 0, 0, 0.5); } #noVNC_control_bar_handle:after { - content: ""; - transition: transform 0.5s ease-in-out; - background: url("../images/handle.svg"); - position: absolute; - top: 22px; /* (50px-6px)/2 */ - right: 5px; - width: 5px; - height: 6px; + content: ""; + transition: transform 0.5s ease-in-out; + background: url("../images/handle.svg"); + position: absolute; + top: 22px; /* (50px-6px)/2 */ + right: 5px; + width: 5px; + height: 6px; } #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { - transform: translateX(1px) rotate(180deg); + transform: translateX(1px) rotate(180deg); } :root:not(.noVNC_connected) #noVNC_control_bar_handle { - display: none; + display: none; } .noVNC_right #noVNC_control_bar_handle { - background-position: left; + background-position: left; } .noVNC_right #noVNC_control_bar_handle:after { - left: 5px; - right: 0; - transform: translateX(1px) rotate(180deg); + left: 5px; + right: 0; + transform: translateX(1px) rotate(180deg); } .noVNC_right #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { - transform: none; + transform: none; } /* Larger touch area for the handle, used when a touch screen is available */ #noVNC_control_bar_handle div { - position: absolute; - right: -35px; - top: 0; - width: 50px; - height: 100%; - display: none; + position: absolute; + right: -35px; + top: 0; + width: 50px; + height: 100%; + display: none; } @media (any-pointer: coarse) { - #noVNC_control_bar_handle div { - display: initial; - } + #noVNC_control_bar_handle div { + display: initial; + } } .noVNC_right #noVNC_control_bar_handle div { - left: -35px; - right: auto; + left: -35px; + right: auto; } #noVNC_control_bar > .noVNC_scroll { - max-height: 100vh; /* Chrome is buggy with 100% */ - overflow-x: hidden; - overflow-y: auto; - padding: 0 10px; + max-height: 100vh; /* Chrome is buggy with 100% */ + overflow-x: hidden; + overflow-y: auto; + padding: 0 10px; } #noVNC_control_bar > .noVNC_scroll > * { - display: block; - margin: 10px auto; + display: block; + margin: 10px auto; } /* Control bar hint */ #noVNC_hint_anchor { - position: fixed; - right: -50px; - left: auto; + position: fixed; + right: -50px; + left: auto; } #noVNC_control_bar_anchor.noVNC_right + #noVNC_hint_anchor { - left: -50px; - right: auto; + left: -50px; + right: auto; } #noVNC_control_bar_hint { - position: relative; - transform: scale(0); - width: 100px; - height: 50%; - max-height: 600px; + position: relative; + transform: scale(0); + width: 100px; + height: 50%; + max-height: 600px; - visibility: hidden; - opacity: 0; - transition: 0.2s ease-in-out; - background: transparent; - box-shadow: 0 0 10px black, inset 0 0 10px 10px rgba(110, 132, 163, 0.8); - border-radius: 10px; - transition-delay: 0s; + visibility: hidden; + opacity: 0; + transition: 0.2s ease-in-out; + background: transparent; + box-shadow: 0 0 10px black, inset 0 0 10px 10px var(--novnc-darkblue); + border-radius: 12px; + transition-delay: 0s; } #noVNC_control_bar_hint.noVNC_active { - visibility: visible; - opacity: 1; - transition-delay: 0.2s; - transform: scale(1); + visibility: visible; + opacity: 1; + transition-delay: 0.2s; + transform: scale(1); } #noVNC_control_bar_hint.noVNC_notransition { - transition: none !important; + transition: none !important; } /* Control bar buttons */ #noVNC_control_bar .noVNC_button { - padding: 4px 4px; - vertical-align: middle; - border:1px solid rgba(255, 255, 255, 0.2); - border-radius: 6px; - background-color: transparent; - background-image: unset; /* we don't want the gradiant from input.css */ + min-width: unset; + padding: 4px 4px; + vertical-align: middle; + border:1px solid rgba(255, 255, 255, 0.2); + border-radius: 6px; + background-color: transparent; } #noVNC_control_bar .noVNC_button.noVNC_selected { - border-color: rgba(0, 0, 0, 0.8); - background-color: rgba(0, 0, 0, 0.5); -} -#noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover { - border-color: rgba(0, 0, 0, 0.4); - background-color: rgba(0, 0, 0, 0.2); -} -#noVNC_control_bar .noVNC_button:not(:disabled):hover { - background-color: rgba(255, 255, 255, 0.2); -} -#noVNC_control_bar .noVNC_button:not(:disabled):active { - padding-top: 5px; - padding-bottom: 3px; -} -#noVNC_control_bar .noVNC_button.noVNC_hidden { - display: none !important; -} - -/* Android browsers don't properly update hover state if touch events are - * intercepted, like they are when clicking on the remote screen. */ -@media (any-pointer: coarse) { - #noVNC_control_bar .noVNC_button:not(:disabled):hover { - background-color: transparent; - } - #noVNC_control_bar .noVNC_button.noVNC_selected:not(:disabled):hover { border-color: rgba(0, 0, 0, 0.8); background-color: rgba(0, 0, 0, 0.5); - } } - +#noVNC_control_bar .noVNC_button.noVNC_hidden { + display: none !important; +} /* Panels */ .noVNC_panel { - transform: translateX(25px); + transform: translateX(25px); - transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; - box-sizing: border-box; /* so max-width don't have to care about padding */ - max-width: calc(100vw - 75px - 25px); /* minus left and right margins */ - max-height: 100vh; /* Chrome is buggy with 100% */ - overflow-x: hidden; - overflow-y: auto; + box-sizing: border-box; /* so max-width don't have to care about padding */ + max-width: calc(100vw - 75px - 25px); /* minus left and right margins */ + max-height: 100vh; /* Chrome is buggy with 100% */ + overflow-x: hidden; + overflow-y: auto; - visibility: hidden; - opacity: 0; + visibility: hidden; + opacity: 0; - padding: 15px; + padding: 15px; - background: #fff; - border-radius: 10px; - color: #000; - border: 2px solid #E0E0E0; - box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); + background: #fff; + border-radius: 12px; + color: #000; + border: 2px solid #E0E0E0; + box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); } .noVNC_panel.noVNC_open { - visibility: visible; - opacity: 1; - transform: translateX(75px); + visibility: visible; + opacity: 1; + transform: translateX(75px); } .noVNC_right .noVNC_vcenter { - left: auto; - right: 0; + left: auto; + right: 0; } .noVNC_right .noVNC_panel { - transform: translateX(-25px); + transform: translateX(-25px); } .noVNC_right .noVNC_panel.noVNC_open { - transform: translateX(-75px); + transform: translateX(-75px); } .noVNC_panel > * { - display: block; - margin: 10px auto; + display: block; + margin: 10px auto; } .noVNC_panel > *:first-child { - margin-top: 0 !important; + margin-top: 0 !important; } .noVNC_panel > *:last-child { - margin-bottom: 0 !important; + margin-bottom: 0 !important; } .noVNC_panel hr { - border: none; - border-top: 1px solid rgb(192, 192, 192); + border: none; + border-top: 1px solid var(--novnc-lightgrey); + width: 100%; /*
inside a flexbox will otherwise be 0px wide */ } .noVNC_panel label { - display: block; - white-space: nowrap; - margin: 5px; + display: block; + white-space: nowrap; + margin: 5px; +} +@media (max-width: 540px) { + /* Allow wrapping on small screens */ + .noVNC_panel label { + white-space: unset; + } } .noVNC_panel li { - margin: 5px; + margin: 5px; +} + +.noVNC_panel button, +.noVNC_panel select, +.noVNC_panel textarea, +.noVNC_panel input:not([type=checkbox]):not([type=radio]) { + margin-left: 6px; + /* Prevent inputs in panels from being too wide */ + max-width: calc(100% - 6px - var(--input-xpadding) * 2); } .noVNC_panel .noVNC_heading { - background-color: rgb(110, 132, 163); - border-radius: 5px; - padding: 5px; - /* Compensate for padding in image */ - padding-right: 8px; - color: white; - font-size: 20px; - white-space: nowrap; + background-color: var(--novnc-blue); + border-radius: 6px; + padding: 5px 8px; + /* Compensate for padding in image */ + padding-right: 11px; + display: flex; + align-items: center; + gap: 6px; + color: white; + font-size: 20px; + font-weight: bold; + white-space: nowrap; } .noVNC_panel .noVNC_heading img { - vertical-align: bottom; + vertical-align: bottom; } -.noVNC_submit { - float: right; +.noVNC_panel form { + display: flex; + flex-direction: column; + gap: 12px +} + +.noVNC_panel .button_row { + margin-top: 10px; + display: flex; + gap: 10px; + justify-content: space-between; +} +.noVNC_panel .button_row *:only-child { + margin-left: auto; /* Align single buttons to the right */ } /* Expanders */ .noVNC_expander { - cursor: pointer; + cursor: pointer; } .noVNC_expander::before { - content: url("../images/expander.svg"); - display: inline-block; - margin-right: 5px; - transition: 0.2s ease-in-out; + content: url("../images/expander.svg"); + display: inline-block; + margin-right: 5px; + transition: 0.2s ease-in-out; } .noVNC_expander.noVNC_open::before { - transform: rotateZ(90deg); + transform: rotateZ(90deg); } .noVNC_expander ~ * { - margin: 5px; - margin-left: 10px; - padding: 5px; - background: rgba(0, 0, 0, 0.05); - border-radius: 5px; + margin: 5px; + margin-left: 10px; + padding: 5px; + background: rgba(0, 0, 0, 0.04); + border-radius: 6px; } .noVNC_expander:not(.noVNC_open) ~ * { - display: none; + display: none; } /* Control bar content */ #noVNC_control_bar .noVNC_logo { - font-size: 13px; + font-size: 13px; } .noVNC_logo + hr { @@ -546,356 +555,352 @@ html { } :root:not(.noVNC_connected) #noVNC_view_drag_button { - display: none; + display: none; } /* noVNC Touch Device only buttons */ :root:not(.noVNC_connected) #noVNC_mobile_buttons { - display: none; + display: none; } @media not all and (any-pointer: coarse) { - /* FIXME: The button for the virtual keyboard is the only button in this - group of "mobile buttons". It is bad to assume that no touch - devices have physical keyboards available. Hopefully we can get - a media query for this: - https://github.com/w3c/csswg-drafts/issues/3871 */ - :root.noVNC_connected #noVNC_mobile_buttons { - display: none; - } + /* FIXME: The button for the virtual keyboard is the only button in this + group of "mobile buttons". It is bad to assume that no touch + devices have physical keyboards available. Hopefully we can get + a media query for this: + https://github.com/w3c/csswg-drafts/issues/3871 */ + :root.noVNC_connected #noVNC_mobile_buttons { + display: none; + } } /* Extra manual keys */ :root:not(.noVNC_connected) #noVNC_toggle_extra_keys_button { - display: none; + display: none; } #noVNC_modifiers { - background-color: rgb(92, 92, 92); - border: none; - padding: 10px; + background-color: var(--novnc-darkgrey); + border: none; + padding: 10px; } /* Shutdown/Reboot */ :root:not(.noVNC_connected) #noVNC_power_button { - display: none; + display: none; } #noVNC_power { } #noVNC_power_buttons { - display: none; + display: none; } #noVNC_power input[type=button] { - width: 100%; + width: 100%; } /* Clipboard */ :root:not(.noVNC_connected) #noVNC_clipboard_button { - display: none; + display: none; } #noVNC_clipboard_text { - width: 360px; - min-width: 150px; - height: 160px; - min-height: 70px; + width: 360px; + min-width: 150px; + height: 160px; + min-height: 70px; - box-sizing: border-box; - max-width: 100%; - /* minus approximate height of title, height of subtitle, and margin */ - max-height: calc(100vh - 10em - 25px); + box-sizing: border-box; + max-width: 100%; + /* minus approximate height of title, height of subtitle, and margin */ + max-height: calc(100vh - 10em - 25px); } /* Settings */ #noVNC_settings { } #noVNC_settings ul { - list-style: none; - padding: 0px; + list-style: none; + padding: 0px; } #noVNC_setting_port { - width: 80px; + width: 80px; } #noVNC_setting_path { - width: 100px; + width: 100px; } /* Version */ .noVNC_version_wrapper { - font-size: small; + font-size: small; } .noVNC_version { - margin-left: 1rem; + margin-left: 1rem; } -/* Connection Controls */ +/* Connection controls */ :root:not(.noVNC_connected) #noVNC_disconnect_button { - display: none; + display: none; } /* ---------------------------------------- - * Status Dialog + * Status dialog * ---------------------------------------- */ #noVNC_status { - position: fixed; - top: 0; - left: 0; - width: 100%; - z-index: 100; - transform: translateY(-100%); + position: fixed; + top: 0; + left: 0; + width: 100%; + z-index: 100; + transform: translateY(-100%); - cursor: pointer; + cursor: pointer; - transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; - visibility: hidden; - opacity: 0; + visibility: hidden; + opacity: 0; - padding: 5px; + padding: 5px; - display: flex; - flex-direction: row; - justify-content: center; - align-content: center; + display: flex; + flex-direction: row; + justify-content: center; + align-content: center; - line-height: 1.6; - word-wrap: break-word; - color: #fff; + line-height: 1.6; + word-wrap: break-word; + color: #fff; - border-bottom: 1px solid rgba(0, 0, 0, 0.9); + border-bottom: 1px solid rgba(0, 0, 0, 0.9); } #noVNC_status.noVNC_open { - transform: translateY(0); - visibility: visible; - opacity: 1; + transform: translateY(0); + visibility: visible; + opacity: 1; } #noVNC_status::before { - content: ""; - display: inline-block; - width: 25px; - height: 25px; - margin-right: 5px; + content: ""; + display: inline-block; + width: 25px; + height: 25px; + margin-right: 5px; } #noVNC_status.noVNC_status_normal { - background: rgba(128,128,128,0.9); + background: rgba(128,128,128,0.9); } #noVNC_status.noVNC_status_normal::before { - content: url("../images/info.svg") " "; + content: url("../images/info.svg") " "; } #noVNC_status.noVNC_status_error { - background: rgba(200,55,55,0.9); + background: rgba(200,55,55,0.9); } #noVNC_status.noVNC_status_error::before { - content: url("../images/error.svg") " "; + content: url("../images/error.svg") " "; } #noVNC_status.noVNC_status_warn { - background: rgba(180,180,30,0.9); + background: rgba(180,180,30,0.9); } #noVNC_status.noVNC_status_warn::before { - content: url("../images/warning.svg") " "; + content: url("../images/warning.svg") " "; } /* ---------------------------------------- - * Connect Dialog + * Connect dialog * ---------------------------------------- */ #noVNC_connect_dlg { - transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; - transform: scale(0, 0); - visibility: hidden; - opacity: 0; + transform: scale(0, 0); + visibility: hidden; + opacity: 0; } #noVNC_connect_dlg.noVNC_open { - transform: scale(1, 1); - visibility: visible; - opacity: 1; + transform: scale(1, 1); + visibility: visible; + opacity: 1; } #noVNC_connect_dlg .noVNC_logo { - transition: 0.5s ease-in-out; - padding: 10px; - margin-bottom: 10px; + transition: 0.5s ease-in-out; + padding: 10px; + margin-bottom: 10px; - font-size: 80px; - text-align: center; + font-size: 80px; + text-align: center; - border-radius: 5px; + border-radius: 6px; } @media (max-width: 440px) { - #noVNC_connect_dlg { - max-width: calc(100vw - 100px); - } - #noVNC_connect_dlg .noVNC_logo { - font-size: calc(25vw - 30px); - } + #noVNC_connect_dlg { + max-width: calc(100vw - 100px); + } + #noVNC_connect_dlg .noVNC_logo { + font-size: calc(25vw - 30px); + } } #noVNC_connect_dlg div { - padding: 12px; + padding: 18px; - background-color: rgb(110, 132, 163); - border-radius: 12px; - text-align: center; - font-size: 20px; + background-color: var(--novnc-darkgrey); + border-radius: 12px; + text-align: center; + font-size: 20px; - box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); + box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); } #noVNC_connect_button { - width: 100%; - padding: 5px 30px; + width: 100%; + padding: 6px 30px; + cursor: pointer; + border-color: transparent; + border-radius: 12px; + background-color: var(--novnc-blue); + color: white; - cursor: pointer; - - border-color: rgb(83, 99, 122); - border-radius: 5px; - - background: linear-gradient(to top, rgb(110, 132, 163), rgb(99, 119, 147)); - color: white; - - /* This avoids it jumping around when :active */ - vertical-align: middle; -} -#noVNC_connect_button:hover { - background: linear-gradient(to top, rgb(110, 132, 163), rgb(105, 125, 155)); + display: flex; + justify-content: center; + place-items: center; + gap: 4px; } #noVNC_connect_button img { - vertical-align: bottom; - height: 1.3em; + vertical-align: bottom; + height: 1.3em; } /* ---------------------------------------- - * Server verification Dialog + * Server verification dialog * ---------------------------------------- */ #noVNC_verify_server_dlg { - position: relative; + position: relative; - transform: translateY(-50px); + transform: translateY(-50px); } #noVNC_verify_server_dlg.noVNC_open { - transform: translateY(0); + transform: translateY(0); } #noVNC_fingerprint_block { - margin: 10px; + margin: 10px; } /* ---------------------------------------- - * Password Dialog + * Password dialog * ---------------------------------------- */ #noVNC_credentials_dlg { - position: relative; + position: relative; - transform: translateY(-50px); + transform: translateY(-50px); } #noVNC_credentials_dlg.noVNC_open { - transform: translateY(0); + transform: translateY(0); } #noVNC_username_block.noVNC_hidden, #noVNC_password_block.noVNC_hidden { - display: none; + display: none; } /* ---------------------------------------- - * Main Area + * Main area * ---------------------------------------- */ /* Transition screen */ #noVNC_transition { - transition: 0.5s ease-in-out; + transition: 0.5s ease-in-out; - display: flex; - opacity: 0; - visibility: hidden; + display: flex; + opacity: 0; + visibility: hidden; - position: fixed; - top: 0; - left: 0; - bottom: 0; - right: 0; + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; - color: white; - background: rgba(0, 0, 0, 0.5); - z-index: 50; + color: white; + background: rgba(0, 0, 0, 0.5); + z-index: 50; - /*display: flex;*/ - align-items: center; - justify-content: center; - flex-direction: column; + /*display: flex;*/ + align-items: center; + justify-content: center; + flex-direction: column; } :root.noVNC_loading #noVNC_transition, :root.noVNC_connecting #noVNC_transition, :root.noVNC_disconnecting #noVNC_transition, :root.noVNC_reconnecting #noVNC_transition { - opacity: 1; - visibility: visible; + opacity: 1; + visibility: visible; } :root:not(.noVNC_reconnecting) #noVNC_cancel_reconnect_button { - display: none; + display: none; } #noVNC_transition_text { - font-size: 1.5em; + font-size: 1.5em; } /* Main container */ #noVNC_container { - width: 100%; - height: 100%; - background-color: #313131; - border-bottom-right-radius: 800px 600px; - /*border-top-left-radius: 800px 600px;*/ + width: 100%; + height: 100%; + background-color: #313131; + border-bottom-right-radius: 800px 600px; + /*border-top-left-radius: 800px 600px;*/ - /* If selection isn't disabled, long-pressing stuff in the sidebar - can accidentally select the container or the canvas. This can - happen when attempting to move the handle. */ - user-select: none; - -webkit-user-select: none; + /* If selection isn't disabled, long-pressing stuff in the sidebar + can accidentally select the container or the canvas. This can + happen when attempting to move the handle. */ + user-select: none; + -webkit-user-select: none; } #noVNC_keyboardinput { - width: 1px; - height: 1px; - background-color: #fff; - color: #fff; - border: 0; - position: absolute; - left: -40px; - z-index: -1; - ime-mode: disabled; + width: 1px; + height: 1px; + background-color: #fff; + color: #fff; + border: 0; + position: absolute; + left: -40px; + z-index: -1; + ime-mode: disabled; } /*Default noVNC logo.*/ /* From: http://fonts.googleapis.com/css?family=Orbitron:700 */ @font-face { - font-family: 'Orbitron'; - font-style: normal; - font-weight: 700; - src: local('?'), url('Orbitron700.woff') format('woff'), - url('Orbitron700.ttf') format('truetype'); + font-family: 'Orbitron'; + font-style: normal; + font-weight: 700; + src: local('?'), url('Orbitron700.woff') format('woff'), + url('Orbitron700.ttf') format('truetype'); } .noVNC_logo { - color:yellow; - font-family: 'Orbitron', 'OrbitronTTF', sans-serif; - line-height: 0.9; - text-shadow: 0.1em 0.1em 0 black; + color: var(--novnc-yellow); + font-family: 'Orbitron', 'OrbitronTTF', sans-serif; + line-height: 0.9; + text-shadow: 0.1em 0.1em 0 black; } .noVNC_logo span{ - color:green; + color: var(--novnc-green); } #noVNC_bell { - display: none; + display: none; } /* ---------------------------------------- @@ -904,19 +909,19 @@ html { */ @media screen and (max-width: 640px){ - #noVNC_logo { - font-size: 150px; - } + #noVNC_logo { + font-size: 150px; + } } @media screen and (min-width: 321px) and (max-width: 480px) { - #noVNC_logo { - font-size: 110px; - } + #noVNC_logo { + font-size: 110px; + } } @media screen and (max-width: 320px) { - #noVNC_logo { - font-size: 90px; - } + #noVNC_logo { + font-size: 90px; + } } diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/constants.css b/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/constants.css new file mode 100644 index 000000000..1123a3efc --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/constants.css @@ -0,0 +1,30 @@ +/* + * noVNC general CSS constant variables + * Copyright (C) 2025 The noVNC authors + * noVNC is licensed under the MPL 2.0 (see LICENSE.txt) + * This file is licensed under the 2-Clause BSD license (see LICENSE.txt). + */ + +/* ---------- COLORS ----------- */ + +:root { + --novnc-grey: rgb(128, 128, 128); + --novnc-lightgrey: rgb(192, 192, 192); + --novnc-darkgrey: rgb(92, 92, 92); + + /* Transparent to make button colors adapt to the background */ + --novnc-buttongrey: rgba(192, 192, 192, 0.5); + + --novnc-blue: rgb(110, 132, 163); + --novnc-lightblue: rgb(74, 144, 217); + --novnc-darkblue: rgb(83, 99, 122); + + --novnc-green: rgb(0, 128, 0); + --novnc-yellow: rgb(255, 255, 0); +} + +/* ------ MISC PROPERTIES ------ */ + +:root { + --input-xpadding: 1em; +} diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/input.css b/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/input.css index dc345aabc..8273d70ad 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/input.css +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/input.css @@ -1,32 +1,170 @@ /* * noVNC general input element CSS - * Copyright (C) 2022 The noVNC Authors + * Copyright (C) 2025 The noVNC authors * noVNC is licensed under the MPL 2.0 (see LICENSE.txt) * This file is licensed under the 2-Clause BSD license (see LICENSE.txt). */ -/* - * Common for all inputs - */ -input, input::file-selector-button, button, select, textarea { - /* Respect standard font settings */ - font: inherit; +/* ------- SHARED BETWEEN INPUT ELEMENTS -------- */ - /* Disable default rendering */ - appearance: none; - background: none; +input, +textarea, +button, +select, +input::file-selector-button { + padding: 0.5em var(--input-xpadding); + border-radius: 6px; + appearance: none; + text-overflow: ellipsis; - padding: 5px; - border: 1px solid rgb(192, 192, 192); - border-radius: 5px; - color: black; - --bg-gradient: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240)); - background-image: var(--bg-gradient); + /* Respect standard font settings */ + font: inherit; + line-height: 1.6; +} +input:disabled, +textarea:disabled, +button:disabled, +select:disabled, +label[disabled] { + opacity: 0.4; } -/* - * Buttons - */ +input:focus-visible, +textarea:focus-visible, +button:focus-visible, +select:focus-visible, +input:focus-visible::file-selector-button { + outline: 2px solid var(--novnc-lightblue); + outline-offset: 1px; +} + +/* ------- TEXT INPUT -------- */ + +input:not([type]), +input[type=date], +input[type=datetime-local], +input[type=email], +input[type=month], +input[type=number], +input[type=password], +input[type=search], +input[type=tel], +input[type=text], +input[type=time], +input[type=url], +input[type=week], +textarea { + border: 1px solid var(--novnc-lightgrey); + /* Account for borders on text inputs, buttons dont have borders */ + padding: calc(0.5em - 1px) var(--input-xpadding); +} +input:not([type]):focus-visible, +input[type=date]:focus-visible, +input[type=datetime-local]:focus-visible, +input[type=email]:focus-visible, +input[type=month]:focus-visible, +input[type=number]:focus-visible, +input[type=password]:focus-visible, +input[type=search]:focus-visible, +input[type=tel]:focus-visible, +input[type=text]:focus-visible, +input[type=time]:focus-visible, +input[type=url]:focus-visible, +input[type=week]:focus-visible, +textarea:focus-visible { + outline-offset: -1px; +} + +textarea { + margin: unset; /* Remove Firefox's built in margin */ + /* Prevent layout from shifting when scrollbars show */ + scrollbar-gutter: stable; + /* Make textareas show at minimum one line. This does not work when + using box-sizing border-box, in which case, vertical padding and + border width needs to be taken into account. */ + min-height: 1lh; + vertical-align: baseline; /* Firefox gives "text-bottom" by default */ +} + +/* ------- NUMBER PICKERS ------- */ + +/* We can't style the number spinner buttons: + https://github.com/w3c/csswg-drafts/issues/8777 */ +input[type=number]::-webkit-inner-spin-button, +input[type=number]::-webkit-outer-spin-button { + /* Get rid of increase/decrease buttons in WebKit */ + appearance: none; +} +input[type=number] { + /* Get rid of increase/decrease buttons in Firefox */ + appearance: textfield; +} + +/* ------- BUTTON ACTIVATIONS -------- */ + +/* A color overlay that depends on the activation level. The level can then be + set for different states on an element, for example hover and click on a + +
+ + + + +
+
+
+ Server identity +
+
+ The server has provided the following identifying information: +
+
+ Fingerprint: + +
+
+ Please verify that the information is correct and press + "Approve". Otherwise press "Reject". +
+
+ + +
+
+
+ + +
+
+
+ Credentials +
+
+ + +
+
+ + +
+
+ +
+
+
+ + +
+
+
+ +
+
+
+ + +
+ + +
+ + + + diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/vnc_lite.html b/emhttp/plugins/dynamix.vm.manager/novnc/vnc_lite.html new file mode 100644 index 000000000..79d481460 --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/vnc_lite.html @@ -0,0 +1,180 @@ + + + + + + noVNC + + + + + + + +
+
Loading
+
Send CtrlAltDel
+
+
+ +
+ + diff --git a/emhttp/plugins/dynamix.vm.manager/vnc.html b/emhttp/plugins/dynamix.vm.manager/vnc.html index edfe49b40..790871eb7 100644 --- a/emhttp/plugins/dynamix.vm.manager/vnc.html +++ b/emhttp/plugins/dynamix.vm.manager/vnc.html @@ -4,7 +4,7 @@ noVNC - - - - - - - - - - - - - - - - - - - - - - + - + @@ -63,6 +37,7 @@ + @@ -72,7 +47,56 @@ - + + @@ -85,7 +109,7 @@ - +
@@ -100,18 +124,18 @@ + title="Move/Drag viewport"> - +
+ id="noVNC_keyboard_button" class="noVNC_button" title="Show keyboard">
+ title="Show extra keys">
- + title="Full screen">
  • - +
  • - +

  • - +
  • - +

  • @@ -220,7 +256,11 @@
    WebSocket
    • - +
    • @@ -238,15 +278,23 @@

    • - +
    • - +

    • - +

    • @@ -267,7 +315,7 @@
- + @@ -282,7 +330,7 @@
- +
@@ -297,7 +345,7 @@
- +
@@ -307,21 +355,21 @@ The server has provided the following identifying information:
- Fingerprint: + Fingerprint:
Please verify that the information is correct and press "Approve". Otherwise press "Reject".
-
- - +
+ +
- +
@@ -335,17 +383,17 @@
-
- +
+
- +
- +