GUAC-919: Copy Angular changes from old GUAC-546 branch.

This commit is contained in:
James Muehlner
2014-11-03 12:51:17 -08:00
committed by Michael Jumper
parent ac2617b92a
commit 5c43ae4ff9
84 changed files with 16551 additions and 7476 deletions

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* The controller for the connection edit modal.
*/
angular.module('manage').controller('connectionEditModalController', ['$scope', '$injector',
function connectionEditModalController($scope, $injector) {
var connectionEditModal = $injector.get('connectionEditModal');
var connectionDAO = $injector.get('connectionDAO');
var displayObjectPreparationService = $injector.get('displayObjectPreparationService');
// Make a copy of the old connection so that we can copy over the changes when done
var oldConnection = $scope.connection;
// Copy data into a new conection object in case the user doesn't want to save
$scope.connection = angular.copy($scope.connection);
var newConnection = !$scope.connection.identifier;
if(newConnection)
// Prepare this connection for display
displayObjectPreparationService.prepareConnection($scope.connection);
// Set it to VNC by default
if(!$scope.connection.protocol)
$scope.connection.protocol = "vnc";
/**
* Close the modal.
*/
$scope.close = function close() {
connectionEditModal.deactivate();
};
/**
* Save the connection and close the modal.
*/
$scope.save = function save() {
connectionDAO.saveConnection($scope.connection).success(function successfullyUpdatedConnection() {
var oldParentID = oldConnection.parentIdentifier;
var newParentID = $scope.connection.parentIdentifier;
// Copy the data back to the original model
angular.extend(oldConnection, $scope.connection);
// We have to move this connection
if(oldParentID !== newParentID)
// New connections are created by default in root - don't try to move it if it's already there.
if(newConnection && newParentID === $scope.rootGroup.identifier) {
$scope.moveItem($scope.connection, oldParentID, newParentID);
} else {
connectionDAO.moveConnection($scope.connection).then(function moveConnection() {
$scope.moveItem($scope.connection, oldParentID, newParentID);
});
}
// Close the modal
connectionEditModal.deactivate();
});
};
/**
* Delete the connection and close the modal.
*/
$scope['delete'] = function deleteConnection() {
// Nothing to delete if the connection is new
var newConnection = !$scope.connection.identifier;
if(newConnection) {
// Close the modal
connectionEditModal.deactivate();
return;
}
connectionDAO.deleteConnection($scope.connection).success(function successfullyDeletedConnection() {
var oldParentID = oldConnection.parentIdentifier;
// We have to remove this connection from the heirarchy
$scope.moveItem($scope.connection, oldParentID);
// Close the modal
connectionEditModal.deactivate();
});
}
}]);

View File

@@ -0,0 +1,115 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* The controller for the connection group edit modal.
*/
angular.module('manage').controller('connectionGroupEditModalController', ['$scope', '$injector',
function connectionEditModalController($scope, $injector) {
var connectionGroupEditModal = $injector.get('connectionGroupEditModal');
var connectionGroupDAO = $injector.get('connectionGroupDAO');
var displayObjectPreparationService = $injector.get('displayObjectPreparationService');
// Make a copy of the old connection group so that we can copy over the changes when done
var oldConnectionGroup = $scope.connectionGroup;
// Copy data into a new conection group object in case the user doesn't want to save
$scope.connectionGroup = angular.copy($scope.connectionGroup);
var newConnectionGroup = !$scope.connectionGroup.identifier;
$scope.types = [
{
label: "organizational",
value: "ORGANIZATIONAL"
},
{
label: "balancing",
value: "BALANCING"
}
];
// Set it to organizational by default
if(!$scope.connectionGroup.type)
$scope.connectionGroup.type = $scope.types[0].value;
/**
* Close the modal.
*/
$scope.close = function close() {
connectionGroupEditModal.deactivate();
};
/**
* Save the connection and close the modal.
*/
$scope.save = function save() {
connectionGroupDAO.saveConnectionGroup($scope.connectionGroup).success(function successfullyUpdatedConnectionGroup() {
// Prepare this connection group for display
displayObjectPreparationService.prepareConnectionGroup($scope.connectionGroup);
var oldParentID = oldConnectionGroup.parentIdentifier;
var newParentID = $scope.connectionGroup.parentIdentifier;
// Copy the data back to the original model
angular.extend(oldConnectionGroup, $scope.connectionGroup);
// New groups are created by default in root - don't try to move it if it's already there.
if(newConnectionGroup && newParentID === $scope.rootGroup.identifier) {
$scope.moveItem($scope.connectionGroup, oldParentID, newParentID);
} else {
connectionGroupDAO.moveConnectionGroup($scope.connectionGroup).then(function moveConnectionGroup() {
$scope.moveItem($scope.connectionGroup, oldParentID, newParentID);
});
}
// Close the modal
connectionGroupEditModal.deactivate();
});
};
/**
* Delete the connection and close the modal.
*/
$scope['delete'] = function deleteConnectionGroup() {
// Nothing to delete if the connection is new
if(newConnectionGroup)
// Close the modal
connectionGroupEditModal.deactivate();
connectionGroupDAO.deleteConnectionGroup($scope.connectionGroup).success(function successfullyDeletedConnectionGroup() {
var oldParentID = oldConnectionGroup.parentIdentifier;
// We have to remove this connection group from the heirarchy
$scope.moveItem($scope.connectionGroup, oldParentID);
// Close the modal
connectionGroupEditModal.deactivate();
});
}
}]);

