diff --git a/UI/Templates/AdministrationUI/UIxAdministration.wox b/UI/Templates/AdministrationUI/UIxAdministration.wox index 2f3249359..52b953ca5 100644 --- a/UI/Templates/AdministrationUI/UIxAdministration.wox +++ b/UI/Templates/AdministrationUI/UIxAdministration.wox @@ -1,15 +1,15 @@ + xmlns:var="http://www.skyrix.com/od/binding" + xmlns:const="http://www.skyrix.com/od/constant" + xmlns:rsrc="OGo:url" + xmlns:label="OGo:label" + className="UIxPageFrame" + title="title" + const:jsFiles="Common.js, Administration.js, + Administration.services.js, Preferences.services.js, + Contacts.services.js, Scheduler.services.js">
@@ -39,77 +39,82 @@ --> diff --git a/UI/Templates/AdministrationUI/UIxAdministrationAclEditor.wox b/UI/Templates/AdministrationUI/UIxAdministrationAclEditor.wox index a98424095..110a7e1e3 100644 --- a/UI/Templates/AdministrationUI/UIxAdministrationAclEditor.wox +++ b/UI/Templates/AdministrationUI/UIxAdministrationAclEditor.wox @@ -6,9 +6,30 @@ xmlns:const="http://www.skyrix.com/od/constant" xmlns:label="OGo:label" > -
- -
+ +
+ +
+
+

{{::acl.user.cn}}

