GUACAMOLE-1904: Merge enhancements to available events/hooks related to client args and menu.

This commit is contained in:
Mike Jumper
2024-01-18 12:26:54 -08:00
committed by GitHub
8 changed files with 92 additions and 28 deletions

View File

@@ -468,8 +468,21 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
else if (menuShownPreviousState) else if (menuShownPreviousState)
$scope.applyParameterChanges($scope.focusedClient); $scope.applyParameterChanges($scope.focusedClient);
/* Broadcast changes to the menu display state */
$scope.$broadcast('guacMenuShown', menuShown);
}); });
// Toggle the menu when the guacClientToggleMenu event is received
$scope.$on('guacToggleMenu',
() => $scope.menu.shown = !$scope.menu.shown);
// Show the menu when the guacClientShowMenu event is received
$scope.$on('guacShowMenu', () => $scope.menu.shown = true);
// Hide the menu when the guacClientHideMenu event is received
$scope.$on('guacHideMenu', () => $scope.menu.shown = false);
// Automatically track and cache the currently-focused client // Automatically track and cache the currently-focused client
$scope.$on('guacClientFocused', function focusedClientChanged(event, newFocusedClient) { $scope.$on('guacClientFocused', function focusedClientChanged(event, newFocusedClient) {
@@ -489,10 +502,9 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
// Automatically update connection parameters that have been modified // Automatically update connection parameters that have been modified
// for the current focused client // for the current focused client
$scope.$on('guacClientArgumentsUpdated', function focusedClientChanged(event, focusedClient) { $scope.$on('guacClientArgumentsUpdated', function argumentsChanged(event, focusedClient) {
// Update available connection parameters, if the updated arguments are // Ignore any updated arguments not for the current focused client
// for the current focused client - otherwise ignore them
if ($scope.focusedClient && $scope.focusedClient === focusedClient) if ($scope.focusedClient && $scope.focusedClient === focusedClient)
$scope.menu.connectionParameters = ManagedClient.getArgumentModel(focusedClient); $scope.menu.connectionParameters = ManagedClient.getArgumentModel(focusedClient);

View File

@@ -62,6 +62,9 @@ angular.module('client').directive('guacTiledClients', [function guacTiledClient
directive.controller = ['$scope', '$injector', '$element', directive.controller = ['$scope', '$injector', '$element',
function guacTiledClientsController($scope, $injector, $element) { function guacTiledClientsController($scope, $injector, $element) {
// Required services
const $rootScope = $injector.get('$rootScope');
// Required types // Required types
const ManagedClient = $injector.get('ManagedClient'); const ManagedClient = $injector.get('ManagedClient');
const ManagedClientGroup = $injector.get('ManagedClientGroup'); const ManagedClientGroup = $injector.get('ManagedClientGroup');
@@ -89,12 +92,17 @@ angular.module('client').directive('guacTiledClients', [function guacTiledClient
// Notify whenever identify of currently-focused client changes // Notify whenever identify of currently-focused client changes
$scope.$watch('getFocusedClient()', function focusedClientChanged(focusedClient) { $scope.$watch('getFocusedClient()', function focusedClientChanged(focusedClient) {
$scope.$emit('guacClientFocused', focusedClient); $rootScope.$broadcast('guacClientFocused', focusedClient);
}); });
// Notify whenever arguments of currently-focused client changes // Notify whenever arguments of currently-focused client changes
$scope.$watch('getFocusedClient().arguments', function focusedClientParametersChanged() { $scope.$watch('getFocusedClient().arguments', function focusedClientParametersChanged() {
$scope.$emit('guacClientArgumentsUpdated', $scope.getFocusedClient()); $rootScope.$broadcast('guacClientArgumentsUpdated', $scope.getFocusedClient());
}, true);
// Notify whenever protocol of currently-focused client changes
$scope.$watch('getFocusedClient().protocol', function focusedClientParametersChanged() {
$rootScope.$broadcast('guacClientProtocolUpdated', $scope.getFocusedClient());
}, true); }, true);
/** /**

View File

@@ -124,6 +124,7 @@
<guac-form namespace="getProtocolNamespace(focusedClient.protocol)" <guac-form namespace="getProtocolNamespace(focusedClient.protocol)"
content="focusedClient.forms" content="focusedClient.forms"
model="menu.connectionParameters" model="menu.connectionParameters"
client="focusedClient"
model-only="true"></guac-form> model-only="true"></guac-form>
</div> </div>

View File

@@ -58,6 +58,16 @@ angular.module('client').factory('ManagedArgument', ['$q', function defineManage
*/ */
this.stream = template.stream; this.stream = template.stream;
/**
* True if this argument has been modified in the webapp, but yet to
* be confirmed by guacd, or false in any other case. A pending
* argument cannot be modified again, and must be recreated before
* editing is enabled again.
*
* @type {boolean}
*/
this.pending = false;
}; };
/** /**
@@ -110,9 +120,9 @@ angular.module('client').factory('ManagedArgument', ['$q', function defineManage
* Sets the given editable argument (connection parameter) to the given * Sets the given editable argument (connection parameter) to the given
* value, updating the behavior of the associated connection in real-time. * value, updating the behavior of the associated connection in real-time.
* If successful, the ManagedArgument provided cannot be used for future * If successful, the ManagedArgument provided cannot be used for future
* calls to setValue() and must be replaced with a new instance. This * calls to setValue() and will be read-only until replaced with a new
* function only has an effect if the new parameter value is different from * instance. This function only has an effect if the new parameter value
* the current value. * is different from the current value.
* *
* @param {ManagedArgument} managedArgument * @param {ManagedArgument} managedArgument
* The ManagedArgument instance associated with the connection * The ManagedArgument instance associated with the connection
@@ -120,33 +130,24 @@ angular.module('client').factory('ManagedArgument', ['$q', function defineManage
* *
* @param {String} value * @param {String} value
* The new value to assign to the connection parameter. * The new value to assign to the connection parameter.
*
* @returns {Boolean}
* true if the connection parameter was sent and the provided
* ManagedArgument instance may no longer be used for future setValue()
* calls, false if the connection parameter was NOT sent as it has not
* changed.
*/ */
ManagedArgument.setValue = function setValue(managedArgument, value) { ManagedArgument.setValue = function setValue(managedArgument, value) {
// Stream new value only if value has changed // Stream new value only if value has changed and a change is not
if (value !== managedArgument.value) { // already pending
if (!managedArgument.pending && value !== managedArgument.value) {
var writer = new Guacamole.StringWriter(managedArgument.stream); var writer = new Guacamole.StringWriter(managedArgument.stream);
writer.sendText(value); writer.sendText(value);
writer.sendEnd(); writer.sendEnd();
// ManagedArgument instance is no longer usable // ManagedArgument instance is no longer usable
return true; managedArgument.pending = true;
} }
// No parameter value change was attempted and the ManagedArgument
// instance may be reused
return false;
}; };
return ManagedArgument; return ManagedArgument;
}]); }]);

View File

@@ -836,8 +836,7 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
*/ */
ManagedClient.setArgument = function setArgument(managedClient, name, value) { ManagedClient.setArgument = function setArgument(managedClient, name, value) {
var managedArgument = managedClient.arguments[name]; var managedArgument = managedClient.arguments[name];
if (managedArgument && ManagedArgument.setValue(managedArgument, value)) managedArgument && ManagedArgument.setValue(managedArgument, value);
delete managedClient.arguments[name];
}; };
/** /**
@@ -1007,4 +1006,4 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
return ManagedClient; return ManagedClient;
}]); }]);

View File

@@ -17,6 +17,7 @@
* under the License. * under the License.
*/ */
/* global _ */
/** /**
* A directive that allows editing of a collection of fields. * A directive that allows editing of a collection of fields.
@@ -79,7 +80,19 @@ angular.module('form').directive('guacForm', [function form() {
* *
* @type String * @type String
*/ */
focused : '=' focused : '=',
/**
* The client associated with this form, if any.
*
* NOTE: If the provided client has any managed arguments in the
* pending state, any fields with the same name rendered by this
* form will be disabled. The fields will be re-enabled when guacd
* sends an updated argument with a the same name.
*
* @type ManagedClient
*/
client: '='
}, },
templateUrl: 'app/form/templates/form.html', templateUrl: 'app/form/templates/form.html',
@@ -240,6 +253,28 @@ angular.module('form').directive('guacForm', [function form() {
}; };
/**
* Returns whether the given field should be disabled (read-only)
* when presented to the current user.
*
* @param {Field} field
* The field to check.
*
* @returns {Boolean}
* true if the given field should be disabled, false otherwise.
*/
$scope.isDisabled = function isDisabled(field) {
/*
* The field is disabled if either the form as a whole is disabled,
* or if a client is provided to the directive, and the field is
* marked as pending.
*/
return $scope.disabled ||
_.get($scope.client, ['arguments', field.name, 'pending']);
};
/** /**
* Returns whether at least one of the given fields should be * Returns whether at least one of the given fields should be
* displayed to the current user. * displayed to the current user.

View File

@@ -68,7 +68,14 @@ angular.module('form').directive('guacFormField', [function formField() {
* *
* @type Boolean * @type Boolean
*/ */
focused : '=' focused : '=',
/**
* The client associated with this form field, if any.
*
* @type ManagedClient
*/
client: '='
}, },
templateUrl: 'app/form/templates/formField.html', templateUrl: 'app/form/templates/formField.html',

View File

@@ -10,9 +10,10 @@
<div class="fields"> <div class="fields">
<guac-form-field ng-repeat="field in form.fields" namespace="namespace" <guac-form-field ng-repeat="field in form.fields" namespace="namespace"
ng-if="isVisible(field)" ng-if="isVisible(field)"
data-disabled="disabled" data-disabled="isDisabled(field)"
focused="isFocused(field)" focused="isFocused(field)"
field="field" field="field"
client="client"
model="values[field.name]"></guac-form-field> model="values[field.name]"></guac-form-field>
</div> </div>