Merge pull request #920 from taigaio/us/67/leave-project

Us/67/leave project
stable
Alejandro 2016-03-18 12:13:22 +01:00
commit b4590269e4
15 changed files with 191 additions and 17 deletions

View File

@ -366,7 +366,7 @@ module.directive("tgMembershipsRowRoleSelector", ["$log", "$tgRepo", "$tgConfirm
## Member Actions Directive ## Member Actions Directive
############################################################################# #############################################################################
MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $translate) -> MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $translate, currentUserService, lightboxFactory) ->
activedTemplate = """ activedTemplate = """
<div class="active" <div class="active"
translate="ADMIN.MEMBERSHIP.STATUS_ACTIVE"> translate="ADMIN.MEMBERSHIP.STATUS_ACTIVE">
@ -421,9 +421,7 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla
$rs.memberships.resendInvitation($scope.member.id).then(onSuccess, onError) $rs.memberships.resendInvitation($scope.member.id).then(onSuccess, onError)
$el.on "click", ".delete", (event) -> leaveConfirm = () ->
event.preventDefault()
title = $translate.instant("ADMIN.MEMBERSHIP.DELETE_MEMBER") title = $translate.instant("ADMIN.MEMBERSHIP.DELETE_MEMBER")
defaultMsg = $translate.instant("ADMIN.MEMBERSHIP.DEFAULT_DELETE_MESSAGE", {email: member.email}) defaultMsg = $translate.instant("ADMIN.MEMBERSHIP.DEFAULT_DELETE_MESSAGE", {email: member.email})
message = if member.user then member.full_name else defaultMsg message = if member.user then member.full_name else defaultMsg
@ -448,6 +446,22 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla
$repo.remove(member).then(onSuccess, onError) $repo.remove(member).then(onSuccess, onError)
$el.on "click", ".delete", (event) ->
event.preventDefault()
if $scope.project.owner.id == member.user
currentUser = currentUserService.getUser()
isCurrentUser = currentUser.get('id') == member.user
lightboxFactory.create("tg-lightbox-leave-project-warning", {
class: "lightbox lightbox-leave-project-warning"
}, {
currentUser: isCurrentUser,
project: $scope.project
})
else
leaveConfirm()
$scope.$on "$destroy", -> $scope.$on "$destroy", ->
$el.off() $el.off()
@ -455,4 +469,4 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla
module.directive("tgMembershipsRowActions", ["$log", "$tgRepo", "$tgResources", "$tgConfirm", "$compile", module.directive("tgMembershipsRowActions", ["$log", "$tgRepo", "$tgResources", "$tgConfirm", "$compile",
"$translate", MembershipsRowActionsDirective]) "$translate", "tgCurrentUserService", "tgLightboxFactory", MembershipsRowActionsDirective])

View File

@ -697,3 +697,15 @@ AttachmentPreviewLightboxDirective = (lightboxService, $template, $compile) ->
} }
module.directive("tgLbAttachmentPreview", ["lightboxService", "$tgTemplate", "$compile", AttachmentPreviewLightboxDirective]) module.directive("tgLbAttachmentPreview", ["lightboxService", "$tgTemplate", "$compile", AttachmentPreviewLightboxDirective])
LightboxLeaveProjectWarningDirective = (lightboxService, $template, $compile) ->
link = ($scope, $el, attrs) ->
lightboxService.open($el)
return {
templateUrl: 'common/lightbox/lightbox-leave-project-warning.html',
link: link,
scope: true
}
module.directive("tgLightboxLeaveProjectWarning", ["lightboxService", LightboxLeaveProjectWarningDirective])

View File