View File

@@ -0,0 +1,242 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* The controller for the administration page.
*/
angular.module('manage').controller('manageController', ['$scope', '$injector',
function manageController($scope, $injector) {
// Get the dependencies commonJS style
var connectionGroupService = $injector.get('connectionGroupService');
var connectionEditModal = $injector.get('connectionEditModal');
var connectionGroupEditModal = $injector.get('connectionGroupEditModal');
var userEditModal = $injector.get('userEditModal');
var protocolDAO = $injector.get('protocolDAO');
var userDAO = $injector.get('userDAO');
var userService = $injector.get('userService');
// All the connections and connection groups in root
$scope.connectionsAndGroups = [];
// All users that the current user has permission to edit
$scope.users = [];
$scope.basicPermissionsLoaded.then(function basicPermissionsHaveBeenLoaded() {
connectionGroupService.getAllGroupsAndConnections([], undefined, true, true).then(function filterConnectionsAndGroups(rootGroupList) {
$scope.rootGroup = rootGroupList[0];
$scope.connectionsAndGroups = $scope.rootGroup.children;
// Filter the items to only include ones that we have UPDATE for
if(!$scope.currentUserIsAdmin) {
connectionGroupService.filterConnectionsAndGroupByPermission(
$scope.connectionsAndGroups,
$scope.currentUserPermissions,
{
'CONNECTION': 'UPDATE',
'CONNECTION_GROUP': 'UPDATE'
}
);
}
});
userDAO.getUsers().success(function filterEditableUsers(users) {
$scope.users = users;
// Filter the users to only include ones that we have UPDATE for
if(!$scope.currentUserIsAdmin) {
userService.filterUsersByPermission(
$scope.users,
$scope.currentUserPermissions,
'UPDATE'
);
}
});
});
/**
* Move the connection or connection group within the group heirarchy,
* initially place a new item, or remove an item from the heirarchy.
* @param {object} item The connection or connection group to move.
* @param {string} fromID The ID of the group to move the item from, if relevant.
* @param {string} toID The ID of the group to move the item to, if relevant.
*/
$scope.moveItem = function moveItem(item, fromID, toID) {
// Remove the item from the old group, if there was one
if(fromID) {
var oldParent = findGroup($scope.rootGroup, fromID),
oldChildren = oldParent.children;
// Find and remove the item from the old group
for(var i = 0; i < oldChildren.length; i++) {
var child = oldChildren[i];
if(child.isConnection === item.isConnection &&
child.identifier === item.identifier) {
oldChildren.splice(i, 1);
break;
}
}
}
// Add the item to the new group, if there is one
if(toID) {
var newParent = findGroup($scope.rootGroup, toID);
newParent.children.push(item);
}
};
function findGroup(group, parentID) {
// Only searching in groups
if(group.isConnection)
return;
if(group.identifier === parentID)
return group;
for(var i = 0; i < group.children.length; i++) {
var child = group.children[i];
var foundGroup = findGroup(child, parentID);
if(foundGroup) return foundGroup;
}
}
$scope.protocols = {};
// Get the protocol information from the server and copy it into the scope
protocolDAO.getProtocols().success(function fetchProtocols(protocols) {
angular.extend($scope.protocols, protocols);
});
/**
* Toggle the open/closed status of the connectionGroup.
*
* @param {object} connectionGroup The connection group to toggle.
*/
$scope.toggleExpanded = function toggleExpanded(connectionGroup) {
connectionGroup.expanded = !connectionGroup.expanded;
};
/**
* Open a modal to edit the connection.
*
* @param {object} connection The connection to edit.
*/
$scope.editConnection = function editConnection(connection) {
connectionEditModal.activate(
{
connection : connection,
protocols : $scope.protocols,
moveItem : $scope.moveItem,
rootGroup : $scope.rootGroup
});
};
/**
* Open a modal to edit a new connection.
*/
$scope.newConnection = function newConnection() {
connectionEditModal.activate(
{
connection : {},
protocols : $scope.protocols,
moveItem : $scope.moveItem,
rootGroup : $scope.rootGroup
});
};
/**
* Open a modal to edit a new connection group.
*/
$scope.newConnectionGroup = function newConnectionGroup() {
connectionGroupEditModal.activate(
{
connectionGroup : {},
moveItem : $scope.moveItem,
rootGroup : $scope.rootGroup
});
};
/**
* Open a modal to edit the connection group.
*
* @param {object} connection The connection group to edit.
*/
$scope.editConnectionGroup = function editConnectionGroup(connectionGroup) {
connectionGroupEditModal.activate(
{
connectionGroup : connectionGroup,
moveItem : $scope.moveItem,
rootGroup : $scope.rootGroup
});
};
// Remove the user from the current list of users
function removeUser(user) {
for(var i = 0; i < $scope.users.length; i++) {
if($scope.users[i].username === user.username) {
$scope.users.splice(i, 1);
break;
}
}
}
/**
* Open a modal to edit the user.
*
* @param {object} user The user to edit.
*/
$scope.editUser = function editUser(user) {
userEditModal.activate(
{
user : user,
rootGroup : $scope.rootGroup,
removeUser : removeUser
});
};
$scope.newUsername = "";
/**
* Open a modal to edit the user.
*
* @param {object} user The user to edit.
*/
$scope.newUser = function newUser() {
if($scope.newUsername) {
var newUser = {
username: $scope.newUsername
};
userDAO.createUser(newUser).success(function addUserToList() {
$scope.users.push(newUser);
});
$scope.newUsername = "";
}
};
}]);

