mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-07 05:31:22 +00:00
GUACAMOLE-724: Provide separate, client-specific notifications for each tiled client.
This commit is contained in:
@@ -32,13 +32,11 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
|
||||
var ScrollState = $injector.get('ScrollState');
|
||||
|
||||
// Required services
|
||||
var $location = $injector.get('$location');
|
||||
var authenticationService = $injector.get('authenticationService');
|
||||
var connectionGroupService = $injector.get('connectionGroupService');
|
||||
var clipboardService = $injector.get('clipboardService');
|
||||
var dataSourceService = $injector.get('dataSourceService');
|
||||
var guacClientManager = $injector.get('guacClientManager');
|
||||
var guacNotification = $injector.get('guacNotification');
|
||||
var iconService = $injector.get('iconService');
|
||||
var preferenceService = $injector.get('preferenceService');
|
||||
var requestService = $injector.get('requestService');
|
||||
@@ -93,129 +91,6 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
|
||||
*/
|
||||
var DEL_KEY = 0xFFFF;
|
||||
|
||||
/**
|
||||
* All client error codes handled and passed off for translation. Any error
|
||||
* code not present in this list will be represented by the "DEFAULT"
|
||||
* translation.
|
||||
*/
|
||||
var CLIENT_ERRORS = {
|
||||
0x0201: true,
|
||||
0x0202: true,
|
||||
0x0203: true,
|
||||
0x0207: true,
|
||||
0x0208: true,
|
||||
0x0209: true,
|
||||
0x020A: true,
|
||||
0x020B: true,
|
||||
0x0301: true,
|
||||
0x0303: true,
|
||||
0x0308: true,
|
||||
0x031D: true
|
||||
};
|
||||
|
||||
/**
|
||||
* All error codes for which automatic reconnection is appropriate when a
|
||||
* client error occurs.
|
||||
*/
|
||||
var CLIENT_AUTO_RECONNECT = {
|
||||
0x0200: true,
|
||||
0x0202: true,
|
||||
0x0203: true,
|
||||
0x0207: true,
|
||||
0x0208: true,
|
||||
0x0301: true,
|
||||
0x0308: true
|
||||
};
|
||||
|
||||
/**
|
||||
* All tunnel error codes handled and passed off for translation. Any error
|
||||
* code not present in this list will be represented by the "DEFAULT"
|
||||
* translation.
|
||||
*/
|
||||
var TUNNEL_ERRORS = {
|
||||
0x0201: true,
|
||||
0x0202: true,
|
||||
0x0203: true,
|
||||
0x0204: true,
|
||||
0x0205: true,
|
||||
0x0207: true,
|
||||
0x0208: true,
|
||||
0x0301: true,
|
||||
0x0303: true,
|
||||
0x0308: true,
|
||||
0x031D: true
|
||||
};
|
||||
|
||||
/**
|
||||
* All error codes for which automatic reconnection is appropriate when a
|
||||
* tunnel error occurs.
|
||||
*/
|
||||
var TUNNEL_AUTO_RECONNECT = {
|
||||
0x0200: true,
|
||||
0x0202: true,
|
||||
0x0203: true,
|
||||
0x0207: true,
|
||||
0x0208: true,
|
||||
0x0308: true
|
||||
};
|
||||
|
||||
/**
|
||||
* Action which logs out from Guacamole entirely.
|
||||
*/
|
||||
var LOGOUT_ACTION = {
|
||||
name : "CLIENT.ACTION_LOGOUT",
|
||||
className : "logout button",
|
||||
callback : function logoutCallback() {
|
||||
authenticationService.logout()
|
||||
['catch'](requestService.IGNORE);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Action which returns the user to the home screen. If the home page has
|
||||
* not yet been determined, this will be null.
|
||||
*/
|
||||
var NAVIGATE_HOME_ACTION = null;
|
||||
|
||||
// Assign home page action once user's home page has been determined
|
||||
userPageService.getHomePage()
|
||||
.then(function homePageRetrieved(homePage) {
|
||||
|
||||
// Define home action only if different from current location
|
||||
if ($location.path() !== homePage.url) {
|
||||
NAVIGATE_HOME_ACTION = {
|
||||
name : "CLIENT.ACTION_NAVIGATE_HOME",
|
||||
className : "home button",
|
||||
callback : function navigateHomeCallback() {
|
||||
$location.url(homePage.url);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}, requestService.WARN);
|
||||
|
||||
/**
|
||||
* Action which replaces the current client with a newly-connected client.
|
||||
*/
|
||||
var RECONNECT_ACTION = {
|
||||
name : "CLIENT.ACTION_RECONNECT",
|
||||
className : "reconnect button",
|
||||
callback : function reconnectCallback() {
|
||||
$scope.client = guacClientManager.replaceManagedClient($routeParams.id);
|
||||
guacNotification.showStatus(false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The reconnect countdown to display if an error or status warrants an
|
||||
* automatic, timed reconnect.
|
||||
*/
|
||||
var RECONNECT_COUNTDOWN = {
|
||||
text: "CLIENT.TEXT_RECONNECT_COUNTDOWN",
|
||||
callback: RECONNECT_ACTION.callback,
|
||||
remaining: 15
|
||||
};
|
||||
|
||||
/**
|
||||
* Menu-specific properties.
|
||||
*/
|
||||
@@ -716,31 +591,6 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
|
||||
$scope.page.title = title;
|
||||
});
|
||||
|
||||
/**
|
||||
* Displays a notification at the end of a Guacamole connection, whether
|
||||
* that connection is ending normally or due to an error. As the end of
|
||||
* a Guacamole connection may be due to changes in authentication status,
|
||||
* this will also implicitly peform a re-authentication attempt to check
|
||||
* for such changes, possibly resulting in auth-related events like
|
||||
* guacInvalidCredentials.
|
||||
*
|
||||
* @param {Notification|Boolean|Object} status
|
||||
* The status notification to show, as would be accepted by
|
||||
* guacNotification.showStatus().
|
||||
*/
|
||||
var notifyConnectionClosed = function notifyConnectionClosed(status) {
|
||||
|
||||
// Re-authenticate to verify auth status at end of connection
|
||||
authenticationService.updateCurrentToken($location.search())
|
||||
['catch'](requestService.IGNORE)
|
||||
|
||||
// Show the requested status once the authentication check has finished
|
||||
['finally'](function authenticationCheckComplete() {
|
||||
guacNotification.showStatus(status);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether the current connection has been flagged as unstable due
|
||||
* to an apparent network disruption.
|
||||
@@ -761,215 +611,6 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Notifies the user that the connection state has changed.
|
||||
*
|
||||
* @param {String} connectionState
|
||||
* The current connection state, as defined by
|
||||
* ManagedClientState.ConnectionState.
|
||||
*/
|
||||
var notifyConnectionState = function notifyConnectionState(connectionState) {
|
||||
|
||||
// Hide any existing status
|
||||
guacNotification.showStatus(false);
|
||||
|
||||
// Do not display status if status not known
|
||||
if (!connectionState)
|
||||
return;
|
||||
|
||||
// Build array of available actions
|
||||
var actions;
|
||||
if (NAVIGATE_HOME_ACTION)
|
||||
actions = [ NAVIGATE_HOME_ACTION, RECONNECT_ACTION, LOGOUT_ACTION ];
|
||||
else
|
||||
actions = [ RECONNECT_ACTION, LOGOUT_ACTION ];
|
||||
|
||||
// Get any associated status code
|
||||
var status = $scope.client.clientState.statusCode;
|
||||
|
||||
// Connecting
|
||||
if (connectionState === ManagedClientState.ConnectionState.CONNECTING
|
||||
|| connectionState === ManagedClientState.ConnectionState.WAITING) {
|
||||
guacNotification.showStatus({
|
||||
title: "CLIENT.DIALOG_HEADER_CONNECTING",
|
||||
text: {
|
||||
key : "CLIENT.TEXT_CLIENT_STATUS_" + connectionState.toUpperCase()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Client error
|
||||
else if (connectionState === ManagedClientState.ConnectionState.CLIENT_ERROR) {
|
||||
|
||||
// Determine translation name of error
|
||||
var errorName = (status in CLIENT_ERRORS) ? status.toString(16).toUpperCase() : "DEFAULT";
|
||||
|
||||
// Determine whether the reconnect countdown applies
|
||||
var countdown = (status in CLIENT_AUTO_RECONNECT) ? RECONNECT_COUNTDOWN : null;
|
||||
|
||||
// Show error status
|
||||
notifyConnectionClosed({
|
||||
className : "error",
|
||||
title : "CLIENT.DIALOG_HEADER_CONNECTION_ERROR",
|
||||
text : {
|
||||
key : "CLIENT.ERROR_CLIENT_" + errorName
|
||||
},
|
||||
countdown : countdown,
|
||||
actions : actions
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Tunnel error
|
||||
else if (connectionState === ManagedClientState.ConnectionState.TUNNEL_ERROR) {
|
||||
|
||||
// Determine translation name of error
|
||||
var errorName = (status in TUNNEL_ERRORS) ? status.toString(16).toUpperCase() : "DEFAULT";
|
||||
|
||||
// Determine whether the reconnect countdown applies
|
||||
var countdown = (status in TUNNEL_AUTO_RECONNECT) ? RECONNECT_COUNTDOWN : null;
|
||||
|
||||
// Show error status
|
||||
notifyConnectionClosed({
|
||||
className : "error",
|
||||
title : "CLIENT.DIALOG_HEADER_CONNECTION_ERROR",
|
||||
text : {
|
||||
key : "CLIENT.ERROR_TUNNEL_" + errorName
|
||||
},
|
||||
countdown : countdown,
|
||||
actions : actions
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Disconnected
|
||||
else if (connectionState === ManagedClientState.ConnectionState.DISCONNECTED) {
|
||||
notifyConnectionClosed({
|
||||
title : "CLIENT.DIALOG_HEADER_DISCONNECTED",
|
||||
text : {
|
||||
key : "CLIENT.TEXT_CLIENT_STATUS_" + connectionState.toUpperCase()
|
||||
},
|
||||
actions : actions
|
||||
});
|
||||
}
|
||||
|
||||
// Hide status and sync local clipboard once connected
|
||||
else if (connectionState === ManagedClientState.ConnectionState.CONNECTED) {
|
||||
|
||||
// Sync with local clipboard
|
||||
clipboardService.getLocalClipboard().then(function clipboardRead(data) {
|
||||
$scope.$broadcast('guacClipboard', data);
|
||||
}, angular.noop);
|
||||
|
||||
// Hide status notification
|
||||
guacNotification.showStatus(false);
|
||||
|
||||
}
|
||||
|
||||
// Hide status for all other states
|
||||
else
|
||||
guacNotification.showStatus(false);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Prompts the user to enter additional connection parameters. If the
|
||||
* protocol and associated parameters of the underlying connection are not
|
||||
* yet known, this function has no effect and should be re-invoked once
|
||||
* the parameters are known.
|
||||
*
|
||||
* @param {Object.<String, String>} requiredParameters
|
||||
* The set of all parameters requested by the server via "required"
|
||||
* instructions, where each object key is the name of a requested
|
||||
* parameter and each value is the current value entered by the user.
|
||||
*/
|
||||
var notifyParametersRequired = function notifyParametersRequired(requiredParameters) {
|
||||
|
||||
/**
|
||||
* Action which submits the current set of parameter values, requesting
|
||||
* that the connection continue.
|
||||
*/
|
||||
var SUBMIT_PARAMETERS = {
|
||||
name : "CLIENT.ACTION_CONTINUE",
|
||||
className : "button",
|
||||
callback : function submitParameters() {
|
||||
if ($scope.client) {
|
||||
var params = $scope.client.requiredParameters;
|
||||
$scope.client.requiredParameters = null;
|
||||
ManagedClient.sendArguments($scope.client, params);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Action which cancels submission of additional parameters and
|
||||
* disconnects from the current connection.
|
||||
*/
|
||||
var CANCEL_PARAMETER_SUBMISSION = {
|
||||
name : "CLIENT.ACTION_CANCEL",
|
||||
className : "button",
|
||||
callback : function cancelSubmission() {
|
||||
$scope.client.requiredParameters = null;
|
||||
$scope.disconnect();
|
||||
}
|
||||
};
|
||||
|
||||
// Attempt to prompt for parameters only if the parameters that apply
|
||||
// to the underlying connection are known
|
||||
if (!$scope.client.protocol || !$scope.client.forms)
|
||||
return;
|
||||
|
||||
// Hide any existing status
|
||||
guacNotification.showStatus(false);
|
||||
|
||||
// Prompt for parameters
|
||||
guacNotification.showStatus({
|
||||
formNamespace : Protocol.getNamespace($scope.client.protocol),
|
||||
forms : $scope.client.forms,
|
||||
formModel : requiredParameters,
|
||||
formSubmitCallback : SUBMIT_PARAMETERS.callback,
|
||||
actions : [ SUBMIT_PARAMETERS, CANCEL_PARAMETER_SUBMISSION ]
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether the given connection state allows for submission of
|
||||
* connection parameters via "argv" instructions.
|
||||
*
|
||||
* @param {String} connectionState
|
||||
* The connection state to test, as defined by
|
||||
* ManagedClientState.ConnectionState.
|
||||
*
|
||||
* @returns {boolean}
|
||||
* true if the given connection state allows submission of connection
|
||||
* parameters via "argv" instructions, false otherwise.
|
||||
*/
|
||||
var canSubmitParameters = function canSubmitParameters(connectionState) {
|
||||
return (connectionState === ManagedClientState.ConnectionState.WAITING ||
|
||||
connectionState === ManagedClientState.ConnectionState.CONNECTED);
|
||||
};
|
||||
|
||||
// Show status dialog when connection status changes
|
||||
$scope.$watchGroup([
|
||||
'client.clientState.connectionState',
|
||||
'client.requiredParameters',
|
||||
'client.protocol',
|
||||
'client.forms'
|
||||
], function clientStateChanged(newValues) {
|
||||
|
||||
var connectionState = newValues[0];
|
||||
var requiredParameters = newValues[1];
|
||||
|
||||
// Prompt for parameters only if parameters can actually be submitted
|
||||
if (requiredParameters && canSubmitParameters(connectionState))
|
||||
notifyParametersRequired(requiredParameters);
|
||||
|
||||
// Otherwise, just show general connection state
|
||||
else
|
||||
notifyConnectionState(connectionState);
|
||||
|
||||
});
|
||||
|
||||
$scope.zoomIn = function zoomIn() {
|
||||
$scope.menu.autoFit = false;
|
||||
|
@@ -0,0 +1,431 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A directive for displaying a non-global notification describing the status
|
||||
* of a specific Guacamole client, including prompts for any information
|
||||
* necessary to continue the connection.
|
||||
*/
|
||||
angular.module('client').directive('guacClientNotification', [function guacClientNotification() {
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'app/client/templates/guacClientNotification.html'
|
||||
};
|
||||
|
||||
directive.scope = {
|
||||
|
||||
/**
|
||||
* The client whose status should be displayed.
|
||||
*
|
||||
* @type ManagedClient
|
||||
*/
|
||||
client : '='
|
||||
|
||||
};
|
||||
|
||||
directive.controller = ['$scope', '$injector', '$element',
|
||||
function guacClientNotificationController($scope, $injector, $element) {
|
||||
|
||||
// Required types
|
||||
var ManagedClient = $injector.get('ManagedClient');
|
||||
var ManagedClientState = $injector.get('ManagedClientState');
|
||||
var Protocol = $injector.get('Protocol');
|
||||
|
||||
// Required services
|
||||
var $location = $injector.get('$location');
|
||||
var authenticationService = $injector.get('authenticationService');
|
||||
var guacClientManager = $injector.get('guacClientManager');
|
||||
var requestService = $injector.get('requestService');
|
||||
var userPageService = $injector.get('userPageService');
|
||||
|
||||
/**
|
||||
* A Notification object describing the client status to display as a
|
||||
* dialog or prompt, as would be accepted by guacNotification.showStatus(),
|
||||
* or false if no status should be shown.
|
||||
*
|
||||
* @type {Notification|Object|Boolean}
|
||||
*/
|
||||
$scope.status = false;
|
||||
|
||||
/**
|
||||
* All client error codes handled and passed off for translation. Any error
|
||||
* code not present in this list will be represented by the "DEFAULT"
|
||||
* translation.
|
||||
*/
|
||||
var CLIENT_ERRORS = {
|
||||
0x0201: true,
|
||||
0x0202: true,
|
||||
0x0203: true,
|
||||
0x0207: true,
|
||||
0x0208: true,
|
||||
0x0209: true,
|
||||
0x020A: true,
|
||||
0x020B: true,
|
||||
0x0301: true,
|
||||
0x0303: true,
|
||||
0x0308: true,
|
||||
0x031D: true
|
||||
};
|
||||
|
||||
/**
|
||||
* All error codes for which automatic reconnection is appropriate when a
|
||||
* client error occurs.
|
||||
*/
|
||||
var CLIENT_AUTO_RECONNECT = {
|
||||
0x0200: true,
|
||||
0x0202: true,
|
||||
0x0203: true,
|
||||
0x0207: true,
|
||||
0x0208: true,
|
||||
0x0301: true,
|
||||
0x0308: true
|
||||
};
|
||||
|
||||
/**
|
||||
* All tunnel error codes handled and passed off for translation. Any error
|
||||
* code not present in this list will be represented by the "DEFAULT"
|
||||
* translation.
|
||||
*/
|
||||
var TUNNEL_ERRORS = {
|
||||
0x0201: true,
|
||||
0x0202: true,
|
||||
0x0203: true,
|
||||
0x0204: true,
|
||||
0x0205: true,
|
||||
0x0207: true,
|
||||
0x0208: true,
|
||||
0x0301: true,
|
||||
0x0303: true,
|
||||
0x0308: true,
|
||||
0x031D: true
|
||||
};
|
||||
|
||||
/**
|
||||
* All error codes for which automatic reconnection is appropriate when a
|
||||
* tunnel error occurs.
|
||||
*/
|
||||
var TUNNEL_AUTO_RECONNECT = {
|
||||
0x0200: true,
|
||||
0x0202: true,
|
||||
0x0203: true,
|
||||
0x0207: true,
|
||||
0x0208: true,
|
||||
0x0308: true
|
||||
};
|
||||
|
||||
/**
|
||||
* Action which logs out from Guacamole entirely.
|
||||
*/
|
||||
var LOGOUT_ACTION = {
|
||||
name : "CLIENT.ACTION_LOGOUT",
|
||||
className : "logout button",
|
||||
callback : function logoutCallback() {
|
||||
authenticationService.logout()
|
||||
['catch'](requestService.IGNORE);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Action which returns the user to the home screen. If the home page has
|
||||
* not yet been determined, this will be null.
|
||||
*/
|
||||
var NAVIGATE_HOME_ACTION = null;
|
||||
|
||||
// Assign home page action once user's home page has been determined
|
||||
userPageService.getHomePage()
|
||||
.then(function homePageRetrieved(homePage) {
|
||||
|
||||
// Define home action only if different from current location
|
||||
if ($location.path() !== homePage.url) {
|
||||
NAVIGATE_HOME_ACTION = {
|
||||
name : "CLIENT.ACTION_NAVIGATE_HOME",
|
||||
className : "home button",
|
||||
callback : function navigateHomeCallback() {
|
||||
$location.url(homePage.url);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}, requestService.WARN);
|
||||
|
||||
/**
|
||||
* Action which replaces the current client with a newly-connected client.
|
||||
*/
|
||||
var RECONNECT_ACTION = {
|
||||
name : "CLIENT.ACTION_RECONNECT",
|
||||
className : "reconnect button",
|
||||
callback : function reconnectCallback() {
|
||||
$scope.client = guacClientManager.replaceManagedClient($scope.client.id);
|
||||
$scope.status = false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The reconnect countdown to display if an error or status warrants an
|
||||
* automatic, timed reconnect.
|
||||
*/
|
||||
var RECONNECT_COUNTDOWN = {
|
||||
text: "CLIENT.TEXT_RECONNECT_COUNTDOWN",
|
||||
callback: RECONNECT_ACTION.callback,
|
||||
remaining: 15
|
||||
};
|
||||
|
||||
/**
|
||||
* Displays a notification at the end of a Guacamole connection, whether
|
||||
* that connection is ending normally or due to an error. As the end of
|
||||
* a Guacamole connection may be due to changes in authentication status,
|
||||
* this will also implicitly peform a re-authentication attempt to check
|
||||
* for such changes, possibly resulting in auth-related events like
|
||||
* guacInvalidCredentials.
|
||||
*
|
||||
* @param {Notification|Boolean|Object} status
|
||||
* The status notification to show, as would be accepted by
|
||||
* guacNotification.showStatus().
|
||||
*/
|
||||
var notifyConnectionClosed = function notifyConnectionClosed(status) {
|
||||
|
||||
// Re-authenticate to verify auth status at end of connection
|
||||
authenticationService.updateCurrentToken($location.search())
|
||||
['catch'](requestService.IGNORE)
|
||||
|
||||
// Show the requested status once the authentication check has finished
|
||||
['finally'](function authenticationCheckComplete() {
|
||||
$scope.status = status;
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Notifies the user that the connection state has changed.
|
||||
*
|
||||
* @param {String} connectionState
|
||||
* The current connection state, as defined by
|
||||
* ManagedClientState.ConnectionState.
|
||||
*/
|
||||
var notifyConnectionState = function notifyConnectionState(connectionState) {
|
||||
|
||||
// Hide any existing status
|
||||
$scope.status = false;
|
||||
|
||||
// Do not display status if status not known
|
||||
if (!connectionState)
|
||||
return;
|
||||
|
||||
// Build array of available actions
|
||||
var actions;
|
||||
if (NAVIGATE_HOME_ACTION)
|
||||
actions = [ NAVIGATE_HOME_ACTION, RECONNECT_ACTION, LOGOUT_ACTION ];
|
||||
else
|
||||
actions = [ RECONNECT_ACTION, LOGOUT_ACTION ];
|
||||
|
||||
// Get any associated status code
|
||||
var status = $scope.client.clientState.statusCode;
|
||||
|
||||
// Connecting
|
||||
if (connectionState === ManagedClientState.ConnectionState.CONNECTING
|
||||
|| connectionState === ManagedClientState.ConnectionState.WAITING) {
|
||||
$scope.status = {
|
||||
title: "CLIENT.DIALOG_HEADER_CONNECTING",
|
||||
text: {
|
||||
key : "CLIENT.TEXT_CLIENT_STATUS_" + connectionState.toUpperCase()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Client error
|
||||
else if (connectionState === ManagedClientState.ConnectionState.CLIENT_ERROR) {
|
||||
|
||||
// Determine translation name of error
|
||||
var errorName = (status in CLIENT_ERRORS) ? status.toString(16).toUpperCase() : "DEFAULT";
|
||||
|
||||
// Determine whether the reconnect countdown applies
|
||||
var countdown = (status in CLIENT_AUTO_RECONNECT) ? RECONNECT_COUNTDOWN : null;
|
||||
|
||||
// Show error status
|
||||
notifyConnectionClosed({
|
||||
className : "error",
|
||||
title : "CLIENT.DIALOG_HEADER_CONNECTION_ERROR",
|
||||
text : {
|
||||
key : "CLIENT.ERROR_CLIENT_" + errorName
|
||||
},
|
||||
countdown : countdown,
|
||||
actions : actions
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Tunnel error
|
||||
else if (connectionState === ManagedClientState.ConnectionState.TUNNEL_ERROR) {
|
||||
|
||||
// Determine translation name of error
|
||||
var errorName = (status in TUNNEL_ERRORS) ? status.toString(16).toUpperCase() : "DEFAULT";
|
||||
|
||||
// Determine whether the reconnect countdown applies
|
||||
var countdown = (status in TUNNEL_AUTO_RECONNECT) ? RECONNECT_COUNTDOWN : null;
|
||||
|
||||
// Show error status
|
||||
notifyConnectionClosed({
|
||||
className : "error",
|
||||
title : "CLIENT.DIALOG_HEADER_CONNECTION_ERROR",
|
||||
text : {
|
||||
key : "CLIENT.ERROR_TUNNEL_" + errorName
|
||||
},
|
||||
countdown : countdown,
|
||||
actions : actions
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Disconnected
|
||||
else if (connectionState === ManagedClientState.ConnectionState.DISCONNECTED) {
|
||||
notifyConnectionClosed({
|
||||
title : "CLIENT.DIALOG_HEADER_DISCONNECTED",
|
||||
text : {
|
||||
key : "CLIENT.TEXT_CLIENT_STATUS_" + connectionState.toUpperCase()
|
||||
},
|
||||
actions : actions
|
||||
});
|
||||
}
|
||||
|
||||
// Hide status and sync local clipboard once connected
|
||||
else if (connectionState === ManagedClientState.ConnectionState.CONNECTED) {
|
||||
|
||||
// TODO: Move clipboard sync elsewhere
|
||||
|
||||
// Sync with local clipboard
|
||||
/*
|
||||
clipboardService.getLocalClipboard().then(function clipboardRead(data) {
|
||||
$scope.$broadcast('guacClipboard', data);
|
||||
}, angular.noop);
|
||||
*/
|
||||
|
||||
// Hide status notification
|
||||
$scope.status = false;
|
||||
|
||||
}
|
||||
|
||||
// Hide status for all other states
|
||||
else
|
||||
$scope.status = false;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Prompts the user to enter additional connection parameters. If the
|
||||
* protocol and associated parameters of the underlying connection are not
|
||||
* yet known, this function has no effect and should be re-invoked once
|
||||
* the parameters are known.
|
||||
*
|
||||
* @param {Object.<String, String>} requiredParameters
|
||||
* The set of all parameters requested by the server via "required"
|
||||
* instructions, where each object key is the name of a requested
|
||||
* parameter and each value is the current value entered by the user.
|
||||
*/
|
||||
var notifyParametersRequired = function notifyParametersRequired(requiredParameters) {
|
||||
|
||||
/**
|
||||
* Action which submits the current set of parameter values, requesting
|
||||
* that the connection continue.
|
||||
*/
|
||||
var SUBMIT_PARAMETERS = {
|
||||
name : "CLIENT.ACTION_CONTINUE",
|
||||
className : "button",
|
||||
callback : function submitParameters() {
|
||||
if ($scope.client) {
|
||||
var params = $scope.client.requiredParameters;
|
||||
$scope.client.requiredParameters = null;
|
||||
ManagedClient.sendArguments($scope.client, params);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Action which cancels submission of additional parameters and
|
||||
* disconnects from the current connection.
|
||||
*/
|
||||
var CANCEL_PARAMETER_SUBMISSION = {
|
||||
name : "CLIENT.ACTION_CANCEL",
|
||||
className : "button",
|
||||
callback : function cancelSubmission() {
|
||||
$scope.client.requiredParameters = null;
|
||||
$scope.disconnect();
|
||||
}
|
||||
};
|
||||
|
||||
// Attempt to prompt for parameters only if the parameters that apply
|
||||
// to the underlying connection are known
|
||||
if (!$scope.client.protocol || !$scope.client.forms)
|
||||
return;
|
||||
|
||||
// Prompt for parameters
|
||||
$scope.status = {
|
||||
formNamespace : Protocol.getNamespace($scope.client.protocol),
|
||||
forms : $scope.client.forms,
|
||||
formModel : requiredParameters,
|
||||
formSubmitCallback : SUBMIT_PARAMETERS.callback,
|
||||
actions : [ SUBMIT_PARAMETERS, CANCEL_PARAMETER_SUBMISSION ]
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether the given connection state allows for submission of
|
||||
* connection parameters via "argv" instructions.
|
||||
*
|
||||
* @param {String} connectionState
|
||||
* The connection state to test, as defined by
|
||||
* ManagedClientState.ConnectionState.
|
||||
*
|
||||
* @returns {boolean}
|
||||
* true if the given connection state allows submission of connection
|
||||
* parameters via "argv" instructions, false otherwise.
|
||||
*/
|
||||
var canSubmitParameters = function canSubmitParameters(connectionState) {
|
||||
return (connectionState === ManagedClientState.ConnectionState.WAITING ||
|
||||
connectionState === ManagedClientState.ConnectionState.CONNECTED);
|
||||
};
|
||||
|
||||
// Show status dialog when connection status changes
|
||||
$scope.$watchGroup([
|
||||
'client.clientState.connectionState',
|
||||
'client.requiredParameters',
|
||||
'client.protocol',
|
||||
'client.forms'
|
||||
], function clientStateChanged(newValues) {
|
||||
|
||||
var connectionState = newValues[0];
|
||||
var requiredParameters = newValues[1];
|
||||
|
||||
// Prompt for parameters only if parameters can actually be submitted
|
||||
if (requiredParameters && canSubmitParameters(connectionState))
|
||||
notifyParametersRequired(requiredParameters);
|
||||
|
||||
// Otherwise, just show general connection state
|
||||
else
|
||||
notifyConnectionState(connectionState);
|
||||
|
||||
});
|
||||
|
||||
}];
|
||||
|
||||
return directive;
|
||||
|
||||
}]);
|
@@ -17,7 +17,60 @@
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
.client .notification .parameters h3,
|
||||
.client .notification .parameters .password-field .toggle-password {
|
||||
.client-status-modal {
|
||||
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
display: none;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
|
||||
}
|
||||
|
||||
.client-status-modal.shown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.client-status-modal guac-modal {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.client-status-modal .notification {
|
||||
background: rgba(80, 80, 80, 0.4);
|
||||
color: white;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
padding: 1em;
|
||||
text-align: center;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.client-status-modal .notification .title-bar {
|
||||
display: none
|
||||
}
|
||||
|
||||
.client-status-modal .notification .button {
|
||||
background: transparent;
|
||||
border: 2px solid white;
|
||||
box-shadow: none;
|
||||
text-shadow: none;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.client-status-modal .notification .button:hover {
|
||||
text-decoration: underline;
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
.client-status-modal .notification .button:active {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.client-status-modal .notification .parameters h3,
|
||||
.client-status-modal .notification .parameters .password-field .toggle-password {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,5 @@
|
||||
<div class="client-status-modal" ng-class="{ shown: status }">
|
||||
<guac-modal>
|
||||
<guac-notification notification="status"></guac-notification>
|
||||
</guac-modal>
|
||||
</div>
|
@@ -8,6 +8,10 @@
|
||||
|
||||
<h3>{{ getClientTitle(client) }}</h3>
|
||||
<guac-client client="client"></guac-client>
|
||||
|
||||
<!-- Client-specific status/error dialog -->
|
||||
<guac-client-notification client="client"></guac-client-notification>
|
||||
|
||||
</li>
|
||||
|
||||
</ul>
|
Reference in New Issue
Block a user