@ -184,7 +184,7 @@ TeamMemberCurrentUserDirective = () ->
return { return {
templateUrl: "team/team-member-current-user.html" templateUrl: "team/team-member-current-user.html"
scope: { scope: {
projectId: "=projectid", project: "=project",
currentUser: "=currentuser", currentUser: "=currentuser",
stats: "=", stats: "=",
issuesEnabled: "=issuesenabled", issuesEnabled: "=issuesenabled",
@ -225,14 +225,14 @@ module.directive("tgTeamMembers", TeamMembersDirective)
## Leave project Directive ## Leave project Directive
############################################################################# #############################################################################
LeaveProjectDirective = ($repo, $confirm, $location, $rs, $navurls, $translate) -> LeaveProjectDirective = ($repo, $confirm, $location, $rs, $navurls, $translate, lightboxFactory) ->
link = ($scope, $el, $attrs) -> link = ($scope, $el, $attrs) ->
$scope.leave = () -> leaveConfirm = () ->
leave_project_text = $translate.instant("TEAM.ACTION_LEAVE_PROJECT") leave_project_text = $translate.instant("TEAM.ACTION_LEAVE_PROJECT")
confirm_leave_project_text = $translate.instant("TEAM.CONFIRM_LEAVE_PROJECT") confirm_leave_project_text = $translate.instant("TEAM.CONFIRM_LEAVE_PROJECT")
$confirm.ask(leave_project_text, confirm_leave_project_text).then (response) => $confirm.ask(leave_project_text, confirm_leave_project_text).then (response) =>
promise = $rs.projects.leave($attrs.projectid) promise = $rs.projects.leave($scope.project.id)
promise.then => promise.then =>
response.finish() response.finish()
@ -243,13 +243,27 @@ LeaveProjectDirective = ($repo, $confirm, $location, $rs, $navurls, $translate)
response.finish() response.finish()
$confirm.notify('error', response.data._error_message) $confirm.notify('error', response.data._error_message)
$scope.leave = () ->
if $scope.project.owner.id == $scope.user.id
lightboxFactory.create("tg-lightbox-leave-project-warning", {
class: "lightbox lightbox-leave-project-warning"
}, {
currentUser: true,
project: $scope.project
})
else
leaveConfirm()
return { return {
scope: {}, scope: {
user: "=",
project: "="
},
templateUrl: "team/leave-project.html", templateUrl: "team/leave-project.html",
link: link link: link
} }
module.directive("tgLeaveProject", ["$tgRepo", "$tgConfirm", "$tgLocation", "$tgResources", "$tgNavUrls", "$translate", module.directive("tgLeaveProject", ["$tgRepo", "$tgConfirm", "$tgLocation", "$tgResources", "$tgNavUrls", "$translate", "tgLightboxFactory",
LeaveProjectDirective]) LeaveProjectDirective])

View File

@ -919,6 +919,17 @@
"CREATE_MEMBER": { "CREATE_MEMBER": {
"PLACEHOLDER_INVITATION_TEXT": "(Optional) Add a personalized text to the invitation. Tell something lovely to your new members ;-)", "PLACEHOLDER_INVITATION_TEXT": "(Optional) Add a personalized text to the invitation. Tell something lovely to your new members ;-)",
"PLACEHOLDER_TYPE_EMAIL": "Type an Email" "PLACEHOLDER_TYPE_EMAIL": "Type an Email"
},
"LEAVE_PROJECT_WARNING": {
"TITLE": "You can not leave the project without owner",
"CURRENT_USER_OWNER": {
"DESC": "You are the project owner before leaving it you must pass the property to someone else.",
"BUTTON": "Change the project owner"
},
"OTHER_USER_OWNER": {
"DESC": "You can't delete the project owner, you must request a new owner before deleting the user.",
"BUTTON": "Request change project owner"
}
} }
}, },
"US": { "US": {

View File

@ -0,0 +1,19 @@
svg.close.icon.icon-close(href="", title="{{'COMMON.CLOSE' | translate}}")
use(xlink:href="#icon-close")
div.content
svg.icon.icon-exclamation
use(xlink:href="#icon-exclamation")
h2.title {{'LIGHTBOX.LEAVE_PROJECT_WARNING.TITLE' | translate}}
div(ng-if="currentUser")
p {{'LIGHTBOX.LEAVE_PROJECT_WARNING.CURRENT_USER_OWNER.DESC' | translate}}
a.button-green(tg-nav="project-admin-home:project=project.slug", href="")
span(translate="LIGHTBOX.LEAVE_PROJECT_WARNING.CURRENT_USER_OWNER.BUTTON")
div(ng-if="!currentUser")
p {{'LIGHTBOX.LEAVE_PROJECT_WARNING.OTHER_USER_OWNER.DESC' | translate}}
a.button-green(tg-nav="project-admin-home:project=project.slug", href="")
span(translate="LIGHTBOX.LEAVE_PROJECT_WARNING.OTHER_USER_OWNER.BUTTON")

View File

@ -31,7 +31,7 @@ section.table-team.basic-table
tg-team-current-user tg-team-current-user
stats="stats" stats="stats"
currentuser="currentUser" currentuser="currentUser"
projectid="projectId" project="project"
issuesEnabled="issuesEnabled" issuesEnabled="issuesEnabled"
tasksenabled="tasksEnabled" tasksenabled="tasksEnabled"
wikienabled="wikiEnabled" wikienabled="wikiEnabled"

View File

@ -12,7 +12,7 @@
.position(tg-bo-bind="currentUser.role_name") .position(tg-bo-bind="currentUser.role_name")
div(tg-leave-project="", projectid="{{projectId}}") div(tg-leave-project="", project="project", user="currentUser")
.member-stats( .member-stats(
tg-team-member-stats tg-team-member-stats

View File

@ -552,3 +552,16 @@
height: 5rem; height: 5rem;
} }
} }
.lightbox-leave-project-warning {
text-align: center;
.icon {
fill: $gray-light;
height: 3rem;
margin-bottom: 1rem;
width: 3rem;
}
.content {
width: 500px;
}
}

View File

@ -35,10 +35,30 @@ helper.getNewMemberLightbox = function() {
return obj; return obj;
}; };
helper.leavingProjectWarningLb = function() {
return $('div[tg-lightbox-leave-project-warning]');
};
helper.isLeaveProjectWarningOpen = function() {
return helper.leavingProjectWarningLb().isPresent();
};
helper.getMembers = function() { helper.getMembers = function() {
return $$('.admin-membership-table .row'); return $$('.admin-membership-table .row');
}; };
helper.getOwner = function() {
return helper.getMembers().filter(async (member) => {
return !!await member.$$('.icon-badge').count();
}).first();
};
helper.excludeOwner = function(members) {
return members.filter(async (member) => {
return !await member.$$('.icon-badge').count();
});
};
helper.isActive = function(elm) { helper.isActive = function(elm) {
return utils.common.hasClass(elm, 'active'); return utils.common.hasClass(elm, 'active');
}; };

View File

@ -23,13 +23,13 @@ helper.createProjectLightbox = function() {
await browser.sleep(1000); await browser.sleep(1000);
}, },
submit: function() { submit: function() {
return $('.wizard-step.active .button-green').click(); return $('div[tg-lb-create-project] .button-green').click();
}, },
name: function() { name: function() {
return $$('.create-step2 input').get(0); return $$('div[tg-lb-create-project] input[type="text"]').get(0);
}, },
description: function() { description: function() {
return $$('.create-step2 textarea'); return $('div[tg-lb-create-project] textarea');
}, },
errors: function() { errors: function() {
return $$('.checksley-error-list li'); return $$('.checksley-error-list li');

View File

@ -53,3 +53,11 @@ helper.filters = function() {
return obj; return obj;
}; };
helper.leavingProjectWarningLb = function() {
return $('div[tg-lightbox-leave-project-warning]');
};
helper.isLeaveProjectWarningOpen = function() {
return helper.leavingProjectWarningLb().isPresent();
};

View File

@ -78,7 +78,7 @@ describe('admin - members', function() {
it('delete member', async function() { it('delete member', async function() {
let initMembersCount = await adminMembershipsHelper.getMembers().count(); let initMembersCount = await adminMembershipsHelper.getMembers().count();
let member = adminMembershipsHelper.getMembers().last(); let member = adminMembershipsHelper.excludeOwner(adminMembershipsHelper.getMembers()).last();
adminMembershipsHelper.delete(member); adminMembershipsHelper.delete(member);
@ -89,6 +89,25 @@ describe('admin - members', function() {
let membersCount = await adminMembershipsHelper.getMembers().count(); let membersCount = await adminMembershipsHelper.getMembers().count();
expect(membersCount).to.be.equal(initMembersCount - 1); expect(membersCount).to.be.equal(initMembersCount - 1);
await utils.notifications.success.close();
});
it('trying to delete owner', async function() {
let member = await adminMembershipsHelper.getOwner();
adminMembershipsHelper.delete(member);
utils.common.takeScreenshot('memberships', 'delete-owner-lb');
let isLeaveProjectWarningOpen = await adminMembershipsHelper.isLeaveProjectWarningOpen();
expect(isLeaveProjectWarningOpen).to.be.equal(true);
let lb = adminMembershipsHelper.leavingProjectWarningLb();
await utils.lightbox.exit(lb);
await utils.lightbox.close(lb);
}); });
it('change role', async function() { it('change role', async function() {

View File

@ -20,6 +20,31 @@ describe('leaving project', function(){
}); });
}); });
describe('leaving project owner', function(){
before(async function(){
await utils.common.createProject();
await utils.nav
.init()
.team()
.go();
});
it('leave project', async function(){
teamHelper.team().leave();
let isLeaveProjectWarningOpen = await teamHelper.isLeaveProjectWarningOpen();
await utils.common.takeScreenshot("team", "leave-project-warning");
expect(isLeaveProjectWarningOpen).to.be.equal(true);
let lb = teamHelper.leavingProjectWarningLb();
await utils.lightbox.exit(lb);
await utils.lightbox.close(lb);
});
});
describe('team', function() { describe('team', function() {
before(async function(){ before(async function(){
browser.get(browser.params.glob.host + 'project/project-5/team'); browser.get(browser.params.glob.host + 'project/project-5/team');

View File

@ -3,6 +3,16 @@ var common = require('./common');
var lightbox = module.exports; var lightbox = module.exports;
var transition = 300; var transition = 300;
lightbox.exit = function(el) {
var deferred = protractor.promise.defer();
if (typeof el === 'string' || el instanceof String) {
el = $(el);
}
el.$('.icon-close').click();
};
lightbox.open = async function(el) { lightbox.open = async function(el) {
var deferred = protractor.promise.defer(); var deferred = protractor.promise.defer();

View File

@ -58,6 +58,11 @@ var actions = {
await common.link(task); await common.link(task);
return common.waitLoader();
},
team: async function() {
await common.link($('#nav-team a'));
return common.waitLoader(); return common.waitLoader();
} }
}; };
@ -95,6 +100,10 @@ var nav = {
this.actions.push(actions.task.bind(null, index)); this.actions.push(actions.task.bind(null, index));
return this; return this;
}, },
team: function(index) {
this.actions.push(actions.team.bind(null, index));
return this;
},
go: function() { go: function() {
let promise = this.actions[0](); let promise = this.actions[0]();