keycloak-memoizeit

Details

diff --git a/ui/src/main/resources/META-INF/resources/ui/js/app.js b/ui/src/main/resources/META-INF/resources/ui/js/app.js
index bc4bc53..93ec13b 100644
--- a/ui/src/main/resources/META-INF/resources/ui/js/app.js
+++ b/ui/src/main/resources/META-INF/resources/ui/js/app.js
@@ -4,177 +4,177 @@ var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.control
 var resourceRequests = 0;
 
 module.config([ '$routeProvider', function($routeProvider) {
-    $routeProvider.when('/create/application', {
-        templateUrl : 'partials/application-detail.html',
-        resolve : {
-            applications : function(ApplicationListLoader) {
-                return ApplicationListLoader();
-            },
-            application : function(ApplicationLoader) {
-                return {};
-            },
-            realms : function(RealmListLoader) {
-                return RealmListLoader();
-            },
-            providers : function(ProviderListLoader) {
-                return ProviderListLoader();
-            }
-        },
-        controller : 'ApplicationDetailCtrl'
-    }).when('/applications/:application', {
-        templateUrl : 'partials/application-detail.html',
-        resolve : {
-            applications : function(ApplicationListLoader) {
-                return ApplicationListLoader();
-            },
-            application : function(ApplicationLoader) {
-                return ApplicationLoader();
-            },
-            realms : function(RealmListLoader) {
-                return RealmListLoader();
-            },
-            providers : function(ProviderListLoader) {
-                return ProviderListLoader();
-            }
-        },
-        controller : 'ApplicationDetailCtrl'
-    }).when('/applications', {
-        templateUrl : 'partials/application-list.html',
-        resolve : {
-            applications : function(ApplicationListLoader) {
-                return ApplicationListLoader();
-            }
-        },
-        controller : 'ApplicationListCtrl'
-    }).when('/realms/:realm/users/:user', {
-        templateUrl : 'partials/user-detail.html',
-        resolve : {
-            realms : function(RealmListLoader) {
-                return RealmListLoader();
-            },
-            realm : function(RealmLoader) {
-                return RealmLoader();
-            },
-            user : function(UserLoader) {
-                return UserLoader();
-            }
-        },
-        controller : 'UserDetailCtrl'
-    }).when('/realms/:realm/users', {
-        templateUrl : 'partials/user-list.html',
-        resolve : {
-            realms : function(RealmListLoader) {
-                return RealmListLoader();
-            },
-            realm : function(RealmLoader) {
-                return RealmLoader();
-            },
-            users : function(UserListLoader) {
-                return UserListLoader();
-            }
-        },
-        controller : 'UserListCtrl'
-    }).when('/create/realm', {
-        templateUrl : 'partials/realm-detail.html',
-        resolve : {
-            realms : function(RealmListLoader) {
-                return RealmListLoader();
-            },
-            realm : function(RealmLoader) {
-                return {};
-            }
-        },
-        controller : 'RealmDetailCtrl'
-    }).when('/realms/:realm', {
-        templateUrl : 'partials/realm-detail.html',
-        resolve : {
-            realms : function(RealmListLoader) {
-                return RealmListLoader();
-            },
-            realm : function(RealmLoader) {
-                return RealmLoader();
-            }
-        },
-        controller : 'RealmDetailCtrl'
-    }).when('/realms', {
-        templateUrl : 'partials/realm-list.html',
-        resolve : {
-            realms : function(RealmListLoader) {
-                return RealmListLoader();
-            }
-        },
-        controller : 'RealmListCtrl'
-    }).otherwise({
-        templateUrl : 'partials/home.html'
-    });
+	$routeProvider.when('/create/application', {
+		templateUrl : 'partials/application-detail.html',
+		resolve : {
+			applications : function(ApplicationListLoader) {
+				return ApplicationListLoader();
+			},
+			application : function(ApplicationLoader) {
+				return {};
+			},
+			realms : function(RealmListLoader) {
+				return RealmListLoader();
+			},
+			providers : function(ProviderListLoader) {
+				return ProviderListLoader();
+			}
+		},
+		controller : 'ApplicationDetailCtrl'
+	}).when('/applications/:application', {
+		templateUrl : 'partials/application-detail.html',
+		resolve : {
+			applications : function(ApplicationListLoader) {
+				return ApplicationListLoader();
+			},
+			application : function(ApplicationLoader) {
+				return ApplicationLoader();
+			},
+			realms : function(RealmListLoader) {
+				return RealmListLoader();
+			},
+			providers : function(ProviderListLoader) {
+				return ProviderListLoader();
+			}
+		},
+		controller : 'ApplicationDetailCtrl'
+	}).when('/applications', {
+		templateUrl : 'partials/application-list.html',
+		resolve : {
+			applications : function(ApplicationListLoader) {
+				return ApplicationListLoader();
+			}
+		},
+		controller : 'ApplicationListCtrl'
+	}).when('/realms/:realm/users/:user', {
+		templateUrl : 'partials/user-detail.html',
+		resolve : {
+			realms : function(RealmListLoader) {
+				return RealmListLoader();
+			},
+			realm : function(RealmLoader) {
+				return RealmLoader();
+			},
+			user : function(UserLoader) {
+				return UserLoader();
+			}
+		},
+		controller : 'UserDetailCtrl'
+	}).when('/realms/:realm/users', {
+		templateUrl : 'partials/user-list.html',
+		resolve : {
+			realms : function(RealmListLoader) {
+				return RealmListLoader();
+			},
+			realm : function(RealmLoader) {
+				return RealmLoader();
+			},
+			users : function(UserListLoader) {
+				return UserListLoader();
+			}
+		},
+		controller : 'UserListCtrl'
+	}).when('/create/realm', {
+		templateUrl : 'partials/realm-detail.html',
+		resolve : {
+			realms : function(RealmListLoader) {
+				return RealmListLoader();
+			},
+			realm : function(RealmLoader) {
+				return {};
+			}
+		},
+		controller : 'RealmDetailCtrl'
+	}).when('/realms/:realm', {
+		templateUrl : 'partials/realm-detail.html',
+		resolve : {
+			realms : function(RealmListLoader) {
+				return RealmListLoader();
+			},
+			realm : function(RealmLoader) {
+				return RealmLoader();
+			}
+		},
+		controller : 'RealmDetailCtrl'
+	}).when('/realms', {
+		templateUrl : 'partials/realm-list.html',
+		resolve : {
+			realms : function(RealmListLoader) {
+				return RealmListLoader();
+			}
+		},
+		controller : 'RealmListCtrl'
+	}).otherwise({
+		templateUrl : 'partials/home.html'
+	});
 } ]);
 
 module.config(function($httpProvider) {
-    $httpProvider.responseInterceptors.push('errorInterceptor');
+	$httpProvider.responseInterceptors.push('errorInterceptor');
 
-    var spinnerFunction = function(data, headersGetter) {
-        if (resourceRequests == 0) {
-            $('#loading').show();
-        }
-        resourceRequests++;
-        return data;
-    };
-    $httpProvider.defaults.transformRequest.push(spinnerFunction);
+	var spinnerFunction = function(data, headersGetter) {
+		if (resourceRequests == 0) {
+			$('#loading').show();
+		}
+		resourceRequests++;
+		return data;
+	};
+	$httpProvider.defaults.transformRequest.push(spinnerFunction);
 
-    $httpProvider.responseInterceptors.push('spinnerInterceptor');
+	$httpProvider.responseInterceptors.push('spinnerInterceptor');
 
 });
 
 module.factory('errorInterceptor', function($q, $window, $rootScope, $location) {
-    return function(promise) {
-        return promise.then(function(response) {
-            $rootScope.httpProviderError = null;
-            return response;
-        }, function(response) {
-            $rootScope.httpProviderError = response.status;
-            return $q.reject(response);
-        });
-    };
+	return function(promise) {
+		return promise.then(function(response) {
+			$rootScope.httpProviderError = null;
+			return response;
+		}, function(response) {
+			$rootScope.httpProviderError = response.status;
+			return $q.reject(response);
+		});
+	};
 });
 
 module.factory('spinnerInterceptor', function($q, $window, $rootScope, $location) {
-    return function(promise) {
-        return promise.then(function(response) {
-            resourceRequests--;
-            if (resourceRequests == 0) {
-                $('#loading').hide();
-            }
-            return response;
-        }, function(response) {
-            resourceRequests--;
-            if (resourceRequests == 0) {
-                $('#loading').hide();
-            }
-
-            return $q.reject(response);
-        });
-    };
+	return function(promise) {
+		return promise.then(function(response) {
+			resourceRequests--;
+			if (resourceRequests == 0) {
+				$('#loading').hide();
+			}
+			return response;
+		}, function(response) {
+			resourceRequests--;
+			if (resourceRequests == 0) {
+				$('#loading').hide();
+			}
+
+			return $q.reject(response);
+		});
+	};
 });
 
 module.directive('kcInput', function() {
 	var d = {
 		scope : true,
-		replace: false,
+		replace : false,
 		link : function(scope, element, attrs) {
 			var form = element.closest('form');
 			var label = element.children('label');
-			var input = element.children('input'); 
-			
+			var input = element.children('input');
+
 			var id = form.attr('name') + '.' + input.attr('name');
-			
+
 			element.attr('class', 'control-group');
-			
+
 			label.attr('class', 'control-label');
 			label.attr('for', id);
-			
+
 			input.wrap('<div class="controls"/>');
 			input.attr('id', id);
-			
+
 			if (!input.attr('placeHolder')) {
 				input.attr('placeHolder', label.text());
 			}
@@ -188,15 +188,27 @@ module.directive('kcInput', function() {
 });
 
 module.directive('kcEnter', function() {
-    return function(scope, element, attrs) {
-        element.bind("keydown keypress", function(event) {
-            if(event.which === 13) {
-                scope.$apply(function(){
-                    scope.$eval(attrs.kcEnter);
-                });
-
-                event.preventDefault();
-            }
-        });
-    };
+	return function(scope, element, attrs) {
+		element.bind("keydown keypress", function(event) {
+			if (event.which === 13) {
+				scope.$apply(function() {
+					scope.$eval(attrs.kcEnter);
+				});
+
+				event.preventDefault();
+			}
+		});
+	};
+});
+
+module.filter('remove', function() {
+	return function(input, remove) {
+		var out = [];
+		for (var i = 0; i < input.length; i++) {
+			if (remove.indexOf(input[i]) == -1) {
+				out.push(input[i]);
+			}
+		}
+		return out;
+	};
 });
\ No newline at end of file
diff --git a/ui/src/main/resources/META-INF/resources/ui/js/controllers.js b/ui/src/main/resources/META-INF/resources/ui/js/controllers.js
index f15a05f..fc25e46 100644
--- a/ui/src/main/resources/META-INF/resources/ui/js/controllers.js
+++ b/ui/src/main/resources/META-INF/resources/ui/js/controllers.js
@@ -39,9 +39,16 @@ module.controller('ApplicationDetailCtrl', function($scope, applications, applic
 		}
 	}, true);
 
-
 	$scope.addRole = function() {
 		if ($scope.newRole) {
+			for (var i = 0; i < $scope.application.roles.length; i++) {
+				if ($scope.application.roles[i] == $scope.newRole) {
+					Notifications.warn("Role already exists");
+					$scope.newRole = null;
+					return;
+				}
+			}
+			
 			if (!$scope.application.roles) {
 				$scope.application.roles = [];
 			}
@@ -51,8 +58,12 @@ module.controller('ApplicationDetailCtrl', function($scope, applications, applic
 		}
 	}
 
-	$scope.removeRole = function(i) {
-		$scope.application.roles.splice(i, 1);
+	$scope.removeRole = function(role) {
+		var i = $scope.application.roles.indexOf(role); 
+		if (i > -1) {
+			$scope.application.roles.splice(i, 1);
+		}
+		$scope.removeInitialRole(role);
 	};
 
 	$scope.addInitialRole = function() {
@@ -66,8 +77,11 @@ module.controller('ApplicationDetailCtrl', function($scope, applications, applic
 		}
 	}
 
-	$scope.removeInitialRole = function(i) {
-		$scope.application.initialRoles.splice(i, 1);
+	$scope.removeInitialRole = function(role) {
+		var i = $scope.application.initialRoles.indexOf(role);
+		if (i > -1) {
+			$scope.application.initialRoles.splice(i, 1);
+		}
 	};
 	
 	$scope.save = function() {
@@ -278,6 +292,14 @@ module.controller('RealmDetailCtrl', function($scope, Realm, realms, realm, $loc
 
 	$scope.addRole = function() {
 		if ($scope.newRole) {
+			for (var i = 0; i < $scope.realm.roles.length; i++) {
+				if ($scope.realm.roles[i] == $scope.newRole) {
+					Notifications.warn("Role already exists");
+					$scope.newRole = null;
+					return;
+				}
+			}
+			
 			if (!$scope.realm.roles) {
 				$scope.realm.roles = [];
 			}
@@ -287,8 +309,12 @@ module.controller('RealmDetailCtrl', function($scope, Realm, realms, realm, $loc
 		}
 	}
 
-	$scope.removeRole = function(i) {
-		$scope.realm.roles.splice(i, 1);
+	$scope.removeRole = function(role) {
+		var i = $scope.realm.roles.indexOf(role); 
+		if (i > -1) {
+			$scope.realm.roles.splice(i, 1);
+		}
+		$scope.removeInitialRole(role);
 	};
 
 	$scope.addInitialRole = function() {
@@ -302,8 +328,11 @@ module.controller('RealmDetailCtrl', function($scope, Realm, realms, realm, $loc
 		}
 	}
 
-	$scope.removeInitialRole = function(i) {
-		$scope.realm.initialRoles.splice(i, 1);
+	$scope.removeInitialRole = function(role) {
+		var i = $scope.realm.initialRoles.indexOf(role);
+		if (i > -1) {
+			$scope.realm.initialRoles.splice(i, 1);
+		}
 	};
 
 	$scope.save = function() {
diff --git a/ui/src/main/resources/META-INF/resources/ui/js/services.js b/ui/src/main/resources/META-INF/resources/ui/js/services.js
index 6f70643..90328f4 100644
--- a/ui/src/main/resources/META-INF/resources/ui/js/services.js
+++ b/ui/src/main/resources/META-INF/resources/ui/js/services.js
@@ -20,14 +20,30 @@ module.factory('Notifications', function($rootScope, $timeout) {
 	if (!$rootScope.notifications) {
 		$rootScope.notifications = [];
 	}
+	
+	notifications.message = function(type, message) {
+		$rootScope.notification = {
+				type : type,
+				message : message
+			};
+
+			schedulePop();
+	}
+
+	notifications.info = function(message) {
+		notifications.message("info", message);
+	};
 
 	notifications.success = function(message) {
-		$rootScope.notification = {
-			type : "success",
-			message : message
-		};
+		notifications.message("success", message);
+	};
+
+	notifications.error = function(message) {
+		notifications.message("error", message);
+	};
 
-		schedulePop();
+	notifications.warn = function(message) {
+		notifications.message("warn", message);
 	};
 
 	return notifications;
diff --git a/ui/src/main/resources/META-INF/resources/ui/partials/application-detail.html b/ui/src/main/resources/META-INF/resources/ui/partials/application-detail.html
index f274cc2..57ea1c5 100644
--- a/ui/src/main/resources/META-INF/resources/ui/partials/application-detail.html
+++ b/ui/src/main/resources/META-INF/resources/ui/partials/application-detail.html
@@ -42,7 +42,7 @@
 					<div class="control-group">
 						<label class="control-label">Roles</label>
 						<div class="controls">
-							<span style="margin-right: 1em;" data-ng-repeat="r in application.roles">{{r}} <button data-ng-click="removeRole($index)"><i class="icon-remove"></i></button></span>
+							<span class="label" style="margin-right: 1em;" data-ng-repeat="r in (application.roles|orderBy:'toString()')">{{r}} <button data-ng-click="removeRole(r)"><i class="icon-remove icon-white"></i></button></span>
 							
 							<div class="input-append">
 								<input class="input-small" type="text" data-ng-model="newRole" placeHolder="Role" data-kc-enter="addRole()" />
@@ -54,11 +54,11 @@
 					<div class="control-group">
 						<label class="control-label">Initial Roles</label>
 						<div class="controls">
-							<span style="margin-right: 1em;" data-ng-repeat="r in application.initialRoles">{{r}} <button data-ng-click="removeInitialRole($index)"><i class="icon-remove"></i></button></span>
+							<span class="label" style="margin-right: 1em;" data-ng-repeat="r in (application.initialRoles|orderBy:'toString()')">{{r}} <button data-ng-click="removeInitialRole(r)"><i class="icon-remove icon-white"></i></button></span>
 							
 							<div class="input-append">
 								<select style="width: auto;" data-ng-model="newInitialRole" data-ng-click="addInitialRole()">
-                                	<option data-ng-repeat="r in application.roles" value="{{r}}">{{r}}</option>
+                                	<option data-ng-repeat="r in (application.roles|remove:application.initialRoles|orderBy:'toString()')" value="{{r}}">{{r}}</option>
                             	</select>
 							</div>
 						</div>
diff --git a/ui/src/main/resources/META-INF/resources/ui/partials/realm-detail.html b/ui/src/main/resources/META-INF/resources/ui/partials/realm-detail.html
index 473e60b..f80b606 100644
--- a/ui/src/main/resources/META-INF/resources/ui/partials/realm-detail.html
+++ b/ui/src/main/resources/META-INF/resources/ui/partials/realm-detail.html
@@ -56,7 +56,7 @@
 					<div class="control-group">
 						<label class="control-label">Roles</label>
 						<div class="controls">
-							<span style="margin-right: 1em;" data-ng-repeat="r in realm.roles">{{r}} <button data-ng-click="removeRole($index)"><i class="icon-remove"></i></button></span>
+							<span class="label" style="margin-right: 1em;" data-ng-repeat="r in (realm.roles|orderBy:'toString()')">{{r}} <button data-ng-click="removeRole(r)"><i class="icon-remove icon-white"></i></button></span>
 							
 							<div class="input-append">
 								<input class="input-small" type="text" data-ng-model="newRole" placeHolder="Role" data-kc-enter="addRole()" />
@@ -68,11 +68,11 @@
 					<div class="control-group">
 						<label class="control-label">Initial Roles</label>
 						<div class="controls">
-							<span style="margin-right: 1em;" data-ng-repeat="r in realm.initialRoles">{{r}} <button data-ng-click="removeInitialRole($index)"><i class="icon-remove"></i></button></span>
+							<span class="label" style="margin-right: 1em;" data-ng-repeat="r in (realm.initialRoles|orderBy:'toString()')">{{r}} <button data-ng-click="removeInitialRole(r)"><i class="icon-remove icon-white"></i></button></span>
 							
 							<div class="input-append">
 								<select style="width: auto;" data-ng-model="newInitialRole" data-ng-click="addInitialRole()">
-                                	<option data-ng-repeat="r in realm.roles" value="{{r}}">{{r}}</option>
+                                	<option data-ng-repeat="r in (realm.roles|remove:realm.initialRoles|orderBy:'toString()')" value="{{r}}">{{r}}</option>
                             	</select>
 							</div>
 						</div>