From cbd357c6838b4f6a38bad12ee7a801ec9518f5c2 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 2 Apr 2019 17:37:57 -0700 Subject: [PATCH] GUACAMOLE-723: Allow connections to be closed/removed directly from the panel. --- .../app/client/directives/guacClientPanel.js | 45 ++++++++++++++++--- .../app/client/styles/other-connections.css | 42 ++++++++++++++++- .../app/client/templates/guacClientPanel.html | 14 +++++- 3 files changed, 92 insertions(+), 9 deletions(-) diff --git a/guacamole/src/main/webapp/app/client/directives/guacClientPanel.js b/guacamole/src/main/webapp/app/client/directives/guacClientPanel.js index 5cd30ec01..658be2fdd 100644 --- a/guacamole/src/main/webapp/app/client/directives/guacClientPanel.js +++ b/guacamole/src/main/webapp/app/client/directives/guacClientPanel.js @@ -25,6 +25,7 @@ angular.module('client').directive('guacClientPanel', ['$injector', function guacClientPanel($injector) { // Required services + var guacClientManager = $injector.get('guacClientManager'); var sessionStorageFactory = $injector.get('sessionStorageFactory'); // Required types @@ -54,7 +55,7 @@ angular.module('client').directive('guacClientPanel', ['$injector', function gua * @type ManagedClient[]|Object. */ clients : '=' - + }, templateUrl: 'app/client/templates/guacClientPanel.html', controller: ['$scope', '$element', function guacClientPanelController($scope, $element) { @@ -82,26 +83,28 @@ angular.module('client').directive('guacClientPanel', ['$injector', function gua * false otherwise. */ $scope.hasClients = function hasClients() { - return !_.isEmpty($scope.clients); + return !!_.find($scope.clients, $scope.isManaged); }; /** - * Returns whether the given client has disconnected due to an - * error. + * Returns whether the status of the given client has changed in a + * way that requires the user's attention. This may be due to an + * error, or due to a server-initiated disconnect. * * @param {ManagedClient} client * The client to test. * * @returns {Boolean} - * true if the given client has disconnected due to an error, + * true if the given client requires the user's attention, * false otherwise. */ - $scope.hasError = function hasError(client) { + $scope.hasStatusUpdate = function hasStatusUpdate(client) { // Test whether the client has encountered an error switch (client.clientState.connectionState) { case ManagedClientState.ConnectionState.CONNECTION_ERROR: case ManagedClientState.ConnectionState.TUNNEL_ERROR: + case ManagedClientState.ConnectionState.DISCONNECTED: return true; } @@ -109,6 +112,36 @@ angular.module('client').directive('guacClientPanel', ['$injector', function gua }; + /** + * Returns whether the given client is currently being managed by + * the guacClientManager service. + * + * @param {ManagedClient} client + * The client to test. + * + * @returns {Boolean} + * true if the given client is being managed by the + * guacClientManager service, false otherwise. + */ + $scope.isManaged = function isManaged(client) { + return !!guacClientManager.getManagedClients()[client.id]; + }; + + /** + * Initiates an orderly disconnect of the given client. The client + * is removed from management such that attempting to connect to + * the same connection will result in a new connection being + * established, rather than displaying a notification that the + * connection has ended. + * + * @param {type} client + * @returns {undefined} + */ + $scope.disconnect = function disconnect(client) { + client.client.disconnect(); + guacClientManager.removeManagedClient(client.id); + }; + /** * Toggles whether the client panel is currently hidden. */ diff --git a/guacamole/src/main/webapp/app/client/styles/other-connections.css b/guacamole/src/main/webapp/app/client/styles/other-connections.css index d726b540f..855960dfb 100644 --- a/guacamole/src/main/webapp/app/client/styles/other-connections.css +++ b/guacamole/src/main/webapp/app/client/styles/other-connections.css @@ -100,7 +100,7 @@ } -#other-connections .client-panel-connection::before { +#other-connections .client-panel-connection a[href]::before { display: block; content: ' '; @@ -110,21 +110,58 @@ left: 0; height: 100%; width: 100%; + z-index: 1; background: url('images/warning-white.png'); background-size: 48px; background-position: center; background-repeat: no-repeat; + background-color: black; opacity: 0; transition: opacity 0.25s; } -#other-connections .client-panel-connection.error::before { +#other-connections .client-panel-connection.needs-attention a[href]::before { opacity: 0.75; } +#other-connections button.close-other-connection { + + position: absolute; + top: 0; + right: 0; + z-index: 2; + + margin: 0; + padding: 4px; + min-width: 0; + border: none; + background: transparent; + box-shadow: none; + text-shadow: none; + + opacity: 0.5; + line-height: 1; + +} + +#other-connections button.close-other-connection:hover { + opacity: 1; +} + +#other-connections button.close-other-connection img { + background: #A43; + border-radius: 18px; + max-width: 18px; + padding: 3px; +} + +#other-connections button.close-other-connection:hover img { + background: #C54; +} + #other-connections .client-panel.hidden .client-panel-connection-list { /* Hide scrollbar when panel is hidden (will be visible through panel * show/hide button otherwise) */ @@ -144,6 +181,7 @@ left: 0; right: 0; bottom: 0; + z-index: 2; text-align: left; color: white; diff --git a/guacamole/src/main/webapp/app/client/templates/guacClientPanel.html b/guacamole/src/main/webapp/app/client/templates/guacClientPanel.html index a09033510..bb6e7e36d 100644 --- a/guacamole/src/main/webapp/app/client/templates/guacClientPanel.html +++ b/guacamole/src/main/webapp/app/client/templates/guacClientPanel.html @@ -7,13 +7,25 @@