From acb008d37efd8c127e3ddf430439a5b9d17a373e Mon Sep 17 00:00:00 2001 From: Sergio Betanzos Date: Mon, 31 May 2021 16:18:22 +0200 Subject: [PATCH] F #5398: Add resolution select to guacamole (#1260) --- src/sunstone/public/app/console/guacamole.js | 25 +++++++----- src/sunstone/public/app/opennebula/vm.js | 4 +- .../public/app/utils/guacamole/controller.js | 17 ++++++++- .../utils/guacamole/directives/guacButtons.js | 1 - .../app/utils/guacamole/types/client.js | 38 ++++++++++--------- src/sunstone/public/css/guac-custom.css | 7 ++++ src/sunstone/views/guac.erb | 10 +++++ 7 files changed, 69 insertions(+), 33 deletions(-) diff --git a/src/sunstone/public/app/console/guacamole.js b/src/sunstone/public/app/console/guacamole.js index 4940c820c7..a05cec36e9 100644 --- a/src/sunstone/public/app/console/guacamole.js +++ b/src/sunstone/public/app/console/guacamole.js @@ -15,22 +15,23 @@ /* -------------------------------------------------------------------------- */ define(function(require) { - require("jquery-ui"); + require('jquery-ui'); var GuacController = require('utils/guacamole/controller'); var controller = new GuacController(); var reconnectButton = document.getElementById('buttons__reconnect'); + var selectResolution = document.getElementById('select__resolution'); var endpoint = new URL(window.location.href); - var encoded_socket = endpoint.searchParams.get("socket"); + var encoded_socket = endpoint.searchParams.get('socket'); var socket_string = atob(encoded_socket); var url = new URL(socket_string); var params = url.searchParams; - var token = params.get("token"); - var connectionType = params.get("type"); - var info = params.get("info"); + var token = params.get('token'); + var connectionType = params.get('type'); + var info = params.get('info'); controller.setInformation(info); @@ -45,18 +46,22 @@ define(function(require) { reconnectButton.onclick = function reconnect() { disconnect(); - document.querySelector('.toolbar__state h5').innerHTML = ""; - document.querySelector('.toolbar__state .spinner').style.display = "block"; + document.querySelector('.toolbar__state h5').innerHTML = ''; + document.querySelector('.toolbar__state .spinner').style.display = 'block'; - setTimeout(connect, 500) + setTimeout(connect, 500); } + + selectResolution.onchange = function() { + reconnectButton.click(); + }; function connect() { try { controller && controller.setConnection(token, connectionType); } catch (error) { controller && controller.disconnect(); - document.querySelector('.toolbar__state h5').innerHTML = "Failed"; + document.querySelector('.toolbar__state h5').innerHTML = 'Failed'; } } @@ -64,7 +69,7 @@ define(function(require) { try { controller && controller.disconnect(); } catch (error) { - document.querySelector('.toolbar__state h5').innerHTML = "Failed"; + document.querySelector('.toolbar__state h5').innerHTML = 'Failed'; } } diff --git a/src/sunstone/public/app/opennebula/vm.js b/src/sunstone/public/app/opennebula/vm.js index 997e83904f..f43d8b5450 100644 --- a/src/sunstone/public/app/opennebula/vm.js +++ b/src/sunstone/public/app/opennebula/vm.js @@ -1054,9 +1054,9 @@ define(function(require) { }); if (ips.length === 0) - return "

--

"; + return "

--

"; else if (ips.length === 1) - return "

"+ips[0]+"

"; + return "

"+ips[0]+"

