diff --git a/.gitignore b/.gitignore index 30f6930f7..058cab56d 100644 --- a/.gitignore +++ b/.gitignore @@ -58,7 +58,6 @@ games/ info/ lib64/ man/ -share/ # Auto-generated when emhttpd/webGUI start emhttp/languages/en_US/helptext.dot diff --git a/emhttp/languages/en_US/helptext.txt b/emhttp/languages/en_US/helptext.txt index 33d9f9b77..57d748267 100644 --- a/emhttp/languages/en_US/helptext.txt +++ b/emhttp/languages/en_US/helptext.txt @@ -256,7 +256,7 @@ Unraid OS uses these default options when creating a multiple-device pool: `-dconvert=raid1 -mconvert=raid1` -For more complete documentation, please refer to the btrfs-balance [Manpage](https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs-balance) +For more complete documentation, please refer to the btrfs-balance [Manpage](https://man7.org/linux/man-pages/man8/btrfs-balance.8.html) *Note: raid5 and raid6 are generally still considered **experimental** by the Linux community* :end @@ -269,7 +269,14 @@ For more complete documentation, please refer to the btrfs-balance [Manpage](htt **Scrub** runs the *btrfs scrub* program which will read all data and metadata blocks from all devices and verify checksums. -If *Repair corrupted blocks* is checked, *btrfs scrub* will repair corrupted blocks if there’s a correct copy available. +*btrfs scrub* will repair corrupted blocks if there is a correct copy available. +:end + +:info_zfs_scrub_help: +**Scrub** runs the *zfs scrub* program which will read all data and metadata blocks from all +devices and verify checksums. + +Click the **Upgrade Pool** button to upgrade the ZFS pool to enable the latest ZFS features. :end :info_scrub_cancel_help: @@ -282,6 +289,10 @@ If *Repair corrupted blocks* is checked, *btrfs scrub* will repair corrupted blo The *Options* field is initialized with *--readonly* which specifies check-only. If repair is needed, you should run a second Check pass, setting the *Options* to *--repair*; this will permit *btrfs check* to fix the file system. +WARNING: **Do not use** *--repair* unless you are advised to do so by a developer or an experienced user, +and then only after having accepted that no fsck successfully repair all types of filesystem corruption. +E.g. some other software or hardware bugs can fatally damage a volume. + After starting a Check, you should Refresh to monitor progress and status. Depending on how large the file system is, and what errors might be present, the operation can take **a long time** to finish (hours). Not much info is printed in the window, but you can verify the operation is running by observing the read/write counters @@ -695,6 +706,12 @@ Summary of security modes: **Secure** All users including guests have read access, you select which of your users have write access. **Private** No guest access at all, you select which of your users have read/write, read-only access or no access. + +Windows Server Signing: + +If you are unable to browse SMB shares with Windows 11 version 24H2 or newer, you need to make some changes to accomodate a new feature called Server Signing. Server Signing is enabled in Unraid and you need to make changes to access Public shares. +You can disable it in Windows, or to work with Unraid with Server Signing enabled, the easiest way is to create a user (with a password set) in Unraid with the same name as the Windows account you are using, Windows should then ask you for the credentials. +If you are using a Microsoft account, it may be better to just create a user in Unraid with a simple username and set a password, then in Windows go to Control Panel -> Credential Manager -> Windows credentials -> Add a Windows Credential and add the correct Unraid server name and credentials. :end :smb_secure_access_help: @@ -727,6 +744,15 @@ Select the desired share name and press **Read** to copy the NFS security settin Select the desired destinations and press **Write** to copy the NFS security settings to the selected shares. :end +:nfs_security_rules_help: +Put the rule for each IP address on a separate line and terminate the Rule with a new line. +You cannot enter a Rule in the format IP1,IP2(...). Unraid does not format the exports file in that format. + +The default rules for every NFS Rule are - async and no_subtree_check. + +**Note:** The Public Rule used is '*(rw,sec=sys,insecure,anongid=100,anonuid=99,no_root_squash)'. +:end + :user_add_username_help: Usernames may be up to 40 characters long and must start with a **lower case letter** or an underscore, followed by **lower case letters**, digits, underscores, or dashes. They can end with a dollar sign. @@ -1283,6 +1309,14 @@ The Local Access URLs shown above are based on your current settings. To adjust URLs or redirects, see the help text for "Use SSL/TLS". :end +:mgmt_wg_access_urls_help: +These URLs will only work when connected via the appropriate WireGuard tunnel as configured on ***Settings > VPN Manager*** +:end + +:mgmt_tailscale_access_urls_help: +These URLs will only work when connected to the appropriate Tailscale Tailnet. +:end + :mgmt_certificate_expiration_help: **Provision** may be used to install a *free* myunraid.net SSL Certificate from [Let's Encrypt](https://letsencrypt.org/). @@ -1445,6 +1479,20 @@ your client. Be aware that setting a value of -1 will cause the memory footprin files/directories you access via NFS this may or may not lead to out-of-memory conditions. :end +:nfs_server_max_protocol_help: +Select the max NFS Protocol version you want your Unraid server to support. +:end + +:nfs_client_max_protocol_help: +Select the max NFS Protocol version you want to use to mount your remote shares. +:end + +:nfs_threads_help: +Set the number of threads for NFS. For light NFS loads, 8 is sufficient. For heaver NFS loads, a higher number of threads might be appropriate. + +If there aren't enough threads, NFS will probably crash. +:end + :shares_enable_disk_help: If set to No, disk shares are unconditionally not exported. @@ -1502,6 +1550,10 @@ This will increase write performance but might possibly decrease read performanc *Auto* selects No. :end +:shares_fuse_file_descriptors_io_help: +Set the number of fuse file descriptors. With a lot of file activity on the array, you may need to increase this value. +:end + :syslog_local_server_help: Let the server act as a central syslog server and collect syslog messages from other systems. The server can listen on UDP, TCP or both with a selectable port number. @@ -1520,7 +1572,6 @@ Select the identifier for the remote system (used in the logfile name). * "IP Address" uses the IP address (IPv4 or IPv6) of the sending system. * "Hostname (from syslog message)" uses the hostname included in each syslog message. * "Hostname (from DNS reverse lookup)" performs a DNS reverse lookup for the sending IP and uses the result. - :end :syslog_local_rotation_help: @@ -2295,6 +2346,141 @@ Generally speaking, it is recommended to leave this setting to its default value IMPORTANT NOTE: If adjusting port mappings, do not modify the settings for the Container port as only the Host port can be adjusted. :end +:docker_container_network_help: +This allows your container to utilize the network configuration of another container. Select the appropriate container from the list.
This setup can be particularly beneficial if you wish to route your container's traffic through a VPN. +:end + +:docker_tailscale_help: +Enable Tailscale to add this container as a machine on your Tailnet. +:end + +:docker_tailscale_hostname_help: +Provide the hostname for this container. It does not need to match the container name, but it must be unique on your Tailnet. Note that an HTTPS certificate will be generated for this hostname, which means it will be placed in a public ledger, so use a name that you don't mind being public. +For more information see enabling https. +:end + +:docker_tailscale_be_exitnode_help: +Enable this if other machines on your Tailnet should route their Internet traffic through this container, this is most useful for containers that connect to commercial VPN services. +Be sure to authorize this Exit Node in your Tailscale Machines Admin Panel. +For more details, see the Tailscale documentation on Exit Nodes. +:end + +:docker_tailscale_exitnode_ip_help: +Optionally route this container's outgoing Internet traffic through an Exit Node on your Tailnet. Choose the Exit Node or input its Tailscale IP address. +For more details, see Exit Nodes. +:end + +:docker_tailscale_lanaccess_help: +Only applies when this container is using an Exit Node. Enable this to allow the container to access the local network. + +WARNING: Even with this feature enabled, systems on your LAN may not be able to access the container unless they have Tailscale installed. +:end + +:docker_tailscale_userspace_networking_help: +When enabled, this container will operate in a restricted environment. Tailscale DNS will not work, and the container will not be able to initiate connections to other Tailscale machines. However, other machines on your Tailnet will still be able to communicate with this container. + +When disabled, this container will have full access to your Tailnet. Tailscale DNS will work, and the container can fully communicate with other machines on the Tailnet. +However, systems on your LAN may not be able to access the container unless they have Tailscale installed. +:end + +:docker_tailscale_ssh_help: +Tailscale SSH is similar to the Docker "Console" option in the Unraid webgui, except you connect with an SSH client and authenticate via Tailscale. +For more details, see the Tailscale SSH documentation. +:end + +:docker_tailscale_serve_mode_help: +Enabling Serve will automatically reverse proxy the primary web service from this container and make it available on your Tailnet using https with a valid certificate! + +Note that when accessing the Tailscale WebUI url, no additional authentication layer is added beyond restricting it to your Tailnet - the container is still responsible for managing usernames/passwords that are allowed to access it. Depending on your configuration, direct access to the container may still be possible as well. + +For more details, see the Tailscale Serve documentation. + +If the documentation recommends additional settings for a more complex use case, enable "Tailscale Show Advanced Settings". Support for these advanced settings is not available beyond confirming the commands are passed to Tailscale correctly. + +Funnel is similar to Serve, except that the web service is made available on the open Internet. Use with care as the service will likely be attacked. As with Serve, the container itself is responsible for handling any authentication. + +We recommend reading the Tailscale Funnel documentation before enabling this feature. + +Note: Enabling Serve or Funnel publishes the Tailscale hostname to a public ledger. +For more details, see the Tailscale Documentation: Enabling HTTPS. +:end + +:docker_tailscale_serve_port_help: +This field should specify the port for the primary web service this container offers. Note: it should specify the port in the container, not a port that was remapped on the host. + +The system attempted to determine the correct port automatically. If it used the wrong value then there is likely an issue with the "Web UI" field for this container, visible by switching from "Basic View" to "Advanced View" in the upper right corner of this page. + +In most cases this port is all you will need to specify in order to Serve the website in this container, although additional options are available below for more complex containers. + +This value is passed to the `` portion of this command which starts serve or funnel:
+`tailscale [serve|funnel] --bg -- http://localhost:`
+For more details see the Tailscale Serve Command Line documentation. +:end + +:docker_tailscale_show_advanced_help: +Here there be dragons! +:end + +:docker_tailscale_serve_local_path_help: +When not specified, this value defaults to an empty string. It is passed to the `` portion of this command which starts serve or funnel:
+`tailscale [serve|funnel] --bg -- http://localhost:`
+For more details see the Tailscale Serve Command Line documentation. +:end + +:docker_tailscale_serve_protocol_help: +When not specified, this value defaults to "https". It is passed to the `` portion of this command which starts serve or funnel:
+`tailscale [serve|funnel] --bg --= http://localhost:`
+For more details see the Tailscale Serve Command Line documentation. +:end + +:docker_tailscale_serve_protocol_port_help: +When not specified, this value defaults to "=443". It is passed to the `` portion of this command which starts serve or funnel:
+`tailscale [serve|funnel] --bg -- http://localhost:`
+For more details see the Tailscale Serve Command Line documentation. +:end + +:docker_tailscale_serve_path_help: +When not specified, this value defaults to an empty string. It is passed to the `` portion of this command which starts serve or funnel:
+`tailscale [serve|funnel] --bg -- http://localhost:`
+For more details see the Tailscale Serve Command Line documentation. +:end + +:docker_tailscale_serve_webui_help: +If Serve is enabled this will be an https url with a proper domain name that is accessible over your Tailnet, no port needed! + +If Funnel is enabled the same url will be available on the Internet. + +If they are disabled then the url will be generated from the container's main "Web UI" field, but modified to use the Tailscale IP. If the wrong port is specified here then switch from "Basic View" to "Advanced View" and review the "Web UI" field for this container. +:end + +:docker_tailscale_advertise_routes_help: +If desired, specify any routes that should be passed to the **`--advertise-routes=`** parameter when running **`tailscale up`**. +For more details see the Subnet routers documentation. +:end + +:docker_tailscale_accept_routes_help: +When enabled, this will accept your subnet routes from other devices, adding the **`--accept-routes`** parameter when running **`tailscale up`**. +For more details see the Use your subnet routes from other devices documentation. +:end + +:docker_tailscale_daemon_extra_params_help: +Specify any extra parameters to pass when starting **`tailscaled`**. +For more details see the tailscaled documentation. +:end + +:docker_tailscale_extra_param_help: +Specify any extra parameters to pass when running **`tailscale up`**. +For more details see the Tailscale CLI documentation. +:end + +:docker_tailscale_statedir_help: +If state directory detection fails on startup, you can specify a persistent directory in the container to override automatic detection, i.e. `/container-path/.tailscale_state` +:end + +:docker_tailscale_troubleshooting_packages_help: +Enable this to install `ping`, `nslookup`, `curl`, and `speedtest-cli` into the container to help troubleshoot networking issues. Once the issues are resolved we recommend disabling this to reduce the size of the container. +:end + :docker_privileged_help: For containers that require the use of host-device access directly or need full exposure to host capabilities, this option will need to be selected. For more information, see this link: https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities diff --git a/emhttp/plugins/dynamix.apcupsd/UPSsettings.page b/emhttp/plugins/dynamix.apcupsd/UPSsettings.page index 025e0cdf1..bf4e63027 100644 --- a/emhttp/plugins/dynamix.apcupsd/UPSsettings.page +++ b/emhttp/plugins/dynamix.apcupsd/UPSsettings.page @@ -44,7 +44,7 @@ $(function() {   - _(Online Manual)_ + _(Online Manual)_
diff --git a/emhttp/plugins/dynamix.apcupsd/include/UPSstatus.php b/emhttp/plugins/dynamix.apcupsd/include/UPSstatus.php index a4a479922..18eb58313 100644 --- a/emhttp/plugins/dynamix.apcupsd/include/UPSstatus.php +++ b/emhttp/plugins/dynamix.apcupsd/include/UPSstatus.php @@ -1,6 +1,6 @@ 0 ? "$power W" : "$power W"; } - if ($power && isset($load)) $status[5] = ($load<90 ? "" : "").round($power*$load/100)." W (".$status[5].")"; + if ( ($power??false) && isset($load)) $status[5] = ($load<90 ? "" : "").round($power*$load/100)." W (".$status[5].")"; elseif (isset($load)) $status[5] = ($load<90 ? "" : "").$status[5].""; $status[6] = isset($output) ? ((!$volt || ($minv<$output && $output<$maxv) ? "" : "").$status[6].(isset($freq) ? " ~ $freq Hz" : "")."") : $status[6]; } diff --git a/emhttp/plugins/dynamix.docker.manager/DockerContainers.page b/emhttp/plugins/dynamix.docker.manager/DockerContainers.page index 32f6672e9..3f1f14d98 100644 --- a/emhttp/plugins/dynamix.docker.manager/DockerContainers.page +++ b/emhttp/plugins/dynamix.docker.manager/DockerContainers.page @@ -115,7 +115,23 @@ function loadlist(init) { $.get('/plugins/dynamix.docker.manager/include/DockerContainers.php',function(d) { clearTimeout(timers.docker); var data = d.split(/\0/); + $(".TS_tooltip").tooltipster("destroy"); $('#docker_list').html(data[0]); + $('.TS_tooltip').tooltipster({ + animation: 'fade', + delay: 200, + trigger: 'custom', + triggerOpen: {click:true,touchstart:true,mouseenter:true}, + triggerClose:{click:true,scroll:false,mouseleave:true}, + interactive: true, + viewportAware: true, + contentAsHTML: true, + functionBefore: function(instance,helper) { + var origin = $(helper.origin); + var TScontent = $(origin).attr("data-tstitle"); + instance.content(TScontent); + } + }); $('head').append(' - diff --git a/emhttp/plugins/dynamix.docker.manager/DockerSettings.page b/emhttp/plugins/dynamix.docker.manager/DockerSettings.page index 21d392048..227be890b 100644 --- a/emhttp/plugins/dynamix.docker.manager/DockerSettings.page +++ b/emhttp/plugins/dynamix.docker.manager/DockerSettings.page @@ -135,10 +135,8 @@ _(Enable Docker)_: _(Enable container table readmore-js)_: : :docker_readmore_help: @@ -195,8 +193,8 @@ _(Docker directory)_: diff --git a/emhttp/plugins/dynamix.vm.manager/VMUsageStats.page b/emhttp/plugins/dynamix.vm.manager/VMUsageStats.page index 9d82042ec..953ca1582 100644 --- a/emhttp/plugins/dynamix.vm.manager/VMUsageStats.page +++ b/emhttp/plugins/dynamix.vm.manager/VMUsageStats.page @@ -1,5 +1,5 @@ Menu="VMs:0" -Title="VM Usage Statisics" +Title="VM Usage Statistics" Nchan="vm_usage:stop" Cond="exec(\"grep -o '^USAGE=.Y' /boot/config/domain.cfg 2>/dev/null\") && is_file('/var/run/libvirt/libvirtd.pid')" --- diff --git a/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php b/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php index 846cbe874..04de17132 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php +++ b/emhttp/plugins/dynamix.vm.manager/include/VMMachines.php @@ -81,7 +81,8 @@ foreach ($vms as $vm) { if ($vmrcport > 0) { $wsport = $lv->domain_get_ws_port($res); $vmrcprotocol = $lv->domain_get_vmrc_protocol($res); - $vmrcurl = autov('/plugins/dynamix.vm.manager/'.$vmrcprotocol.'.html',true).'&autoconnect=true&host='._var($_SERVER,'HTTP_HOST'); + if ($vmrcprotocol == "vnc") $vmrcscale = "&resize=scale"; else $vmrcscale = ""; + $vmrcurl = autov('/plugins/dynamix.vm.manager/'.$vmrcprotocol.'.html',true).$vmrcscale.'&autoconnect=true&host='._var($_SERVER,'HTTP_HOST'); if ($vmrcprotocol == "spice") $vmrcurl .= '&vmname='. urlencode($vm) .'&port=/wsproxy/'.$vmrcport.'/'; else $vmrcurl .= '&port=&path=/wsproxy/'.$wsport.'/'; $graphics = strtoupper($vmrcprotocol).":".$vmrcport."\n"; $virtual = true ; @@ -112,7 +113,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')\"", htmlentities($vm, ENT_QUOTES),addslashes($uuid),addslashes($template),$state,addslashes($vmrcurl),strtoupper($vmrcprotocol),htmlentities($log,ENT_QUOTES),addslashes($fstype), $vmrcconsole,false,addslashes(str_replace('"',"'",$WebUI))); $kvm[] = "kvm.push({id:'$uuid',state:'$state'});"; switch ($state) { case 'running': diff --git a/emhttp/plugins/dynamix.vm.manager/include/VMajax.php b/emhttp/plugins/dynamix.vm.manager/include/VMajax.php index 7e9b18735..934cd9e20 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/VMajax.php +++ b/emhttp/plugins/dynamix.vm.manager/include/VMajax.php @@ -133,7 +133,8 @@ case 'domain-start-console': $vmrcurl = autov('/plugins/dynamix.vm.manager/'.$protocol.'.html',true).'&autoconnect=true&host='._var($_SERVER,'HTTP_HOST'); if ($protocol == "spice") $vmrcurl .= '&vmname='. urlencode($domName) .'&port=/wsproxy/'.$vmrcport.'/'; else $vmrcurl .= '&port=&path=/wsproxy/'.$wsport.'/'; } - $arrResponse['vmrcurl'] = $vmrcurl; + if ($protocol == "vnc") $vmrcscale = "&resize=scale"; else $vmrcscale = ""; + $arrResponse['vmrcurl'] = $vmrcurl.$vmrcscale; break; case 'domain-start-consoleRV': @@ -149,7 +150,9 @@ case 'domain-start-consoleRV': $vvarray = array() ; $vvarray[] = "[virt-viewer]\n"; $vvarray[] = "type=$protocol\n"; - $vvarray[] = "host="._var($_SERVER,'HTTP_HOST')."\n" ; + $vvarrayhost = _var($_SERVER,'HTTP_HOST'); + if (strpos($vvarrayhost,":")) $vvarrayhost = parse_url($vvarrayhost,PHP_URL_HOST); + $vvarray[] = "host=$vvarrayhost\n" ; $vvarray[] = "port=$port\n" ; $vvarray[] = "delete-this-file=1\n" ; if (!is_dir("/mnt/user/system/remoteviewer")) mkdir("/mnt/user/system/remoteviewer") ; @@ -182,7 +185,9 @@ case 'domain-consoleRV': $vvarray = array() ; $vvarray[] = "[virt-viewer]\n"; $vvarray[] = "type=$protocol\n"; - $vvarray[] = "host="._var($_SERVER,'HTTP_HOST')."\n" ; + $vvarrayhost = _var($_SERVER,'HTTP_HOST'); + if (strpos($vvarrayhost,":")) $vvarrayhost = parse_url($vvarrayhost,PHP_URL_HOST); + $vvarray[] = "host=$vvarrayhost\n" ; $vvarray[] = "port=$port\n" ; $vvarray[] = "delete-this-file=1\n" ; if (!is_dir("/mnt/user/system/remoteviewer")) mkdir("/mnt/user/system/remoteviewer") ; diff --git a/emhttp/plugins/dynamix.vm.manager/include/libvirt.php b/emhttp/plugins/dynamix.vm.manager/include/libvirt.php index 33e224e98..042a17ae0 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/libvirt.php +++ b/emhttp/plugins/dynamix.vm.manager/include/libvirt.php @@ -910,9 +910,9 @@ } if ($gpu['multi'] == "on"){ - $newgpu_bus= 0x10; + $newgpu_bus= 0x07; if (!isset($multibus[$newgpu_bus])) { - $multibus[$newgpu_bus] = 0x10; + $multibus[$newgpu_bus] = 0x07; } else { #Get next bus $newgpu_bus = end($multibus) + 0x01; @@ -2004,8 +2004,17 @@ if (is_file($cfg)) unlink($cfg); if (is_file($xml)) unlink($xml); if (is_dir($dir) && $this->is_dir_empty($dir)) { - $error = my_rmdir($dir); - qemu_log("$domain","delete empty $dir $error"); + $result= my_rmdir($dir); + if ($result['type'] == "zfs") { + qemu_log("$domain","delete empty zfs $dir {$result['rtncode']}"); + if (isset($result['dataset'])) qemu_log("$domain","dataset {$result['dataset']} "); + if (isset($result['cmd'])) qemu_log("$domain","Command {$result['cmd']} "); + if (isset($result['output'])) { + $outputlogs = implode(" ",$result['output']); + qemu_log("$domain","Output $outputlogs end"); + } + } + else qemu_log("$domain","delete empty $dir {$result['rtncode']}"); } } diff --git a/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php b/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php index 59c77cbd2..e2e9526ba 100644 --- a/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php +++ b/emhttp/plugins/dynamix.vm.manager/include/libvirt_helpers.php @@ -712,7 +712,7 @@ private static $encoding = 'UTF-8'; $domain_cfgfile = "/boot/config/domain.cfg"; $domain_cfg = parse_ini_file($domain_cfgfile); - if ($domain_cfg['DEBUG'] != "yes") { + if ( ($domain_cfg['DEBUG'] ?? false) != "yes") { error_reporting(0); } @@ -1115,6 +1115,7 @@ private static $encoding = 'UTF-8'; $arrValidVNCModels = [ 'cirrus' => 'Cirrus', 'qxl' => 'QXL (best)', + 'virtio' => 'Virtio(2d)', 'vmvga' => 'vmvga' ]; @@ -1749,6 +1750,9 @@ private static $encoding = 'UTF-8'; $pi = pathinfo($config["disk"][$diskid]["new"]) ; $isdir = is_dir($pi['dirname']) ; if (is_file($config["disk"][$diskid]["new"])) $file_exists = true ; + write("addLog\0".htmlspecialchars("Checking from file:".$file_clone[$diskid]["source"])); + write("addLog\0".htmlspecialchars("Checking to file:".$config["disk"][$diskid]["new"])); + write("addLog\0".htmlspecialchars("File exists value:". ($file_exists ? "True" : "False"))); $file_clone[$diskid]["target"] = $config["disk"][$diskid]["new"] ; } diff --git a/emhttp/plugins/dynamix.vm.manager/javascript/vmmanager.js b/emhttp/plugins/dynamix.vm.manager/javascript/vmmanager.js index b40ba4162..e7899cb32 100644 --- a/emhttp/plugins/dynamix.vm.manager/javascript/vmmanager.js +++ b/emhttp/plugins/dynamix.vm.manager/javascript/vmmanager.js @@ -239,7 +239,7 @@ function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, f }}); } } - if (usage) context.attach('#vmusage-'+uuid, opts); else context.attach('#vm-'+uuid, opts); + if (usage) { context.destroy('#vmusage-'+uuid); context.attach('#vmusage-'+uuid, opts); } else { context.destroy('#vm-'+uuid); context.attach('#vm-'+uuid, opts); } } function addVMSnapContext(name, uuid, template, state, snapshotname, method){ var opts = []; @@ -273,6 +273,7 @@ function addVMSnapContext(name, uuid, template, state, snapshotname, method){ $('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin'); selectsnapshot(uuid, name, snapshotname, "remove",true) ; }}); + context.destroy('#vmsnap-'+uuid); context.attach('#vmsnap-'+uuid, opts); } function startAll() { diff --git a/emhttp/plugins/dynamix.vm.manager/nchan/vm_usage b/emhttp/plugins/dynamix.vm.manager/nchan/vm_usage index ce62b8a93..194e3f4e4 100755 --- a/emhttp/plugins/dynamix.vm.manager/nchan/vm_usage +++ b/emhttp/plugins/dynamix.vm.manager/nchan/vm_usage @@ -77,11 +77,11 @@ while (true) { $echodata .= "$vm" ; $echodata .= "".$vmdata['cpuguest']."%
"; $echodata .= "".$vmdata['cpuhost']."%
"; - $echodata .= my_scale($vmdata['mem']*1024,$unit)."$unit / ".my_scale($vmdata['curmem']*1024,$unit)."$unit"; + $echodata .= my_scale($vmdata['mem']*1024,$unit,null,null,1024)."$unit / ".my_scale($vmdata['curmem']*1024,$unit,null,null,1024)."$unit"; if ($vmdata['curmem'] === $vmdata['maxmem']) $echodata .= " "; - else $echodata .= " / " .my_scale($vmdata['maxmem']*1024,$unit)."$unit "; - $echodata .= _("Read").": ".my_scale($vmdata['rdrate'],$unit)."$unit/s
"._("Write").": ".my_scale($vmdata['wrrate'],$unit)."$unit/s"; - $echodata .= _("RX").": ".my_scale($vmdata['rxrate'],$unit)."$unit/s
"._("TX").": ".my_scale($vmdata['txrate'],$unit)."$unit/s"; + else $echodata .= " / " .my_scale($vmdata['maxmem']*1024,$unit,null,null,1024)."$unit "; + $echodata .= _("Read").": ".my_scale($vmdata['rdrate']/$timer,$unit,null,null,1024)."$unit/s
"._("Write").": ".my_scale($vmdata['wrrate']/$timer,$unit,null,null,1024)."$unit/s"; + $echodata .= _("RX").": ".my_scale($vmdata['rxrate']/$timer,$unit,null,null,1024)."$unit/s
"._("TX").": ".my_scale($vmdata['txrate']/$timer,$unit,null,null,1024)."$unit/s"; } $echo = $echodata ; } 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 81a6cba8e..67b63720c 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/error-handler.js +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/error-handler.js @@ -6,61 +6,74 @@ * See README.md for usage and integration instructions. */ -// NB: this should *not* be included as a module until we have -// native support in the browsers, so that our error handler -// can catch script-loading errors. +// Fallback for all uncought errors +function handleError(event, err) { + try { + const msg = document.getElementById('noVNC_fallback_errormsg'); -// No ES6 can be used in this file since it's used for the translation -/* eslint-disable prefer-arrow-callback */ - -(function _scope() { - "use strict"; - - // Fallback for all uncought errors - function handleError(event, err) { - try { - const msg = document.getElementById('noVNC_fallback_errormsg'); - - // Only show the initial error - if (msg.hasChildNodes()) { - return false; - } - - let div = document.createElement("div"); - div.classList.add('noVNC_message'); - div.appendChild(document.createTextNode(event.message)); - msg.appendChild(div); - - if (event.filename) { - div = document.createElement("div"); - div.className = 'noVNC_location'; - let text = event.filename; - if (event.lineno !== undefined) { - text += ":" + event.lineno; - if (event.colno !== undefined) { - text += ":" + event.colno; - } - } - div.appendChild(document.createTextNode(text)); - msg.appendChild(div); - } - - if (err && err.stack) { - div = document.createElement("div"); - div.className = 'noVNC_stack'; - div.appendChild(document.createTextNode(err.stack)); - msg.appendChild(div); - } - - document.getElementById('noVNC_fallback_error') - .classList.add("noVNC_open"); - } catch (exc) { - document.write("noVNC encountered an error."); + // Work around Firefox bug: + // https://bugzilla.mozilla.org/show_bug.cgi?id=1685038 + if (event.message === "ResizeObserver loop completed with undelivered notifications.") { + return false; } - // Don't return true since this would prevent the error - // from being printed to the browser console. - return false; + + // Only show the initial error + if (msg.hasChildNodes()) { + return false; + } + + let div = document.createElement("div"); + div.classList.add('noVNC_message'); + div.appendChild(document.createTextNode(event.message)); + msg.appendChild(div); + + if (event.filename) { + div = document.createElement("div"); + div.className = 'noVNC_location'; + let text = event.filename; + if (event.lineno !== undefined) { + text += ":" + event.lineno; + if (event.colno !== undefined) { + text += ":" + event.colno; + } + } + div.appendChild(document.createTextNode(text)); + msg.appendChild(div); + } + + if (err && err.stack) { + div = document.createElement("div"); + div.className = 'noVNC_stack'; + div.appendChild(document.createTextNode(err.stack)); + msg.appendChild(div); + } + + document.getElementById('noVNC_fallback_error') + .classList.add("noVNC_open"); + + } catch (exc) { + document.write("noVNC encountered an error."); } - window.addEventListener('error', function onerror(evt) { handleError(evt, evt.error); }); - window.addEventListener('unhandledrejection', function onreject(evt) { handleError(evt.reason, evt.reason); }); -})(); + + // Try to disable keyboard interaction, best effort + try { + // Remove focus from the currently focused element in order to + // prevent keyboard interaction from continuing + if (document.activeElement) { document.activeElement.blur(); } + + // Don't let any element be focusable when showing the error + let keyboardFocusable = 'a[href], button, input, textarea, select, details, [tabindex]'; + document.querySelectorAll(keyboardFocusable).forEach((elem) => { + elem.setAttribute("tabindex", "-1"); + }); + } catch (exc) { + // Do nothing + } + + // Don't return true since this would prevent the error + // from being printed to the browser console. + return false; +} + +window.addEventListener('error', evt => handleError(evt, evt.error)); +window.addEventListener('unhandledrejection', evt => handleError(evt.reason, evt.reason)); diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/Makefile b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/Makefile index be564b43b..03eaed071 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/Makefile +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/Makefile @@ -1,42 +1,42 @@ -ICONS := \ - novnc-16x16.png \ - novnc-24x24.png \ - novnc-32x32.png \ - novnc-48x48.png \ - novnc-64x64.png +BROWSER_SIZES := 16 24 32 48 64 +#ANDROID_SIZES := 72 96 144 192 +# FIXME: The ICO is limited to 8 icons due to a Chrome bug: +# https://bugs.chromium.org/p/chromium/issues/detail?id=1381393 +ANDROID_SIZES := 96 144 192 +WEB_ICON_SIZES := $(BROWSER_SIZES) $(ANDROID_SIZES) -ANDROID_LAUNCHER := \ - novnc-48x48.png \ - novnc-72x72.png \ - novnc-96x96.png \ - novnc-144x144.png \ - novnc-192x192.png +#IOS_1X_SIZES := 20 29 40 76 # No such devices exist anymore +IOS_2X_SIZES := 40 58 80 120 152 167 +IOS_3X_SIZES := 60 87 120 180 +ALL_IOS_SIZES := $(IOS_1X_SIZES) $(IOS_2X_SIZES) $(IOS_3X_SIZES) -IPHONE_LAUNCHER := \ - novnc-60x60.png \ - novnc-120x120.png - -IPAD_LAUNCHER := \ - novnc-76x76.png \ - novnc-152x152.png - -ALL_ICONS := $(ICONS) $(ANDROID_LAUNCHER) $(IPHONE_LAUNCHER) $(IPAD_LAUNCHER) +ALL_ICONS := \ + $(ALL_IOS_SIZES:%=novnc-ios-%.png) \ + novnc.ico all: $(ALL_ICONS) -novnc-16x16.png: novnc-icon-sm.svg - convert -density 90 \ - -background transparent "$<" "$@" -novnc-24x24.png: novnc-icon-sm.svg - convert -density 135 \ - -background transparent "$<" "$@" -novnc-32x32.png: novnc-icon-sm.svg - convert -density 180 \ - -background transparent "$<" "$@" +# Our testing shows that the ICO file need to be sorted in largest to +# smallest to get the apporpriate behviour +WEB_ICON_SIZES_REVERSE := $(shell echo $(WEB_ICON_SIZES) | tr ' ' '\n' | sort -nr | tr '\n' ' ') +WEB_BASE_ICONS := $(WEB_ICON_SIZES_REVERSE:%=novnc-%.png) +.INTERMEDIATE: $(WEB_BASE_ICONS) +novnc.ico: $(WEB_BASE_ICONS) + convert $(WEB_BASE_ICONS) "$@" + +# General conversion novnc-%.png: novnc-icon.svg - convert -density $$[`echo $* | cut -d x -f 1` * 90 / 48] \ - -background transparent "$<" "$@" + convert -depth 8 -background transparent \ + -size $*x$* "$(lastword $^)" "$@" + +# iOS icons use their own SVG +novnc-ios-%.png: novnc-ios-icon.svg + convert -depth 8 -background transparent \ + -size $*x$* "$(lastword $^)" "$@" + +# The smallest sizes are generated using a different SVG +novnc-16.png novnc-24.png novnc-32.png: novnc-icon-sm.svg clean: rm -f *.png diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-120.png b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-120.png new file mode 100644 index 000000000..8da7bab3d Binary files /dev/null and b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-120.png differ diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-152.png b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-152.png new file mode 100644 index 000000000..60b2bcef5 Binary files /dev/null and b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-152.png differ diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-167.png b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-167.png new file mode 100644 index 000000000..98fade2e2 Binary files /dev/null and b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-167.png differ diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-180.png b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-180.png new file mode 100644 index 000000000..5d24df70a Binary files /dev/null and b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-180.png differ diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-40.png b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-40.png new file mode 100644 index 000000000..cf14894da Binary files /dev/null and b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-40.png differ diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-58.png b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-58.png new file mode 100644 index 000000000..f6dfbebd2 Binary files /dev/null and b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-58.png differ diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-60.png b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-60.png new file mode 100644 index 000000000..8cda29530 Binary files /dev/null and b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-60.png differ diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-80.png b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-80.png new file mode 100644 index 000000000..6c417c47e Binary files /dev/null and b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-80.png differ diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-87.png b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-87.png new file mode 100644 index 000000000..4377d874b Binary files /dev/null and b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-87.png differ diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-icon.svg b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-icon.svg new file mode 100644 index 000000000..009452ac6 --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc-ios-icon.svg @@ -0,0 +1,183 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc.ico b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc.ico new file mode 100644 index 000000000..c3bc58e38 Binary files /dev/null and b/emhttp/plugins/dynamix.vm.manager/novnc/app/images/icons/novnc.ico differ 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 f801251c5..4df3e03c4 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/el.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/el.json @@ -1,4 +1,5 @@ { + "HTTPS is required for full functionality": "Το HTTPS είναι απαιτούμενο για πλήρη λειτουργικότητα", "Connecting...": "Συνδέεται...", "Disconnecting...": "Aποσυνδέεται...", "Reconnecting...": "Επανασυνδέεται...", @@ -7,19 +8,15 @@ "Connected (encrypted) to ": "Συνδέθηκε (κρυπτογραφημένα) με το ", "Connected (unencrypted) to ": "Συνδέθηκε (μη κρυπτογραφημένα) με το ", "Something went wrong, connection is closed": "Κάτι πήγε στραβά, η σύνδεση διακόπηκε", + "Failed to connect to server": "Αποτυχία στη σύνδεση με το διακομιστή", "Disconnected": "Αποσυνδέθηκε", "New connection has been rejected with reason: ": "Η νέα σύνδεση απορρίφθηκε διότι: ", "New connection has been rejected": "Η νέα σύνδεση απορρίφθηκε ", - "Password is required": "Απαιτείται ο κωδικός πρόσβασης", + "Credentials are required": "Απαιτούνται διαπιστευτήρια", "noVNC encountered an error:": "το noVNC αντιμετώπισε ένα σφάλμα:", "Hide/Show the control bar": "Απόκρυψη/Εμφάνιση γραμμής ελέγχου", + "Drag": "Σύρσιμο", "Move/Drag Viewport": "Μετακίνηση/Σύρσιμο Θεατού πεδίου", - "viewport drag": "σύρσιμο θεατού πεδίου", - "Active Mouse Button": "Ενεργό Πλήκτρο Ποντικιού", - "No mousebutton": "Χωρίς Πλήκτρο Ποντικιού", - "Left mousebutton": "Αριστερό Πλήκτρο Ποντικιού", - "Middle mousebutton": "Μεσαίο Πλήκτρο Ποντικιού", - "Right mousebutton": "Δεξί Πλήκτρο Ποντικιού", "Keyboard": "Πληκτρολόγιο", "Show Keyboard": "Εμφάνιση Πληκτρολογίου", "Extra keys": "Επιπλέον πλήκτρα", @@ -28,6 +25,8 @@ "Toggle Ctrl": "Εναλλαγή Ctrl", "Alt": "Alt", "Toggle Alt": "Εναλλαγή Alt", + "Toggle Windows": "Εναλλαγή Παράθυρων", + "Windows": "Παράθυρα", "Send Tab": "Αποστολή Tab", "Tab": "Tab", "Esc": "Esc", @@ -41,8 +40,7 @@ "Reboot": "Επανεκκίνηση", "Reset": "Επαναφορά", "Clipboard": "Πρόχειρο", - "Clear": "Καθάρισμα", - "Fullscreen": "Πλήρης Οθόνη", + "Edit clipboard content in the textarea below.": "Επεξεργαστείτε το περιεχόμενο του πρόχειρου στην περιοχή κειμένου παρακάτω.", "Settings": "Ρυθμίσεις", "Shared Mode": "Κοινόχρηστη Λειτουργία", "View Only": "Μόνο Θέαση", @@ -52,6 +50,8 @@ "Local Scaling": "Τοπική Κλιμάκωση", "Remote Resizing": "Απομακρυσμένη Αλλαγή μεγέθους", "Advanced": "Για προχωρημένους", + "Quality:": "Ποιότητα:", + "Compression level:": "Επίπεδο συμπίεσης:", "Repeater ID:": "Repeater ID:", "WebSocket": "WebSocket", "Encrypt": "Κρυπτογράφηση", @@ -60,10 +60,20 @@ "Path:": "Διαδρομή:", "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:": "Κωδικός Πρόσβασης:", - "Cancel": "Ακύρωση", - "Canvas not supported.": "Δεν υποστηρίζεται το στοιχείο Canvas" + "Send Credentials": "Αποστολή Διαπιστευτηρίων", + "Cancel": "Ακύρωση" } \ 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 23f23f497..b9e663a3d 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/es.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/es.json @@ -4,9 +4,9 @@ "Connected (unencrypted) to ": "Conectado (sin encriptación) a", "Disconnecting...": "Desconectando...", "Disconnected": "Desconectado", - "Must set host": "Debes configurar el host", + "Must set host": "Se debe configurar el host", "Reconnecting...": "Reconectando...", - "Password is required": "Contraseña es obligatoria", + "Password is required": "La contraseña es obligatoria", "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", @@ -41,6 +41,7 @@ "Clear": "Vaciar", "Fullscreen": "Pantalla Completa", "Settings": "Configuraciones", + "Encrypt": "Encriptar", "Shared Mode": "Modo Compartido", "View Only": "Solo visualización", "Clip to Window": "Recortar al tamaño de la ventana", @@ -51,18 +52,17 @@ "Remote Resizing": "Cambio de tamaño remoto", "Advanced": "Avanzado", "Local Cursor": "Cursor Local", - "Repeater ID:": "ID del Repetidor", + "Repeater ID:": "ID del Repetidor:", "WebSocket": "WebSocket", - "Encrypt": "", - "Host:": "Host", - "Port:": "Puesto", - "Path:": "Ruta", + "Host:": "Host:", + "Port:": "Puerto:", + "Path:": "Ruta:", "Automatic Reconnect": "Reconexión automática", - "Reconnect Delay (ms):": "Retraso en la reconexión (ms)", - "Logging:": "Logging", + "Reconnect Delay (ms):": "Retraso en la reconexión (ms):", + "Logging:": "Registrando:", "Disconnect": "Desconectar", "Connect": "Conectar", - "Password:": "Contraseña", + "Password:": "Contraseña:", "Cancel": "Cancelar", - "Canvas not supported.": "Canvas no está soportado" + "Canvas not supported.": "Canvas no soportado." } \ No newline at end of file diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/fr.json b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/fr.json new file mode 100644 index 000000000..c0eeec7d3 --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/fr.json @@ -0,0 +1,72 @@ +{ + "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", + "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", + "Failed to connect to server": "Échec de connexion au serveur", + "Disconnected": "Déconnecté", + "New connection has been rejected with reason: ": "Une nouvelle connexion a été rejetée avec motif : ", + "New connection has been rejected": "Une nouvelle connexion a été rejetée", + "Credentials are required": "Les identifiants sont requis", + "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", + "Keyboard": "Clavier", + "Show Keyboard": "Afficher le clavier", + "Extra keys": "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", + "Esc": "Esc", + "Send Escape": "Envoyer Escape", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Envoyer Ctrl-Alt-Del", + "Shutdown/Reboot": "Arrêter/Redémarrer", + "Shutdown/Reboot...": "Arrêter/Redémarrer...", + "Power": "Alimentation", + "Shutdown": "Arrêter", + "Reboot": "Redémarrer", + "Reset": "Réinitialiser", + "Clipboard": "Presse-papiers", + "Clear": "Effacer", + "Fullscreen": "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 :", + "None": "Aucun", + "Local Scaling": "Mise à l'échelle locale", + "Remote Resizing": "Redimensionnement à distance", + "Advanced": "Avancé", + "Quality:": "Qualité :", + "Compression level:": "Niveau de compression :", + "Repeater ID:": "ID Répéteur :", + "WebSocket": "WebSocket", + "Encrypt": "Chiffrer", + "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", + "Logging:": "Se connecter :", + "Version:": "Version :", + "Disconnect": "Déconnecter", + "Connect": "Connecter", + "Username:": "Nom d'utilisateur :", + "Password:": "Mot de passe :", + "Send Credentials": "Envoyer les identifiants", + "Cancel": "Annuler" +} \ 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 new file mode 100644 index 000000000..18a7f7447 --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/it.json @@ -0,0 +1,68 @@ +{ + "Connecting...": "Connessione in corso...", + "Disconnecting...": "Disconnessione...", + "Reconnecting...": "Riconnessione...", + "Internal error": "Errore interno", + "Must set host": "Devi impostare l'host", + "Connected (encrypted) to ": "Connesso (crittografato) a ", + "Connected (unencrypted) to ": "Connesso (non crittografato) a", + "Something went wrong, connection is closed": "Qualcosa è andato storto, la connessione è stata chiusa", + "Failed to connect to server": "Impossibile connettersi al server", + "Disconnected": "Disconnesso", + "New connection has been rejected with reason: ": "La nuova connessione è stata rifiutata con motivo: ", + "New connection has been rejected": "La nuova connessione è stata rifiutata", + "Credentials are required": "Le credenziali sono obbligatorie", + "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", + "Extra keys": "Tasti Aggiuntivi", + "Show Extra Keys": "Mostra Tasti Aggiuntivi", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Tieni premuto Ctrl", + "Alt": "Alt", + "Toggle Alt": "Tieni premuto Alt", + "Toggle Windows": "Tieni premuto Windows", + "Windows": "Windows", + "Send Tab": "Invia Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Invia Esc", + "Ctrl+Alt+Del": "Ctrl+Alt+Canc", + "Send Ctrl-Alt-Del": "Invia Ctrl-Alt-Canc", + "Shutdown/Reboot": "Spegnimento/Riavvio", + "Shutdown/Reboot...": "Spegnimento/Riavvio...", + "Power": "Alimentazione", + "Shutdown": "Spegnimento", + "Reboot": "Riavvio", + "Reset": "Reset", + "Clipboard": "Clipboard", + "Clear": "Pulisci", + "Fullscreen": "Schermo intero", + "Settings": "Impostazioni", + "Shared Mode": "Modalità condivisa", + "View Only": "Sola Visualizzazione", + "Scaling Mode:": "Modalità di ridimensionamento:", + "None": "Nessuna", + "Local Scaling": "Ridimensionamento Locale", + "Remote Resizing": "Ridimensionamento Remoto", + "Advanced": "Avanzate", + "Quality:": "Qualità:", + "Compression level:": "Livello Compressione:", + "Repeater ID:": "ID Ripetitore:", + "WebSocket": "WebSocket", + "Encrypt": "Crittografa", + "Host:": "Host:", + "Port:": "Porta:", + "Path:": "Percorso:", + "Automatic Reconnect": "Riconnessione Automatica", + "Reconnect Delay (ms):": "Ritardo Riconnessione (ms):", + "Show Dot when No Cursor": "Mostra Punto quando Nessun Cursore", + "Version:": "Versione:", + "Disconnect": "Disconnetti", + "Connect": "Connetti", + "Username:": "Utente:", + "Password:": "Password:", + "Send Credentials": "Invia Credenziale", + "Cancel": "Annulla" +} \ No newline at end of file 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 e5fe3401f..70fd7a5d1 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ja.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ja.json @@ -1,4 +1,5 @@ { + "HTTPS is required for full functionality": "すべての機能を使用するにはHTTPS接続が必要です", "Connecting...": "接続しています...", "Disconnecting...": "切断しています...", "Reconnecting...": "再接続しています...", @@ -6,30 +7,25 @@ "Must set host": "ホストを設定する必要があります", "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: ": "新規接続は次の理由で拒否されました: ", "New connection has been rejected": "新規接続は拒否されました", - "Password is required": "パスワードが必要です", + "Credentials are required": "資格情報が必要です", "noVNC encountered an error:": "noVNC でエラーが発生しました:", "Hide/Show the control bar": "コントロールバーを隠す/表示する", + "Drag": "ドラッグ", "Move/Drag Viewport": "ビューポートを移動/ドラッグ", - "viewport drag": "ビューポートをドラッグ", - "Active Mouse Button": "アクティブなマウスボタン", - "No mousebutton": "マウスボタンなし", - "Left mousebutton": "左マウスボタン", - "Middle mousebutton": "中マウスボタン", - "Right mousebutton": "右マウスボタン", "Keyboard": "キーボード", "Show Keyboard": "キーボードを表示", "Extra keys": "追加キー", "Show Extra Keys": "追加キーを表示", "Ctrl": "Ctrl", - "Toggle Ctrl": "Ctrl キーを切り替え", + "Toggle Ctrl": "Ctrl キーをトグル", "Alt": "Alt", - "Toggle Alt": "Alt キーを切り替え", - "Toggle Windows": "Windows キーを切り替え", + "Toggle Alt": "Alt キーをトグル", + "Toggle Windows": "Windows キーをトグル", "Windows": "Windows", "Send Tab": "Tab キーを送信", "Tab": "Tab", @@ -44,17 +40,19 @@ "Reboot": "再起動", "Reset": "リセット", "Clipboard": "クリップボード", - "Clear": "クリア", - "Fullscreen": "全画面表示", + "Edit clipboard content in the textarea below.": "以下の入力欄からクリップボードの内容を編集できます。", + "Full Screen": "全画面表示", "Settings": "設定", "Shared Mode": "共有モード", - "View Only": "表示のみ", + "View Only": "表示専用", "Clip to Window": "ウィンドウにクリップ", "Scaling Mode:": "スケーリングモード:", "None": "なし", "Local Scaling": "ローカルスケーリング", "Remote Resizing": "リモートでリサイズ", "Advanced": "高度", + "Quality:": "品質:", + "Compression level:": "圧縮レベル:", "Repeater ID:": "リピーター ID:", "WebSocket": "WebSocket", "Encrypt": "暗号化", @@ -63,11 +61,20 @@ "Path:": "パス:", "Automatic Reconnect": "自動再接続", "Reconnect Delay (ms):": "再接続する遅延 (ミリ秒):", - "Show Dot when No Cursor": "カーソルがないときにドットを表示", + "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 Password": "パスワードを送信", + "Send Credentials": "資格情報を送信", "Cancel": "キャンセル" } \ 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 new file mode 100644 index 000000000..aa130f764 --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/pt_BR.json @@ -0,0 +1,72 @@ +{ + "Connecting...": "Conectando...", + "Disconnecting...": "Desconectando...", + "Reconnecting...": "Reconectando...", + "Internal error": "Erro interno", + "Must set host": "É necessário definir o host", + "Connected (encrypted) to ": "Conectado (com criptografia) a ", + "Connected (unencrypted) to ": "Conectado (sem criptografia) a ", + "Something went wrong, connection is closed": "Algo deu errado. A conexão foi encerrada.", + "Failed to connect to server": "Falha ao conectar-se ao servidor", + "Disconnected": "Desconectado", + "New connection has been rejected with reason: ": "A nova conexão foi rejeitada pelo motivo: ", + "New connection has been rejected": "A nova conexão foi rejeitada", + "Credentials are required": "Credenciais são obrigatórias", + "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", + "Keyboard": "Teclado", + "Show Keyboard": "Mostrar teclado", + "Extra keys": "Teclas adicionais", + "Show Extra Keys": "Mostar teclas adicionais", + "Ctrl": "Ctrl", + "Toggle Ctrl": "Pressionar/soltar Ctrl", + "Alt": "Alt", + "Toggle Alt": "Pressionar/soltar Alt", + "Toggle Windows": "Pressionar/soltar Windows", + "Windows": "Windows", + "Send Tab": "Enviar Tab", + "Tab": "Tab", + "Esc": "Esc", + "Send Escape": "Enviar Esc", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "Enviar Ctrl-Alt-Del", + "Shutdown/Reboot": "Desligar/reiniciar", + "Shutdown/Reboot...": "Desligar/reiniciar...", + "Power": "Ligar", + "Shutdown": "Desligar", + "Reboot": "Reiniciar", + "Reset": "Reiniciar (forçado)", + "Clipboard": "Área de transferência", + "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:", + "None": "Nenhum", + "Local Scaling": "Local", + "Remote Resizing": "Remoto", + "Advanced": "Avançado", + "Quality:": "Qualidade:", + "Compression level:": "Nível de compressão:", + "Repeater ID:": "ID do repetidor:", + "WebSocket": "WebSocket", + "Encrypt": "Criptografar", + "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", + "Logging:": "Registros:", + "Version:": "Versão:", + "Disconnect": "Desconectar", + "Connect": "Conectar", + "Username:": "Nome de usuário:", + "Password:": "Senha:", + "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 52e57f37f..cab97396e 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ru.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/ru.json @@ -9,26 +9,21 @@ "Something went wrong, connection is closed": "Что-то пошло не так, подключение разорвано", "Failed to connect to server": "Ошибка подключения к серверу", "Disconnected": "Отключено", - "New connection has been rejected with reason: ": "Подключиться не удалось: ", - "New connection has been rejected": "Подключиться не удалось", - "Password is required": "Требуется пароль", + "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": "Скрыть/Показать контрольную панель", + "Drag": "Переместить", "Move/Drag Viewport": "Переместить окно", - "viewport drag": "Переместить окно", - "Active Mouse Button": "Активировать кнопки мыши", - "No mousebutton": "Отключить кнопки мыши", - "Left mousebutton": "Левая кнопка мыши", - "Middle mousebutton": "Средняя кнопка мыши", - "Right mousebutton": "Правая кнопка мыши", "Keyboard": "Клавиатура", "Show Keyboard": "Показать клавиатуру", - "Extra keys": "Доп. кнопки", - "Show Extra Keys": "Показать дополнительные кнопки", + "Extra keys": "Дополнительные Кнопки", + "Show Extra Keys": "Показать Дополнительные Кнопки", "Ctrl": "Ctrl", - "Toggle Ctrl": "Передать нажатие Ctrl", + "Toggle Ctrl": "Переключение нажатия Ctrl", "Alt": "Alt", - "Toggle Alt": "Передать нажатие Alt", + "Toggle Alt": "Переключение нажатия Alt", "Toggle Windows": "Переключение вкладок", "Windows": "Вкладка", "Send Tab": "Передать нажатие Tab", @@ -48,13 +43,15 @@ "Fullscreen": "Во весь экран", "Settings": "Настройки", "Shared Mode": "Общий режим", - "View Only": "Просмотр", + "View Only": "Только Просмотр", "Clip to Window": "В окно", "Scaling Mode:": "Масштаб:", "None": "Нет", "Local Scaling": "Локльный масштаб", - "Remote Resizing": "Удаленный масштаб", + "Remote Resizing": "Удаленная перенастройка размера", "Advanced": "Дополнительно", + "Quality:": "Качество", + "Compression level:": "Уровень Сжатия", "Repeater ID:": "Идентификатор ID:", "WebSocket": "WebSocket", "Encrypt": "Шифрование", @@ -65,9 +62,11 @@ "Reconnect Delay (ms):": "Задержка переподключения (мс):", "Show Dot when No Cursor": "Показать точку вместо курсора", "Logging:": "Лог:", + "Version:": "Версия", "Disconnect": "Отключение", "Connect": "Подключение", + "Username:": "Имя Пользователя", "Password:": "Пароль:", - "Send Password": "Пароль: ", + "Send Credentials": "Передача Учетных Данных", "Cancel": "Выход" } \ No newline at end of file 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 e46df45b5..80a400bfa 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/sv.json +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/locale/sv.json @@ -1,9 +1,11 @@ { + "Running without HTTPS is not recommended, crashes or other issues are likely.": "Det är ej rekommenderat att köra utan HTTPS, krascher och andra problem är troliga.", "Connecting...": "Ansluter...", "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 ", "Something went wrong, connection is closed": "Något gick fel, anslutningen avslutades", @@ -39,8 +41,8 @@ "Reboot": "Boota om", "Reset": "Återställ", "Clipboard": "Urklipp", - "Clear": "Rensa", - "Fullscreen": "Fullskärm", + "Edit clipboard content in the textarea below.": "Redigera urklippets innehåll i fältet nedan.", + "Full Screen": "Fullskärm", "Settings": "Inställningar", "Shared Mode": "Delat Läge", "View Only": "Endast Visning", @@ -65,6 +67,13 @@ "Version:": "Version:", "Disconnect": "Koppla från", "Connect": "Anslut", + "Server identity": "Server-identitet", + "The server has provided the following identifying information:": "Servern har gett följande identifierande information:", + "Fingerprint:": "Fingeravtryck:", + "Please verify that the information is correct and press \"Approve\". Otherwise press \"Reject\".": "Kontrollera att informationen är korrekt och tryck sedan \"Godkänn\". Tryck annars \"Neka\".", + "Approve": "Godkänn", + "Reject": "Neka", + "Credentials": "Användaruppgifter", "Username:": "Användarnamn:", "Password:": "Lösenord:", "Send Credentials": "Skicka Användaruppgifter", 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 f0aea9af3..3679eaddd 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,69 +1,69 @@ { "Connecting...": "连接中...", + "Connected (encrypted) to ": "已连接(已加密)到", + "Connected (unencrypted) to ": "已连接(未加密)到", "Disconnecting...": "正在断开连接...", - "Reconnecting...": "重新连接中...", - "Internal error": "内部错误", - "Must set host": "请提供主机名", - "Connected (encrypted) to ": "已连接到(加密)", - "Connected (unencrypted) to ": "已连接到(未加密)", - "Something went wrong, connection is closed": "发生错误,连接已关闭", - "Failed to connect to server": "无法连接到服务器", "Disconnected": "已断开连接", - "New connection has been rejected with reason: ": "连接被拒绝,原因:", - "New connection has been rejected": "连接被拒绝", + "Must set host": "必须设置主机", + "Reconnecting...": "重新连接中...", "Password is required": "请提供密码", + "Disconnect timeout": "超时断开", "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": "鼠标右鍵", + "Move/Drag Viewport": "移动/拖动窗口", + "viewport drag": "窗口拖动", + "Active Mouse Button": "启动鼠标按键", + "No mousebutton": "禁用鼠标按键", + "Left mousebutton": "鼠标左键", + "Middle mousebutton": "鼠标中键", + "Right mousebutton": "鼠标右键", "Keyboard": "键盘", "Show Keyboard": "显示键盘", "Extra keys": "额外按键", "Show Extra Keys": "显示额外按键", "Ctrl": "Ctrl", "Toggle Ctrl": "切换 Ctrl", + "Edit clipboard content in the textarea below.": "在下面的文本区域中编辑剪贴板内容。", "Alt": "Alt", "Toggle Alt": "切换 Alt", "Send Tab": "发送 Tab 键", "Tab": "Tab", "Esc": "Esc", "Send Escape": "发送 Escape 键", - "Ctrl+Alt+Del": "Ctrl-Alt-Del", - "Send Ctrl-Alt-Del": "发送 Ctrl-Alt-Del 键", - "Shutdown/Reboot": "关机/重新启动", - "Shutdown/Reboot...": "关机/重新启动...", + "Ctrl+Alt+Del": "Ctrl+Alt+Del", + "Send Ctrl-Alt-Del": "发送 Ctrl+Alt+Del 键", + "Shutdown/Reboot": "关机/重启", + "Shutdown/Reboot...": "关机/重启...", "Power": "电源", "Shutdown": "关机", - "Reboot": "重新启动", + "Reboot": "重启", "Reset": "重置", "Clipboard": "剪贴板", "Clear": "清除", "Fullscreen": "全屏", "Settings": "设置", + "Encrypt": "加密", "Shared Mode": "分享模式", "View Only": "仅查看", "Clip to Window": "限制/裁切窗口大小", "Scaling Mode:": "缩放模式:", "None": "无", "Local Scaling": "本地缩放", + "Local Downscaling": "降低本地尺寸", "Remote Resizing": "远程调整大小", "Advanced": "高级", + "Local Cursor": "本地光标", "Repeater ID:": "中继站 ID", "WebSocket": "WebSocket", - "Encrypt": "加密", "Host:": "主机:", "Port:": "端口:", "Path:": "路径:", "Automatic Reconnect": "自动重新连接", "Reconnect Delay (ms):": "重新连接间隔 (ms):", "Logging:": "日志级别:", - "Disconnect": "中断连接", + "Disconnect": "断开连接", "Connect": "连接", "Password:": "密码:", - "Cancel": "取消" + "Cancel": "取消", + "Canvas not supported.": "不支持 Canvas。" } \ No newline at end of file diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/localization.js b/emhttp/plugins/dynamix.vm.manager/novnc/app/localization.js index 100901c9d..7d7e6e6af 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/localization.js +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/localization.js @@ -16,13 +16,19 @@ export class Localizer { this.language = 'en'; // Current dictionary of translations - this.dictionary = undefined; + this._dictionary = undefined; } // Configure suitable language based on user preferences - setup(supportedLanguages) { + async setup(supportedLanguages, baseURL) { this.language = 'en'; // Default: US English + this._dictionary = undefined; + this._setupLanguage(supportedLanguages); + await this._setupDictionary(baseURL); + } + + _setupLanguage(supportedLanguages) { /* * Navigator.languages only available in Chrome (32+) and FireFox (32+) * Fall back to navigator.language for other browsers @@ -40,12 +46,6 @@ export class Localizer { .replace("_", "-") .split("-"); - // Built-in default? - if ((userLang[0] === 'en') && - ((userLang[1] === undefined) || (userLang[1] === 'us'))) { - return; - } - // First pass: perfect match for (let j = 0; j < supportedLanguages.length; j++) { const supLang = supportedLanguages[j] @@ -64,7 +64,12 @@ export class Localizer { return; } - // Second pass: fallback + // Second pass: English fallback + if (userLang[0] === 'en') { + return; + } + + // Third pass pass: other fallback for (let j = 0;j < supportedLanguages.length;j++) { const supLang = supportedLanguages[j] .toLowerCase() @@ -84,10 +89,32 @@ export class Localizer { } } + async _setupDictionary(baseURL) { + if (baseURL) { + if (!baseURL.endsWith("/")) { + baseURL = baseURL + "/"; + } + } else { + baseURL = ""; + } + + if (this.language === "en") { + return; + } + + let response = await fetch(baseURL + this.language + ".json"); + if (!response.ok) { + throw Error("" + response.status + " " + response.statusText); + } + + this._dictionary = await response.json(); + } + // Retrieve localised text get(id) { - if (typeof this.dictionary !== 'undefined' && this.dictionary[id]) { - return this.dictionary[id]; + if (typeof this._dictionary !== 'undefined' && + this._dictionary[id]) { + return this._dictionary[id]; } else { return id; } @@ -103,13 +130,20 @@ export class Localizer { return items.indexOf(searchElement) !== -1; } + function translateString(str) { + // We assume surrounding whitespace, and whitespace around line + // breaks is just for source formatting + str = str.split("\n").map(s => s.trim()).join(" ").trim(); + return self.get(str); + } + function translateAttribute(elem, attr) { - const str = self.get(elem.getAttribute(attr)); + const str = translateString(elem.getAttribute(attr)); elem.setAttribute(attr, str); } function translateTextNode(node) { - const str = self.get(node.data.trim()); + const str = translateString(node.data); node.data = str; } 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 fd78b79c7..f83ad4b93 100644 --- a/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/base.css +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/base.css @@ -19,10 +19,23 @@ * 10000: Max (used for polyfills) */ +/* + * State variables (set on :root): + * + * noVNC_loading: Page is still loading + * noVNC_connecting: Connecting to server + * noVNC_reconnecting: Re-establishing a connection + * noVNC_connected: Connected to server (most common state) + * noVNC_disconnecting: Disconnecting from server + */ + +:root { + font-family: sans-serif; +} + body { margin:0; padding:0; - font-family: Helvetica; /*Background image with light grey curve.*/ background-color:#494949; background-repeat:no-repeat; @@ -78,144 +91,6 @@ html { 50% { box-shadow: 60px 10px 0 rgba(255, 255, 255, 0); width: 10px; } } -/* ---------------------------------------- - * Input Elements - * ---------------------------------------- - */ - -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 { - /* Disable default rendering */ - -webkit-appearance: none; - -moz-appearance: none; - background: none; - - margin: 2px; - padding: 2px; - border: 1px solid rgb(192, 192, 192); - border-radius: 5px; - color: black; - background: linear-gradient(to top, rgb(255, 255, 255) 80%, rgb(240, 240, 240)); -} - -input[type=button], -input[type=color], -input[type=reset], -input[type=submit], -select { - /* Disable default rendering */ - -webkit-appearance: none; - -moz-appearance: none; - background: none; - - margin: 2px; - padding: 2px; - border: 1px solid rgb(192, 192, 192); - border-bottom-width: 2px; - border-radius: 5px; - color: black; - background: linear-gradient(to top, rgb(255, 255, 255), rgb(240, 240, 240)); - - /* This avoids it jumping around when :active */ - vertical-align: middle; -} - -input[type=button], -input[type=color], -input[type=reset], -input[type=submit] { - padding-left: 20px; - padding-right: 20px; -} - -option { - color: black; - background: white; -} - -input:not([type]):focus, -input[type=button]:focus, -input[type=color]:focus, -input[type=date]:focus, -input[type=datetime-local]:focus, -input[type=email]:focus, -input[type=month]:focus, -input[type=number]:focus, -input[type=password]:focus, -input[type=reset]:focus, -input[type=search]:focus, -input[type=submit]:focus, -input[type=tel]:focus, -input[type=text]:focus, -input[type=time]:focus, -input[type=url]:focus, -input[type=week]:focus, -select:focus, -textarea:focus { - box-shadow: 0px 0px 3px rgba(74, 144, 217, 0.5); - border-color: rgb(74, 144, 217); - outline: none; -} - -input[type=button]::-moz-focus-inner, -input[type=color]::-moz-focus-inner, -input[type=reset]::-moz-focus-inner, -input[type=submit]::-moz-focus-inner { - border: none; -} - -input:not([type]):disabled, -input[type=button]:disabled, -input[type=color]:disabled, -input[type=date]:disabled, -input[type=datetime-local]:disabled, -input[type=email]:disabled, -input[type=month]:disabled, -input[type=number]:disabled, -input[type=password]:disabled, -input[type=reset]:disabled, -input[type=search]:disabled, -input[type=submit]:disabled, -input[type=tel]:disabled, -input[type=text]:disabled, -input[type=time]:disabled, -input[type=url]:disabled, -input[type=week]:disabled, -select:disabled, -textarea:disabled { - color: rgb(128, 128, 128); - background: rgb(240, 240, 240); -} - -input[type=button]:active, -input[type=color]:active, -input[type=reset]:active, -input[type=submit]:active, -select:active { - border-bottom-width: 1px; - margin-top: 3px; -} - -:root:not(.noVNC_touch) input[type=button]:hover:not(:disabled), -:root:not(.noVNC_touch) input[type=color]:hover:not(:disabled), -:root:not(.noVNC_touch) input[type=reset]:hover:not(:disabled), -:root:not(.noVNC_touch) input[type=submit]:hover:not(:disabled), -:root:not(.noVNC_touch) select:hover:not(:disabled) { - background: linear-gradient(to top, rgb(255, 255, 255), rgb(250, 250, 250)); -} - /* ---------------------------------------- * WebKit centering hacks * ---------------------------------------- @@ -242,13 +117,15 @@ select:active { pointer-events: auto; } .noVNC_vcenter { - display: flex; + 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 > * { @@ -272,13 +149,20 @@ select:active { #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; } #noVNC_fallback_error.noVNC_open { visibility: visible; } #noVNC_fallback_error > div { - max-width: 90%; + max-width: calc(100vw - 30px - 30px); + max-height: calc(100vh - 30px - 30px); + overflow: auto; + padding: 15px; transition: 0.5s ease-in-out; @@ -317,7 +201,6 @@ select:active { } #noVNC_fallback_error .noVNC_stack { - max-height: 50vh; padding: 10px; margin: 10px; font-size: 0.8em; @@ -361,6 +244,9 @@ select:active { background-color: rgb(110, 132, 163); border-radius: 0 10px 10px 0; + 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); @@ -433,38 +319,50 @@ select:active { .noVNC_right #noVNC_control_bar.noVNC_open #noVNC_control_bar_handle:after { 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: 50px; -} -:root:not(.noVNC_touch) #noVNC_control_bar_handle div { + height: 100%; display: none; } +@media (any-pointer: coarse) { + #noVNC_control_bar_handle div { + display: initial; + } +} .noVNC_right #noVNC_control_bar_handle div { left: -35px; right: auto; } -#noVNC_control_bar .noVNC_scroll { +#noVNC_control_bar > .noVNC_scroll { max-height: 100vh; /* Chrome is buggy with 100% */ overflow-x: hidden; overflow-y: auto; - padding: 0 10px 0 5px; + padding: 0 10px; } -.noVNC_right #noVNC_control_bar .noVNC_scroll { - padding: 0 5px 0 10px; + +#noVNC_control_bar > .noVNC_scroll > * { + display: block; + margin: 10px auto; } /* Control bar hint */ -#noVNC_control_bar_hint { +#noVNC_hint_anchor { position: fixed; - left: calc(100vw - 50px); + right: -50px; + left: auto; +} +#noVNC_control_bar_anchor.noVNC_right + #noVNC_hint_anchor { + left: -50px; right: auto; - top: 50%; - transform: translateY(-50%) scale(0); +} +#noVNC_control_bar_hint { + position: relative; + transform: scale(0); width: 100px; height: 50%; max-height: 600px; @@ -477,61 +375,65 @@ select:active { border-radius: 10px; transition-delay: 0s; } -#noVNC_control_bar_anchor.noVNC_right #noVNC_control_bar_hint{ - left: auto; - right: calc(100vw - 50px); -} #noVNC_control_bar_hint.noVNC_active { visibility: visible; opacity: 1; transition-delay: 0.2s; - transform: translateY(-50%) scale(1); + transform: scale(1); +} +#noVNC_control_bar_hint.noVNC_notransition { + transition: none !important; } -/* General button style */ -.noVNC_button { - display: block; +/* Control bar buttons */ +#noVNC_control_bar .noVNC_button { padding: 4px 4px; - margin: 10px 0; 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 */ } -.noVNC_button.noVNC_selected { +#noVNC_control_bar .noVNC_button.noVNC_selected { border-color: rgba(0, 0, 0, 0.8); - background: rgba(0, 0, 0, 0.5); + background-color: rgba(0, 0, 0, 0.5); } -.noVNC_button:disabled { - opacity: 0.4; +#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_button:focus { - outline: none; +#noVNC_control_bar .noVNC_button:not(:disabled):hover { + background-color: rgba(255, 255, 255, 0.2); } -.noVNC_button:active { +#noVNC_control_bar .noVNC_button:not(:disabled):active { padding-top: 5px; padding-bottom: 3px; } -/* Android browsers don't properly update hover state if touch events - * are intercepted, but focus should be safe to display */ -:root:not(.noVNC_touch) .noVNC_button.noVNC_selected:hover, -.noVNC_button.noVNC_selected:focus { - border-color: rgba(0, 0, 0, 0.4); - background: rgba(0, 0, 0, 0.2); +#noVNC_control_bar .noVNC_button.noVNC_hidden { + display: none !important; } -:root:not(.noVNC_touch) .noVNC_button:hover, -.noVNC_button:focus { - background: rgba(255, 255, 255, 0.2); -} -.noVNC_button.noVNC_hidden { - display: none; + +/* 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); + } } + /* Panels */ .noVNC_panel { transform: translateX(25px); 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; @@ -563,6 +465,17 @@ select:active { transform: translateX(-75px); } +.noVNC_panel > * { + display: block; + margin: 10px auto; +} +.noVNC_panel > *:first-child { + margin-top: 0 !important; +} +.noVNC_panel > *:last-child { + margin-bottom: 0 !important; +} + .noVNC_panel hr { border: none; border-top: 1px solid rgb(192, 192, 192); @@ -571,6 +484,11 @@ select:active { .noVNC_panel label { display: block; white-space: nowrap; + margin: 5px; +} + +.noVNC_panel li { + margin: 5px; } .noVNC_panel .noVNC_heading { @@ -581,7 +499,6 @@ select:active { padding-right: 8px; color: white; font-size: 20px; - margin-bottom: 10px; white-space: nowrap; } .noVNC_panel .noVNC_heading img { @@ -622,6 +539,12 @@ select:active { font-size: 13px; } +.noVNC_logo + hr { + /* Remove all but top border */ + border: none; + border-top: 1px solid rgba(255, 255, 255, 0.2); +} + :root:not(.noVNC_connected) #noVNC_view_drag_button { display: none; } @@ -630,8 +553,15 @@ select:active { :root:not(.noVNC_connected) #noVNC_mobile_buttons { display: none; } -:root:not(.noVNC_touch) #noVNC_mobile_buttons { - 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; + } } /* Extra manual keys */ @@ -642,7 +572,7 @@ select:active { #noVNC_modifiers { background-color: rgb(92, 92, 92); border: none; - padding: 0 10px; + padding: 10px; } /* Shutdown/Reboot */ @@ -663,13 +593,16 @@ select:active { :root:not(.noVNC_connected) #noVNC_clipboard_button { display: none; } -#noVNC_clipboard { - /* Full screen, minus padding and left and right margins */ - max-width: calc(100vw - 2*15px - 75px - 25px); -} #noVNC_clipboard_text { - width: 500px; + 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); } /* Settings */ @@ -677,7 +610,6 @@ select:active { } #noVNC_settings ul { list-style: none; - margin: 0px; padding: 0px; } #noVNC_setting_port { @@ -729,7 +661,7 @@ select:active { justify-content: center; align-content: center; - line-height: 25px; + line-height: 1.6; word-wrap: break-word; color: #fff; @@ -803,36 +735,32 @@ select:active { font-size: calc(25vw - 30px); } } -#noVNC_connect_button { - cursor: pointer; +#noVNC_connect_dlg div { + padding: 12px; - padding: 10px; - - color: white; background-color: rgb(110, 132, 163); border-radius: 12px; - text-align: center; font-size: 20px; box-shadow: 6px 6px 0px rgba(0, 0, 0, 0.5); } -#noVNC_connect_button div { - margin: 2px; +#noVNC_connect_button { + width: 100%; padding: 5px 30px; - border: 1px solid rgb(83, 99, 122); - border-bottom-width: 2px; + + 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 div:active { - border-bottom-width: 1px; - margin-top: 3px; -} -:root:not(.noVNC_touch) #noVNC_connect_button div:hover { +#noVNC_connect_button:hover { background: linear-gradient(to top, rgb(110, 132, 163), rgb(105, 125, 155)); } @@ -841,6 +769,23 @@ select:active { height: 1.3em; } +/* ---------------------------------------- + * Server verification Dialog + * ---------------------------------------- + */ + +#noVNC_verify_server_dlg { + position: relative; + + transform: translateY(-50px); +} +#noVNC_verify_server_dlg.noVNC_open { + transform: translateY(0); +} +#noVNC_fingerprint_block { + margin: 10px; +} + /* ---------------------------------------- * Password Dialog * ---------------------------------------- @@ -854,12 +799,8 @@ select:active { #noVNC_credentials_dlg.noVNC_open { transform: translateY(0); } -#noVNC_credentials_dlg ul { - list-style: none; - margin: 0px; - padding: 0px; -} -.noVNC_hidden { +#noVNC_username_block.noVNC_hidden, +#noVNC_password_block.noVNC_hidden { display: none; } @@ -871,7 +812,11 @@ select:active { /* Transition screen */ #noVNC_transition { - display: none; + transition: 0.5s ease-in-out; + + display: flex; + opacity: 0; + visibility: hidden; position: fixed; top: 0; @@ -892,7 +837,8 @@ select:active { :root.noVNC_connecting #noVNC_transition, :root.noVNC_disconnecting #noVNC_transition, :root.noVNC_reconnecting #noVNC_transition { - display: flex; + opacity: 1; + visibility: visible; } :root:not(.noVNC_reconnecting) #noVNC_cancel_reconnect_button { display: none; @@ -908,6 +854,12 @@ select:active { 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; } #noVNC_keyboardinput { @@ -935,7 +887,7 @@ select:active { .noVNC_logo { color:yellow; font-family: 'Orbitron', 'OrbitronTTF', sans-serif; - line-height:90%; + line-height: 0.9; text-shadow: 0.1em 0.1em 0 black; } .noVNC_logo span{ diff --git a/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/input.css b/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/input.css new file mode 100644 index 000000000..dc345aabc --- /dev/null +++ b/emhttp/plugins/dynamix.vm.manager/novnc/app/styles/input.css @@ -0,0 +1,281 @@ +/* + * noVNC general input element CSS + * Copyright (C) 2022 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; + + /* Disable default rendering */ + appearance: none; + background: none; + + 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); +} + +/* + * Buttons + */ +input[type=button], +input[type=color], +input[type=image], +input[type=reset], +input[type=submit], +input::file-selector-button, +button, +select { + border-bottom-width: 2px; + + /* This avoids it jumping around when :active */ + vertical-align: middle; + margin-top: 0; + + padding-left: 20px; + padding-right: 20px; + + /* Disable Chrome's touch tap highlight */ + -webkit-tap-highlight-color: transparent; +} + +/* + * Select dropdowns + */ +select { + --select-arrow: url('data:image/svg+xml;utf8, \ + \ + \ + '); + background-image: var(--select-arrow), var(--bg-gradient); + background-position: calc(100% - 7px), left top; + background-repeat: no-repeat; + padding-right: calc(2*7px + 8px); + padding-left: 7px; +} +/* FIXME: :active isn't set when the - + - +
+ id="snap-rename" class="orange-text"> _(Rename disabled, snapshot(s) exists.)_ +
_(Name)_: type="text" name="domain[name]" id="domain_name" oninput="checkName(this.value)" class="textTemplate" title="_(Name of virtual machine)_" placeholder="_(e.g.)_ _(My Workstation)_" value="" required />
@@ -2202,6 +2217,7 @@ $(function() { $disk_file_sections.filter('.advanced').removeClass('advanced').addClass('wasadvanced'); $disk_input.attr('name', $disk_input.attr('name').replace('new', 'image')); + if (info.isfile) $table.find('.disk_driver').val(info.format); } else { $disk_file_sections.filter('.wasadvanced').removeClass('wasadvanced').addClass('advanced'); slideDownRows($disk_file_sections.not(isVMAdvancedMode() ? '.basic' : '.advanced')); @@ -2546,13 +2562,13 @@ $(function() { $button.val($button.attr('busyvalue')); swal({ - title: _("Template Name")_, - text: _("Enter name:\nIf name already exists it will be replaced.")_, + title: '_(Template Name)_', + text: "_(Enter name:\nIf name already exists it will be replaced.)_", type: "input", showCancelButton: true, closeOnConfirm: false, //animation: "slide-from-top", - inputPlaceholder: _("Leaving blank will use OS name.")_ + inputPlaceholder: "_(Leaving blank will use OS name.)_" }, function(inputValue){ @@ -2627,13 +2643,13 @@ $(function() { $button.val($button.attr('busyvalue')); swal({ - title: _("Template Name")_, - text: _("Enter name:\nIf name already exists it will be replaced.")_, + title: "_(Template Name)_", + text: "_(Enter name:\nIf name already exists it will be replaced.)_", type: "input", showCancelButton: true, closeOnConfirm: false, //animation: "slide-from-top", - inputPlaceholder: _("Leaving blank will use OS name.")_ + inputPlaceholder: "_(Leaving blank will use OS name.)_" }, function(inputValue){ diff --git a/emhttp/plugins/dynamix.vm.manager/templates/XML_Expert.form.php b/emhttp/plugins/dynamix.vm.manager/templates/XML_Expert.form.php index 3162c2d30..900c05733 100644 --- a/emhttp/plugins/dynamix.vm.manager/templates/XML_Expert.form.php +++ b/emhttp/plugins/dynamix.vm.manager/templates/XML_Expert.form.php @@ -216,13 +216,13 @@ $(function() { $form.find('input').prop('disabled', true); $button.val($button.attr('busyvalue')); swal({ - title: _("Template Name")_, - text: _("Enter name:\nIf name already exists it will be replaced.")_, + title: "_(Template Name)_", + text: "_(Enter name:\nIf name already exists it will be replaced.)_", type: "input", showCancelButton: true, closeOnConfirm: false, //animation: "slide-from-top", - inputPlaceholder: _("Leaving blank will use OS name.")_ + inputPlaceholder: "_(Leaving blank will use OS name.)_" }, function(inputValue){ postdata=postdata+"&templatename="+inputValue; diff --git a/emhttp/plugins/dynamix.vm.manager/vnc.html b/emhttp/plugins/dynamix.vm.manager/vnc.html index 6e9ea184e..edfe49b40 100644 --- a/emhttp/plugins/dynamix.vm.manager/vnc.html +++ b/emhttp/plugins/dynamix.vm.manager/vnc.html @@ -12,13 +12,13 @@ http://example.com/?host=HOST&port=PORT&encrypt=1 or the fragment: http://example.com/#host=HOST&port=PORT&encrypt=1 + + 1.5 --> noVNC - - - + @@ -42,31 +42,37 @@ --> + - - - - - + + + + + + + + + + + + + + - - + + + + - - - - - - - - + + @@ -89,6 +95,8 @@

no
VNC

+
+ Clipboard +

+ Edit clipboard content in the textarea below. +

-
- - + title="Full Screen">
+
+ Settings +
    -
  • - Settings -
  • @@ -267,39 +275,69 @@
-
- +
+
+
+
+
- -
- 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". +
+
+ + +
+
+
+
-
    -
  • - - -
  • -
  • - - -
  • -
  • - -
  • -
+
+ Credentials +
+
+ + +
+
+ + +
+
+ +
@@ -318,7 +356,8 @@ html attributes which attempt to disable text suggestions on the on-screen keyboard. Let's hope Chrome implements the ime-mode style for example --> - +
- +   : diff --git a/emhttp/plugins/dynamix/CacheDevices.page b/emhttp/plugins/dynamix/CacheDevices.page index 855dd31d2..2160557b1 100644 --- a/emhttp/plugins/dynamix/CacheDevices.page +++ b/emhttp/plugins/dynamix/CacheDevices.page @@ -193,7 +193,7 @@ _(Name)_: - + _(Slots)_: diff --git a/emhttp/plugins/dynamix/Credits.page b/emhttp/plugins/dynamix/Credits.page index a56d6732d..1399ee27c 100644 --- a/emhttp/plugins/dynamix/Credits.page +++ b/emhttp/plugins/dynamix/Credits.page @@ -3,7 +3,7 @@ Title="Credits" Icon="icon-credits" Tag="trophy" --- -**Unraid webGUI** Copyright © 2005-2023, [Lime Technology, Inc.](http://lime-technology.com) +**Unraid webGUI** Copyright © 2005-2023, [Lime Technology, Inc.](https://unraid.net/) **Dynamix** Copyright © 2012-2023, Bergware International. @@ -29,7 +29,7 @@ and may not be used in any other project without written permission from Lime Te * Settings, Tools and Case icons. Copyright © 2018-2020, [Magnus Engø.](http://www.magnusengo.net/) Used with permission. -**Unraid**® is a registered trademark of [Lime Technology, Inc.](http://lime-technology.com) +**Unraid**® is a registered trademark of [Lime Technology, Inc.](https://unraid.net/) This file shall be included in all copies or substantial portions of the Software. @@ -47,6 +47,6 @@ foreach (glob("$plugins/lang-*.xml", GLOB_NOSORT) as $link) { $author = language('Author', $xml_file); $credits[] = "
  • $lang ($local) translation by $author

  • "; } -if (count($credits)) echo '
    Language Translations Copyright © 2020-2023,
    Lime Technology, Inc.
      '.implode('',$credits).'
    '; +if (count($credits)) echo '
    Language Translations Copyright © 2020-2023, Lime Technology, Inc.
      '.implode('',$credits).'
    '; ?>
    diff --git a/emhttp/plugins/dynamix/DashStats.page b/emhttp/plugins/dynamix/DashStats.page index 7ed28b7fa..a697d32f7 100644 --- a/emhttp/plugins/dynamix/DashStats.page +++ b/emhttp/plugins/dynamix/DashStats.page @@ -2,7 +2,8 @@ Menu="Dashboard" Nchan="wg_poller,update_1,update_2,update_3,ups_status:stop,vm_dashusage" --- /dev/null")!='folder' ? _('Docker vdisk') : _('Docker folder'); $dot = _var($display,'number','.,')[0]; $zfs = count(array_filter(array_column($disks,'fsType'),function($fs){return str_replace('luks:','',$fs??'')=='zfs';})); @@ -698,8 +699,8 @@ function hideShow() { _(VM Name)_: _(Snapshot Name)_:_(Check free space)_: _(Description)_: -_(Memory dump )_: -_(FS Native Snapshot )_:_(Unchecked will use QEMU External Snapshot)_ +_(Memory dump)_: +_(FS Native Snapshot)_:_(Unchecked will use QEMU External Snapshot)_ @@ -1032,6 +1033,7 @@ function smartMenu(table) { opts.push({text:"_(Acknowledge)_",icon:'fa-check-square-o',action:function(e){e.preventDefault();acknowledge(id,disk);}}); } $(id).bind('click',function(){update2=false;}).bind('mouseout',function(){setTimeout(function(){update2=true;},15000);}); + context.destroy(id); context.attach(id,opts); }); } @@ -1539,7 +1541,7 @@ vmdashusage.on('message', function(msg){ var data = JSON.parse(msg); for (const [vm, vmdata] of Object.entries(data)) { for (const [displayitem, value] of Object.entries(vmdata)) { - $('#vmmetrics-'+displayitem + '-' + vm ).html(value); + $('#vmmetrics-'+displayitem + '-' + vm ).html(value); } } }); diff --git a/emhttp/plugins/dynamix/DateTime.page b/emhttp/plugins/dynamix/DateTime.page index d7fdaae60..3c1c13f5a 100644 --- a/emhttp/plugins/dynamix/DateTime.page +++ b/emhttp/plugins/dynamix/DateTime.page @@ -59,6 +59,14 @@ _(Use NTP)_: :use_ntp_help: +_(NTP interval)_: +: _(Use DEFAULT setting when public NTP servers are defined)_ + _(NTP server)_ 1: : @@ -107,12 +115,14 @@ function presetTime(form) { function checkDateTimeSettings(form) { if (form.USE_NTP.value=="yes") { form.newDateTime.disabled=true; + form.display_ntppoll.disabled=false; form.NTP_SERVER1.disabled=false; form.NTP_SERVER2.disabled=false; form.NTP_SERVER3.disabled=false; form.NTP_SERVER4.disabled=false; } else { form.newDateTime.disabled=false; + form.display_ntppoll.disabled=true; form.NTP_SERVER1.disabled=true; form.NTP_SERVER2.disabled=true; form.NTP_SERVER3.disabled=true; diff --git a/emhttp/plugins/dynamix/DeviceInfo.page b/emhttp/plugins/dynamix/DeviceInfo.page index 92cd59bd0..3c15156c5 100755 --- a/emhttp/plugins/dynamix/DeviceInfo.page +++ b/emhttp/plugins/dynamix/DeviceInfo.page @@ -17,7 +17,6 @@ Tag="hdd-o" 0 ? $sheets[$i-1] : $sheets[$end]; $next = $i<$end ? $sheets[$i+1] : $sheets[0]; $textErase = isPool($name) ? _('This will ERASE content of ALL devices in the pool') : _('This will ERASE ALL device content'); $textDelete = _('This will unassign all devices from the pool but will NOT modify any device contents'); -$fsTypeImmutable = !(_var($var,'fsState')=='Stopped' && (empty(_var($disk,'uuid')) || _var($disk,'slots',1)==1)); function disabled_if($condition) { if ($condition !== false) echo ' disabled'; @@ -111,6 +125,14 @@ function isPool($name) { global $pools; return in_array($name,$pools); } +/* Check to see if a pool has already been upgraded. */ +function is_upgraded_ZFS_pool($pool_name) { + + /* See if the pool is aready upgraded. */ + $upgrade = trim(shell_exec("/usr/sbin/zpool status ".escapeshellarg($pool_name)." | /usr/bin/grep 'Enable all features using.'") ?? ""); + + return ($upgrade ? false : true); +} ?> "> "> @@ -200,7 +222,7 @@ function prepareZFS(form) { } -function selectDiskFsWidth(slots) { +function setDiskFsWidth(slots) { $('#diskFsWidth').empty(); $('#diskFsWidth').append($('