View File

@@ -0,0 +1,263 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* The controller for the connection edit modal.
*/
angular.module('manage').controller('userEditModalController', ['$scope', '$injector',
function userEditModalController($scope, $injector) {
var userEditModal = $injector.get('userEditModal');
var userDAO = $injector.get('userDAO');
var permissionDAO = $injector.get('permissionDAO');
// Make a copy of the old user so that we can copy over the changes when done
var oldUser = $scope.user;
// Copy data into a new conection object in case the user doesn't want to save
$scope.user = angular.copy($scope.user);
/**
* Close the modal.
*/
$scope.close = function close() {
userEditModal.deactivate();
};
/*
* All the permissions that have been modified since this modal was opened.
* Maps of type or id to value.
*/
$scope.modifiedSystemPermissions = {};
$scope.modifiedConnectionPermissions = {};
$scope.modifiedConnectionGroupPermissions = {};
$scope.markSystemPermissionModified = function markSystemPermissionModified(type) {
$scope.modifiedSystemPermissions[type] = $scope.systemPermissions[type];
};
$scope.markConnectionPermissionModified = function markConnectionPermissionModified(id) {
$scope.modifiedConnectionPermissions[id] = $scope.connectionPermissions[id];
};
$scope.markConnectionGroupPermissionModified = function markConnectionGroupPermissionModified(id) {
$scope.modifiedConnectionGroupPermissions[id] = $scope.connectionGroupPermissions[id];
};
/**
* Save the user and close the modal.
*/
$scope.save = function save() {
if($scope.passwordMatch !== $scope.user.password) {
//TODO: Display an error
return;
}
userDAO.saveUser($scope.user).success(function successfullyUpdatedUser() {
//Figure out what permissions have changed
var connectionPermissionsToCreate = [],
connectionPermissionsToDelete = [],
connectionGroupPermissionsToCreate = [],
connectionGroupPermissionsToDelete = [],
systemPermissionsToCreate = [],
systemPermissionsToDelete = [];
for(var type in $scope.modifiedSystemPermissions) {
// It was added
if($scope.modifiedSystemPermissions[type] && !originalSystemPermissions[type]) {
systemPermissionsToCreate.push(type);
}
// It was removed
else if(!$scope.modifiedSystemPermissions[type] && originalSystemPermissions[type]) {
systemPermissionsToDelete.push(type);
}
}
for(var id in $scope.modifiedConnectionPermissions) {
// It was added
if($scope.modifiedConnectionPermissions[id] && !originalConnectionPermissions[id]) {
connectionPermissionsToCreate.push(id);
}
// It was removed
else if(!$scope.modifiedConnectionPermissions[id] && originalConnectionPermissions[id]) {
connectionPermissionsToDelete.push(id);
}
}
for(var id in $scope.modifiedConnectionGroupPermissions) {
// It was added
if($scope.modifiedConnectionGroupPermissions[id] && !originalConnectionGroupPermissions[id]) {
connectionGroupPermissionsToCreate.push(id);
}
// It was removed
else if(!$scope.modifiedConnectionGroupPermissions[id] && originalConnectionGroupPermissions[id]) {
connectionGroupPermissionsToDelete.push(id);
}
}
var permissionsToAdd = [];
var permissionsToRemove = [];
// Create new connection permissions
for(var i = 0; i < connectionPermissionsToCreate.length; i++) {
permissionsToAdd.push({
objectType : "CONNECTION",
objectIdentifier : connectionPermissionsToCreate[i],
permissionType : "READ"
});
}
// Delete old connection permissions
for(var i = 0; i < connectionPermissionsToDelete.length; i++) {
permissionsToRemove.push({
objectType : "CONNECTION",
objectIdentifier : connectionPermissionsToDelete[i],
permissionType : "READ"
});
}
// Create new connection group permissions
for(var i = 0; i < connectionGroupPermissionsToCreate.length; i++) {
permissionsToAdd.push({
objectType : "CONNECTION_GROUP",
objectIdentifier : connectionGroupPermissionsToCreate[i],
permissionType : "READ"
});
}
// Delete old connection group permissions
for(var i = 0; i < connectionGroupPermissionsToDelete.length; i++) {
permissionsToRemove.push({
objectType : "CONNECTION_GROUP",
objectIdentifier : connectionGroupPermissionsToDelete[i],
permissionType : "READ"
});
}
// Create new system permissions
for(var i = 0; i < systemPermissionsToCreate.length; i++) {
permissionsToAdd.push({
objectType : "SYSTEM",
permissionType : systemPermissionsToCreate[i]
});
}
// Delete old system permissions
for(var i = 0; i < systemPermissionsToDelete.length; i++) {
permissionsToRemove.push({
objectType : "SYSTEM",
permissionType : systemPermissionsToDelete[i]
});
}
function completeSaveProcess() {
// Close the modal
userEditModal.deactivate();
}
function handleFailure() {
//TODO: Handle the permission API call failure
}
if(permissionsToAdd.length || permissionsToRemove.length) {
// Make the call to update the permissions
permissionDAO.patchPermissions(
$scope.user.username, permissionsToAdd, permissionsToRemove)
.success(completeSaveProcess).error(handleFailure);
} else {
completeSaveProcess();
}
});
};
$scope.permissions = [];
// Maps of connection and connection group IDs to access permission booleans
$scope.connectionPermissions = {};
$scope.connectionGroupPermissions = {};
$scope.systemPermissions = {};
// The original permissions to compare against
var originalConnectionPermissions,
originalConnectionGroupPermissions,
originalSystemPermissions;
// Get the permissions for the user we are editing
permissionDAO.getPermissions($scope.user.username).success(function gotPermissions(permissions) {
$scope.permissions = permissions;
// Figure out if the user has any system level permissions
for(var i = 0; i < $scope.permissions.length; i++) {
var permission = $scope.permissions[i];
if(permission.objectType === "SYSTEM") {
$scope.systemPermissions[permission.permissionType] = true;
// Only READ permission is editable via this UI
} else if (permission.permissionType === "READ") {
switch(permission.objectType) {
case "CONNECTION":
$scope.connectionPermissions[permission.objectIdentifier] = true;
break;
case "CONNECTION_GROUP":
$scope.connectionGroupPermissions[permission.objectIdentifier] = true;
break;
}
}
}
// Copy the original permissions so we can compare later
originalConnectionPermissions = angular.copy($scope.connectionPermissions);
originalConnectionGroupPermissions = angular.copy($scope.connectionGroupPermissions);
originalSystemPermissions = angular.copy($scope.systemPermissions);
});
/**
* Delete the user and close the modal.
*/
$scope['delete'] = function deleteUser() {
userDAO.deleteUser($scope.user).success(function successfullyDeletedUser() {
// Remove the user from the list
$scope.removeUser($scope.user);
// Close the modal
userEditModal.deactivate();
});
}
/**
* Toggle the open/closed status of the connectionGroup.
*
* @param {object} connectionGroup The connection group to toggle.
*/
$scope.toggleExpanded = function toggleExpanded(connectionGroup) {
connectionGroup.expanded = !connectionGroup.expanded;
};
}]);

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* A directive for choosing the location of a connection or connection group.
*/
angular.module('manage').directive('locationChooser', [function locationChooser() {
return {
// Element only
restrict: 'E',
replace: true,
scope: {
item: '=item',
root: '=root',
},
templateUrl: 'app/manage/templates/locationChooser.html',
controller: ['$scope', '$injector', function locationChooserController($scope, $injector) {
// The dropdown should start closed
$scope.showDropDown = false;
// Map of ID to name for all connection groups
$scope.connectionGroupNameMap = {};
// Set up the group for display and search
mapConnectionGroupNames($scope.root);
$scope.connectionGroups = [$scope.root];
// Should be in the root group by default
if(!$scope.item.parentIdentifier)
$scope.item.parentIdentifier = $scope.root.parentIdentifier;
setCurrentParentName();
// Add the name of all connection groups under group to the group name map
function mapConnectionGroupNames(group) {
$scope.connectionGroupNameMap[group.identifier] = group.name;
for(var i = 0; i < group.children.length; i++) {
var child = group.children[i];
if(!child.isConnection)
mapConnectionGroupNames(child);
}
}
//Set the current connection group name to the name of the connection group with the currently chosen ID
function setCurrentParentName() {
$scope.currentConnectionGroupName = $scope.connectionGroupNameMap[$scope.item.parentIdentifier];
}
// Watch for changes to the parentID, and update the current name as needed
$scope.currentConnectionGroupName = "";
$scope.$watch('item.parentIdentifier', function watchParentID() {
setCurrentParentName();
});
/**
* Toggle the drop down - open or closed.
*/
$scope.toggleDropDown = function toggleDropDown() {
$scope.showDropDown = !$scope.showDropDown;
}
/**
* Choose a new parent ID for the item.
* @param {type} parentID The new parentID.
*/
$scope.chooseParentID = function chooseParentID(parentID) {
$scope.item.parentIdentifier = parentID;
}
}]
};
}]);

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* The module for the administration functionality.
*/
angular.module('manage', ['btford.modal', 'protocol', 'connectionGroup', 'util']);

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* A modal for editing a connection.
*/
angular.module('manage').factory('connectionEditModal', ['btfModal',
function connectionEditModal(btfModal) {
// Create the modal object to be used later to actually create the modal
return btfModal({
controller: 'connectionEditModalController',
controllerAs: 'modal',
templateUrl: 'app/manage/templates/editableConnection.html',
});
}]);

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* A modal for editing a connection group.
*/
angular.module('manage').factory('connectionGroupEditModal', ['btfModal',
function connectionGroupEditModal(btfModal) {
// Create the modal object to be used later to actually create the modal
return btfModal({
controller: 'connectionGroupEditModalController',
controllerAs: 'modal',
templateUrl: 'app/manage/templates/editableConnectionGroup.html',
});
}]);

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* A modal for editing a connection.
*/
angular.module('manage').factory('userEditModal', ['btfModal',
function userEditModal(btfModal) {
// Create the modal object to be used later to actually create the modal
return btfModal({
controller: 'userEditModalController',
controllerAs: 'modal',
templateUrl: 'app/manage/templates/editableUser.html',
});
}]);

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2014 Glyptodon LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
button.add-user {
background-image: url('images/action-icons/guac-user-add.png');
background-repeat: no-repeat;
background-size: 1em;
background-position: 0.5em 0.45em;
padding-left: 1.8em;
}
button.add-connection {
background-image: url('images/action-icons/guac-monitor-add.png');
background-repeat: no-repeat;
background-size: 1em;
background-position: 0.5em 0.45em;
padding-left: 1.8em;
}
button.add-connection-group {
background-image: url('images/action-icons/guac-group-add.png');
background-repeat: no-repeat;
background-size: 1em;
background-position: 0.5em 0.45em;
padding-left: 1.8em;
}

