You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by ma...@apache.org on 2016/10/13 10:12:27 UTC

syncope git commit: [SYNCOPE-958] adds enduser improvements

Repository: syncope
Updated Branches:
  refs/heads/2_0_X 45db7fc65 -> 2416b8d1b


[SYNCOPE-958] adds enduser improvements


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/2416b8d1
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/2416b8d1
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/2416b8d1

Branch: refs/heads/2_0_X
Commit: 2416b8d1b851f06bc12c3aae2bc29da7a3fe03fb
Parents: 45db7fc
Author: Matteo Di Carlo <ma...@tirasa.net>
Authored: Tue Oct 11 16:35:47 2016 +0200
Committer: Matteo Di Carlo <ma...@tirasa.net>
Committed: Thu Oct 13 12:10:11 2016 +0200

----------------------------------------------------------------------
 .../META-INF/resources/app/css/editUser.css     | 20 +++----
 .../resources/META-INF/resources/app/index.html |  1 -
 .../resources/META-INF/resources/app/js/app.js  |  6 +++
 .../app/js/controllers/LanguageController.js    | 57 --------------------
 .../app/js/controllers/LoginController.js       |  1 -
 .../app/js/controllers/UserController.js        | 24 ++++++---
 .../resources/app/js/directives/captcha.js      |  1 -
 .../app/js/directives/dynamicPlainAttribute.js  |  5 +-
 .../js/directives/dynamicVirtualAttributes.js   |  4 --
 .../app/js/directives/navigationButtons.js      |  5 +-
 .../resources/app/js/services/authService.js    |  2 +-
 .../resources/app/languages/de/dynamic.json     |  2 +-
 .../resources/app/languages/de/static.json      | 13 ++++-
 .../resources/app/languages/en/dynamic.json     |  2 +-
 .../resources/app/languages/en/static.json      | 13 ++++-
 .../resources/app/languages/it/dynamic.json     |  2 +-
 .../resources/app/languages/it/static.json      | 12 ++++-
 .../resources/app/views/auxClasses.html         |  2 +-
 .../META-INF/resources/app/views/editUser.html  |  3 +-
 .../META-INF/resources/app/views/groups.html    |  2 +-
 .../resources/app/views/passwordreset.html      |  4 +-
 .../META-INF/resources/app/views/resources.html |  2 +-
 .../META-INF/resources/app/views/self.html      |  8 +--
 .../resources/app/views/user-credentials.html   | 26 ++++-----
 .../app/views/user-derived-schemas.html         |  4 +-
 .../resources/app/views/user-form-finish.html   |  2 +-
 .../resources/app/views/user-groups.html        |  3 ++
 .../resources/app/views/user-plain-schemas.html |  4 +-
 .../resources/app/views/user-resources.html     |  2 +
 .../app/views/user-virtual-schemas.html         |  4 +-
 30 files changed, 114 insertions(+), 122 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/css/editUser.css
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/css/editUser.css b/client/enduser/src/main/resources/META-INF/resources/app/css/editUser.css
index 7617856..10d1105 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/css/editUser.css
+++ b/client/enduser/src/main/resources/META-INF/resources/app/css/editUser.css
@@ -139,13 +139,14 @@ under the License.
   /*width: 15%;*/
 }
 
-#form-views             { width:auto; }
+#form-views { width:100%; }
 
 /* basic styling for entering and leaving */
 /* left and right to add to ensure full width: position:absolute; left:30px; right:30px; */
 #form-views.ng-enter,
 #form-views.ng-leave      { 
-  transition:0.5s all ease; -moz-transition:0.5s all ease; -webkit-transition:0.5s all ease; 
+    position: absolute;
+  transition:0.5s all ease-in; -moz-transition:0.5s all ease-in; -webkit-transition:0.5s all ease; 
 }
 
 /* enter animation */
@@ -157,6 +158,7 @@ under the License.
 
 /* leave animation */
 #form-views.ng-leave            { 
+  position:absolute;
   -webkit-animation:slideOutLeft 0.5s both ease;
   -moz-animation:slideOutLeft 0.5s both ease;
   animation:slideOutLeft 0.5s both ease;   
@@ -260,30 +262,30 @@ under the License.
 ============================================================================= */
 /* slide out to the left */
 @keyframes slideOutLeft {
-  to      { transform: translateX(-200%); }
+  to      { transform: translateX(-300%); }
 }
 @-moz-keyframes slideOutLeft {  
-  to      { -moz-transform: translateX(-200%); }
+  to      { -moz-transform: translateX(-300%); }
 }
 @-webkit-keyframes slideOutLeft {
-  to      { -webkit-transform: translateX(-200%); }
+  to      { -webkit-transform: translateX(-300%); }
 }
 
 /* slide in from the right */
 @keyframes slideInRight {
-  from    { transform:translateX(200%); }
+  from    { transform:translateX(300%); }
   to      { transform: translateX(0); }
 }
 @-moz-keyframes slideInRight {
-  from    { -moz-transform:translateX(200%); }
+  from    { -moz-transform:translateX(300%); }
   to      { -moz-transform: translateX(0); }
 }
 @-webkit-keyframes slideInRight {
-  from    { -webkit-transform:translateX(200%); }
+  from    { -webkit-transform:translateX(300%); }
   to      { -webkit-transform: translateX(0); }
 }
 
