mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 21:27:40 +00:00
GUACAMOLE-78: Merge anonymous user display refinements.
This commit is contained in:
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
package org.apache.guacamole.auth.jdbc.sharing.user;
|
package org.apache.guacamole.auth.jdbc.sharing.user;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser;
|
import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser;
|
||||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||||
@@ -61,7 +60,8 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser {
|
|||||||
/**
|
/**
|
||||||
* Creates a new SharedAuthenticatedUser associating the given user with
|
* Creates a new SharedAuthenticatedUser associating the given user with
|
||||||
* their corresponding credentials and share key. The identifier (username)
|
* their corresponding credentials and share key. The identifier (username)
|
||||||
* of the user will be randomly generated.
|
* of the user will be the standard identifier for anonymous users as
|
||||||
|
* defined by the Guacamole extension API.
|
||||||
*
|
*
|
||||||
* @param authenticationProvider
|
* @param authenticationProvider
|
||||||
* The AuthenticationProvider that has authenticated the given user.
|
* The AuthenticationProvider that has authenticated the given user.
|
||||||
@@ -77,7 +77,7 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser {
|
|||||||
Credentials credentials, String shareKey) {
|
Credentials credentials, String shareKey) {
|
||||||
super(authenticationProvider, credentials);
|
super(authenticationProvider, credentials);
|
||||||
this.shareKey = shareKey;
|
this.shareKey = shareKey;
|
||||||
this.identifier = UUID.randomUUID().toString();
|
this.identifier = AuthenticatedUser.ANONYMOUS_IDENTIFIER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -28,6 +28,12 @@ package org.apache.guacamole.net.auth;
|
|||||||
*/
|
*/
|
||||||
public interface AuthenticatedUser extends Identifiable {
|
public interface AuthenticatedUser extends Identifiable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifier reserved for representing a user that has authenticated
|
||||||
|
* anonymously.
|
||||||
|
*/
|
||||||
|
public static final String ANONYMOUS_IDENTIFIER = "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the AuthenticationProvider that authenticated this user.
|
* Returns the AuthenticationProvider that authenticated this user.
|
||||||
*
|
*
|
||||||
|
@@ -42,7 +42,8 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
function authenticationService($injector) {
|
function authenticationService($injector) {
|
||||||
|
|
||||||
// Required types
|
// Required types
|
||||||
var Error = $injector.get('Error');
|
var AuthenticationResult = $injector.get('AuthenticationResult');
|
||||||
|
var Error = $injector.get('Error');
|
||||||
|
|
||||||
// Required services
|
// Required services
|
||||||
var $cookieStore = $injector.get('$cookieStore');
|
var $cookieStore = $injector.get('$cookieStore');
|
||||||
@@ -53,13 +54,84 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
var service = {};
|
var service = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The unique identifier of the local cookie which stores the user's
|
* The most recent authentication result, or null if no authentication
|
||||||
* current authentication token and username.
|
* result is cached.
|
||||||
|
*
|
||||||
|
* @type AuthenticationResult
|
||||||
|
*/
|
||||||
|
var cachedResult = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique identifier of the local cookie which stores the result of the
|
||||||
|
* last authentication attempt.
|
||||||
*
|
*
|
||||||
* @type String
|
* @type String
|
||||||
*/
|
*/
|
||||||
var AUTH_COOKIE_ID = "GUAC_AUTH";
|
var AUTH_COOKIE_ID = "GUAC_AUTH";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the last successful authentication result. If the user has not
|
||||||
|
* yet authenticated, the user has logged out, or the last authentication
|
||||||
|
* attempt failed, null is returned.
|
||||||
|
*
|
||||||
|
* @returns {AuthenticationResult}
|
||||||
|
* The last successful authentication result, or null if the user is not
|
||||||
|
* currently authenticated.
|
||||||
|
*/
|
||||||
|
var getAuthenticationResult = function getAuthenticationResult() {
|
||||||
|
|
||||||
|
// Use cached result, if any
|
||||||
|
if (cachedResult)
|
||||||
|
return cachedResult;
|
||||||
|
|
||||||
|
// Return explicit null if no auth data is currently stored
|
||||||
|
var data = $cookieStore.get(AUTH_COOKIE_ID);
|
||||||
|
if (!data)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Update cache and return retrieved auth result
|
||||||
|
return (cachedResult = new AuthenticationResult(data));
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the given authentication result for future retrieval. The given
|
||||||
|
* result MUST be the result of the most recent authentication attempt.
|
||||||
|
*
|
||||||
|
* @param {AuthenticationResult} data
|
||||||
|
* The last successful authentication result, or null if the last
|
||||||
|
* authentication attempt failed.
|
||||||
|
*/
|
||||||
|
var setAuthenticationResult = function setAuthenticationResult(data) {
|
||||||
|
|
||||||
|
// Clear the currently-stored result if the last attempt failed
|
||||||
|
if (!data) {
|
||||||
|
cachedResult = null;
|
||||||
|
$cookieStore.remove(AUTH_COOKIE_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise store the authentication attempt directly
|
||||||
|
else {
|
||||||
|
|
||||||
|
// Always store in cache
|
||||||
|
cachedResult = data;
|
||||||
|
|
||||||
|
// Store cookie ONLY if not anonymous
|
||||||
|
if (data.username !== AuthenticationResult.ANONYMOUS_USERNAME)
|
||||||
|
$cookieStore.put(AUTH_COOKIE_ID, data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the stored authentication result, if any. If no authentication
|
||||||
|
* result is currently stored, this function has no effect.
|
||||||
|
*/
|
||||||
|
var clearAuthenticationResult = function clearAuthenticationResult() {
|
||||||
|
setAuthenticationResult(null);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a request to authenticate a user using the token REST API endpoint
|
* Makes a request to authenticate a user using the token REST API endpoint
|
||||||
* and given arbitrary parameters, returning a promise that succeeds only
|
* and given arbitrary parameters, returning a promise that succeeds only
|
||||||
@@ -95,12 +167,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
var completeAuthentication = function completeAuthentication(data) {
|
var completeAuthentication = function completeAuthentication(data) {
|
||||||
|
|
||||||
// Store auth data
|
// Store auth data
|
||||||
$cookieStore.put(AUTH_COOKIE_ID, {
|
setAuthenticationResult(new AuthenticationResult(data));
|
||||||
'authToken' : data.authToken,
|
|
||||||
'username' : data.username,
|
|
||||||
'dataSource' : data.dataSource,
|
|
||||||
'availableDataSources' : data.availableDataSources
|
|
||||||
});
|
|
||||||
|
|
||||||
// Process is complete
|
// Process is complete
|
||||||
authenticationProcess.resolve();
|
authenticationProcess.resolve();
|
||||||
@@ -114,7 +181,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
},
|
},
|
||||||
data: $.param(parameters),
|
data: $.param(parameters)
|
||||||
})
|
})
|
||||||
|
|
||||||
// If authentication succeeds, handle received auth data
|
// If authentication succeeds, handle received auth data
|
||||||
@@ -243,7 +310,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
|
|
||||||
// Clear authentication data
|
// Clear authentication data
|
||||||
var token = service.getCurrentToken();
|
var token = service.getCurrentToken();
|
||||||
$cookieStore.remove(AUTH_COOKIE_ID);
|
clearAuthenticationResult();
|
||||||
|
|
||||||
// Notify listeners that a token is being destroyed
|
// Notify listeners that a token is being destroyed
|
||||||
$rootScope.$broadcast('guacLogout', token);
|
$rootScope.$broadcast('guacLogout', token);
|
||||||
@@ -256,6 +323,19 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current user has authenticated anonymously. An
|
||||||
|
* anonymous user is denoted by the identifier reserved by the Guacamole
|
||||||
|
* extension API for anonymous users (the empty string).
|
||||||
|
*
|
||||||
|
* @returns {Boolean}
|
||||||
|
* true if the current user has authenticated anonymously, false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
service.isAnonymous = function isAnonymous() {
|
||||||
|
return service.getCurrentUsername() === '';
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the username of the current user. If the current user is not
|
* Returns the username of the current user. If the current user is not
|
||||||
* logged in, this value may not be valid.
|
* logged in, this value may not be valid.
|
||||||
@@ -267,7 +347,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
service.getCurrentUsername = function getCurrentUsername() {
|
service.getCurrentUsername = function getCurrentUsername() {
|
||||||
|
|
||||||
// Return username, if available
|
// Return username, if available
|
||||||
var authData = $cookieStore.get(AUTH_COOKIE_ID);
|
var authData = getAuthenticationResult();
|
||||||
if (authData)
|
if (authData)
|
||||||
return authData.username;
|
return authData.username;
|
||||||
|
|
||||||
@@ -287,7 +367,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
service.getCurrentToken = function getCurrentToken() {
|
service.getCurrentToken = function getCurrentToken() {
|
||||||
|
|
||||||
// Return auth token, if available
|
// Return auth token, if available
|
||||||
var authData = $cookieStore.get(AUTH_COOKIE_ID);
|
var authData = getAuthenticationResult();
|
||||||
if (authData)
|
if (authData)
|
||||||
return authData.authToken;
|
return authData.authToken;
|
||||||
|
|
||||||
@@ -307,7 +387,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
service.getDataSource = function getDataSource() {
|
service.getDataSource = function getDataSource() {
|
||||||
|
|
||||||
// Return data source, if available
|
// Return data source, if available
|
||||||
var authData = $cookieStore.get(AUTH_COOKIE_ID);
|
var authData = getAuthenticationResult();
|
||||||
if (authData)
|
if (authData)
|
||||||
return authData.dataSource;
|
return authData.dataSource;
|
||||||
|
|
||||||
@@ -327,7 +407,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
service.getAvailableDataSources = function getAvailableDataSources() {
|
service.getAvailableDataSources = function getAvailableDataSources() {
|
||||||
|
|
||||||
// Return data sources, if available
|
// Return data sources, if available
|
||||||
var authData = $cookieStore.get(AUTH_COOKIE_ID);
|
var authData = getAuthenticationResult();
|
||||||
if (authData)
|
if (authData)
|
||||||
return authData.availableDataSources;
|
return authData.availableDataSources;
|
||||||
|
|
||||||
|
@@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service which defines the AuthenticationResult class.
|
||||||
|
*/
|
||||||
|
angular.module('auth').factory('AuthenticationResult', [function defineAuthenticationResult() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object returned by REST API calls when representing the successful
|
||||||
|
* result of an authentication attempt.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @param {AuthenticationResult|Object} [template={}]
|
||||||
|
* The object whose properties should be copied within the new
|
||||||
|
* AuthenticationResult.
|
||||||
|
*/
|
||||||
|
var AuthenticationResult = function AuthenticationResult(template) {
|
||||||
|
|
||||||
|
// Use empty object by default
|
||||||
|
template = template || {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique token generated for the user that authenticated.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
this.authToken = template.authToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name which uniquely identifies the user that authenticated.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
this.username = template.username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique identifier of the data source which authenticated the
|
||||||
|
* user.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
this.dataSource = template.dataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifiers of all data sources available to the user that
|
||||||
|
* authenticated.
|
||||||
|
*
|
||||||
|
* @type String[]
|
||||||
|
*/
|
||||||
|
this.availableDataSources = template.availableDataSources;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The username reserved by the Guacamole extension API for users which have
|
||||||
|
* authenticated anonymously.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
AuthenticationResult.ANONYMOUS_USERNAME = '';
|
||||||
|
|
||||||
|
return AuthenticationResult;
|
||||||
|
|
||||||
|
}]);
|
@@ -88,7 +88,7 @@ angular.module('index').config(['$routeProvider', '$locationProvider',
|
|||||||
|
|
||||||
// Otherwise, reject and reroute
|
// Otherwise, reject and reroute
|
||||||
else {
|
else {
|
||||||
$location.url(homePage.url);
|
$location.path(homePage.url);
|
||||||
route.reject();
|
route.reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* 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 which graphically represents an individual user.
|
||||||
|
*/
|
||||||
|
angular.module('list').directive('guacUserItem', [function guacUserItem() {
|
||||||
|
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
replace: true,
|
||||||
|
scope: {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The username of the user represented by this guacUserItem.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
username : '='
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
templateUrl: 'app/list/templates/guacUserItem.html',
|
||||||
|
controller: ['$scope', '$injector',
|
||||||
|
function guacUserItemController($scope, $injector) {
|
||||||
|
|
||||||
|
// Required types
|
||||||
|
var AuthenticationResult = $injector.get('AuthenticationResult');
|
||||||
|
|
||||||
|
// Required services
|
||||||
|
var $translate = $injector.get('$translate');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The string to display when listing the user having the provided
|
||||||
|
* username. Generally, this will be the username itself, but can
|
||||||
|
* also be an arbitrary human-readable representation of the user,
|
||||||
|
* or null if the display name is not yet determined.
|
||||||
|
*
|
||||||
|
* @type String
|
||||||
|
*/
|
||||||
|
$scope.displayName = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the username provided to this directive denotes
|
||||||
|
* a user that authenticated anonymously.
|
||||||
|
*
|
||||||
|
* @returns {Boolean}
|
||||||
|
* true if the username provided represents an anonymous user,
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
|
$scope.isAnonymous = function isAnonymous() {
|
||||||
|
return $scope.username === AuthenticationResult.ANONYMOUS_USERNAME;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update display name whenever provided username changes
|
||||||
|
$scope.$watch('username', function updateDisplayName(username) {
|
||||||
|
|
||||||
|
// If the user is anonymous, pull the display name for anonymous
|
||||||
|
// users from the translation service
|
||||||
|
if ($scope.isAnonymous()) {
|
||||||
|
$translate('LIST.TEXT_ANONYMOUS_USER')
|
||||||
|
.then(function retrieveAnonymousDisplayName(anonymousDisplayName) {
|
||||||
|
$scope.displayName = anonymousDisplayName;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// For all other users, use the username verbatim
|
||||||
|
else
|
||||||
|
$scope.displayName = username;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}] // end controller
|
||||||
|
|
||||||
|
};
|
||||||
|
}]);
|
@@ -21,4 +21,6 @@
|
|||||||
* Module for displaying, sorting, and filtering the contents of a list, split
|
* Module for displaying, sorting, and filtering the contents of a list, split
|
||||||
* into multiple pages.
|
* into multiple pages.
|
||||||
*/
|
*/
|
||||||
angular.module('list', []);
|
angular.module('list', [
|
||||||
|
'auth'
|
||||||
|
]);
|
||||||
|
23
guacamole/src/main/webapp/app/list/styles/user-item.css
Normal file
23
guacamole/src/main/webapp/app/list/styles/user-item.css
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.user-item.anonymous {
|
||||||
|
font-style: italic;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
@@ -0,0 +1,3 @@
|
|||||||
|
<div class="user-item" ng-class="{'anonymous' : isAnonymous() }">
|
||||||
|
<span class="username">{{displayName}}</span>
|
||||||
|
</div>
|
@@ -75,7 +75,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr ng-repeat="wrapper in wrapperPage">
|
<tr ng-repeat="wrapper in wrapperPage">
|
||||||
<td class="username">{{wrapper.entry.username}}</td>
|
<td class="username"><guac-user-item username="wrapper.entry.username"></guac-user-item></td>
|
||||||
<td class="start">{{wrapper.entry.startDate | date:historyDateFormat}}</td>
|
<td class="start">{{wrapper.entry.startDate | date:historyDateFormat}}</td>
|
||||||
<td class="duration"
|
<td class="duration"
|
||||||
translate="{{wrapper.durationText}}"
|
translate="{{wrapper.durationText}}"
|
||||||
|
@@ -68,7 +68,18 @@ angular.module('navigation').directive('guacUserMenu', [function guacUserMenu()
|
|||||||
.then(function retrievedMainPages(pages) {
|
.then(function retrievedMainPages(pages) {
|
||||||
$scope.pages = pages;
|
$scope.pages = pages;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the current user has authenticated anonymously.
|
||||||
|
*
|
||||||
|
* @returns {Boolean}
|
||||||
|
* true if the current user has authenticated anonymously, false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
$scope.isAnonymous = function isAnonymous() {
|
||||||
|
return authenticationService.isAnonymous();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs out the current user, redirecting them to back to the root
|
* Logs out the current user, redirecting them to back to the root
|
||||||
* after logout completes.
|
* after logout completes.
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<div class="user-menu">
|
<div class="user-menu" ng-show="!isAnonymous()">
|
||||||
<guac-menu menu-title="username">
|
<guac-menu menu-title="username">
|
||||||
|
|
||||||
<!-- Local actions -->
|
<!-- Local actions -->
|
||||||
|
@@ -32,7 +32,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody ng-class="{loading: !isLoaded()}">
|
<tbody ng-class="{loading: !isLoaded()}">
|
||||||
<tr ng-repeat="historyEntryWrapper in historyEntryWrapperPage" class="history">
|
<tr ng-repeat="historyEntryWrapper in historyEntryWrapperPage" class="history">
|
||||||
<td>{{historyEntryWrapper.username}}</td>
|
<td><guac-user-item username="historyEntryWrapper.username"></guac-user-item></td>
|
||||||
<td>{{historyEntryWrapper.startDate | date : dateFormat}}</td>
|
<td>{{historyEntryWrapper.startDate | date : dateFormat}}</td>
|
||||||
<td translate="{{historyEntryWrapper.readableDurationText}}"
|
<td translate="{{historyEntryWrapper.readableDurationText}}"
|
||||||
translate-values="{VALUE: historyEntryWrapper.readableDuration.value, UNIT: historyEntryWrapper.readableDuration.unit}"></td>
|
translate-values="{VALUE: historyEntryWrapper.readableDuration.value, UNIT: historyEntryWrapper.readableDuration.unit}"></td>
|
||||||
|
@@ -37,7 +37,7 @@
|
|||||||
<td class="select-session">
|
<td class="select-session">
|
||||||
<input ng-change="wrapperSelectionChange(wrapper)" type="checkbox" ng-model="wrapper.checked" />
|
<input ng-change="wrapperSelectionChange(wrapper)" type="checkbox" ng-model="wrapper.checked" />
|
||||||
</td>
|
</td>
|
||||||
<td>{{wrapper.activeConnection.username}}</td>
|
<td><guac-user-item username="wrapper.activeConnection.username"></guac-user-item></td>
|
||||||
<td>{{wrapper.startDate}}</td>
|
<td>{{wrapper.startDate}}</td>
|
||||||
<td>{{wrapper.activeConnection.remoteHost}}</td>
|
<td>{{wrapper.activeConnection.remoteHost}}</td>
|
||||||
<td>{{wrapper.name}}</td>
|
<td>{{wrapper.name}}</td>
|
||||||
|
@@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
"INFO_ACTIVE_USER_COUNT" : "Currently in use by {USERS} {USERS, plural, one{user} other{users}}.",
|
"INFO_ACTIVE_USER_COUNT" : "Currently in use by {USERS} {USERS, plural, one{user} other{users}}.",
|
||||||
|
|
||||||
|
"TEXT_ANONYMOUS_USER" : "Anonymous",
|
||||||
"TEXT_HISTORY_DURATION" : "{VALUE} {UNIT, select, second{{VALUE, plural, one{second} other{seconds}}} minute{{VALUE, plural, one{minute} other{minutes}}} hour{{VALUE, plural, one{hour} other{hours}}} day{{VALUE, plural, one{day} other{days}}} other{}}"
|
"TEXT_HISTORY_DURATION" : "{VALUE} {UNIT, select, second{{VALUE, plural, one{second} other{seconds}}} minute{{VALUE, plural, one{minute} other{minutes}}} hour{{VALUE, plural, one{hour} other{hours}}} day{{VALUE, plural, one{day} other{days}}} other{}}"
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -166,6 +167,12 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"LIST" : {
|
||||||
|
|
||||||
|
"TEXT_ANONYMOUS_USER" : "Anonymous"
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
"LOGIN": {
|
"LOGIN": {
|
||||||
|
|
||||||
"ACTION_ACKNOWLEDGE" : "@:APP.ACTION_ACKNOWLEDGE",
|
"ACTION_ACKNOWLEDGE" : "@:APP.ACTION_ACKNOWLEDGE",
|
||||||
|
Reference in New Issue
Block a user