View File

@@ -0,0 +1,131 @@
<!--
Copyright 2014 Glyptodon LLC.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<!-- Dialog container for the modal -->
<div class="dialog-container">
<div class="dialog edit">
<!-- Connection name -->
<div class="header">
<h2>{{connection.name}}</h2>
</div>
<!-- Main connection edit section -->
<div class="body">
<div class="form">
<div class="settings section">
<dl>
<dd>
<table class="fields section">
<!-- Edit connection name -->
<tr>
<th>{{'manage.edit.connection.name' | translate}}</th>
<td><input type="text" ng-model="connection.name"/></td>
</tr>
<!-- Edit connection location -->
<tr>
<th>{{'manage.edit.connection.location' | translate}}</th>
<td>
<location-chooser item="connection" root="rootGroup"/>
</td>
</tr>
<!-- Edit connection protocol -->
<tr>
<th>{{'manage.edit.connection.protocol' | translate}}</th>
<td>
<select ng-model="connection.protocol" ng-options="name as 'protocol.' + protocol.name + '.label' | translate for (name, protocol) in protocols | orderBy: name"></select>
</td>
</tr>
</table>
</dd>
<dd>
<table class="fields section">
<!-- All the different possible editable field types -->
<tr ng-repeat="parameter in protocols[connection.protocol].parameters">
<th>{{'protocol.' + connection.protocol + '.parameters.' + parameter.name + '.label' | translate}}:</th>
<td ng-show="parameter.type === 'TEXT'">
<input type="text" ng-model="connection.parameters[parameter.name]"/>
</td>
<td ng-show="parameter.type === 'NUMERIC'">
<input type="number" ng-model="connection.parameters[parameter.name]"/>
</td>
<td ng-show="parameter.type === 'PASSWORD'">
<input type="password" ng-model="connection.parameters[parameter.name]"/>
</td>
<td ng-show="parameter.type === 'BOOLEAN'">
<input type="checkbox" ng-model="connection.parameters[parameter.name]"/>
</td>
<td ng-show="parameter.type === 'ENUM'">
<select ng-model="connection.parameters[parameter.name]" ng-options="option.value as 'protocol.' + connection.protocol + '.parameters.' + parameter.name + '.options.' + (option.value || 'empty') | translate for option in parameter.options | orderBy: value"></select>
</td>
</tr>
</table>
</dd>
<!-- History connection area -->
<dt>{{'manage.edit.connection.history.usageHistory' | translate}}</dt>
<dd ng-hide="connection.history.length">
<p>{{'manage.edit.connection.history.connectionNotUsed' | translate}}</p>
</dd>
<!-- History connection list -->
<dd ng-show="connection.history.length">
<table class="history section">
<tr>
<th>{{'manage.edit.connection.history.username' | translate}}</th>
<th>{{'manage.edit.connection.history.startTime' | translate}}</th>
<th>{{'manage.edit.connection.history.duration' | translate}}</th>
</tr>
<tbody>
<tr ng-repeat="record in connection.history">
<td class="username">{{record.username}}</td>
<td class="start">{{record.startDate | date:'short'}}</td>
<td ng-show="record.endDate" class="duration">{{record.endDate}}</td>
<td ng-hide="record.endDate" class="duration">{{'manage.edit.connection.history.activeNow' | translate}}</td>
</tr>
</tbody>
</table>
</dd>
</dl>
</div>
</div>
</div>
<!-- Control buttons -->
<div class="footer">
<button ng-click="save()">{{'manage.edit.connection.save' | translate}}</button>
<button ng-click="close()">{{'manage.edit.connection.cancel' | translate}}</button>
<button ng-click="delete()" class="danger">{{'manage.edit.connection.delete' | translate}}</button>
</div>
</div>
</div>

