Merge pull request #931 from taigaio/issue/187/max-members-lightbox
Refactor add-member lightbox and fix some error messagesstable
commit
f32ee54874
|
@ -27,153 +27,112 @@ debounce = @.taiga.debounce
|
||||||
|
|
||||||
module = angular.module("taigaKanban")
|
module = angular.module("taigaKanban")
|
||||||
|
|
||||||
MAX_MEMBERSHIP_FIELDSETS = 4
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
## Create Members Lightbox Directive
|
## Create Members Lightbox Directive
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
||||||
CreateMembersDirective = ($rs, $rootScope, $confirm, $loading, lightboxService, $compile) ->
|
class LightboxAddMembersController
|
||||||
extraTextTemplate = """
|
@.$inject = [
|
||||||
<fieldset class="extra-text">
|
"$scope",
|
||||||
<textarea ng-attr-placeholder="{{'LIGHTBOX.CREATE_MEMBER.PLACEHOLDER_INVITATION_TEXT' | translate}}"
|
"lightboxService",
|
||||||
maxlength="255"></textarea>
|
"tgLoader",
|
||||||
</fieldset>
|
"$tgConfirm",
|
||||||
"""
|
"$tgResources",
|
||||||
|
"$rootScope",
|
||||||
|
]
|
||||||
|
|
||||||
template = _.template("""
|
constructor: (@scope, @lightboxService, @tgLoader, @confirm, @rs, @rootScope) ->
|
||||||
<div class="add-member-wrapper">
|
@._defaultMaxInvites = 4
|
||||||
<fieldset>
|
@._defaultRole = @.project.roles[0].id
|
||||||
<input tg-capslock type="email" placeholder="{{'LIGHTBOX.CREATE_MEMBER.PLACEHOLDER_TYPE_EMAIL' | translate}}"
|
@.form = null
|
||||||
<% if(required) { %> data-required="true" <% } %> data-type="email" />
|
@.submitInvites = false
|
||||||
</fieldset>
|
@.canAddUsers = true
|
||||||
<fieldset>
|
@.memberInvites = []
|
||||||
<select <% if(required) { %> data-required="true" <% } %> data-required="true">
|
|
||||||
<% _.each(roleList, function(role) { %>
|
|
||||||
<option value="<%- role.id %>"><%- role.name %></option>
|
|
||||||
<% }); %>
|
|
||||||
</select>
|
|
||||||
<a class="add-fieldset" href="">
|
|
||||||
<svg class="icon icon-add">
|
|
||||||
<use xlink:href="#icon-add">
|
|
||||||
</svg>
|
|
||||||
</a>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
""")
|
|
||||||
|
|
||||||
link = ($scope, $el, $attrs) ->
|
if @.project.max_memberships == null
|
||||||
createButton = (type) ->
|
@.membersLimit = @._defaultMaxInvites
|
||||||
html = "<svg class='icon " + type + "'><use xlink:href='#" + type + "'></svg>";
|
else
|
||||||
return html
|
pendingMembersCount = Math.max(@.project.max_memberships - @.project.total_memberships, 0)
|
||||||
|
@.membersLimit = Math.min(pendingMembersCount, @._defaultMaxInvites)
|
||||||
|
|
||||||
createFieldSet = (required = true)->
|
@.addSingleMember()
|
||||||
ctx = {roleList: $scope.project.roles, required: required}
|
|
||||||
return $compile(template(ctx))($scope)
|
|
||||||
|
|
||||||
resetForm = ->
|
addSingleMember: () ->
|
||||||
$el.find("form textarea").remove()
|
@.memberInvites.push({email:'', role_id: @._defaultRole})
|
||||||
$el.find("form .add-member-wrapper").remove()
|
|
||||||
|
|
||||||
invitations = $el.find(".add-member-forms")
|
if @.memberInvites.length >= @.membersLimit
|
||||||
invitations.html($compile(extraTextTemplate)($scope))
|
@.canAddUsers = false
|
||||||
|
@.showWarningMessage = (!@.canAddUsers &&
|
||||||
|
@.project.total_memberships + @.memberInvites.length == @.project.max_memberships)
|
||||||
|
|
||||||
fieldSet = createFieldSet()
|
removeSingleMember: (index) ->
|
||||||
invitations.prepend(fieldSet)
|
@.memberInvites.splice(index, 1)
|
||||||
|
|
||||||
$scope.$on "membersform:new", ->
|
@.canAddUsers = true
|
||||||
resetForm()
|
@.showWarningMessage = @.membersLimit == 1
|
||||||
lightboxService.open($el)
|
|
||||||
|
|
||||||
$scope.$on "$destroy", ->
|
submit: () ->
|
||||||
$el.off()
|
# Need to reset the form constrains
|
||||||
|
@.form.initializeFields()
|
||||||
|
@.form.reset()
|
||||||
|
return if not @.form.validate()
|
||||||
|
|
||||||
$el.on "click", ".delete-fieldset", (event) ->
|
@.submitInvites = true
|
||||||
event.preventDefault()
|
promise = @rs.memberships.bulkCreateMemberships(
|
||||||
target = angular.element(event.currentTarget)
|
@.project.id,
|
||||||
fieldSet = target.closest('.add-member-wrapper')
|
@.memberInvites,
|
||||||
|
@.invitationText
|
||||||
|
)
|
||||||
|
promise.then(
|
||||||
|
@._onSuccessInvite.bind(this),
|
||||||
|
@._onErrorInvite.bind(this)
|
||||||
|
)
|
||||||
|
|
||||||
fieldSet.remove()
|
_onSuccessInvite: () ->
|
||||||
|
@.submitInvites = false
|
||||||
|
@rootScope.$broadcast("membersform:new:success")
|
||||||
|
@lightboxService.closeAll()
|
||||||
|
@confirm.notify("success")
|
||||||
|
|
||||||
lastActionButton = $el.find(".add-member-wrapper fieldset:last > a")
|
_onErrorInvite: (response) ->
|
||||||
if lastActionButton.hasClass("delete-fieldset")
|
@.submitInvites = false
|
||||||
lastActionButton.removeClass("delete-fieldset").addClass("add-fieldset")
|
@.form.setErrors(response.data)
|
||||||
svg = createButton('icon-add')
|
if response.data._error_message
|
||||||
lastActionButton.html(svg)
|
@confirm.notify("error", response.data._error_message)
|
||||||
|
|
||||||
$el.on "click", ".add-fieldset", (event) ->
|
module.controller("LbAddMembersController", LightboxAddMembersController)
|
||||||
event.preventDefault()
|
|
||||||
target = angular.element(event.currentTarget)
|
|
||||||
fieldSet = target.closest('.add-member-wrapper')
|
|
||||||
|
|
||||||
target.removeClass("add-fieldset").addClass("delete-fieldset")
|
|
||||||
svg = createButton('icon-trash')
|
|
||||||
target.html(svg)
|
|
||||||
|
|
||||||
newFieldSet = createFieldSet(false)
|
|
||||||
fieldSet.after(newFieldSet)
|
|
||||||
|
|
||||||
$scope.$digest() # To compile newFieldSet and translate text
|
LightboxAddMembersDirective = (lightboxService) ->
|
||||||
|
link = (scope, el, attrs, ctrl) ->
|
||||||
|
lightboxService.open(el)
|
||||||
|
ctrl.form = el.find("form").checksley()
|
||||||
|
|
||||||
if $el.find(".add-member-wrapper").length == MAX_MEMBERSHIP_FIELDSETS
|
return {
|
||||||
$el.find(".add-member-wrapper fieldset:last > a")
|
scope: {},
|
||||||
.removeClass("add-fieldset").addClass("delete-fieldset")
|
bindToController: {
|
||||||
svg = createButton('icon-trash')
|
project: '=',
|
||||||
$el.find(".add-member-wrapper fieldset:last > a").html(svg)
|
},
|
||||||
|
controller: 'LbAddMembersController',
|
||||||
|
controllerAs: 'vm',
|
||||||
|
templateUrl: 'admin/lightbox-add-members.html',
|
||||||
|
link: link
|
||||||
|
}
|
||||||
|
|
||||||
submit = debounce 2000, (event) =>
|
module.directive("tgLbAddMembers", ["lightboxService", LightboxAddMembersDirective])
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
currentLoading = $loading()
|
|
||||||
.target(submitButton)
|
|
||||||
.start()
|
|
||||||
|
|
||||||
onSuccess = (data) ->
|
#############################################################################
|
||||||
currentLoading.finish()
|
## Warning message directive
|
||||||
lightboxService.close($el)
|
#############################################################################
|
||||||
$confirm.notify("success")
|
|
||||||
$rootScope.$broadcast("membersform:new:success")
|
|
||||||
|
|
||||||
onError = (data) ->
|
LightboxAddMembersWarningMessageDirective = () ->
|
||||||
currentLoading.finish()
|
return {
|
||||||
lightboxService.close($el)
|
templateUrl: "admin/lightbox-add-members-no-more=memberships-warning-message.html"
|
||||||
$confirm.notify("error")
|
scope: {
|
||||||
$rootScope.$broadcast("membersform:new:error")
|
project: "="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
form = $el.find("form").checksley()
|
module.directive("tgLightboxAddMembersWarningMessage", [LightboxAddMembersWarningMessageDirective])
|
||||||
|
|
||||||
#checksley find new fields
|
|
||||||
form.destroy()
|
|
||||||
form.initialize()
|
|
||||||
if not form.validate()
|
|
||||||
return
|
|
||||||
|
|
||||||
memberWrappers = $el.find("form .add-member-wrapper")
|
|
||||||
memberWrappers = _.filter memberWrappers, (mw) ->
|
|
||||||
angular.element(mw).find("input").hasClass('checksley-ok')
|
|
||||||
|
|
||||||
invitations = _.map memberWrappers, (mw) ->
|
|
||||||
memberWrapper = angular.element(mw)
|
|
||||||
email = memberWrapper.find("input")
|
|
||||||
role = memberWrapper.find("select")
|
|
||||||
|
|
||||||
return {
|
|
||||||
email: email.val()
|
|
||||||
role_id: role.val()
|
|
||||||
}
|
|
||||||
|
|
||||||
if invitations.length
|
|
||||||
invitation_extra_text = $el.find("form textarea").val()
|
|
||||||
|
|
||||||
promise = $rs.memberships.bulkCreateMemberships($scope.project.id,
|
|
||||||
invitations, invitation_extra_text)
|
|
||||||
promise.then(onSuccess, onError)
|
|
||||||
|
|
||||||
submitButton = $el.find(".submit-button")
|
|
||||||
|
|
||||||
$el.on "submit", "form", submit
|
|
||||||
|
|
||||||
return {link: link}
|
|
||||||
|
|
||||||
module.directive("tgLbCreateMembers", ["$tgResources", "$rootScope", "$tgConfirm", "$tgLoading",
|
|
||||||
"lightboxService", "$compile", CreateMembersDirective])
|
|
||||||
|
|
|
@ -49,10 +49,11 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai
|
||||||
"tgAppMetaService",
|
"tgAppMetaService",
|
||||||
"$translate",
|
"$translate",
|
||||||
"$tgAuth"
|
"$tgAuth"
|
||||||
|
"tgLightboxFactory"
|
||||||
]
|
]
|
||||||
|
|
||||||
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @analytics,
|
constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @analytics,
|
||||||
@appMetaService, @translate, @tgAuth) ->
|
@appMetaService, @translate, @auth, @lightboxFactory) ->
|
||||||
bindMethods(@)
|
bindMethods(@)
|
||||||
|
|
||||||
@scope.project = {}
|
@scope.project = {}
|
||||||
|
@ -64,7 +65,6 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai
|
||||||
title = @translate.instant("ADMIN.MEMBERSHIPS.PAGE_TITLE", {projectName: @scope.project.name})
|
title = @translate.instant("ADMIN.MEMBERSHIPS.PAGE_TITLE", {projectName: @scope.project.name})
|
||||||
description = @scope.project.description
|
description = @scope.project.description
|
||||||
@appMetaService.setAll(title, description)
|
@appMetaService.setAll(title, description)
|
||||||
@._checkUsersLimit()
|
|
||||||
|
|
||||||
promise.then null, @.onInitialDataError.bind(@)
|
promise.then null, @.onInitialDataError.bind(@)
|
||||||
|
|
||||||
|
@ -79,8 +79,10 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai
|
||||||
|
|
||||||
@scope.projectId = project.id
|
@scope.projectId = project.id
|
||||||
@scope.project = project
|
@scope.project = project
|
||||||
@scope.$emit('project:loaded', project)
|
|
||||||
|
|
||||||
|
@scope.canAddUsers = project.max_memberships == null || project.max_memberships > project.total_memberships
|
||||||
|
|
||||||
|
@scope.$emit('project:loaded', project)
|
||||||
return project
|
return project
|
||||||
|
|
||||||
loadMembers: ->
|
loadMembers: ->
|
||||||
|
@ -99,7 +101,7 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai
|
||||||
return @.loadProject().then () =>
|
return @.loadProject().then () =>
|
||||||
return @q.all([
|
return @q.all([
|
||||||
@.loadMembers(),
|
@.loadMembers(),
|
||||||
@tgAuth.refresh()
|
@auth.refresh()
|
||||||
])
|
])
|
||||||
|
|
||||||
getUrlFilters: ->
|
getUrlFilters: ->
|
||||||
|
@ -107,16 +109,25 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai
|
||||||
filters.page = 1 if not filters.page
|
filters.page = 1 if not filters.page
|
||||||
return filters
|
return filters
|
||||||
|
|
||||||
|
# Actions
|
||||||
|
|
||||||
addNewMembers: ->
|
addNewMembers: ->
|
||||||
@rootscope.$broadcast("membersform:new")
|
@lightboxFactory.create(
|
||||||
|
'tg-lb-add-members',
|
||||||
|
{
|
||||||
|
"class": "lightbox lightbox-add-member",
|
||||||
|
"project": "project"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"project": @scope.project
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
_checkUsersLimit: ->
|
showLimitUsersWarningMessage: ->
|
||||||
@scope.canAddUsers = @.project.get('total_memberships') > @.project.get('max_memberships')
|
|
||||||
@.maxMembers = @.project.get('max_memberships')
|
|
||||||
|
|
||||||
limitUsersWarning: ->
|
|
||||||
title = @translate.instant("ADMIN.MEMBERSHIPS.LIMIT_USERS_WARNING")
|
title = @translate.instant("ADMIN.MEMBERSHIPS.LIMIT_USERS_WARNING")
|
||||||
message = @translate.instant("ADMIN.MEMBERSHIPS.LIMIT_USERS_WARNING_MESSAGE", {members: @.maxMembers})
|
message = @translate.instant("ADMIN.MEMBERSHIPS.LIMIT_USERS_WARNING_MESSAGE", {
|
||||||
|
members: @scope.project.max_memberships
|
||||||
|
})
|
||||||
icon = "/" + window._version + "/svg/icons/team-question.svg"
|
icon = "/" + window._version + "/svg/icons/team-question.svg"
|
||||||
@confirm.success(title, message,icon)
|
@confirm.success(title, message,icon)
|
||||||
|
|
||||||
|
@ -266,6 +277,18 @@ MembershipsRowAdminCheckboxDirective = ($log, $repo, $confirm, $template, $compi
|
||||||
template = $template.get("admin/admin-memberships-row-checkbox.html", true)
|
template = $template.get("admin/admin-memberships-row-checkbox.html", true)
|
||||||
|
|
||||||
link = ($scope, $el, $attrs) ->
|
link = ($scope, $el, $attrs) ->
|
||||||
|
$scope.$on "$destroy", ->
|
||||||
|
$el.off()
|
||||||
|
|
||||||
|
if not $attrs.tgMembershipsRowAdminCheckbox?
|
||||||
|
return $log.error "MembershipsRowAdminCheckboxDirective: the directive need a member"
|
||||||
|
|
||||||
|
member = $scope.$eval($attrs.tgMembershipsRowAdminCheckbox)
|
||||||
|
|
||||||
|
if member.is_owner
|
||||||
|
$el.find(".js-check").remove()
|
||||||
|
return
|
||||||
|
|
||||||
render = (member) ->
|
render = (member) ->
|
||||||
ctx = {inputId: "is-admin-#{member.id}"}
|
ctx = {inputId: "is-admin-#{member.id}"}
|
||||||
|
|
||||||
|
@ -274,15 +297,6 @@ MembershipsRowAdminCheckboxDirective = ($log, $repo, $confirm, $template, $compi
|
||||||
|
|
||||||
$el.html(html)
|
$el.html(html)
|
||||||
|
|
||||||
if not $attrs.tgMembershipsRowAdminCheckbox?
|
|
||||||
return $log.error "MembershipsRowAdminCheckboxDirective: the directive need a member"
|
|
||||||
|
|
||||||
member = $scope.$eval($attrs.tgMembershipsRowAdminCheckbox)
|
|
||||||
html = render(member)
|
|
||||||
|
|
||||||
if member.is_admin
|
|
||||||
$el.find(":checkbox").prop("checked", true)
|
|
||||||
|
|
||||||
$el.on "click", ":checkbox", (event) =>
|
$el.on "click", ":checkbox", (event) =>
|
||||||
onSuccess = ->
|
onSuccess = ->
|
||||||
$confirm.notify("success")
|
$confirm.notify("success")
|
||||||
|
@ -296,8 +310,10 @@ MembershipsRowAdminCheckboxDirective = ($log, $repo, $confirm, $template, $compi
|
||||||
member.is_admin = target.prop("checked")
|
member.is_admin = target.prop("checked")
|
||||||
$repo.save(member).then(onSuccess, onError)
|
$repo.save(member).then(onSuccess, onError)
|
||||||
|
|
||||||
$scope.$on "$destroy", ->
|
html = render(member)
|
||||||
$el.off()
|
|
||||||
|
if member.is_admin
|
||||||
|
$el.find(":checkbox").prop("checked", true)
|
||||||
|
|
||||||
return {link: link}
|
return {link: link}
|
||||||
|
|
||||||
|
@ -469,4 +485,19 @@ MembershipsRowActionsDirective = ($log, $repo, $rs, $confirm, $compile, $transla
|
||||||
|
|
||||||
|
|
||||||
module.directive("tgMembershipsRowActions", ["$log", "$tgRepo", "$tgResources", "$tgConfirm", "$compile",
|
module.directive("tgMembershipsRowActions", ["$log", "$tgRepo", "$tgResources", "$tgConfirm", "$compile",
|
||||||
"$translate", "tgCurrentUserService", "tgLightboxFactory", MembershipsRowActionsDirective])
|
"$translate", MembershipsRowActionsDirective])
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## No more memberships explanation directive
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
NoMoreMembershipsExplanationDirective = () ->
|
||||||
|
return {
|
||||||
|
templateUrl: "admin/no-more-memberships-explanation.html"
|
||||||
|
scope: {
|
||||||
|
project: "="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.directive("tgNoMoreMembershipsExplanation", [NoMoreMembershipsExplanationDirective])
|
||||||
|
|
|
@ -409,8 +409,8 @@
|
||||||
"PAGE_TITLE": "Memberships - {{projectName}}",
|
"PAGE_TITLE": "Memberships - {{projectName}}",
|
||||||
"ADD_BUTTON": "+ New member",
|
"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_FOR_ADMIN": "This project has reached its limit of allowed members <strong>({{members}})</strong>.",
|
||||||
"LIMIT_USERS_WARNING_MESSAGE": "Currently you can only have <strong>{{members}}</strong> members per project. If you want to add more members get in touch with the administrators"
|
"LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project has reached its limit of allowed members <strong>({{members}})</strong>. If you want to add more members please contact the administrators."
|
||||||
},
|
},
|
||||||
"PROJECT_EXPORT": {
|
"PROJECT_EXPORT": {
|
||||||
"TITLE": "Export",
|
"TITLE": "Export",
|
||||||
|
@ -918,7 +918,9 @@
|
||||||
},
|
},
|
||||||
"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",
|
||||||
|
"LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER": "This project can't have more than <strong>{{maxMembers}}</strong> members.<br> If you want to add more members contact the administrators.",
|
||||||
|
"LIMIT_USERS_WARNING_MESSAGE": "This project can't have more than <strong>{{maxMembers}}</strong> members."
|
||||||
},
|
},
|
||||||
"LEAVE_PROJECT_WARNING": {
|
"LEAVE_PROJECT_WARNING": {
|
||||||
"TITLE": "You can not leave the project without owner",
|
"TITLE": "You can not leave the project without owner",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.check
|
.check.js-check
|
||||||
input(type="checkbox", id!="<%- inputId %>")
|
input(type="checkbox", id!="<%- inputId %>")
|
||||||
div
|
div
|
||||||
span.check-text.check-yes(translate="COMMON.YES")
|
span.check-text.check-yes(translate="COMMON.YES")
|
||||||
|
|
|
@ -1,35 +1,30 @@
|
||||||
doctype html
|
doctype html
|
||||||
|
|
||||||
div.wrapper.memberships(ng-controller="MembershipsController as ctrl",
|
div.wrapper.memberships(
|
||||||
ng-init="section='admin'; sectionName='ADMIN.MEMBERSHIPS.TITLE'", tg-memberships)
|
ng-controller="MembershipsController as ctrl"
|
||||||
|
ng-init="section='admin'; sectionName='ADMIN.MEMBERSHIPS.TITLE'"
|
||||||
|
tg-memberships
|
||||||
|
)
|
||||||
tg-project-menu
|
tg-project-menu
|
||||||
|
|
||||||
sidebar.menu-secondary.sidebar.settings-nav(tg-admin-navigation="memberships")
|
sidebar.menu-secondary.sidebar.settings-nav(tg-admin-navigation="memberships")
|
||||||
include ../includes/modules/admin-menu
|
include ../includes/modules/admin-menu
|
||||||
|
|
||||||
section.main.admin-membership
|
section.main.admin-membership.admin-common
|
||||||
.header-with-actions
|
.header-with-actions
|
||||||
header
|
header
|
||||||
include ../includes/components/mainTitle
|
include ../includes/components/mainTitle
|
||||||
|
tg-no-more-memberships-explanation(ng-if="canAddUsers == false", project="project")
|
||||||
|
|
||||||
.action-buttons
|
.action-buttons
|
||||||
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(
|
button.button-green(
|
||||||
|
translate="ADMIN.MEMBERSHIPS.ADD_BUTTON"
|
||||||
title="{{ ADMIN.MEMBERSHIPS.ADD_BUTTON_TITLE | translate }}",
|
title="{{ ADMIN.MEMBERSHIPS.ADD_BUTTON_TITLE | translate }}",
|
||||||
ng-click="ctrl.addNewMembers()"
|
ng-click="ctrl.addNewMembers()"
|
||||||
translate="ADMIN.MEMBERSHIPS.ADD_BUTTON"
|
ng-disabled="canAddUsers == false"
|
||||||
ng-disabled="!canAddUsers"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
include ../includes/modules/admin/admin-membership-table
|
include ../includes/modules/admin/admin-membership-table
|
||||||
|
|
||||||
div.paginator.memberships-paginator
|
div.paginator.memberships-paginator
|
||||||
|
|
||||||
div.lightbox.lightbox-add-member(tg-lb-create-members)
|
|
||||||
include ../includes/modules/lightbox-add-member
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
p.member-limit-warning(
|
||||||
|
ng-if="project.i_am_owner == true"
|
||||||
|
translate="LIGHTBOX.CREATE_MEMBER.LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER"
|
||||||
|
translate-values="{maxMembers: project.max_memberships}"
|
||||||
|
)
|
||||||
|
|
||||||
|
p.member-limit-warning(
|
||||||
|
ng-if="project.i_am_owner == false"
|
||||||
|
translate="LIGHTBOX.CREATE_MEMBER.LIMIT_USERS_WARNING_MESSAGE"
|
||||||
|
translate-values="{maxMembers: project.max_memberships}"
|
||||||
|
)
|
|
@ -0,0 +1,58 @@
|
||||||
|
a.close(
|
||||||
|
href=""
|
||||||
|
title="close"
|
||||||
|
)
|
||||||
|
svg.icon.icon-close
|
||||||
|
use(xlink:href="#icon-close")
|
||||||
|
.add-member-wrapper
|
||||||
|
h2.title(translate="LIGHTBOX.ADD_MEMBER.TITLE")
|
||||||
|
form.add-member-form(ng-submit="vm.submit()")
|
||||||
|
.add-single-member(ng-repeat="member in vm.memberInvites")
|
||||||
|
fieldset
|
||||||
|
input(
|
||||||
|
type="email"
|
||||||
|
required
|
||||||
|
placeholder="{{'LIGHTBOX.CREATE_MEMBER.PLACEHOLDER_TYPE_EMAIL' | translate}}"
|
||||||
|
data-required="true"
|
||||||
|
data-type="email"
|
||||||
|
ng-model="member.email"
|
||||||
|
)
|
||||||
|
fieldset
|
||||||
|
select(
|
||||||
|
ng-if="vm.project"
|
||||||
|
ng-model="member.role_id"
|
||||||
|
ng-options="role.id as role.name for role in vm.project.roles"
|
||||||
|
)
|
||||||
|
fieldset
|
||||||
|
a.add-fieldset.ng-animate-disabled(
|
||||||
|
href=""
|
||||||
|
ng-click="vm.addSingleMember()"
|
||||||
|
ng-if="$last && vm.canAddUsers"
|
||||||
|
)
|
||||||
|
svg.icon.icon-add
|
||||||
|
use(xlink:href="#icon-add")
|
||||||
|
a.remove-fieldset.ng-animate-disabled(
|
||||||
|
href=""
|
||||||
|
ng-click="vm.removeSingleMember($index)"
|
||||||
|
ng-if="!$last || ($last && !vm.canAddUsers && vm.membersLimit > 1)"
|
||||||
|
)
|
||||||
|
svg.icon.icon-trash
|
||||||
|
use(xlink:href="#icon-trash")
|
||||||
|
|
||||||
|
tg-lightbox-add-members-warning-message(ng-if="vm.showWarningMessage", project="vm.project")
|
||||||
|
|
||||||
|
fieldset.invitation-text
|
||||||
|
textarea(
|
||||||
|
ng-attr-placeholder="{{'LIGHTBOX.CREATE_MEMBER.PLACEHOLDER_INVITATION_TEXT' | translate}}"
|
||||||
|
maxlength="255"
|
||||||
|
ng-model="vm.invitationText"
|
||||||
|
)
|
||||||
|
|
||||||
|
button.button-green.submit-button(
|
||||||
|
type="submit"
|
||||||
|
title="{{'COMMON.CREATE' | translate}}"
|
||||||
|
translate="COMMON.CREATE"
|
||||||
|
tg-loading="vm.submitInvites"
|
||||||
|
)
|
||||||
|
|
||||||
|
p.help-text(translate="LIGHTBOX.ADD_MEMBER.HELP_TEXT")
|
|
@ -0,0 +1,11 @@
|
||||||
|
p.admin-subtitle(
|
||||||
|
ng-if="project.i_am_owner == true"
|
||||||
|
translate="ADMIN.MEMBERSHIPS.LIMIT_USERS_WARNING_MESSAGE_FOR_OWNER"
|
||||||
|
translate-values="{members: project.total_memberships}"
|
||||||
|
)
|
||||||
|
|
||||||
|
p.admin-subtitle(
|
||||||
|
ng-if="project.i_am_owner == false"
|
||||||
|
translate="ADMIN.MEMBERSHIPS.LIMIT_USERS_WARNING_MESSAGE_FOR_ADMIN"
|
||||||
|
translate-values="{members: project.total_memberships}"
|
||||||
|
)
|
|
@ -1,12 +0,0 @@
|
||||||
a.close(href="", title="close")
|
|
||||||
svg.icon.icon-close
|
|
||||||
use(xlink:href="#icon-close")
|
|
||||||
form
|
|
||||||
h2.title(translate="LIGHTBOX.ADD_MEMBER.TITLE")
|
|
||||||
|
|
||||||
//- Form is set in a directive
|
|
||||||
.add-member-forms
|
|
||||||
|
|
||||||
button.button-green.submit-button(type="submit", title="{{'COMMON.CREATE' | translate}}", translate="COMMON.CREATE")
|
|
||||||
|
|
||||||
p.help-text(translate="LIGHTBOX.ADD_MEMBER.HELP_TEXT")
|
|
|
@ -88,12 +88,14 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-with-actions {
|
.header-with-actions {
|
||||||
align-content: stretch;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
|
header {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
.action-buttons {
|
.action-buttons {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,54 +142,62 @@
|
||||||
|
|
||||||
.lightbox-add-member {
|
.lightbox-add-member {
|
||||||
.add-member-wrapper {
|
.add-member-wrapper {
|
||||||
|
max-width: 600px;
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
.add-single-member {
|
||||||
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
margin-bottom: .5rem;
|
margin-bottom: .5rem;
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
fieldset {
|
fieldset {
|
||||||
position: relative;
|
display: inline-block;
|
||||||
&:first-child {
|
flex: 1;
|
||||||
flex-basis: 400px;
|
margin: 0 .5rem 0 0;
|
||||||
flex-grow: 3;
|
|
||||||
}
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
flex-basis: 200px;
|
flex-basis: 30px;
|
||||||
flex-grow: 1;
|
flex-grow: 0;
|
||||||
margin-left: .5rem;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
&:first-child {
|
||||||
|
flex-basis: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.extra-text {
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
fieldset {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
select {
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
||||||
.icon {
|
.icon {
|
||||||
|
@include svg-size(1.25rem);
|
||||||
fill: $gray;
|
fill: $gray;
|
||||||
margin-left: .5rem;
|
margin-left: .5rem;
|
||||||
transition: fill .2s;
|
|
||||||
}
|
}
|
||||||
.icon-add {
|
.icon-add {
|
||||||
&:hover {
|
&:hover {
|
||||||
fill: $primary-light;
|
fill: $primary;
|
||||||
|
transition: fill .2s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.icon-trash {
|
.icon-trash {
|
||||||
|
fill: $red-light;
|
||||||
&:hover {
|
&:hover {
|
||||||
fill: $red;
|
fill: $red;
|
||||||
|
transition: fill .2s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.button {
|
.member-limit-warning {
|
||||||
margin-top: 1rem;
|
@extend %small;
|
||||||
|
background: $red-light;
|
||||||
|
color: $white;
|
||||||
|
margin: 1rem 0;
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
.help-text {
|
.help-text {
|
||||||
@extend %small;
|
@extend %small;
|
||||||
padding: .5rem 1rem;
|
@extend %light;
|
||||||
|
margin-top: 1rem;
|
||||||
}
|
}
|
||||||
.checksley-error-list {
|
.checksley-error-list {
|
||||||
right: .5rem;
|
right: .5rem;
|
||||||
|
|
Loading…
Reference in New Issue