mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
GUACAMOLE-680: Merge do not immediately re-authenticate after logout.
This commit is contained in:
@@ -175,7 +175,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
|
|
||||||
// If an old token existed, request that the token be revoked
|
// If an old token existed, request that the token be revoked
|
||||||
if (currentToken) {
|
if (currentToken) {
|
||||||
service.logout().catch(angular.noop)
|
service.revokeToken(currentToken).catch(angular.noop);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify of login and new token
|
// Notify of login and new token
|
||||||
@@ -252,6 +252,24 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a request to revoke an authentication token using the token REST
|
||||||
|
* API endpoint, returning a promise that succeeds only if the token was
|
||||||
|
* successfully revoked.
|
||||||
|
*
|
||||||
|
* @param {string} token
|
||||||
|
* The authentication token to revoke.
|
||||||
|
*
|
||||||
|
* @returns {Promise}
|
||||||
|
* A promise which succeeds only if the token was successfully revoked.
|
||||||
|
*/
|
||||||
|
service.revokeToken = function revokeToken(token) {
|
||||||
|
return requestService({
|
||||||
|
method: 'DELETE',
|
||||||
|
url: 'api/tokens/' + token
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
* with a username and password, ignoring any currently-stored token,
|
* with a username and password, ignoring any currently-stored token,
|
||||||
@@ -276,8 +294,8 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes a request to logout a user using the login REST API endpoint,
|
* Makes a request to logout a user using the token REST API endpoint,
|
||||||
* returning a promise succeeds only if the logout operation was
|
* returning a promise that succeeds only if the logout operation was
|
||||||
* successful.
|
* successful.
|
||||||
*
|
*
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
@@ -294,10 +312,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
|
|||||||
$rootScope.$broadcast('guacLogout', token);
|
$rootScope.$broadcast('guacLogout', token);
|
||||||
|
|
||||||
// Delete old token
|
// Delete old token
|
||||||
return requestService({
|
return service.revokeToken(token);
|
||||||
method: 'DELETE',
|
|
||||||
url: 'api/tokens/' + token
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -167,10 +167,7 @@ angular.module('client').controller('clientController', ['$scope', '$routeParams
|
|||||||
className : "logout button",
|
className : "logout button",
|
||||||
callback : function logoutCallback() {
|
callback : function logoutCallback() {
|
||||||
authenticationService.logout()
|
authenticationService.logout()
|
||||||
['catch'](requestService.IGNORE)
|
['catch'](requestService.IGNORE);
|
||||||
['finally'](function logoutComplete() {
|
|
||||||
$location.url('/');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -25,6 +25,7 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
|
|||||||
|
|
||||||
// Required services
|
// Required services
|
||||||
var $document = $injector.get('$document');
|
var $document = $injector.get('$document');
|
||||||
|
var $route = $injector.get('$route');
|
||||||
var $window = $injector.get('$window');
|
var $window = $injector.get('$window');
|
||||||
var clipboardService = $injector.get('clipboardService');
|
var clipboardService = $injector.get('clipboardService');
|
||||||
var guacNotification = $injector.get('guacNotification');
|
var guacNotification = $injector.get('guacNotification');
|
||||||
@@ -50,6 +51,13 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
|
|||||||
*/
|
*/
|
||||||
$scope.loginHelpText = null;
|
$scope.loginHelpText = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the user has selected to log back in after having logged out.
|
||||||
|
*
|
||||||
|
* @type boolean
|
||||||
|
*/
|
||||||
|
$scope.reAuthenticating = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The credentials that the authentication service is has already accepted,
|
* The credentials that the authentication service is has already accepted,
|
||||||
* pending additional credentials, if any. If the user is logged in, or no
|
* pending additional credentials, if any. If the user is logged in, or no
|
||||||
@@ -69,6 +77,51 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
|
|||||||
*/
|
*/
|
||||||
$scope.expectedCredentials = null;
|
$scope.expectedCredentials = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible overall states of the client side of the web application.
|
||||||
|
*
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
|
var ApplicationState = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application has fully loaded but is awaiting credentials from
|
||||||
|
* the user before proceeding.
|
||||||
|
*/
|
||||||
|
AWAITING_CREDENTIALS : 'awaitingCredentials',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fatal error has occurred that will prevent the client side of the
|
||||||
|
* application from functioning properly.
|
||||||
|
*/
|
||||||
|
FATAL_ERROR : 'fatalError',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application has just started within the user's browser and has
|
||||||
|
* not yet settled into any specific state.
|
||||||
|
*/
|
||||||
|
LOADING : 'loading',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user has manually logged out.
|
||||||
|
*/
|
||||||
|
LOGGED_OUT : 'loggedOut',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The application has fully loaded and the user has logged in
|
||||||
|
*/
|
||||||
|
READY : 'ready'
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current overall state of the client side of the application.
|
||||||
|
* Possible values are defined by {@link ApplicationState}.
|
||||||
|
*
|
||||||
|
* @type string
|
||||||
|
*/
|
||||||
|
$scope.applicationState = ApplicationState.LOADING;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic page-level information.
|
* Basic page-level information.
|
||||||
*/
|
*/
|
||||||
@@ -103,7 +156,7 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
|
|||||||
|
|
||||||
// Do not handle key events if not logged in or if a notification is
|
// Do not handle key events if not logged in or if a notification is
|
||||||
// shown
|
// shown
|
||||||
if ($scope.expectedCredentials || guacNotification.getStatus())
|
if ($scope.applicationState !== ApplicationState.READY || guacNotification.getStatus())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Warn of pending keydown
|
// Warn of pending keydown
|
||||||
@@ -122,7 +175,7 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
|
|||||||
|
|
||||||
// Do not handle key events if not logged in or if a notification is
|
// Do not handle key events if not logged in or if a notification is
|
||||||
// shown
|
// shown
|
||||||
if ($scope.expectedCredentials || guacNotification.getStatus())
|
if ($scope.applicationState !== ApplicationState.READY || guacNotification.getStatus())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Warn of pending keyup
|
// Warn of pending keyup
|
||||||
@@ -168,32 +221,59 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
|
|||||||
|
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reloads the current route and controller, effectively forcing
|
||||||
|
* reauthentication. If the user is not logged in, this will result in
|
||||||
|
* the login screen appearing.
|
||||||
|
*/
|
||||||
|
$scope.reAuthenticate = function reAuthenticate() {
|
||||||
|
$scope.reAuthenticating = true;
|
||||||
|
$route.reload();
|
||||||
|
};
|
||||||
|
|
||||||
// Display login screen if a whole new set of credentials is needed
|
// Display login screen if a whole new set of credentials is needed
|
||||||
$scope.$on('guacInvalidCredentials', function loginInvalid(event, parameters, error) {
|
$scope.$on('guacInvalidCredentials', function loginInvalid(event, parameters, error) {
|
||||||
|
|
||||||
|
$scope.applicationState = ApplicationState.AWAITING_CREDENTIALS;
|
||||||
$scope.page.title = 'APP.NAME';
|
$scope.page.title = 'APP.NAME';
|
||||||
$scope.page.bodyClassName = '';
|
$scope.page.bodyClassName = '';
|
||||||
|
|
||||||
$scope.loginHelpText = null;
|
$scope.loginHelpText = null;
|
||||||
$scope.acceptedCredentials = {};
|
$scope.acceptedCredentials = {};
|
||||||
$scope.expectedCredentials = error.expected;
|
$scope.expectedCredentials = error.expected;
|
||||||
$scope.fatalError = null;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Prompt for remaining credentials if provided credentials were not enough
|
// Prompt for remaining credentials if provided credentials were not enough
|
||||||
$scope.$on('guacInsufficientCredentials', function loginInsufficient(event, parameters, error) {
|
$scope.$on('guacInsufficientCredentials', function loginInsufficient(event, parameters, error) {
|
||||||
|
|
||||||
|
$scope.applicationState = ApplicationState.AWAITING_CREDENTIALS;
|
||||||
$scope.page.title = 'APP.NAME';
|
$scope.page.title = 'APP.NAME';
|
||||||
$scope.page.bodyClassName = '';
|
$scope.page.bodyClassName = '';
|
||||||
|
|
||||||
$scope.loginHelpText = error.translatableMessage;
|
$scope.loginHelpText = error.translatableMessage;
|
||||||
$scope.acceptedCredentials = parameters;
|
$scope.acceptedCredentials = parameters;
|
||||||
$scope.expectedCredentials = error.expected;
|
$scope.expectedCredentials = error.expected;
|
||||||
$scope.fatalError = null;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Replace absolutely all content with an error message if the page itself
|
// Replace absolutely all content with an error message if the page itself
|
||||||
// cannot be displayed due to an error
|
// cannot be displayed due to an error
|
||||||
$scope.$on('guacFatalPageError', function fatalPageError(error) {
|
$scope.$on('guacFatalPageError', function fatalPageError(error) {
|
||||||
|
|
||||||
|
$scope.applicationState = ApplicationState.FATAL_ERROR;
|
||||||
$scope.page.title = 'APP.NAME';
|
$scope.page.title = 'APP.NAME';
|
||||||
$scope.page.bodyClassName = '';
|
$scope.page.bodyClassName = '';
|
||||||
|
|
||||||
$scope.fatalError = error;
|
$scope.fatalError = error;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Replace the overall user interface with an informational message if the
|
||||||
|
// user has manually logged out
|
||||||
|
$scope.$on('guacLogout', function loggedOut() {
|
||||||
|
$scope.applicationState = ApplicationState.LOGGED_OUT;
|
||||||
|
$scope.reAuthenticating = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ensure new pages always start with clear keyboard state
|
// Ensure new pages always start with clear keyboard state
|
||||||
@@ -209,10 +289,7 @@ angular.module('index').controller('indexController', ['$scope', '$injector',
|
|||||||
|
|
||||||
// Clear login screen if route change was successful (and thus
|
// Clear login screen if route change was successful (and thus
|
||||||
// login was either successful or not required)
|
// login was either successful or not required)
|
||||||
$scope.loginHelpText = null;
|
$scope.applicationState = ApplicationState.READY;
|
||||||
$scope.acceptedCredentials = null;
|
|
||||||
$scope.expectedCredentials = null;
|
|
||||||
$scope.fatalError = null;
|
|
||||||
|
|
||||||
// Set title
|
// Set title
|
||||||
var title = current.$$route.title;
|
var title = current.$$route.title;
|
||||||
|
27
guacamole/src/main/frontend/src/app/index/styles/cloak.css
Normal file
27
guacamole/src/main/frontend/src/app/index/styles/cloak.css
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hide portions of DOM by default until Angular has finished loading,
|
||||||
|
* compiling, etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
*[ng-cloak], .translate-cloak {
|
||||||
|
display: none !important;
|
||||||
|
}
|
@@ -17,23 +17,10 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.fatal-page-error-outer {
|
.fatal-page-error-modal guac-modal {
|
||||||
display: table;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
z-index: 30;
|
z-index: 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fatal-page-error-middle {
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fatal-page-error {
|
.fatal-page-error {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.logged-out-modal guac-modal {
|
||||||
|
background: white;
|
||||||
|
z-index: 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logged-out-modal .notification {
|
||||||
|
display: inline-block;
|
||||||
|
max-width: 3in;
|
||||||
|
width: 100%;
|
||||||
|
}
|
@@ -17,25 +17,11 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.status-outer {
|
.global-status-modal guac-modal {
|
||||||
display: table;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
background: rgba(0, 0, 0, 0.5);
|
background: rgba(0, 0, 0, 0.5);
|
||||||
z-index: 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-middle {
|
.global-status-modal .notification {
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-middle .notification {
|
|
||||||
|
|
||||||
width: 75%;
|
width: 75%;
|
||||||
max-width: 5in;
|
max-width: 5in;
|
||||||
@@ -47,34 +33,10 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-middle .notification .body {
|
.global-status-modal .notification .body {
|
||||||
margin: 1.25em;
|
margin: 1.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-middle .notification .buttons {
|
.global-status-modal .notification .buttons {
|
||||||
margin: 1em;
|
margin: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fade entire status area in/out based on shown status */
|
|
||||||
|
|
||||||
.status-outer {
|
|
||||||
visibility: hidden;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity, visibility;
|
|
||||||
transition-duration: 0.25s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shown.status-outer {
|
|
||||||
visibility: visible;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hide dialog immediately based on status */
|
|
||||||
|
|
||||||
.status-middle .notification {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shown .status-middle .notification {
|
|
||||||
visibility: visible;
|
|
||||||
}
|
|
||||||
|
@@ -36,8 +36,6 @@
|
|||||||
max-width: 3in;
|
max-width: 3in;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
border: 1px solid rgba(0, 0, 0, 0.25);
|
|
||||||
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25);
|
|
||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<div class="login-dialog-middle">
|
<div class="login-dialog-middle">
|
||||||
|
|
||||||
<div class="login-dialog">
|
<div class="login-dialog notification">
|
||||||
|
|
||||||
<form class="login-form" ng-submit="login()">
|
<form class="login-form" ng-submit="login()">
|
||||||
|
|
||||||
|
@@ -140,13 +140,7 @@ angular.module('navigation').directive('guacUserMenu', [function guacUserMenu()
|
|||||||
*/
|
*/
|
||||||
$scope.logout = function logout() {
|
$scope.logout = function logout() {
|
||||||
authenticationService.logout()
|
authenticationService.logout()
|
||||||
['catch'](requestService.IGNORE)
|
['catch'](requestService.IGNORE);
|
||||||
['finally'](function logoutComplete() {
|
|
||||||
if ($location.path() !== '/')
|
|
||||||
$location.url('/');
|
|
||||||
else
|
|
||||||
$route.reload();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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 arbitrary modal content.
|
||||||
|
*/
|
||||||
|
angular.module('notification').directive('guacModal', [function guacModal() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
templateUrl: 'app/notification/templates/guacModal.html',
|
||||||
|
transclude: true
|
||||||
|
};
|
||||||
|
}]);
|
@@ -17,78 +17,25 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.dialog-container {
|
guac-modal {
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
background: rgba(0, 0, 0, 0.5);
|
|
||||||
padding: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-outer {
|
|
||||||
display: table;
|
display: table;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
background: rgba(0, 0, 0, 0.5);
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-middle {
|
guac-modal .modal-contents {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: table-cell;
|
display: table-cell;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog.edit {
|
guac-modal {
|
||||||
max-height: 100%;
|
animation: fadein 0.125s linear;
|
||||||
}
|
-moz-animation: fadein 0.125s linear;
|
||||||
|
-webkit-animation: fadein 0.125s linear;
|
||||||
.dialog {
|
|
||||||
|
|
||||||
max-width: 100%;
|
|
||||||
width: 8in;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.5);
|
|
||||||
background: #E7E7E7;
|
|
||||||
|
|
||||||
-moz-border-radius: 0.2em;
|
|
||||||
-webkit-border-radius: 0.2em;
|
|
||||||
-khtml-border-radius: 0.2em;
|
|
||||||
border-radius: 0.2em;
|
|
||||||
|
|
||||||
box-shadow: 0.1em 0.1em 0.2em rgba(0, 0, 0, 0.6);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog > * {
|
|
||||||
margin: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog .header {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog td {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog .overlay {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog .footer {
|
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
@@ -18,8 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.notification {
|
.notification {
|
||||||
border: 1px solid rgba(0, 0, 0, 0.125);
|
border: 1px solid rgba(0, 0, 0, 0.25);
|
||||||
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.125);
|
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25);
|
||||||
background: white;
|
background: white;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,3 @@
|
|||||||
|
<div class="modal-contents">
|
||||||
|
<ng-transclude></ng-transclude>
|
||||||
|
</div>
|
@@ -38,41 +38,48 @@
|
|||||||
|
|
||||||
<title ng-bind="page.title | translate"></title>
|
<title ng-bind="page.title | translate"></title>
|
||||||
</head>
|
</head>
|
||||||
<body ng-class="page.bodyClassName">
|
<body ng-cloak translate-cloak ng-class="page.bodyClassName" ng-switch="applicationState">
|
||||||
|
|
||||||
<div ng-if="!fatalError">
|
<!-- Manually logged-out -->
|
||||||
|
<div class="logged-out-modal" ng-switch-when="loggedOut">
|
||||||
<!-- Content for logged-in users -->
|
<guac-modal>
|
||||||
<div ng-if="!expectedCredentials">
|
<div class="notification">
|
||||||
|
<p translate="APP.INFO_LOGGED_OUT"></p>
|
||||||
<!-- Global status/error dialog -->
|
<p>
|
||||||
<div ng-class="{shown: guacNotification.getStatus()}" class="status-outer">
|
<button translate="APP.ACTION_LOGIN_AGAIN" ng-disabled="reAuthenticating"
|
||||||
<div class="status-middle">
|
ng-click="reAuthenticate()"></button>
|
||||||
<guac-notification notification="guacNotification.getStatus()"></guac-notification>
|
</p>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</guac-modal>
|
||||||
<div id="content" ng-view>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Login screen for logged-out users -->
|
|
||||||
<guac-login ng-show="expectedCredentials"
|
|
||||||
help-text="loginHelpText"
|
|
||||||
form="expectedCredentials"
|
|
||||||
values="acceptedCredentials"></guac-login>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Absolute fatal error -->
|
<!-- Absolute fatal error -->
|
||||||
<div ng-if="fatalError" ng-class="{shown: fatalError}" class="fatal-page-error-outer">
|
<div class="fatal-page-error-modal" ng-switch-when="fatalError">
|
||||||
<div class="fatal-page-error-middle">
|
<guac-modal>
|
||||||
<div class="fatal-page-error">
|
<div class="fatal-page-error">
|
||||||
<h1 translate="APP.DIALOG_HEADER_ERROR"></h1>
|
<h1 translate="APP.DIALOG_HEADER_ERROR"></h1>
|
||||||
<p translate="APP.ERROR_PAGE_UNAVAILABLE"></p>
|
<p translate="APP.ERROR_PAGE_UNAVAILABLE"></p>
|
||||||
</div>
|
</div>
|
||||||
|
</guac-modal>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Login screen for logged-out users -->
|
||||||
|
<guac-login ng-switch-when="awaitingCredentials"
|
||||||
|
help-text="loginHelpText"
|
||||||
|
form="expectedCredentials"
|
||||||
|
values="acceptedCredentials"></guac-login>
|
||||||
|
|
||||||
|
<!-- Content for logged-in users -->
|
||||||
|
<div ng-switch-default>
|
||||||
|
|
||||||
|
<!-- Global status/error dialog -->
|
||||||
|
<guac-modal class="global-status-modal" ng-if="guacNotification.getStatus()">
|
||||||
|
<guac-notification notification="guacNotification.getStatus()"></guac-notification>
|
||||||
|
</guac-modal>
|
||||||
|
|
||||||
|
<div id="content" ng-view>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Polyfills -->
|
<!-- Polyfills -->
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
"ACTION_DELETE_SESSIONS" : "Kill Sessions",
|
"ACTION_DELETE_SESSIONS" : "Kill Sessions",
|
||||||
"ACTION_DOWNLOAD" : "Download",
|
"ACTION_DOWNLOAD" : "Download",
|
||||||
"ACTION_LOGIN" : "Login",
|
"ACTION_LOGIN" : "Login",
|
||||||
|
"ACTION_LOGIN_AGAIN" : "Re-login",
|
||||||
"ACTION_LOGOUT" : "Logout",
|
"ACTION_LOGOUT" : "Logout",
|
||||||
"ACTION_MANAGE_CONNECTIONS" : "Connections",
|
"ACTION_MANAGE_CONNECTIONS" : "Connections",
|
||||||
"ACTION_MANAGE_PREFERENCES" : "Preferences",
|
"ACTION_MANAGE_PREFERENCES" : "Preferences",
|
||||||
@@ -44,6 +45,7 @@
|
|||||||
"FORMAT_DATE_TIME_PRECISE" : "yyyy-MM-dd HH:mm:ss",
|
"FORMAT_DATE_TIME_PRECISE" : "yyyy-MM-dd HH:mm:ss",
|
||||||
|
|
||||||
"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}}.",
|
||||||
|
"INFO_LOGGED_OUT" : "You have been logged out.",
|
||||||
|
|
||||||
"TEXT_ANONYMOUS_USER" : "Anonymous",
|
"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{}}",
|
||||||
|
Reference in New Issue
Block a user