View File

@@ -0,0 +1,79 @@
<!--
Copyright 2014 Glyptodon LLC.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<!-- Dialog container for the modal -->
<div class="dialog-container">
<div class="dialog edit">
<!-- Connection group name -->
<div class="header">
<h2>{{connectionGroup.name}}</h2>
</div>
<!-- Main connection group edit section -->
<div class="body">
<div class="form">
<div class="settings section">
<dl>
<dd>
<table class="fields section">
<!-- Edit connection group name -->
<tr>
<th>{{'manage.edit.connectionGroup.name' | translate}}</th>
<td><input type="text" ng-model="connectionGroup.name"/></td>
</tr>
<!-- Edit connection group location -->
<tr>
<th>{{'manage.edit.connectionGroup.location' | translate}}</th>
<td>
<location-chooser item="connectionGroup" root="rootGroup"/>
</td>
</tr>
<!-- Edit connection group type -->
<tr>
<th>{{'manage.edit.connectionGroup.type.label' | translate}}</th>
<td>
<select ng-model="connectionGroup.type" ng-options="type.value as 'manage.edit.connectionGroup.type.' + type.label | translate for type in types | orderBy: name"></select>
</td>
</tr>
</table>
</dd>
</dl>
</div>
</div>
</div>
<!-- Control buttons -->
<div class="footer">
<button ng-click="save()">{{'manage.edit.connectionGroup.save' | translate}}</button>
<button ng-click="close()">{{'manage.edit.connectionGroup.cancel' | translate}}</button>
<button ng-click="delete()" class="danger">{{'manage.edit.connectionGroup.delete' | translate}}</button>
</div>
</div>
</div>

