From d0b1fb7d7fa3e9490a15d6b91f946654c19b72f2 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 16 Jun 2021 21:59:10 -0700 Subject: [PATCH] GUACAMOLE-724: Control only the currently-focused client with client-specific menu options. --- .../client/controllers/clientController.js | 92 +++++++++++++++---- .../app/client/directives/guacFileBrowser.js | 10 +- .../src/app/client/templates/client.html | 12 +-- .../app/client/types/ManagedClientGroup.js | 12 ++- .../src/app/client/types/ManagedFilesystem.js | 18 ++-- 5 files changed, 101 insertions(+), 43 deletions(-) diff --git a/guacamole/src/main/frontend/src/app/client/controllers/clientController.js b/guacamole/src/main/frontend/src/app/client/controllers/clientController.js index ba6225805..5dc0beaf0 100644 --- a/guacamole/src/main/frontend/src/app/client/controllers/clientController.js +++ b/guacamole/src/main/frontend/src/app/client/controllers/clientController.js @@ -156,10 +156,20 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams */ $scope.applyParameterChanges = function applyParameterChanges() { angular.forEach($scope.menu.connectionParameters, function sendArgv(value, name) { - ManagedClient.setArgument($scope.client, name, value); + if ($scope.focusedClient) + ManagedClient.setArgument($scope.focusedClient, name, value); }); }; + /** + * The currently-focused client within the current ManagedClientGroup. If + * there is no current group, no client is focused, or multiple clients are + * focused, this will be null. + * + * @type ManagedClient + */ + $scope.focusedClient = null; + /** * The set of clients that should be attached to the client UI. This will * be immediately initialized by a call to updateAttachedClients() below. @@ -173,6 +183,11 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams */ $scope.getName = ManagedClientGroup.getName; + /** + * @borrows ManagedClientGroup.getTitle + */ + $scope.getTitle = ManagedClientGroup.getTitle; + /** * Reloads the contents of $scope.clientGroup to reflect the client IDs * currently listed in the URL. @@ -231,6 +246,27 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams // reloading the route $scope.$on('$routeUpdate', updateAttachedClients); + /** + * Returns the currently-focused ManagedClient. If there is no such client, + * or multiple clients are focused, null is returned. + * + * @returns {ManagedClient} + * The currently-focused client, or null if there are no focused + * clients or if multiple clients are focused. + */ + $scope.getFocusedClient = function getFocusedClient() { + + var managedClientGroup = $scope.clientGroup; + if (managedClientGroup) { + var focusedClients = _.filter(managedClientGroup.clients, client => client.clientProperties.focused); + if (focusedClients.length === 1) + return focusedClients[0]; + } + + return null; + + }; + /** * The root connection groups of the connection hierarchy that should be * presented to the user for selecting a different connection, as a map of @@ -456,11 +492,6 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams $scope.applyParameterChanges(); } - // Obtain snapshot of current editable connection parameters when menu - // is opened - else if (menuShown) - $scope.menu.connectionParameters = ManagedClient.getArgumentModel($scope.client); - // Disable client keyboard if the menu is shown angular.forEach($scope.clientGroup.clients, function updateKeyboardEnabled(client) { client.clientProperties.keyboardEnabled = !menuShown; @@ -468,8 +499,25 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams }); + // Automatically track and cache the currently-focused client + $scope.$watch('getFocusedClient()', function focusedClientChanged(client) { + + // Apply any parameter changes when focus is changing (as + // applyParameterChanges() depends on the value of focusedClient, this + // must be called BEFORE updating focusedClient + $scope.applyParameterChanges(); + + $scope.focusedClient = client; + + // Update available connection parameters, if there is a focused + // client + $scope.menu.connectionParameters = $scope.focusedClient ? + ManagedClient.getArgumentModel($scope.focusedClient) : {}; + + }); + // Update page icon when thumbnail changes - $scope.$watch('client.thumbnail.canvas', function thumbnailChanged(canvas) { + $scope.$watch('focusedClient.thumbnail.canvas', function thumbnailChanged(canvas) { iconService.setIcons(canvas); }); @@ -487,7 +535,7 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams }); // Pull sharing profiles once the tunnel UUID is known - $scope.$watch('client.tunnel.uuid', function retrieveSharingProfiles(uuid) { + $scope.$watch('focusedClient.tunnel.uuid', function retrieveSharingProfiles(uuid) { // Only pull sharing profiles if tunnel UUID is actually available if (!uuid) @@ -510,7 +558,8 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams * The sharing profile to use to generate the sharing link. */ $scope.share = function share(sharingProfile) { - ManagedClient.createShareLink($scope.client, sharingProfile); + if ($scope.focusedClient) + ManagedClient.createShareLink($scope.focusedClient, sharingProfile); }; /** @@ -521,7 +570,7 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams * link, false otherwise. */ $scope.isShared = function isShared() { - return ManagedClient.isShared($scope.client); + return !!$scope.focusedClient && ManagedClient.isShared($scope.focusedClient); }; /** @@ -534,9 +583,12 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams */ $scope.getShareLinkCount = function getShareLinkCount() { + if (!$scope.focusedClient) + return 0; + // Count total number of links within the ManagedClient's share link map var linkCount = 0; - for (var dummy in $scope.client.shareLinks) + for (var dummy in $scope.focusedClient.shareLinks) linkCount++; return linkCount; @@ -625,7 +677,7 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams }); // Update page title when client title changes - $scope.$watch('client.title', function clientTitleChanged(title) { + $scope.$watch('getTitle(clientGroup)', function clientTitleChanged(title) { $scope.page.title = title; }); @@ -678,13 +730,17 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams }; /** - * Immediately disconnects the currently-connected client, if any. + * Immediately disconnects all currently-focused clients, if any. */ $scope.disconnect = function disconnect() { // Disconnect if client is available - if ($scope.client) - $scope.client.client.disconnect(); + if ($scope.clientGroup) { + $scope.clientGroup.clients.forEach(client => { + if (client.clientProperties.focused) + client.client.disconnect(); + }); + } // Hide menu $scope.menu.shown = false; @@ -804,13 +860,9 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams */ $scope.uploadFiles = function uploadFiles(files) { - // Ignore file uploads if no attached client - if (!$scope.client) - return; - // Upload each file for (var i = 0; i < files.length; i++) - ManagedClient.uploadFile($scope.client, files[i], $scope.filesystemMenuContents); + ManagedClient.uploadFile($scope.filesystemMenuContents.client, files[i], $scope.filesystemMenuContents); }; diff --git a/guacamole/src/main/frontend/src/app/client/directives/guacFileBrowser.js b/guacamole/src/main/frontend/src/app/client/directives/guacFileBrowser.js index fe1a5e249..f1daf3eb6 100644 --- a/guacamole/src/main/frontend/src/app/client/directives/guacFileBrowser.js +++ b/guacamole/src/main/frontend/src/app/client/directives/guacFileBrowser.js @@ -28,14 +28,6 @@ angular.module('client').directive('guacFileBrowser', [function guacFileBrowser( replace: true, scope: { - /** - * The client whose file transfers should be managed by this - * directive. - * - * @type ManagedClient - */ - client : '=', - /** * @type ManagedFilesystem */ @@ -116,7 +108,7 @@ angular.module('client').directive('guacFileBrowser', [function guacFileBrowser( * The file to download. */ $scope.downloadFile = function downloadFile(file) { - ManagedFilesystem.downloadFile($scope.client, $scope.filesystem, file.streamName); + ManagedFilesystem.downloadFile($scope.filesystem, file.streamName); }; /** diff --git a/guacamole/src/main/frontend/src/app/client/templates/client.html b/guacamole/src/main/frontend/src/app/client/templates/client.html index 788e382cd..9d4f52209 100644 --- a/guacamole/src/main/frontend/src/app/client/templates/client.html +++ b/guacamole/src/main/frontend/src/app/client/templates/client.html @@ -87,7 +87,7 @@ translate="CLIENT.HELP_SHARE_LINK" translate-values="{LINKS : getShareLinkCount()}">

- + @@ -105,19 +105,19 @@ -
{{link.value.name}} {{link.value.href}}