+
+ + {{::acl.folder.name}} +
+
+
+ + save + +
+ +
+ search - - save - -
- - - - -
- -
- -
-
-
-
-
-
{{user.cn}}
-
{{user.c_email}}
+
+ + +
+ +
+
- - delete - +
+
+
+
+
{{user.cn}}
+
{{user.c_email}}
- - - - - - - -
+ + delete + +
+
+ + + + + + +
- - -
-
- -
+ --> + + +
+
diff --git a/UI/WebServerResources/js/Administration/Administration.app.js b/UI/WebServerResources/js/Administration/Administration.app.js index ff9a7e69c..b1c620501 100644 --- a/UI/WebServerResources/js/Administration/Administration.app.js +++ b/UI/WebServerResources/js/Administration/Administration.app.js @@ -42,6 +42,7 @@ } }, resolve: { + stateUser: stateUser, stateFolder: stateFolder } }); @@ -49,39 +50,75 @@ // if none of the above states are matched, use this as the fallback $urlRouterProvider.otherwise('/rights'); } - - stateFolder.$inject = ['$stateParams', 'User', 'AddressBook', 'Calendar']; - function stateFolder($stateParams, User, AddressBook, Calendar) { - var user = _.find(User.$users, function(user) { + + /** + * @ngInject + */ + stateUser.$inject = ['$q', '$stateParams', 'User']; + function stateUser($q, $stateParams, User) { + var user; + + user = _.find(User.$users, function(user) { return user.uid == $stateParams.userId; }); - var folder = _.find(user.$$folders, function(folder) { - return folder.name == $stateParams.folderId; - }); + if (angular.isUndefined(user)) { + return User.$filter($stateParams.userId).then(function(users) { + user = _.find(User.$users, function(user) { + return user.uid == $stateParams.userId; + }); + if (angular.isUndefined(user)) { + return $q.reject('User with ID ' + $stateParams.userId + ' not found'); + } + else { + // Resolve folders + return user.$folders().then(function() { + return user; + }); + } + return user; + }); + } - var o; + return user; + } + + /** + * @ngInject + */ + stateFolder.$inject = ['$state', '$stateParams', 'decodeUriFilter', 'stateUser', 'AddressBook', 'Calendar']; + function stateFolder($state, $stateParams, decodeUriFilter, stateUser, AddressBook, Calendar) { + var folder, o, + folderId = decodeUriFilter($stateParams.folderId); + + folder = _.find(stateUser.$$folders, function(folder) { + return folder.name == folderId; + }); if (folder.type == "Appointment") { - o = new Calendar({id: folder.name.split('/').pop(), - owner: folder.owner, - name: folder.displayName}); + o = new Calendar({ id: folder.name.split('/').pop(), + owner: folder.owner, + name: folder.displayName }); } else { - o = new AddressBook({id: folder.name.split('/').pop(), - owner: folder.owner, - name: folder.displayName}); + o = new AddressBook({ id: folder.name.split('/').pop(), + owner: folder.owner, + name: folder.displayName }); } - + return o; } /** * @ngInject */ - runBlock.$inject = ['$rootScope']; - function runBlock($rootScope) { + runBlock.$inject = ['$log', '$rootScope', '$state']; + function runBlock($log, $rootScope, $state) { + $rootScope.$on('$stateChangeError', function(event, toState, toParams, fromState, fromParams, error) { + $log.error(error); + $state.go('administration.rights'); + }); $rootScope.$on('$routeChangeError', function(event, current, previous, rejection) { - console.error(event, current, previous, rejection); + $log.error(event, current, previous, rejection); }); } diff --git a/UI/WebServerResources/js/Administration/AdministrationAclController.js b/UI/WebServerResources/js/Administration/AdministrationAclController.js index 64c4e7427..bc965fc9d 100644 --- a/UI/WebServerResources/js/Administration/AdministrationAclController.js +++ b/UI/WebServerResources/js/Administration/AdministrationAclController.js @@ -7,13 +7,18 @@ /** * @ngInject */ - AdministrationAclController.$inject = ['$state', '$mdToast', 'stateFolder', 'User']; - function AdministrationAclController($state, $mdToast, stateFolder, User) { + AdministrationAclController.$inject = ['$animate', '$state', '$mdToast', 'stateUser', 'stateFolder', 'User']; + function AdministrationAclController($animate, $state, $mdToast, stateUser, stateFolder, User) { var vm = this; + vm.user = stateUser; + vm.folder = stateFolder; + vm.folderType = angular.isDefined(stateFolder.$cards)? 'AddressBook' : 'Calendar'; vm.selectedUser = null; - vm.getTemplate = getTemplate; + vm.selectedUid = null; vm.selectUser = selectUser; + vm.removeUser = removeUser; + vm.getTemplate = getTemplate; vm.save = save; vm.userToAdd = ''; @@ -33,19 +38,26 @@ } function selectUser(user) { - if (vm.selectedUser == user) { - vm.selectedUser = null; + if (vm.selectedUid == user.uid) { + vm.selectedUid = null; } else { + vm.selectedUid = user.uid; vm.selectedUser = user; vm.selectedUser.$rights(); } } function userFilter($query) { - return User.$filter($query, stateFolder.$acl.users); + return User.$filter($query, stateFolder.$acl.users, { dry: true }); } - + + function removeUser(user) { + stateFolder.$acl.$removeUser(user.uid).catch(function(data, status) { + Dialog.alert(l('Warning'), l('An error occured please try again.')); + }); + } + function addUser(data) { if (data) { stateFolder.$acl.$addUser(data, stateFolder.owner).then(function() { @@ -69,7 +81,6 @@ Dialog.alert(l('Warning'), l('An error occured please try again.')); }); } - } angular diff --git a/UI/WebServerResources/js/Administration/AdministrationController.js b/UI/WebServerResources/js/Administration/AdministrationController.js index de9a4e6ee..fb4e6b40a 100644 --- a/UI/WebServerResources/js/Administration/AdministrationController.js +++ b/UI/WebServerResources/js/Administration/AdministrationController.js @@ -7,8 +7,8 @@ /** * @ngInject */ - AdministrationController.$inject = ['$state', '$mdDialog', '$mdToast', 'Dialog', 'User', 'Administration']; - function AdministrationController($state, $mdDialog, $mdToast, Dialog, User, Administration) { + AdministrationController.$inject = ['$state', '$mdDialog', '$mdToast', 'Dialog', 'encodeUriFilter', 'User', 'Administration']; + function AdministrationController($state, $mdDialog, $mdToast, Dialog, encodeUriFilter, User, Administration) { var vm = this; vm.administration = Administration; @@ -26,8 +26,7 @@ } function filter(searchText) { - User.$filter(searchText).then(function() { - }); + User.$filter(searchText); } function selectUser(i) { @@ -43,7 +42,7 @@ } function selectFolder(folder) { - $state.go('administration.rights.edit', {userId: vm.selectedUser.uid, folderId: folder.name}); + $state.go('administration.rights.edit', {userId: vm.selectedUser.uid, folderId: encodeUriFilter(folder.name)}); } } diff --git a/UI/WebServerResources/js/Common/User.service.js b/UI/WebServerResources/js/Common/User.service.js index 355e08e80..c77de8ab8 100644 --- a/UI/WebServerResources/js/Common/User.service.js +++ b/UI/WebServerResources/js/Common/User.service.js @@ -43,25 +43,33 @@ * @param {object[]} excludedUsers - a list of User objects that must be excluded from the results * @return a promise of an array of matching User objects */ - User.$filter = function(search, excludedUsers) { + User.$filter = function(search, excludedUsers, options) { var _this = this, param = {search: search}; - if (!search) { - // No query specified - User.$users.splice(0, User.$users.length); - return User.$q.when(User.$users); + if (!options || !options.dry) { + if (!search) { + // No query specified + User.$users.splice(0, User.$users.length); + return User.$q.when(User.$users); + } + if (User.$query == search) { + // Query hasn't changed + return User.$q.when(User.$users); + } + User.$query = search; } - if (User.$query == search) { - // Query hasn't changed - return User.$q.when(User.$users); - } - User.$query = search; return User.$$resource.fetch(null, 'usersSearch', param).then(function(response) { - var results, index, user, + var results, index, user, users, compareUids = function(data) { return this.uid == data.uid; }; + + if (options && options.dry) + users = []; + else + users = User.$users; + if (excludedUsers) { // Remove excluded users from response results = _.filter(response.users, function(user) { @@ -73,21 +81,21 @@ } // Remove users that no longer match the search query - for (index = User.$users.length - 1; index >= 0; index--) { - user = User.$users[index]; + for (index = users.length - 1; index >= 0; index--) { + user = users[index]; if (!_.find(results, compareUids, user)) { - User.$users.splice(index, 1); + users.splice(index, 1); } } // Add new users matching the search query _.each(results, function(data, index) { - if (_.isUndefined(_.find(User.$users, compareUids, data))) { + if (_.isUndefined(_.find(users, compareUids, data))) { var user = new User(data); - User.$users.splice(index, 0, user); + users.splice(index, 0, user); } }); - User.$log.debug(User.$users); - return User.$users; + User.$log.debug(users); + return users; }); }; diff --git a/UI/WebServerResources/scss/components/card/card.scss b/UI/WebServerResources/scss/components/card/card.scss index f1dcc638e..e290edde4 100644 --- a/UI/WebServerResources/scss/components/card/card.scss +++ b/UI/WebServerResources/scss/components/card/card.scss @@ -16,6 +16,15 @@ md-card { margin: 0; flex-direction: row; } + .md-icon-button { + transition: $swift-linear; + transition-delay: 0.2s; + opacity: 1; + &.ng-hide { + transition: $swift-linear; + opacity: 0; + } + } md-card-content { order: 1; transition: $swift-ease-in-out; @@ -40,6 +49,9 @@ md-card { &.sg-expanded { @extend .md-whiteframe-z2; margin: 0 0 1px 0; + &-remove { + transition-delay: 0.5s; + } } .md-button { diff --git a/UI/WebServerResources/scss/core/typography.scss b/UI/WebServerResources/scss/core/typography.scss index 40cbdd49a..6f694b148 100644 --- a/UI/WebServerResources/scss/core/typography.scss +++ b/UI/WebServerResources/scss/core/typography.scss @@ -342,12 +342,24 @@ html p { font-weight: $sg-font-regular; white-space: nowrap; } -.#{$md}-display-2--light { +.#{$md}-display-2--thin { $lineHeight: $sg-line-height-7; font-size: $sg-font-size-7; line-height: $lineHeight; - font-weight: $sg-font-light; + font-weight: $sg-font-thin; } +.#{$md}-display-2-subheader { + @extend .#{$md}-title; + margin-bottom: $mg; + font-weight: $sg-font-regular; + white-space: normal; +} +.#{$md}-display-2-subheader--thin { + @extend .#{$md}-title; + margin-bottom: $mg; + font-weight: $sg-font-thin; + white-space: normal; +} .#{$md}-display-3 { $lineHeight : $sg-line-height-8; font-size: $sg-font-size-8; @@ -362,12 +374,6 @@ html p { font-weight: $sg-font-light; white-space: nowrap; } -.#{$md}-display-2-subheader { - @extend .#{$md}-title; - margin-bottom: $mg; - font-weight: $sg-font-thin; - white-space: normal; -} .sg-no-wrap { overflow: hidden; diff --git a/UI/WebServerResources/scss/views/AdministrationUI.scss b/UI/WebServerResources/scss/views/AdministrationUI.scss new file mode 100644 index 000000000..1d3cba1d1 --- /dev/null +++ b/UI/WebServerResources/scss/views/AdministrationUI.scss @@ -0,0 +1,20 @@ +/// AdministrationUI.scss -*- Mode: scss; indent-tabs-mode: nil; basic-offset: 2 -*- + +[id="usersList"] > md-list { + // Since the users list doesn't use the virtual repeater, force the vertical scroll + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + overflow: hidden; + overflow-y: auto; + + .sg-folder .md-button { + // Buttons in list-item to view the ACLs of a user's folder + @extend .sg-no-wrap; + flex: 1 1 auto; + text-align: left; + text-transform: none; + } +} diff --git a/UI/WebServerResources/scss/views/_view.scss b/UI/WebServerResources/scss/views/_view.scss index 783b6b9af..bb77240dc 100644 --- a/UI/WebServerResources/scss/views/_view.scss +++ b/UI/WebServerResources/scss/views/_view.scss @@ -5,6 +5,7 @@ @import 'ContactsUI.scss'; @import 'MessageEditorUI'; @import 'SchedulerUI'; +@import 'AdministrationUI'; .view[layout=row], .view.layout-row {