View File

@@ -0,0 +1,141 @@
<!--
Copyright 2014 Glyptodon LLC.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<!-- Hierarchical connection and connection group permission selector -->
<script type="text/ng-template" id="nestedUserPermissionEditGroup.html">
<!-- Connection -->
<div class="choice" ng-show="item.isConnection">
<input type="checkbox" ng-model="connectionPermissions[item.identifier]" ng-change="markConnectionPermissionModified(item.identifier)"/>
<div class="connection list-item">
<div class="caption">
<div class="protocol">
<div class="icon" ng-class="item.protocol"></div>
</div><span class="name">{{item.name}}</span>
</div>
</div>
</div>
<!-- Connection group -->
<div class="choice" ng-show="!item.isConnection">
<input type="checkbox" ng-model="connectionGroupPermissions[item.identifier]" ng-change="markConnectionGroupPermissionModified(item.identifier)"/>
<div class="group empty list-item balancer">
<div class="caption">
<div class="icon group" ng-click="toggleExpanded(item)" ng-class="{expanded: item.expanded, empty: !item.children.length, balancer: item.balancer && !item.children.length}"></div>
<span class="name">{{item.name}}</span>
</div>
<!-- Connection group children -->
<div class="children" ng-show="item.expanded">
<div ng-repeat="item in item.children | orderBy : 'name'" ng-include="'nestedUserPermissionEditGroup.html'">
</div>
</div>
</div>
</script>
<!-- User edit modal -->
<div class="dialog-container">
<div class="dialog edit">
<div class="header">
<h2>{{user.username}}</h2>
</div>
<div class="body">
<div class="form">
<div class="settings section">
<dl>
<!-- User properties section -->
<dt>{{'manage.edit.user.properties' | translate}}</dt>
<dd>
<table class="fields section">
<tr>
<th>{{'manage.edit.user.password' | translate}}</th>
<td><input ng-model="user.password" type="password" /></td>
</tr>
<tr>
<th>{{'manage.edit.user.passwordMatch' | translate}}</th>
<td><input ng-model="passwordMatch" type="password" /></td>
</tr>
</table>
</dd>
<!-- System permissions section -->
<dt>{{'manage.edit.user.permissions' | translate}}</dt>
<dd>
<table class="permissions section">
<tr>
<th>{{'manage.edit.user.administerSystem' | translate}}</th>
<td><input type="checkbox" ng-model="systemPermissions.ADMINISTER" ng-change="markSystemPermissionModified('ADMINISTER')" /></td>
</tr>
<tr>
<th>{{'manage.edit.user.createUser' | translate}}</th>
<td><input type="checkbox" ng-model="systemPermissions.CREATE_USER" ng-change="markSystemPermissionModified('CREATE_USER')" /></td>
</tr>
<tr>
<th>{{'manage.edit.user.createConnection' | translate}}</th>
<td><input type="checkbox" ng-model="systemPermissions.CREATE_CONNECTION" ng-change="markSystemPermissionModified('CREATE_CONNECTION')" /></td>
</tr>
<tr>
<th>{{'manage.edit.user.createConnectionGroup' | translate}}</th>
<td><input type="checkbox" ng-model="systemPermissions.CREATE_CONNECTION_GROUP" ng-change="markSystemPermissionModified('CREATE_CONNECTION_GROUP')" /></td>
</tr>
</table>
</dd>
<!-- Connection and connection group permission section -->
<dt>{{'manage.edit.user.connections' | translate}}</dt>
<dd>
<div class="group-view">
<div class="list">
<div ng-repeat="item in rootGroup.children | orderBy : 'name'" ng-include="'nestedUserPermissionEditGroup.html'"></div>
</div>
</div>
</dd>
</dl>
</div>
</div>
</div>
<!-- Form controls -->
<div class="footer">
<button ng-click="save()">{{'manage.edit.user.save' | translate}}</button>
<button ng-click="close()">{{'manage.edit.user.cancel' | translate}}</button>
<button ng-click="delete()" class="danger">{{'manage.edit.user.delete' | translate}}</button>
</div>
</div>
</div>

