From acfd53edbfc2540658fc0c7dc93344f5705089cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Mon, 29 Feb 2016 10:40:45 +0100 Subject: [PATCH] Warning Max Users per Project --- CHANGELOG.md | 1 + app/coffee/modules/admin/memberships.coffee | 30 +++- app/coffee/modules/common/confirm.coffee | 7 +- app/locales/taiga/locale-en.json | 4 +- .../dropdown-project-list.jade | 4 +- .../services/current-user.service.coffee | 19 +++ .../services/current-user.service.spec.coffee | 108 ++++++++++++- app/partials/admin/admin-memberships.jade | 16 +- app/styles/components/buttons.scss | 10 -- app/styles/dependencies/helpers.scss | 5 + app/styles/layout/admin-memberships.scss | 5 + app/styles/modules/common/lightbox.scss | 4 +- app/svg/icons/team-question.svg | 4 + app/svg/sprite.svg | 147 ++++++++++++------ 14 files changed, 293 insertions(+), 71 deletions(-) create mode 100644 app/svg/icons/team-question.svg diff --git a/CHANGELOG.md b/CHANGELOG.md index 3edcdd55..4246e874 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Moved from iconfont to SVG sprite icon system and redesign. - Redesign 'Admin > Project > Modules' panel. - Add badge to project owners +- Limit of user per project. ### Misc - Lots of small and not so small bugfixes. diff --git a/app/coffee/modules/admin/memberships.coffee b/app/coffee/modules/admin/memberships.coffee index bd3dc25e..9dbae4fe 100644 --- a/app/coffee/modules/admin/memberships.coffee +++ b/app/coffee/modules/admin/memberships.coffee @@ -47,11 +47,13 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai "$tgNavUrls", "$tgAnalytics", "tgAppMetaService", - "$translate" + "$translate", + "tgCurrentUserService", + "$tgAuth" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @analytics, - @appMetaService, @translate) -> + @appMetaService, @translate, @currentUserService, @tgAuth) -> bindMethods(@) @scope.project = {} @@ -63,6 +65,7 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai title = @translate.instant("ADMIN.MEMBERSHIPS.PAGE_TITLE", {projectName: @scope.project.name}) description = @scope.project.description @appMetaService.setAll(title, description) + @._checkUsersLimit() promise.then null, @.onInitialDataError.bind(@) @@ -93,8 +96,11 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai loadInitialData: -> promise = @.loadProject() - promise.then => - @.loadMembers() + + @q.all([ + @.loadMembers(), + @tgAuth.refresh() + ]) return promise @@ -106,6 +112,22 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai addNewMembers: -> @rootscope.$broadcast("membersform:new") + _checkUsersLimit: -> + @scope.canAddUsers = true + userData = @currentUserService.getUser().toJS() + + if @currentUserService.canAddMoreMembersInPrivateProjects(@scope.projectId).valid == false + @.maxMembers = userData.max_members_private_projects + @scope.canAddUsers = false + else if @currentUserService.canAddMoreMembersInPublicProjects(@scope.projectId).valid == false + @.maxMembers = userData.max_members_private_projects + @scope.canAddUsers = false + + limitUsersWarning: -> + title = @translate.instant("ADMIN.MEMBERSHIPS.LIMIT_USERS_WARNING") + message = @translate.instant("ADMIN.MEMBERSHIPS.LIMIT_USERS_WARNING_MESSAGE", {members: @.maxMembers}) + icon = "/" + window._version + "/svg/icons/team-question.svg" + @confirm.success(title, message,icon) module.controller("MembershipsController", MembershipsController) diff --git a/app/coffee/modules/common/confirm.coffee b/app/coffee/modules/common/confirm.coffee index c7c93e20..e9e6184e 100644 --- a/app/coffee/modules/common/confirm.coffee +++ b/app/coffee/modules/common/confirm.coffee @@ -161,11 +161,16 @@ class ConfirmService extends taiga.Service return defered.promise - success: (title, message) -> + success: (title, message, icon) -> defered = @q.defer() el = angular.element(".lightbox-generic-success") + el.find("img").remove() + detailImage = $('').addClass('lb-icon').attr('src', icon) + if detailImage + el.find('section').prepend(detailImage) + # Render content el.find(".title").html(title) if title el.find(".message").html(message) if message diff --git a/app/locales/taiga/locale-en.json b/app/locales/taiga/locale-en.json index 9b644e2d..c53fc45b 100644 --- a/app/locales/taiga/locale-en.json +++ b/app/locales/taiga/locale-en.json @@ -408,7 +408,9 @@ "TITLE": "Manage members", "PAGE_TITLE": "Memberships - {{projectName}}", "ADD_BUTTON": "+ New member", - "ADD_BUTTON_TITLE": "Add new member" + "ADD_BUTTON_TITLE": "Add new member", + "LIMIT_USERS_WARNING": "Why can't I add more members", + "LIMIT_USERS_WARNING_MESSAGE": "Currently you can only have {{members}} members per project. If you want to add more members get in touch with the administrators" }, "PROJECT_EXPORT": { "TITLE": "Export", diff --git a/app/modules/navigation-bar/dropdown-project-list/dropdown-project-list.jade b/app/modules/navigation-bar/dropdown-project-list/dropdown-project-list.jade index 50bc0a4d..47a2a7c0 100644 --- a/app/modules/navigation-bar/dropdown-project-list/dropdown-project-list.jade +++ b/app/modules/navigation-bar/dropdown-project-list/dropdown-project-list.jade @@ -4,8 +4,8 @@ a(href="", title="Projects", tg-nav="projects") div.navbar-dropdown.dropdown-project-list ul - li(tg-repeat="project in vm.projects track by project.get('id')") - a(href="#", tg-nav="project:project=project.get('slug')") {{::project.get("name")}} + li(tg-repeat="project in vm.projects track by project.get('id')") + a(href="#", tg-nav="project:project=project.get('slug')") {{::project.get("name")}} a.see-more-projects-btn.button-gray( href="#", diff --git a/app/modules/services/current-user.service.coffee b/app/modules/services/current-user.service.coffee index a14ffb8d..cfc5ad4b 100644 --- a/app/modules/services/current-user.service.coffee +++ b/app/modules/services/current-user.service.coffee @@ -118,6 +118,25 @@ class CurrentUserService return @.projects + canAddMoreMembersInPrivateProjects: (projectId) -> + project = @.projects.get('all').find (project) -> project.get('id') == projectId + user = @.getUser() + + if user.get('max_members_private_projects') != null && project.get('members').size >= user.get('max_members_private_projects') + return {valid: false, reason: 'max_members_private_projects', type: 'private_project'} + + return {valid: true} + + canAddMoreMembersInPublicProjects: (projectId) -> + project = @.projects.get('all').find (project) -> project.get('id') == projectId + user = @.getUser() + + if user.get('max_members_public_projects') != null && project.get('members').size >= user.get('max_members_public_projects') + return {valid: false, reason: 'max_members_public_projects', type: 'public_project'} + + return {valid: true} + + canBePrivateProject: (projectId) -> project = @.projects.get('all').find (project) -> project.get('id') == projectId diff --git a/app/modules/services/current-user.service.spec.coffee b/app/modules/services/current-user.service.spec.coffee index 32b51b0b..9747924b 100644 --- a/app/modules/services/current-user.service.spec.coffee +++ b/app/modules/services/current-user.service.spec.coffee @@ -204,6 +204,112 @@ describe "tgCurrentUserService", -> done() + it "the user can't add more members in private projects", () -> + user = Immutable.fromJS({ + id: 1, + name: "fake1", + max_members_private_projects: 2 + }) + + projects = Immutable.fromJS({ + all: [ + {id: 1, name: "fake1"}, + {id: 2, name: "fake2", members: [1, 2, 3, 4, 5], is_private: true}, + {id: 3, name: "fake3"}, + {id: 4, name: "fake4"} + ] + }) + + currentUserService._user = user + currentUserService._projects = projects + + result = currentUserService.canAddMoreMembersInPrivateProjects(2) + + expect(result).to.be.eql({ + valid: false, + reason: 'max_members_private_projects', + type: 'private_project' + }) + + it "the user can add more members in private projects", () -> + user = Immutable.fromJS({ + id: 1, + name: "fake1", + max_members_private_projects: 7 + }) + + currentUserService._user = user + + projects = Immutable.fromJS({ + all: [ + {id: 1, name: "fake1"}, + {id: 2, name: "fake2", members: [1, 2, 3, 4, 5], is_private: true}, + {id: 3, name: "fake3"}, + {id: 4, name: "fake4"} + ] + }) + + currentUserService._projects = projects + + result = currentUserService.canAddMoreMembersInPrivateProjects(2) + + expect(result).to.be.eql({ + valid: true + }) + + it "the user can't add more members in public projects", () -> + user = Immutable.fromJS({ + id: 1, + name: "fake1", + max_members_public_projects: 2 + }) + + projects = Immutable.fromJS({ + all: [ + {id: 1, name: "fake1"}, + {id: 2, name: "fake2", members: [1, 2, 3, 4, 5], is_private: false}, + {id: 3, name: "fake3"}, + {id: 4, name: "fake4"} + ] + }) + + currentUserService._user = user + currentUserService._projects = projects + + result = currentUserService.canAddMoreMembersInPublicProjects(2) + + expect(result).to.be.eql({ + valid: false, + reason: 'max_members_public_projects', + type: 'public_project' + }) + + it "the user can add more members in public projects", () -> + user = Immutable.fromJS({ + id: 1, + name: "fake1", + max_members_public_projects: 7 + }) + + projects = Immutable.fromJS({ + all: [ + {id: 1, name: "fake1"}, + {id: 2, name: "fake2", members: [1, 2, 3, 4, 5], is_private: false}, + {id: 3, name: "fake3"}, + {id: 4, name: "fake4"} + ] + }) + + currentUserService._user = user + currentUserService._projects = projects + + result = currentUserService.canAddMoreMembersInPublicProjects(2) + + expect(result).to.be.eql({ + valid: true + }) + + it "the user can't create private projects if they reach the maximum number of private projects", () -> user = Immutable.fromJS({ id: 1, @@ -214,7 +320,7 @@ describe "tgCurrentUserService", -> currentUserService._user = user - result = currentUserService.canCreatePrivateProjects(0) + result = currentUserService.canCreatePrivateProjects() expect(result).to.be.eql({ valid: false, diff --git a/app/partials/admin/admin-memberships.jade b/app/partials/admin/admin-memberships.jade index 1944fb21..b97c5451 100644 --- a/app/partials/admin/admin-memberships.jade +++ b/app/partials/admin/admin-memberships.jade @@ -13,9 +13,19 @@ div.wrapper.memberships(ng-controller="MembershipsController as ctrl", include ../includes/components/mainTitle .action-buttons - a.button-green(href="", title="{{ ADMIN.MEMBERSHIPS.ADD_BUTTON_TITLE | translate }}", - ng-click="ctrl.addNewMembers()") - span.text(translate="ADMIN.MEMBERSHIPS.ADD_BUTTON") + a.limit-users-warning( + ng-if="!canAddUsers" + translate="ADMIN.MEMBERSHIPS.LIMIT_USERS_WARNING" + translate-values="{members: ctrl.maxMembers}" + href="" + ng-click="ctrl.limitUsersWarning()" + ) + button.button-green( + title="{{ ADMIN.MEMBERSHIPS.ADD_BUTTON_TITLE | translate }}", + ng-click="ctrl.addNewMembers()" + translate="ADMIN.MEMBERSHIPS.ADD_BUTTON" + ng-disabled="!canAddUsers" + ) include ../includes/modules/admin/admin-membership-table diff --git a/app/styles/components/buttons.scss b/app/styles/components/buttons.scss index 77c4b389..1be18ede 100755 --- a/app/styles/components/buttons.scss +++ b/app/styles/components/buttons.scss @@ -44,7 +44,6 @@ } } } - .trans-button { @extend %medium; @extend %title; @@ -61,12 +60,9 @@ color: $blackish; } } - - .submit-button { width: 100%; } - .button-green, a.button-green { @extend %button; @@ -77,7 +73,6 @@ a.button-green { color: $white; } } - .button-gray, a.button-gray { @extend %button; @@ -88,7 +83,6 @@ a.button-gray { color: $white; } } - .button-blackish { @extend %button; background: $blackish; @@ -98,7 +92,6 @@ a.button-gray { color: $white; } } - .button-red { @extend %button; background: $red-light; @@ -110,7 +103,6 @@ a.button-gray { color: $white; } } - .button-block { background: $white; color: $red; @@ -119,7 +111,6 @@ a.button-gray { color: $white; } } - .button-bulk { @extend %button; background: $primary; @@ -134,7 +125,6 @@ a.button-gray { background: $primary-light; } } - .button-auth { @extend %button; background: $grayer; diff --git a/app/styles/dependencies/helpers.scss b/app/styles/dependencies/helpers.scss index e71a081c..d6d4d8aa 100644 --- a/app/styles/dependencies/helpers.scss +++ b/app/styles/dependencies/helpers.scss @@ -50,6 +50,11 @@ opacity: 0; transition: opacity .3s ease; } + .lb-icon { + @include svg-size(6rem); + display: block; + margin: 1rem auto; + } .title { text-align: center; } diff --git a/app/styles/layout/admin-memberships.scss b/app/styles/layout/admin-memberships.scss index 7d7ad3c4..6a8d22fd 100644 --- a/app/styles/layout/admin-memberships.scss +++ b/app/styles/layout/admin-memberships.scss @@ -5,6 +5,11 @@ float: right; } } + .limit-users-warning { + @extend %small; + color: $primary; + margin-right: 1rem; + } .check { input { // IE needs smaller size height: 40px; diff --git a/app/styles/modules/common/lightbox.scss b/app/styles/modules/common/lightbox.scss index 2cc9ed85..1a9b3379 100644 --- a/app/styles/modules/common/lightbox.scss +++ b/app/styles/modules/common/lightbox.scss @@ -1,8 +1,8 @@ .lightbox { @extend %lightbox; h2 { - @extend %larger; - @extend %text; + @extend %xlarge; + @extend %light; } } diff --git a/app/svg/icons/team-question.svg b/app/svg/icons/team-question.svg new file mode 100644 index 00000000..e8678f64 --- /dev/null +++ b/app/svg/icons/team-question.svg @@ -0,0 +1,4 @@ + + + diff --git a/app/svg/sprite.svg b/app/svg/sprite.svg index a0283ab7..68d91a7e 100644 --- a/app/svg/sprite.svg +++ b/app/svg/sprite.svg @@ -2,32 +2,38 @@ iocaine - lock - promote - trash - unlock - client-requirement - @@ -36,7 +42,8 @@ team-requirement - @@ -49,7 +56,8 @@ bulk - @@ -58,12 +66,14 @@ dashboard - discover - @@ -72,12 +82,14 @@ exclamation - flag - @@ -94,7 +106,8 @@ issues - @@ -103,32 +116,38 @@ like-empty - like - question - search - settings - team - @@ -145,22 +164,26 @@ unwatch - user - wiki - archive - @@ -181,7 +204,8 @@ attachment - @@ -198,7 +222,8 @@ bug - @@ -211,12 +236,14 @@ clipboard - document - @@ -233,7 +260,8 @@ error - @@ -246,27 +274,32 @@ github - maximize - minimize - move - reload - @@ -283,12 +316,14 @@ writer - watch - @@ -297,37 +332,44 @@ task - api - customize - feel-love - highly-designed - integration - lend-hand - @@ -336,17 +378,20 @@ smiley - social-management - speak-up - @@ -359,11 +404,19 @@ Looking for people - + Owner Badge - + + + + team-question +