-.multivalue>button{
+.multivalue button{
   float: right
 }
 .schema-type #date{

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/index.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/index.html b/client/enduser/src/main/resources/META-INF/resources/app/index.html
index 457cb76..55b34a5 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/index.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/index.html
@@ -97,7 +97,6 @@ under the License.
   <!--controllers-->
   <script src="js/controllers/HomeController.js"></script>
   <script src="js/controllers/LoginController.js"></script>
-  <script src="js/controllers/LanguageController.js"></script>
   <script src="js/controllers/UserController.js"></script>
   <script src="js/controllers/TailController.js"></script>
   <!--directives-->

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
index 5bffed2..12c814c 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/app.js
@@ -261,6 +261,8 @@ app.run(['$rootScope', '$location', '$state', 'AuthService',
     // main program
     // keep user logged in after page refresh
     //If the route change failed due to authentication error, redirect them out
+    $rootScope.endReached = false;
+
     $rootScope.$on('$routeChangeError', function (event, current, previous, rejection) {
       if (rejection === 'Not Authenticated') {
         $location.path('/self');
@@ -283,6 +285,7 @@ app.run(['$rootScope', '$location', '$state', 'AuthService',
           $state.go('self');
         }
         );
+
       } else if (toState.name === 'home' || toState.name === 'self') {
         AuthService.islogged().then(function (response) {
           if (response === "true") {
@@ -295,6 +298,9 @@ app.run(['$rootScope', '$location', '$state', 'AuthService',
           $state.go('self');
         }
         );
+        //enable "finish" button on every page in create mode
+      } else if (toState.name === 'create.finish') {
+        $rootScope.endReached = true;
       } else {
         $state.go(toState);
       }

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LanguageController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LanguageController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LanguageController.js
deleted file mode 100644
index 14e3acc..0000000
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LanguageController.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/* 
- * 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.
- */
-
-'use strict';
-
-angular.module('language')
-        .controller('LanguageController', function ($scope) {
-
-          $scope.init = function () {
-//            MainService.settings().then(function (response) {
-//              $scope.mainSettings = response;
-//            });
-
-            console.debug("Init language controller");
-          };
-
-          $scope.changeLanguage = function (language) {
-
-            console.info("Language changed to: ", language);
-            
-            $scope.languages.selectedLanguage = language;
-            
-//            $translate.use(langKey);
-//            LanguageService.switchLocale.query({language: langKey}, {}, function (response) {
-//              $scope.selectedLanguage.locale = langKey;
-//            });
-          };
-
-          this.retrieveLanguages = function () {
-//            LanguageService.language.query({}, function (response) {
-//              $scope.languages = response;
-//            });
-            console.debug("Retrieving available languages");
-          };
-
-
-          this.retrieveLanguages();
-
-
-        });
-

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js
index 9715bb4..75d41a6 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/LoginController.js
@@ -92,7 +92,6 @@ angular.module("login").controller("LoginController", ['$scope', '$http', '$loca
       });
     };
     $scope.switchLanguage = function () {
-      console.log('$scope.languages.selectedLanguage', $scope.languages.selectedLanguage.code);
       $translate.use($scope.languages.selectedLanguage.code);
     };
   }]);

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
index ebf5c81..7e84c17 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/controllers/UserController.js
@@ -204,7 +204,7 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
 
       $scope.refreshGroups = function () {
         initGroups();
-      }
+      };
 
       var initAuxClasses = function () {
         //fetching default user classes, that should remain in any case
@@ -213,15 +213,15 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
           AnyService.getAuxClasses().then(function (response) {
             for (var i = 0; i < response.length; i++) {
               //we should only add schemas that aren't in the anyUserType
-              if ($scope.dynamicForm.anyUserType.indexOf(response[i].key) == -1) {
+              if ($scope.dynamicForm.anyUserType.indexOf(response[i].key) === -1) {
                 $scope.dynamicForm.auxClasses.push(response[i].key);
               }
             }
           }, function (e) {
-            $scope.showError("An error occur during retrieving auxiliary classes " + e, $scope.notification)
+            $scope.showError("An error occur during retrieving auxiliary classes " + e, $scope.notification);
           });
         }, function (e) {
-          $scope.showError("An error occur during retrieving auxiliary classes " + e, $scope.notification)
+          $scope.showError("An error occur during retrieving auxiliary classes " + e, $scope.notification);
         });
       };
 
@@ -243,6 +243,7 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
         UserSelfService.read().then(function (response) {
           $scope.user = UserUtil.getUnwrappedUser(response);
           $scope.user.password = undefined;
+
           
           $scope.initialSecurityQuestion = $scope.user.securityQuestion;
           // initialize already assigned resources
@@ -367,7 +368,6 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
     };
 
     $scope.saveUser = function (user) {
-      console.debug("Save user: ", user);
       var wrappedUser = UserUtil.getWrappedUser(user);
       if ($scope.createMode) {
         UserSelfService.create(wrappedUser, $scope.captchaInput.value).then(function (response) {
@@ -409,7 +409,7 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
         });
       }
     };
-    
+
     $scope.retrieveSecurityQuestion = function (user) {
       if ($rootScope.pwdResetRequiringSecurityQuestions) {
         if (user && user.username && user.username.length) {
@@ -431,7 +431,7 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
         }
       }
     };
-    
+
     $scope.resetPassword = function (user) {
       if (user && user.username) {
         $scope.retrieveSecurityQuestion(user);
@@ -521,4 +521,14 @@ angular.module("self").controller("UserController", ['$scope', '$rootScope', '$l
         console.error("Logout failed: ", response);
       });
     };
+
+    $scope.finish = function (message) {
+      console.info("finish");
+      if ($scope.createMode) {
+        $state.go('create.finish');
+      } else {
+        $state.go('update.finish');
+      }
+    };
+
   }]);

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/js/directives/captcha.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/captcha.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/captcha.js
index a2d5938..ce62b88 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/captcha.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/captcha.js
@@ -32,7 +32,6 @@ angular.module('self')
 
               //initialize captcha
               $scope.refreshCaptcha = function () {
-                console.debug("REFRESH CAPTCHA")
                 $scope.captchaUrl = '/syncope-enduser/api/captcha' + '?' + new Date();
               };
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttribute.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttribute.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttribute.js
index 40d9fad..437d43a 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttribute.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicPlainAttribute.js
@@ -95,13 +95,10 @@ angular.module('self')
                     $scope.bindDateToModel = function (selectedDate, selectedTime) {
                       if (selectedDate && selectedTime) {
                         var extractedDate = selectedDate.toString().substring(0, 15);
-                        console.debug("selectedDate: ", extractedDate);
                         var extractedTime = selectedTime.toString().substring(16);
-                        console.debug("selectedTime: ", extractedTime);
                         var resultDate = extractedDate + ' ' + extractedTime;
                         var tmpdate = new Date(resultDate);
                         var milliseconds = tmpdate.getTime();
-                        console.debug("resultDate in milliseconds", milliseconds);
                         $scope.user.plainAttrs[schema.key].values[index] = milliseconds;
                       }
                     };
@@ -112,7 +109,7 @@ angular.module('self')
 
                     // Disable weekend selection
                     $scope.disabled = function (date, mode) {
-                      // example if you want to disable weekends
+                      // if you want to disable weekends:
                       // return (mode === 'day' && (date.getDay() === 0 || date.getDay() === 6));
                       return false;
                     };

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttributes.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttributes.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttributes.js
index 5e13233..7aeb3d4 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttributes.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/dynamicVirtualAttributes.js
@@ -55,14 +55,10 @@ angular.module('self')
               };
 
               $scope.addVirtualAttributeField = function (virSchemaKey) {
-                console.debug("Add VIRTUAL value:", virSchemaKey);
-                console.debug(" ", ($scope.dynamicForm.virtualAttributeTable[virSchemaKey].fields.length));
                 $scope.dynamicForm.virtualAttributeTable[virSchemaKey].fields.push(virSchemaKey + "_" + ($scope.dynamicForm.virtualAttributeTable[virSchemaKey].fields.length));
               };
 
               $scope.removeVirtualAttributeField = function (virSchemaKey, index) {
-                console.debug("Remove VIRTUAL value: ", virSchemaKey);
-                console.debug("Remove VIRTUAL value: ", index);
                 $scope.dynamicForm.virtualAttributeTable[virSchemaKey].fields.splice(index, 1);
                 // clean user model
                 $scope.user.virAttrs[virSchemaKey].values.splice(index, 1);

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/js/directives/navigationButtons.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/navigationButtons.js b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/navigationButtons.js
index d8b6986..9fa8292 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/directives/navigationButtons.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/directives/navigationButtons.js
@@ -28,7 +28,7 @@ angular.module('self')
                 current: "@"
               },
               link: function (scope, element, attrs) {
-                var base = (scope.base && scope.base != "" ? scope.base + "." : "");
+                var base = (scope.base && scope.base !== "" ? scope.base + "." : "");
                 scope.wizard = scope.$eval(attrs.wizard) || scope.$parent.wizard;
                 scope.previous = "none";
                 if (scope.wizard) {
@@ -43,7 +43,7 @@ angular.module('self')
                 $scope.validateAndNext = function (event, state) {
                   //getting the enclosing form in order to access to its name                
                   var currentForm = GenericUtil.getEnclosingForm(event.target);
-                  if (currentForm != null) {
+                  if (currentForm !== null) {
                     if (ValidationExecutor.validate(currentForm, $scope.$parent)) {
                       if (state) {
                         $scope.nextTab(state);
@@ -57,7 +57,6 @@ angular.module('self')
 
                 $scope.nextTab = function (state) {
                   //change route through parent event
-                  console.log("State: ", state);
                   $state.go(state);
                 };
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/js/services/authService.js
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/js/services/authService.js b/client/enduser/src/main/resources/META-INF/resources/app/js/services/authService.js
index d23e68a..45bef0f 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/js/services/authService.js
+++ b/client/enduser/src/main/resources/META-INF/resources/app/js/services/authService.js
@@ -50,7 +50,7 @@ angular.module('login')
               return $http
                       .get('/syncope-enduser/api/self/islogged')
                       .then(function (response) {
-                        console.debug("user logged:", response.data);
+//                        console.debug("user logged:", response.data);
                         return response.data;
                       }, function (response) {
                         console.error("error retrieving user login status");

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/languages/de/dynamic.json
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/languages/de/dynamic.json b/client/enduser/src/main/resources/META-INF/resources/app/languages/de/dynamic.json
index 452a4e3..aacf5ac 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/languages/de/dynamic.json
+++ b/client/enduser/src/main/resources/META-INF/resources/app/languages/de/dynamic.json
@@ -1,5 +1,5 @@
 {
-  "credentials": "Referenzen",
+  "credentials": "Details",
   "groups": "Gruppen",
   "plainSchemas": "PlainSchemas",
   "derivedSchemas": "DerivedSchemas",

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/languages/de/static.json
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/languages/de/static.json b/client/enduser/src/main/resources/META-INF/resources/app/languages/de/static.json
index 9c800db..3d67d89 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/languages/de/static.json
+++ b/client/enduser/src/main/resources/META-INF/resources/app/languages/de/static.json
@@ -2,8 +2,9 @@
   "USER": "Benutzer",
   "CHOSENLANGUAGE": "Gew�hlte sprache",
   "CAPTCHA": "Bitte geben sie den code im bild angezeigt.",
-  "CONFIRM_PASSWORD_RESET": "Best�tigen Sie Passwort-Reset",
+  "PASSWORD_PLACEHOLDER": "Passwort",
   "PASSWORD_RESET": "Passwort reset",
+  "CONFIRM_PASSWORD_RESET": "Best�tigen Sie Passwort-Reset",
   "NOTSECURE": "Nicht sicher!",
   "ALMOSTSECURE": "Sicher, aber man k�nnte es besser machen",
   "SUBMIT": "Einreichen",
@@ -11,18 +12,23 @@
   "PASSWORD_CHANGE_REQUIRED": "Passwort�nderung erforderlich",
   "PASSWORD_CHANGE": "Passwort�nderung",
   "CONFIRM_PASSWORD": "Best�tige das Passwort",
+  "CONFIRM_PASSWORD_PLACEHOLDER": "Best�tige das passwort",
   "VERYGOOD": "Sehr gut!",
   "PASSWORD_STRENGTH": "Passwort-Sicherheit",
   "NEXT": "N�chster",
   "PREVIOUS": "Fr�her",
+  "SAVE": "Speichern",
+  "FINISH": "Finish",  
   "USERDETAILS": "Nutzerdetails",
   "SECURITYQUESTION": "Sicherheitsfrage",
   "SELECTSECURITYQUESTION": "W�hlen Sie die Sicherheitsfrage",
   "SECURITYANSWER": "Sicherheitsantwort",
+  "SECURITYANSWER_PLACEHOLDER": "Sicherheitsantwort",
   "ISREQUIRED": "Wird ben�tigt",
   "SELFREGISTRATION": "Selbstregistrierung",
   "PASSWORDRESET": "Passwort zur�cksetzen",
   "USERNAME": "Benutzername",
+  "USERNAME_PLACEHOLDER": "Benutzername",
   "PASSWORD": "Passwort",
   "LOGIN": "Anmeldung",
   "LANGUAGES": "Sprachen",
@@ -30,12 +36,15 @@
   "ITALIAN": "Italienisch",
   "GERMAN": "Deutsch",
   "GROUPS": "Gruppen",
+  "GROUPS_PLACEHOLDER": "Klicken sie auf gruppen auszuw�hlen...",
   "AUXILIARY CLASSES": "Hilfsklassen",
-  "CREDENZIALI": "Referenzen",
+  "AUXILIARY_CLASSES_PLACEHOLDER": "Klicken sie auf hilfsklasse zu w�hlen",
+  "CREDENZIALI": "Details",
   "PLAINSCHEMAS": "PlainSchemas",
   "DERIVEDSCHEMAS": "Abgeleitet schemen",
   "VIRTUALSCHEMAS": "Virtuelle Schemen",
   "RESOURCES": "Ressourcen",
+  "RESOURCES_PLACEHOLDER": "Klicken sie auf ressourcen zu w�hlen...",
   "REALM": "Realm",
   "NEWUSER": "Neuer benutzer",
   "SUCCESSFULLY_CREATED": "succes aangemaakt",

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/languages/en/dynamic.json
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/languages/en/dynamic.json b/client/enduser/src/main/resources/META-INF/resources/app/languages/en/dynamic.json
index 2a68559..5583eb7 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/languages/en/dynamic.json
+++ b/client/enduser/src/main/resources/META-INF/resources/app/languages/en/dynamic.json
@@ -1,5 +1,5 @@
 {
-  "credentials": "Credentials",
+  "credentials": "Details",
   "groups": "Groups",
   "plainSchemas": "PlainSchemas",
   "derivedSchemas": "DerivedSchemas",

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/languages/en/static.json
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/languages/en/static.json b/client/enduser/src/main/resources/META-INF/resources/app/languages/en/static.json
index 543803e..fe88e0f 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/languages/en/static.json
+++ b/client/enduser/src/main/resources/META-INF/resources/app/languages/en/static.json
@@ -2,8 +2,9 @@
   "USER": "User",
   "CHOSENLANGUAGE": "Chosen language",
   "CAPTCHA": "Please enter the code displayed within the image.",
-  "CONFIRM_PASSWORD_RESET": "Confirm password reset",
+  "PASSWORD_PLACEHOLDER": "Password",
   "PASSWORD_RESET": "Password reset",
+  "CONFIRM_PASSWORD_RESET": "Confirm password reset",
   "NOTSECURE": "Not secure!",
   "ALMOSTSECURE": "Secure, but you could do better",
   "SUBMIT": "Submit",
@@ -11,18 +12,23 @@
   "PASSWORD_CHANGE_REQUIRED": "Password change required",
   "PASSWORD_CHANGE": "Password change",
   "CONFIRM_PASSWORD": "Confirm Password",
+  "CONFIRM_PASSWORD_PLACEHOLDER": "Confirm password",
   "VERYGOOD": "Very Good!",
   "PASSWORD_STRENGTH": "Password strength",
   "NEXT": "Next",
+  "SAVE": "Save",
+  "FINISH": "Finish",
   "PREVIOUS": "Previous",
   "USERDETAILS": "User Details",
   "SECURITYQUESTION": "Security question",
   "SELECTSECURITYQUESTION": "Select security question",
   "SECURITYANSWER": "Security answer",
+  "SECURITYANSWER_PLACEHOLDER": "Security answer",
   "ISREQUIRED": "is required",
   "SELFREGISTRATION": "Self registration",
   "PASSWORDRESET": "Password Reset",
   "USERNAME": "Username",
+  "USERNAME_PLACEHOLDER": "Username",
   "PASSWORD": "Password",
   "LOGIN": "Login",
   "LANGUAGES": "Languages",
@@ -30,12 +36,15 @@
   "ITALIAN": "Italian",
   "GERMAN": "German",
   "GROUPS": "Groups",
+  "GROUPS_PLACEHOLDER": "Click to select groups...",
   "AUXILIARY CLASSES": "Auxiliary classes",
-  "CREDENZIALI": "Credentials",
+  "AUXILIARY_CLASSES_PLACEHOLDER": "Click to select auxclasses...",
+  "CREDENZIALI": "Details",
   "PLAINSCHEMAS": "PlainSchemas",
   "DERIVEDSCHEMAS": "DerivedSchemas",
   "VIRTUALSCHEMAS": "VirtualSchemas",
   "RESOURCES": "Resources",
+  "RESOURCES_PLACEHOLDER": "Click to select resources...",
   "REALM": "Realm",
   "NEWUSER": "New User",
   "SUCCESSFULLY_CREATED": "succesfully created",

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/languages/it/dynamic.json
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/languages/it/dynamic.json b/client/enduser/src/main/resources/META-INF/resources/app/languages/it/dynamic.json
index 252c611..8ad757a 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/languages/it/dynamic.json
+++ b/client/enduser/src/main/resources/META-INF/resources/app/languages/it/dynamic.json
@@ -1,5 +1,5 @@
 {
-  "credentials": "Credenziali",
+  "credentials": "Dettagli",
   "groups": "Gruppi",
   "plainSchemas": "PlainSchemas",
   "derivedSchemas": "DerivedSchemas",

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/languages/it/static.json
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/languages/it/static.json b/client/enduser/src/main/resources/META-INF/resources/app/languages/it/static.json
index d1fee7c..803885f 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/languages/it/static.json
+++ b/client/enduser/src/main/resources/META-INF/resources/app/languages/it/static.json
@@ -2,7 +2,9 @@
   "USER": "Utente",
   "CHOSENLANGUAGE": "Lingua selezionata",
   "CAPTCHA": "Inserire il codice mostrato nell'immagine.",
+  "PASSWORD_PLACEHOLDER": "Password",
   "PASSWORD_RESET": "Recupero password",
+  "CONFIRM_PASSWORD_RESET": "Confirm password reset",
   "NOTSECURE": "Insicura!",
   "ALMOSTSECURE": "Sicura, ma potresti fare di meglio!",
   "SUBMIT": "Submit",
@@ -10,18 +12,23 @@
   "PASSWORD_CHANGE_REQUIRED": "Richiesta di cambio password",
   "PASSWORD_CHANGE": "Cambio Password",
   "CONFIRM_PASSWORD": "Conferma Password",
+  "CONFIRM_PASSWORD_PLACEHOLDER": "Conferma password",
   "PASSWORD_STRENGTH": "Sicurezza della password",
   "VERYGOOD": "Molto bene!",
   "NEXT": "Successivo",
   "PREVIOUS": "Precedente",
+  "SAVE": "Salva",
+  "FINISH": "Fine",
   "USERDETAILS": "Dettagli Utente",
   "SECURITYQUESTION": "Domanda di sicurezza",
   "SELECTSECURITYQUESTION": "Domanda di sicurezza",
   "SECURITYANSWER": "Risposta di sicurezza",
+  "SECURITYANSWER_PLACEHOLDER": "Risposta di sicurezza",
   "ISREQUIRED": "e' richiesto",
   "SELFREGISTRATION": "Registrazione",
   "PASSWORDRESET": "Password Reset",
   "USERNAME": "Nome Utente",
+  "USERNAME_PLACEHOLDER": "Nome Utente",
   "PASSWORD": "Password",
   "LOGIN": "Login",
   "LANGUAGES": "Linguaggi",
@@ -29,12 +36,15 @@
   "ITALIAN": "Italiano",
   "GERMAN": "Tedesco",
   "GROUPS": "Gruppi",
+  "GROUPS_PLACEHOLDER": "Clicca per selezionare i gruppi...",
   "AUXILIARY CLASSES": "Classi Ausiliari",
-  "CREDENZIALI": "CredentialI",
+  "AUXILIARY_CLASSES_PLACEHOLDER": "Clicca per selezionare le classi ausiliarie...",
+  "CREDENZIALI": "Dettagli",
   "PLAINSCHEMAS": "PlainSchemas",
   "DERIVEDSCHEMAS": "DerivedSchemas",
   "VIRTUALSCHEMAS": "VirtualSchemas",
   "RESOURCES": "Risorse",
+  "RESOURCES_PLACEHOLDER": "Clicca per selezionare risorse...",
   "NEWUSER": "Nuovo utente",
   "REALM": "Realm",
   "SUCCESSFULLY_CREATED": "creato con successo",

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/views/auxClasses.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/auxClasses.html b/client/enduser/src/main/resources/META-INF/resources/app/views/auxClasses.html
index d9bfbc1..9383f38 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/views/auxClasses.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/auxClasses.html
@@ -20,7 +20,7 @@ under the License.
   <ui-select on-select="addAuxClass($item, $model)" on-remove="removeAuxClass($item, $model)" multiple
              ng-model="dynamicForm.selectedAuxClasses" theme="select2" class="attribute-ui-select" 
              ng-disabled="{{auxClassDisabled}}">
-    <ui-select-match placeholder="Click to select auxiliary class..." class="ui-select-match">
+    <ui-select-match placeholder="{{'AUXILIARY_CLASSES_PLACEHOLDER'| translate}}" class="ui-select-match">
       {{$item}}
     </ui-select-match>
     <ui-select-choices repeat="auxClass in dynamicForm.auxClasses" class="ui-select-choices">

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/views/editUser.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/editUser.html b/client/enduser/src/main/resources/META-INF/resources/app/views/editUser.html
index e020c660..caa17a8 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/views/editUser.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/editUser.html
@@ -40,7 +40,8 @@ under the License.
           </div>
         </div>
         <form class="signup-form" name="userForm" ng-submit="saveUser(user)" novalidate>
-          <div id="form-views" ui-view>
+          <div id="form-views" ui-view >
+
           </div>
         </form>
       </div>

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/views/groups.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/groups.html b/client/enduser/src/main/resources/META-INF/resources/app/views/groups.html
index 2f00a9a..72fedf1 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/views/groups.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/groups.html
@@ -20,7 +20,7 @@ under the License.
   <ui-select on-select="addGroup($item, $model)" on-remove="removeGroup($item, $model)" multiple
              ng-model="dynamicForm.selectedGroups" theme="select2" class="attribute-ui-select" 
              ng-disabled="{{groupDisabled}}">
-    <ui-select-match placeholder="Click to select groups..." class="ui-select-match">
+    <ui-select-match placeholder="{{'GROUPS_PLACEHOLDER'| translate}}" class="ui-select-match">
       {{$item.groupName}}
     </ui-select-match>
     <ui-select-choices repeat="group in dynamicForm.groups | propsFilter: {selected: dynamicForm.selectedGroups} 

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/views/passwordreset.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/passwordreset.html b/client/enduser/src/main/resources/META-INF/resources/app/views/passwordreset.html
index 47abae5..3bb21c3 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/views/passwordreset.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/passwordreset.html
@@ -41,7 +41,7 @@ under the License.
             <div id="attribute" class="form-group">
               <label for="user.username">{{'USER'| translate}}</label>
               <input name="username" type="text" class="form-control" ng-model="user.username" required 
-                     placeholder="Username" ng-blur="retrieveSecurityQuestion(user)">
+                     placeholder="{{'USERNAME_PLACEHOLDER'|translate}}" ng-blur="retrieveSecurityQuestion(user)">
               <p ng-show="(userForm.username.$error.required && !userForm.username.$pristine)" 
                  class="text-validation-error">Username is required</p>
             </div>
@@ -54,7 +54,7 @@ under the License.
             <div id="attribute" class="form-group" ng-show="$root.pwdResetRequiringSecurityQuestions">
               <label for="user.securityAnswer">{{'SECURITYANSWER'| translate}}</label>
               <input name="securityAnswer" type="text" class="form-control" ng-model="user.securityAnswer" 
-                     placeholder="Security Answer" id="securityAnswer">              
+                     placeholder="{{'SECURITYANSWER_PLACEHOLDER'| translate}}" id="securityAnswer">              
             </div>
             <div id="attribute" class="form-group row">
               <!--captcha-->

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/views/resources.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/resources.html b/client/enduser/src/main/resources/META-INF/resources/app/views/resources.html
index 8072f05..4aee069 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/views/resources.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/resources.html
@@ -18,7 +18,7 @@ under the License.
 -->
 <ui-select on-select="addResource($item, $model)" on-remove="removeResource($item, $model)" multiple
            ng-model="dynamicForm.selectedResources" theme="select2" class="attribute-ui-select">
-  <ui-select-match placeholder="Select resource..." class="ui-select-match">{{$item}}</ui-select-match>
+  <ui-select-match placeholder="{{'RESOURCES_PLACEHOLDER'|translate}}" class="ui-select-match">{{$item}}</ui-select-match>
   <ui-select-choices repeat="resource in dynamicForm.resources" class="ui-select-choices">
     <div ng-bind-html="resource | highlight: $select.search"></div>
   </ui-select-choices>

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/views/self.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/self.html b/client/enduser/src/main/resources/META-INF/resources/app/views/self.html
index 818af7c..90cf216 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/views/self.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/self.html
@@ -34,12 +34,12 @@ under the License.
             <form id="login-form" class="form form-signin" novalidate>
               <fieldset class="form-group input-group">
                 <div class="form-group">
-                  <input autofocus="autofocus" type="text" class="form-control" id="login-username" placeholder="Username"
-                         ng-required ng-model="credentials.username" placeholder="username">
+                  <input autofocus="autofocus" type="text" class="form-control" id="login-username" placeholder="{{'USERNAME_PLACEHOLDER'| translate}}"
+                         ng-required ng-model="credentials.username">
                 </div>
                 <div class="form-group">
-                  <input type="password" class="form-control" id="login-password" placeholder="Password" 
-                         ng-required ng-model="credentials.password" placeholder="password">
+                  <input type="password" class="form-control" id="login-password" placeholder="{{'PASSWORD_PLACEHOLDER'| translate}}" 
+                         ng-required ng-model="credentials.password">
                 </div>
                 <div class="form-group">
                   <select  ng-change="switchLanguage()" id="language" style="width: 100%" class="btn dropdown-toggle btn-default" 

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/views/user-credentials.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/user-credentials.html b/client/enduser/src/main/resources/META-INF/resources/app/views/user-credentials.html
index 06cfe39..fca6237 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/views/user-credentials.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/user-credentials.html
@@ -17,28 +17,28 @@ specific language governing permissions and limitations
 under the License.
 -->
 <div id="attribute" class="form-group">
-  <label for="user.username">{{'USERNAME' | translate}} <span>*</span></label>
-  <input name="username" type="text" class="form-control" ng-model="user.username" required placeholder="username" validate="true"/>
+  <label for="user.username">{{'USERNAME'| translate}} <span>*</span></label>
+  <input name="username" type="text" class="form-control" ng-model="user.username" required placeholder="{{'USERNAME_PLACEHOLDER'|translate}}" validate="true"/>
   <validation-message name="username" template="requiredMessage" />
 </div>
 
 <div id="attribute" class="form-group">
   <label for="user.password">{{"PASSWORD"|translate}}</label>
-  <input type="password" class="form-control" name="password" ng-model="user.password" placeholder="password">
+  <input type="password" class="form-control" name="password" ng-model="user.password" placeholder="{{'PASSWORD_PLACEHOLDER'|translate}}">
 </div>
 
 <div id="attribute" class="form-group">
   <label for="confirmPassword">{{'CONFIRM_PASSWORD'| translate}}</label>
   <input name="password" type="password" class="form-control" equals="user.password" ng-model="confirmPassword.value"
-         placeholder="confirm password" validate="true">
+         placeholder="{{'CONFIRM_PASSWORD_PLACEHOLDER'| translate}}" validate="true">
   <validation-message name="password"/>
 </div>
 
 <div id="attribute" class="form-group">
   <div class="suggestions">
-   {{'PASSWORD_STRENGTH' | translate}}: 
-    <span ng-if="passStrength < 50">{{'NOTSECURE' | translate}}</span>
-    <span ng-if="passStrength >= 50 && passStrength <= 82">{{'ALMOSTSECURE' | translate}}</span>
+    {{'PASSWORD_STRENGTH'| translate}}: 
+    <span ng-if="passStrength < 50">{{'NOTSECURE'| translate}}</span>
+    <span ng-if="passStrength >= 50 && passStrength <= 82">{{'ALMOSTSECURE'| translate}}</span>
     <span ng-if="passStrength > 82">{{'VERYGOOD'| translate}}</span>
   </div>
   <div ng-password-strength="user.password" strength="passStrength" inner-class="progress-bar" inner-class-prefix="progress-bar-">
@@ -46,25 +46,27 @@ under the License.
 </div>
 
 <div id="attribute" class="form-group">
-  <label for="securityQuestion">{{'SECURITYQUESTION' | translate}}</label>
+  <label for="securityQuestion">{{'SECURITYQUESTION'| translate}}</label>
   <select name="securityQuestion" class="form-control"
           ng-model="user.securityQuestion"
           ng-options="securityQuestion.key as securityQuestion.content for securityQuestion in availableSecurityQuestions">
-    <option value="">{{'SELECTSECURITYQUESTION' | translate}}</option>
+    <option value="">{{'SELECTSECURITYQUESTION'| translate}}</option>
   </select>
 </div>
 
 <div id="attribute" class="form-group">
-  <label for="securityAnswer">{{'SECURITYANSWER' | translate}}</label>
+  <label for="securityAnswer">{{'SECURITYANSWER'| translate}}</label>
   <input ng-disabled="user.securityQuestion === null || user.securityQuestion === ''" name="securityAnswer" type="text" class="form-control" 
          ng-model="user.securityAnswer"
-         placeholder="security answer">
+         placeholder="{{'SECURITYANSWER_PLACEHOLDER'| translate}}">
 </div>
 
 <div id="attribute" class="form-group row">
+  <button id="save" ng-show="!createMode" type="button" class="btn btn-default pull-right" ng-click="finish()">{{'FINISH'| translate}}</button>
+  <button id="save" ng-show="createMode && endReached" type="button" class="btn btn-default pull-right" ng-click="finish()">{{'FINISH'| translate}}</button>
   <navigation-buttons ng-show="createMode" base="create" current="credentials" wizard="{{wizard}}"></navigation-buttons>
   <navigation-buttons ng-show="!createMode" base= "update" current="credentials" wizard="{{wizard}}"></navigation-buttons>
   <div class="pull-left">
-    <a id="cancel" href="#/self" class="btn btn-danger pull-left" ng-click="logout()">{{'CANCEL' | translate}}</a>
+    <a id="cancel" href="#/self" class="btn btn-danger pull-left" ng-click="logout()">{{'CANCEL'| translate}}</a>
   </div>
 </div>

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/views/user-derived-schemas.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/user-derived-schemas.html b/client/enduser/src/main/resources/META-INF/resources/app/views/user-derived-schemas.html
index 4f53652..f98e1c1 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/views/user-derived-schemas.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/user-derived-schemas.html
@@ -21,9 +21,11 @@ under the License.
 </div>
 
 <div id="attribute" class="form-group row">
+  <button id="save" ng-show="!createMode" type="button" class="btn btn-default pull-right" ng-click="finish()">{{'FINISH'| translate}}</button>
+  <button id="save" ng-show="createMode && endReached" type="button" class="btn btn-default pull-right" ng-click="finish()">{{'FINISH'| translate}}</button>
   <navigation-buttons ng-show="createMode" base="create" current="derivedSchemas" wizard="{{wizard}}"></navigation-buttons>
   <navigation-buttons ng-show="!createMode" base="update" current="derivedSchemas" wizard="{{wizard}}"></navigation-buttons>
   <div class="pull-left">
-    <a id="cancel" href="#/self" class="btn btn-danger" ng-click="logout()">{{'CANCEL' | translate}}</a>
+    <a id="cancel" href="#/self" class="btn btn-danger" ng-click="logout()">{{'CANCEL'| translate}}</a>
   </div>
 </div>

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/views/user-form-finish.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/user-form-finish.html b/client/enduser/src/main/resources/META-INF/resources/app/views/user-form-finish.html
index 8944ef7..b263324 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/views/user-form-finish.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/user-form-finish.html
@@ -21,7 +21,7 @@ under the License.
   <div class="form-group row">
     <captcha input="captchaInput" enabled="captchaEnabled"></captcha>
   </div>
-  <button id="save" type="submit" class="btn btn-default pull-right">Save</button>
+  <button id="save" type="submit" class="btn btn-default pull-right">{{'SAVE'| translate}}</button>
   <navigation-buttons ng-show="createMode" base="create" current="finish" wizard="{{wizard}}"></navigation-buttons>
   <navigation-buttons ng-show="!createMode" base="update" current="finish" wizard="{{wizard}}"></navigation-buttons>
   <div class="pull-left">

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/views/user-groups.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/user-groups.html b/client/enduser/src/main/resources/META-INF/resources/app/views/user-groups.html
index 632da03..9e31904 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/views/user-groups.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/user-groups.html
@@ -33,6 +33,9 @@ under the License.
   <auxiliary form="dynamicForm" user="user"></auxiliary>
 </div>
 <div id="attribute" class="form-group row">
+  <button id="save" ng-show="!createMode" type="button" class="btn btn-default pull-right" ng-click="finish()">{{'FINISH'| translate}}</button>
+  <button id="save" ng-show="createMode && endReached" type="button" class="btn btn-default pull-right" ng-click="finish()">{{'FINISH'| translate}}</button>
+
   <navigation-buttons ng-show="createMode" base="create" current="groups" wizard="{{wizard}}"></navigation-buttons>
   <navigation-buttons ng-show="!createMode" base="update" current="groups" wizard="{{wizard}}"></navigation-buttons>
   <div class="pull-left">

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/views/user-plain-schemas.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/user-plain-schemas.html b/client/enduser/src/main/resources/META-INF/resources/app/views/user-plain-schemas.html
index 7a9dd88..4885a85 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/views/user-plain-schemas.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/user-plain-schemas.html
@@ -21,9 +21,11 @@ under the License.
 </div>
 
 <div id="attribute" class="form-group row">
+  <button id="save" ng-show="!createMode" type="button" class="btn btn-default pull-right" ng-click="finish()">{{'FINISH'| translate}}</button>
+  <button id="save" ng-show="createMode && endReached" type="button" class="btn btn-default pull-right" ng-click="finish()">{{'FINISH'| translate}}</button>
   <navigation-buttons ng-show="createMode" base="create" current="plainSchemas" wizard="{{wizard}}"></navigation-buttons>
   <navigation-buttons ng-show="!createMode" base="update" current="plainSchemas" wizard="{{wizard}}"></navigation-buttons>
   <div class="pull-left">
-    <a id="cancel" href="#/self" class="btn btn-danger pull-left" ng-click="logout()">{{'CANCEL' | translate}}</a>
+    <a id="cancel" href="#/self" class="btn btn-danger pull-left" ng-click="logout()">{{'CANCEL'| translate}}</a>
   </div>
 </div>

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/views/user-resources.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/user-resources.html b/client/enduser/src/main/resources/META-INF/resources/app/views/user-resources.html
index ca45d79..0c2b2db 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/views/user-resources.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/user-resources.html
@@ -20,8 +20,10 @@ under the License.
   <resources form="dynamicForm" user="user"></resources>
 </div>
 <div id="attribute" class="form-group row">
+  <button id="save" ng-show="!createMode" type="button" class="btn btn-default pull-right" ng-click="finish()">{{'FINISH'| translate}}</button>
   <navigation-buttons ng-show="createMode" base="create" current="resources" wizard="{{wizard}}"></navigation-buttons>
   <navigation-buttons ng-show="!createMode" base="update" current="resources" wizard="{{wizard}}"></navigation-buttons>
+
   <div class="pull-left">
     <a id="cancel" href="#/self" class="btn btn-danger" ng-click="logout()">{{'CANCEL'| translate}}</a>
   </div>

http://git-wip-us.apache.org/repos/asf/syncope/blob/2416b8d1/client/enduser/src/main/resources/META-INF/resources/app/views/user-virtual-schemas.html
----------------------------------------------------------------------
diff --git a/client/enduser/src/main/resources/META-INF/resources/app/views/user-virtual-schemas.html b/client/enduser/src/main/resources/META-INF/resources/app/views/user-virtual-schemas.html
index b40c4c2..89653d6 100644
--- a/client/enduser/src/main/resources/META-INF/resources/app/views/user-virtual-schemas.html
+++ b/client/enduser/src/main/resources/META-INF/resources/app/views/user-virtual-schemas.html
@@ -22,9 +22,11 @@ under the License.
 </div>
 
 <div id="attribute" class="form-group row">
+  <button id="save" ng-show="!createMode" type="button" class="btn btn-default pull-right" ng-click="finish()">{{'FINISH'| translate}}</button>
+  <button id="save" ng-show="createMode && endReached" type="button" class="btn btn-default pull-right" ng-click="finish()">{{'FINISH'| translate}}</button>
   <navigation-buttons ng-show="createMode" base="create" current="virtualSchemas" wizard="{{wizard}}"></navigation-buttons>
   <navigation-buttons ng-show="!createMode" base="update" current="virtualSchemas" wizard="{{wizard}}"></navigation-buttons>
   <div class="pull-left">
-    <a id="cancel" href="#/self" class="btn btn-danger" ng-click="logout()">{{'CANCEL' | translate}}</a>
+    <a id="cancel" href="#/self" class="btn btn-danger" ng-click="logout()">{{'CANCEL'| translate}}</a>
   </div>
 </div>