"; var sshWithPortForwarding = getSshWithPortForwarding(element) || ''; var firstIP = ipsHtml.split("")[0]; diff --git a/src/sunstone/public/app/utils/guacamole/controller.js b/src/sunstone/public/app/utils/guacamole/controller.js index cc3673f2ba..77217e8ae9 100644 --- a/src/sunstone/public/app/utils/guacamole/controller.js +++ b/src/sunstone/public/app/utils/guacamole/controller.js @@ -35,6 +35,7 @@ define(function(require) { var $elements = { main: document.querySelector('.wrapper__display'), displayContainer: document.getElementById('display'), + selectResolution: document.getElementById('select__resolution'), osk: document.getElementById('osk'), closeOskButton: document.querySelector('.osk__header__buttons .close'), @@ -55,7 +56,19 @@ define(function(require) { ? $elements.displayContainer.classList.add('ssh') : $elements.displayContainer.classList.remove('ssh'); - var managedClient = ManagedClient.getInstance(token, undefined, $elements.displayContainer) + var isRDP = $scope.connectionType === ConnectionTypes.RDP + var resolution = $elements.selectResolution.value; + + isRDP && $elements.selectResolution.classList.remove('hidden'); + + var displayOptions = isRDP && resolution && resolution !== '' + ? { + width: resolution.split('x')[0], + height: resolution.split('x')[1] + } + : { display: $elements.displayContainer }; // get width & height from container + + var managedClient = ManagedClient.getInstance(token, displayOptions) new GuacKeyboard($guac, $scope, $elements); new GuacMouse($guac, $scope, $elements); @@ -144,7 +157,7 @@ define(function(require) { var pixelDensity = window.devicePixelRatio || 1; var width = $elements.main.offsetWidth * pixelDensity; var height = $elements.main.offsetHeight * pixelDensity; - + if ($guac.display.getWidth() !== width || $guac.display.getHeight() !== height) { $guac.client.sendSize(width, height); } diff --git a/src/sunstone/public/app/utils/guacamole/directives/guacButtons.js b/src/sunstone/public/app/utils/guacamole/directives/guacButtons.js index 5c7539c41f..2e73f9255c 100644 --- a/src/sunstone/public/app/utils/guacamole/directives/guacButtons.js +++ b/src/sunstone/public/app/utils/guacamole/directives/guacButtons.js @@ -17,7 +17,6 @@ define(function(require) { var Files = require('utils/files'); - var ConnectionTypes = require("utils/guacamole/types/connection-types"); function GuacButtons($guac, $scope, $elements) { $elements.screenshotButton.onclick = function() { diff --git a/src/sunstone/public/app/utils/guacamole/types/client.js b/src/sunstone/public/app/utils/guacamole/types/client.js index bcf7654a3d..29654a189d 100644 --- a/src/sunstone/public/app/utils/guacamole/types/client.js +++ b/src/sunstone/public/app/utils/guacamole/types/client.js @@ -207,34 +207,37 @@ define(function(require) { * guaranteed to resolve successfully. * * @param {String} token The identifier representing the connection or group to connect to. - * @param {String[]} [connectionParameters] Any additional HTTP parameters to pass while connecting. - * @param {Element} [display] Element where the connection will be displayed. + * @param {Element} options.display Element where the connection will be displayed. + * @param {String} options.width Forced width connection + * @param {String} options.height Forced height connection * * @returns {String} A string of connection parameters to be passed to the Guacamole client. */ - function getConnectString(token, connectionParameters, display = window) { + function getConnectString(token, options = {}) { + options = Object.assign({ display: window }, options) + // Calculate optimal width/height for display var pixel_density = window.devicePixelRatio || 1; - var optimal_dpi = pixel_density * 96; + var optimal_dpi = options.dpi || pixel_density * 96; - var optimal_width = display instanceof Window - ? display.innerWidth * pixel_density - : display.offsetWidth * pixel_density; + var display = options.display - var optimal_height = display instanceof Window - ? display.innerHeight * pixel_density - : display.offsetHeight * pixel_density; + var width = options.width || ( + display instanceof Window ? display.innerWidth : display.offsetWidth + ) + + var height = options.height || ( + display instanceof Window ? display.innerHeight : display.offsetHeight + ) // Build base connect string var connectString = [ "token=" + encodeURIComponent(token), - "width=" + Math.floor(optimal_width), - "height=" + Math.floor(optimal_height), + "width=" + Math.floor(width * pixel_density), + "height=" + Math.floor(height * pixel_density), "dpi=" + Math.floor(optimal_dpi) ]; - connectionParameters && connectString.concat(connectionParameters); - return connectString.join('&'); } @@ -272,14 +275,13 @@ define(function(require) { * or group. * * @param {String} token The token of the connection. - * @param {String[]} [connectionParameters] Any additional HTTP parameters to pass while connecting. - * @param {Element} [display] Element where the connection will be displayed. + * @param {Object} displayOptions The options to client display * * @returns {ManagedClient} * A new ManagedClient instance which is connected to the connection or * connection group having the given ID. */ - ManagedClient.getInstance = function getInstance(token, connectionParameters, display = window) { + ManagedClient.getInstance = function getInstance(token, displayOptions) { var endpoint = new URL(Config.publicFireedgeEndpoint); var websocketProtocol = endpoint.protocol === 'https:' ? 'wss:' : 'ws:'; @@ -454,7 +456,7 @@ define(function(require) { managedClient.managedDisplay = ManagedDisplay.getInstance(client.getDisplay()); // Connect the Guacamole client - var connectString = getConnectString(token, connectionParameters, display); + var connectString = getConnectString(token, displayOptions); client.connect(connectString); return managedClient; diff --git a/src/sunstone/public/css/guac-custom.css b/src/sunstone/public/css/guac-custom.css index 170049502e..7cb58e7ff9 100644 --- a/src/sunstone/public/css/guac-custom.css +++ b/src/sunstone/public/css/guac-custom.css @@ -73,6 +73,13 @@ header { justify-content: flex-end; } +.toolbar__buttons > button, +.toolbar__buttons > select { + max-height: 32px; + margin-bottom: 0; + width: auto; +} + @media (max-width: 768px) { .toolbar__state { justify-content: end; diff --git a/src/sunstone/views/guac.erb b/src/sunstone/views/guac.erb index 5a57262eb0..cb6e02160f 100644 --- a/src/sunstone/views/guac.erb +++ b/src/sunstone/views/guac.erb @@ -40,6 +40,16 @@ +