View File

@@ -0,0 +1,46 @@
<div>
<!--
Copyright 2014 Glyptodon LLC.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<script type="text/ng-template" id="nestedGroupSelect.html">
<div class="group" ng-show="!item.isConnection">
<div class="caption">
<div class="icon group type" ng-click="item.expanded = !item.expanded" ng-class="{expanded: item.expanded, empty: !item.children.length, balancer: item.balancer && !item.children.length}"></div>
<span class="name" ng-click="chooseParentID(item.identifier); toggleDropDown()">{{item.name}}</span>
</div>
<div class="children" ng-show="item.expanded">
<div class="list-item" ng-repeat="item in item.children | orderBy : 'name'" ng-include="'nestedGroupSelect.html'">
</div>
</div>
</script>
<!-- Open the dropdown -->
<div ng-click="toggleDropDown()" class="location">{{currentConnectionGroupName}}</div>
<div ng-show="showDropDown" class="dropdown">
<div class="group-view">
<div class="list">
<div class="list-item" ng-repeat="item in connectionGroups | orderBy : 'name'" ng-include="'nestedGroupSelect.html'"></div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,92 @@
<!--
Copyright 2014 Glyptodon LLC.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<script type="text/ng-template" id="nestedGroup.html">
<div class="connection" ng-click="editConnection(item)" ng-show="item.isConnection">
<div class="caption">
<div class="protocol">
<div class="icon type" ng-class="item.protocol"></div>
</div>
<span class="name">{{item.name}}</span>
</div>
</div>
<div class="group" ng-show="!item.isConnection">
<div class="caption">
<div class="icon group type" ng-click="toggleExpanded(item)" ng-class="{expanded: item.expanded, empty: !item.children.length, balancer: item.balancer && !item.children.length}"></div>
<span ng-click="editConnectionGroup(item)" class="name">
<span>{{item.name}}</span>
</span>
</div>
<div class="children" ng-show="item.expanded">
<div class="list-item" ng-repeat="item in item.children | orderBy : 'name'" ng-include="'nestedGroup.html'">
</div>
</div>
</script>
<div class="logout-panel">
<a class="back button" href="#/">{{'manage.back' | translate}}</a>
<a class="logout button" href="#/login">{{'home.logout' | translate}}</a>
</div>
<h2>{{'manage.administration' | translate}}</h2>
<div ng-show="currentUserHasUpdate" class="settings section">
<h3 class="require-manage-users">{{'manage.users' | translate}}</h3>
<div class="require-manage-users users">
<p>{{'manage.usersDescription' | translate}}</p>
<!-- Control to create a new user -->
<div class="user-add-form">
<input type="text" ng-model="newUsername" class="name username"/>
<button class="add-user" ng-click="newUser()">{{'manage.addUser' | translate}}</button>
</div>
<!-- List of users this user has access to -->
<div class="user-list">
<div ng-click="editUser(user)" ng-repeat="user in users | orderBy : 'username'" class="list-item">
<div class="caption">
<div class="icon user"></div>
<span class="name">{{user.username}}</span>
</div>
</div>
</div>
</div>
<h3 class="require-manage-connections">{{'manage.connections' | translate}}</h3>
<div class="require-manage-connections connections">
<p>{{'manage.connectionsDescription' | translate}}</p>
<!-- Control to create a new connection or group -->
<div class="connection-add-form">
<button ng-click="newConnection()" class="add-connection">{{'manage.newConnection' | translate}}</button>
<button ng-click="newConnectionGroup()" class="add-connection-group">{{'manage.newGroup' | translate}}</button>
</div>
<!-- List of connections and groups this user has access to -->
<div class="connection-list">
<div class="list-item" ng-repeat="item in connectionsAndGroups | orderBy : 'name'" ng-include="'nestedGroup.html'"></div>
</div>
</div>
</div>