Generic lightbox form to create/edit us, tasks and issues
parent
c2f69429df
commit
90fbaaee0e
|
@ -541,7 +541,12 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
||||||
|
|
||||||
return @rs.userstories.getByRef(projectId, ref).then (us) =>
|
return @rs.userstories.getByRef(projectId, ref).then (us) =>
|
||||||
@rs2.attachments.list("us", us.id, projectId).then (attachments) =>
|
@rs2.attachments.list("us", us.id, projectId).then (attachments) =>
|
||||||
@rootscope.$broadcast("usform:edit", us, attachments.toJS())
|
@rootscope.$broadcast("genericform:edit", {
|
||||||
|
'objType': 'us',
|
||||||
|
'statusList': @scope.usStatusList,
|
||||||
|
'obj': us,
|
||||||
|
'attachments': attachments.toJS()
|
||||||
|
})
|
||||||
currentLoading.finish()
|
currentLoading.finish()
|
||||||
|
|
||||||
deleteUserStory: (us) ->
|
deleteUserStory: (us) ->
|
||||||
|
@ -566,8 +571,12 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F
|
||||||
|
|
||||||
addNewUs: (type) ->
|
addNewUs: (type) ->
|
||||||
switch type
|
switch type
|
||||||
when "standard" then @rootscope.$broadcast("usform:new", @scope.projectId,
|
when "standard" then @rootscope.$broadcast("genericform:new",
|
||||||
@scope.project.default_us_status, @scope.usStatusList)
|
{
|
||||||
|
'objType': 'us',
|
||||||
|
'project': @scope.project,
|
||||||
|
'statusList': @scope.usStatusList
|
||||||
|
})
|
||||||
when "bulk" then @rootscope.$broadcast("usform:bulk", @scope.projectId,
|
when "bulk" then @rootscope.$broadcast("usform:bulk", @scope.projectId,
|
||||||
@scope.project.default_us_status)
|
@scope.project.default_us_status)
|
||||||
|
|
||||||
|
|
|
@ -525,6 +525,266 @@ module.directive("tgAssignedTo", ["$rootScope", "$tgConfirm", "$tgRepo", "$tgLoa
|
||||||
AssignedToDirective])
|
AssignedToDirective])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## Assigned to (inline) directive
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
AssignedToInlineDirective = ($rootscope, $confirm, $repo, $loading, $modelTransform, $template
|
||||||
|
$translate, $compile, $currentUserService, avatarService) ->
|
||||||
|
link = ($scope, $el, $attrs, $model) ->
|
||||||
|
isEditable = ->
|
||||||
|
return $scope.project?.my_permissions?.indexOf($attrs.requiredPerm) != -1
|
||||||
|
|
||||||
|
normalizeString = (string) ->
|
||||||
|
normalizedString = string
|
||||||
|
normalizedString = normalizedString.replace("Á", "A").replace("Ä", "A").replace("À", "A")
|
||||||
|
normalizedString = normalizedString.replace("É", "E").replace("Ë", "E").replace("È", "E")
|
||||||
|
normalizedString = normalizedString.replace("Í", "I").replace("Ï", "I").replace("Ì", "I")
|
||||||
|
normalizedString = normalizedString.replace("Ó", "O").replace("Ö", "O").replace("Ò", "O")
|
||||||
|
normalizedString = normalizedString.replace("Ú", "U").replace("Ü", "U").replace("Ù", "U")
|
||||||
|
return normalizedString
|
||||||
|
|
||||||
|
filterUsers = (text, user) ->
|
||||||
|
username = user.full_name_display.toUpperCase()
|
||||||
|
username = normalizeString(username)
|
||||||
|
text = text.toUpperCase()
|
||||||
|
text = normalizeString(text)
|
||||||
|
return _.includes(username, text)
|
||||||
|
|
||||||
|
renderUserlist = (text) ->
|
||||||
|
users = _.clone($scope.activeUsers, true)
|
||||||
|
users = _.reject(users, {"id": $scope.selected.id}) if $scope.selected?
|
||||||
|
users = _.sortBy(users, (o) -> if o.id is $scope.user.id then 0 else o.id)
|
||||||
|
users = _.filter(users, _.partial(filterUsers, text)) if text?
|
||||||
|
|
||||||
|
visibleUsers = _.slice(users, 0, 5)
|
||||||
|
visibleUsers = _.map visibleUsers, (user) -> user.avatar = avatarService.getAvatar(user)
|
||||||
|
|
||||||
|
$scope.users = _.slice(users, 0, 5)
|
||||||
|
$scope.showMore = users.length > 5
|
||||||
|
|
||||||
|
renderUser = (assignedObject) ->
|
||||||
|
if assignedObject?.assigned_to
|
||||||
|
$scope.selected = assignedObject.assigned_to
|
||||||
|
assignedObject.assigned_to_extra_info = $scope.usersById[$scope.selected]
|
||||||
|
$scope.fullName = assignedObject.assigned_to_extra_info?.full_name_display
|
||||||
|
$scope.isUnassigned = false
|
||||||
|
$scope.avatar = avatarService.getAvatar(assignedObject.assigned_to_extra_info)
|
||||||
|
$scope.bg = $scope.avatar.bg
|
||||||
|
$scope.isIocaine = assignedObject?.is_iocaine
|
||||||
|
else
|
||||||
|
$scope.fullName = $translate.instant("COMMON.ASSIGNED_TO.ASSIGN")
|
||||||
|
$scope.isUnassigned = true
|
||||||
|
$scope.avatar = avatarService.getAvatar(null)
|
||||||
|
$scope.bg = null
|
||||||
|
$scope.isIocaine = false
|
||||||
|
|
||||||
|
$scope.fullNameVisible = !($scope.isUnassigned && !$currentUserService.isAuthenticated())
|
||||||
|
$scope.isEditable = isEditable()
|
||||||
|
|
||||||
|
$el.on "click", ".users-dropdown", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
renderUserlist()
|
||||||
|
$scope.$apply()
|
||||||
|
$el.find(".pop-users").popover().open()
|
||||||
|
|
||||||
|
$el.on "click", ".users-search", (event) ->
|
||||||
|
event.stopPropagation()
|
||||||
|
|
||||||
|
$el.on "click", ".assign-to-me", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
return if not isEditable()
|
||||||
|
$model.$modelValue.assigned_to = $currentUserService.getUser().get('id')
|
||||||
|
renderUser($model.$modelValue)
|
||||||
|
$scope.$apply()
|
||||||
|
|
||||||
|
$el.on "click", ".remove-user", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
return if not isEditable()
|
||||||
|
$model.$modelValue.assigned_to = null
|
||||||
|
renderUser()
|
||||||
|
$scope.$apply()
|
||||||
|
|
||||||
|
$scope.$watch "usersSearch", (searchingText) ->
|
||||||
|
if searchingText?
|
||||||
|
renderUserlist(searchingText)
|
||||||
|
$el.find('input').focus()
|
||||||
|
|
||||||
|
$el.on "click", ".user-list-single", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
$model.$modelValue.assigned_to = target.data("user-id")
|
||||||
|
renderUser($model.$modelValue)
|
||||||
|
$scope.$apply()
|
||||||
|
|
||||||
|
$scope.$watch $attrs.ngModel, (instance) ->
|
||||||
|
renderUser(instance)
|
||||||
|
|
||||||
|
$scope.$on "isiocaine:changed", (ctx, instance) ->
|
||||||
|
renderUser(instance)
|
||||||
|
|
||||||
|
$scope.$on "$destroy", ->
|
||||||
|
$el.off()
|
||||||
|
|
||||||
|
return {
|
||||||
|
link:link,
|
||||||
|
require:"ngModel",
|
||||||
|
templateUrl: "common/components/assigned-to-inline.html"
|
||||||
|
}
|
||||||
|
|
||||||
|
module.directive("tgAssignedToInline", ["$rootScope", "$tgConfirm", "$tgRepo", "$tgLoading"
|
||||||
|
"$tgQueueModelTransformation", "$tgTemplate", "$translate", "$compile","tgCurrentUserService"
|
||||||
|
"tgAvatarService", AssignedToInlineDirective])
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## Assigned users (inline) directive
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
AssignedUsersInlineDirective = ($rootscope, $confirm, $repo, $loading, $modelTransform, $template
|
||||||
|
$translate, $compile, $currentUserService, avatarService) ->
|
||||||
|
link = ($scope, $el, $attrs, $model) ->
|
||||||
|
currentAssignedIds = []
|
||||||
|
currentAssignedTo = null
|
||||||
|
|
||||||
|
isAssigned = ->
|
||||||
|
return currentAssignedIds.length > 0
|
||||||
|
|
||||||
|
normalizeString = (string) ->
|
||||||
|
normalizedString = string
|
||||||
|
normalizedString = normalizedString.replace("Á", "A").replace("Ä", "A").replace("À", "A")
|
||||||
|
normalizedString = normalizedString.replace("É", "E").replace("Ë", "E").replace("È", "E")
|
||||||
|
normalizedString = normalizedString.replace("Í", "I").replace("Ï", "I").replace("Ì", "I")
|
||||||
|
normalizedString = normalizedString.replace("Ó", "O").replace("Ö", "O").replace("Ò", "O")
|
||||||
|
normalizedString = normalizedString.replace("Ú", "U").replace("Ü", "U").replace("Ù", "U")
|
||||||
|
return normalizedString
|
||||||
|
|
||||||
|
filterUsers = (text, user) ->
|
||||||
|
username = user.full_name_display.toUpperCase()
|
||||||
|
username = normalizeString(username)
|
||||||
|
text = text.toUpperCase()
|
||||||
|
text = normalizeString(text)
|
||||||
|
return _.includes(username, text)
|
||||||
|
|
||||||
|
renderUsersList = (text) ->
|
||||||
|
users = _.clone($scope.activeUsers, true)
|
||||||
|
users = _.sortBy(users, (o) -> if o.id is $scope.user.id then 0 else o.id)
|
||||||
|
users = _.filter(users, _.partial(filterUsers, text)) if text?
|
||||||
|
|
||||||
|
# Add selected users
|
||||||
|
selected = []
|
||||||
|
_.map users, (user) ->
|
||||||
|
if user.id in currentAssignedIds
|
||||||
|
user.avatar = avatarService.getAvatar(user)
|
||||||
|
selected.push(user)
|
||||||
|
|
||||||
|
# Filter users in searchs
|
||||||
|
visible = []
|
||||||
|
_.map users, (user) ->
|
||||||
|
if user.id not in currentAssignedIds
|
||||||
|
user.avatar = avatarService.getAvatar(user)
|
||||||
|
visible.push(user)
|
||||||
|
|
||||||
|
$scope.selected = _.slice(selected, 0, 5)
|
||||||
|
if $scope.selected.length < 5
|
||||||
|
$scope.users = _.slice(visible, 0, 5 - $scope.selected.length)
|
||||||
|
else
|
||||||
|
$scope.users = []
|
||||||
|
$scope.showMore = users.length > 5
|
||||||
|
|
||||||
|
renderUsers = () ->
|
||||||
|
assignedUsers = _.map(currentAssignedIds, (assignedUserId) -> $scope.usersById[assignedUserId])
|
||||||
|
assignedUsers = _.filter assignedUsers, (it) -> return !!it
|
||||||
|
|
||||||
|
$scope.hiddenUsers = if currentAssignedIds.length > 3 then currentAssignedIds.length - 3 else 0
|
||||||
|
$scope.assignedUsers = _.slice(assignedUsers, 0, 3)
|
||||||
|
|
||||||
|
$scope.isAssigned = isAssigned()
|
||||||
|
|
||||||
|
applyToModel = () ->
|
||||||
|
_.map currentAssignedIds, (userId) ->
|
||||||
|
if !$scope.usersById[userId]
|
||||||
|
currentAssignedIds.splice(currentAssignedIds.indexOf(userId), 1)
|
||||||
|
if currentAssignedIds.length == 0
|
||||||
|
currentAssignedTo = null
|
||||||
|
else if currentAssignedIds.indexOf(currentAssignedTo) == -1 || !currentAssignedTo
|
||||||
|
currentAssignedTo = currentAssignedIds[0]
|
||||||
|
$model.$modelValue.setAttr('assigned_users', currentAssignedIds)
|
||||||
|
$model.$modelValue.assigned_to = currentAssignedTo
|
||||||
|
|
||||||
|
$el.on "click", ".users-dropdown", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
renderUsersList()
|
||||||
|
$scope.$apply()
|
||||||
|
$el.find(".pop-users").popover().open()
|
||||||
|
|
||||||
|
$el.on "click", ".users-search", (event) ->
|
||||||
|
event.stopPropagation()
|
||||||
|
|
||||||
|
$el.on "click", ".assign-to-me", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
currentAssignedIds.push($currentUserService.getUser().get('id'))
|
||||||
|
renderUsers()
|
||||||
|
applyToModel()
|
||||||
|
$scope.usersSearch = null
|
||||||
|
$scope.$apply()
|
||||||
|
|
||||||
|
$scope.$watch "usersSearch", (searchingText) ->
|
||||||
|
if searchingText?
|
||||||
|
renderUsersList(searchingText)
|
||||||
|
$el.find('input').focus()
|
||||||
|
|
||||||
|
$el.on "click", ".user-list-single", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
index = currentAssignedIds.indexOf(target.data("user-id"))
|
||||||
|
if index == -1
|
||||||
|
currentAssignedIds.push(target.data("user-id"))
|
||||||
|
else
|
||||||
|
currentAssignedIds.splice(index, 1)
|
||||||
|
renderUsers()
|
||||||
|
applyToModel()
|
||||||
|
$el.find(".pop-users").popover().close()
|
||||||
|
$scope.usersSearch = null
|
||||||
|
$scope.$apply()
|
||||||
|
|
||||||
|
$el.on "click", ".remove-user", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
index = currentAssignedIds.indexOf(target.data("user-id"))
|
||||||
|
if index > -1
|
||||||
|
currentAssignedIds.splice(index, 1)
|
||||||
|
renderUsers()
|
||||||
|
applyToModel()
|
||||||
|
$scope.$apply()
|
||||||
|
|
||||||
|
$scope.$watch $attrs.ngModel, (item) ->
|
||||||
|
return if not item?
|
||||||
|
currentAssignedIds = []
|
||||||
|
assigned_to = null
|
||||||
|
|
||||||
|
if item.assigned_users?
|
||||||
|
currentAssignedIds = item.assigned_users
|
||||||
|
assigned_to = item.assigned_to
|
||||||
|
renderUsers()
|
||||||
|
|
||||||
|
$scope.$on "$destroy", ->
|
||||||
|
$el.off()
|
||||||
|
|
||||||
|
return {
|
||||||
|
link:link,
|
||||||
|
require: "ngModel",
|
||||||
|
templateUrl: "common/components/assigned-users-inline.html"
|
||||||
|
}
|
||||||
|
|
||||||
|
module.directive("tgAssignedUsersInline", ["$rootScope", "$tgConfirm", "$tgRepo",
|
||||||
|
"$tgLoading", "$tgQueueModelTransformation", "$tgTemplate", "$translate", "$compile",
|
||||||
|
"tgCurrentUserService", "tgAvatarService", AssignedUsersInlineDirective])
|
||||||
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
## Block Button directive
|
## Block Button directive
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
|
@ -294,237 +294,6 @@ BlockingMessageInputDirective = ($log, $template, $compile) ->
|
||||||
module.directive("tgBlockingMessageInput", ["$log", "$tgTemplate", "$compile", BlockingMessageInputDirective])
|
module.directive("tgBlockingMessageInput", ["$log", "$tgTemplate", "$compile", BlockingMessageInputDirective])
|
||||||
|
|
||||||
|
|
||||||
#############################################################################
|
|
||||||
## Create/Edit Userstory Lightbox Directive
|
|
||||||
#############################################################################
|
|
||||||
|
|
||||||
CreateEditUserstoryDirective = ($repo, $model, $rs, $rootScope, lightboxService, $loading, $translate, $confirm, $q, attachmentsService) ->
|
|
||||||
link = ($scope, $el, attrs) ->
|
|
||||||
form = null
|
|
||||||
$scope.createEditUs = {}
|
|
||||||
$scope.isNew = true
|
|
||||||
|
|
||||||
attachmentsToAdd = Immutable.List()
|
|
||||||
attachmentsToDelete = Immutable.List()
|
|
||||||
|
|
||||||
resetAttachments = () ->
|
|
||||||
attachmentsToAdd = Immutable.List()
|
|
||||||
attachmentsToDelete = Immutable.List()
|
|
||||||
|
|
||||||
$scope.addAttachment = (attachment) ->
|
|
||||||
attachmentsToAdd = attachmentsToAdd.push(attachment)
|
|
||||||
|
|
||||||
$scope.deleteAttachment = (attachment) ->
|
|
||||||
attachmentsToAdd = attachmentsToAdd.filter (it) ->
|
|
||||||
return it.get('name') != attachment.get('name')
|
|
||||||
|
|
||||||
if attachment.get("id")
|
|
||||||
attachmentsToDelete = attachmentsToDelete.push(attachment)
|
|
||||||
|
|
||||||
$scope.addTag = (tag, color) ->
|
|
||||||
value = trim(tag.toLowerCase())
|
|
||||||
|
|
||||||
tags = $scope.project.tags
|
|
||||||
projectTags = $scope.project.tags_colors
|
|
||||||
|
|
||||||
tags = [] if not tags?
|
|
||||||
projectTags = {} if not projectTags?
|
|
||||||
|
|
||||||
if value not in tags
|
|
||||||
tags.push(value)
|
|
||||||
|
|
||||||
projectTags[tag] = color || null
|
|
||||||
|
|
||||||
$scope.project.tags = tags
|
|
||||||
|
|
||||||
itemtags = _.clone($scope.us.tags)
|
|
||||||
|
|
||||||
inserted = _.find itemtags, (it) -> it[0] == value
|
|
||||||
|
|
||||||
if !inserted
|
|
||||||
itemtags.push([value , color])
|
|
||||||
$scope.us.tags = itemtags
|
|
||||||
|
|
||||||
$scope.deleteTag = (tag) ->
|
|
||||||
value = trim(tag[0].toLowerCase())
|
|
||||||
|
|
||||||
tags = $scope.project.tags
|
|
||||||
itemtags = _.clone($scope.us.tags)
|
|
||||||
|
|
||||||
_.remove itemtags, (tag) -> tag[0] == value
|
|
||||||
|
|
||||||
$scope.us.tags = itemtags
|
|
||||||
|
|
||||||
_.pull($scope.us.tags, value)
|
|
||||||
|
|
||||||
$scope.$on "usform:new", (ctx, projectId, status, statusList) ->
|
|
||||||
form.reset() if form
|
|
||||||
$scope.isNew = true
|
|
||||||
$scope.usStatusList = statusList
|
|
||||||
$scope.attachments = Immutable.List()
|
|
||||||
|
|
||||||
resetAttachments()
|
|
||||||
|
|
||||||
$scope.us = $model.make_model("userstories", {
|
|
||||||
project: projectId
|
|
||||||
points : {}
|
|
||||||
status: status
|
|
||||||
is_archived: false
|
|
||||||
tags: []
|
|
||||||
subject: ""
|
|
||||||
description: ""
|
|
||||||
})
|
|
||||||
|
|
||||||
# Update texts for creation
|
|
||||||
$el.find(".button-green").html($translate.instant("COMMON.CREATE"))
|
|
||||||
$el.find(".title").html($translate.instant("LIGHTBOX.CREATE_EDIT_US.NEW_US"))
|
|
||||||
$el.find(".tag-input").val("")
|
|
||||||
|
|
||||||
$el.find(".blocked-note").addClass("hidden")
|
|
||||||
$el.find("label.blocked").removeClass("selected")
|
|
||||||
$el.find("label.team-requirement").removeClass("selected")
|
|
||||||
$el.find("label.client-requirement").removeClass("selected")
|
|
||||||
|
|
||||||
$scope.createEditUsOpen = true
|
|
||||||
|
|
||||||
lightboxService.open $el, () ->
|
|
||||||
$scope.createEditUsOpen = false
|
|
||||||
|
|
||||||
$scope.$on "usform:edit", (ctx, us, attachments) ->
|
|
||||||
form.reset() if form
|
|
||||||
|
|
||||||
$scope.us = us
|
|
||||||
$scope.attachments = Immutable.fromJS(attachments)
|
|
||||||
$scope.isNew = false
|
|
||||||
|
|
||||||
resetAttachments()
|
|
||||||
|
|
||||||
# Update texts for edition
|
|
||||||
$el.find(".button-green").html($translate.instant("COMMON.SAVE"))
|
|
||||||
$el.find(".title").html($translate.instant("LIGHTBOX.CREATE_EDIT_US.EDIT_US"))
|
|
||||||
$el.find(".tag-input").val("")
|
|
||||||
|
|
||||||
# Update requirement info (team, client or blocked)
|
|
||||||
if us.is_blocked
|
|
||||||
$el.find(".blocked-note").removeClass("hidden")
|
|
||||||
$el.find("label.blocked").addClass("selected")
|
|
||||||
else
|
|
||||||
$el.find(".blocked-note").addClass("hidden")
|
|
||||||
$el.find("label.blocked").removeClass("selected")
|
|
||||||
|
|
||||||
if us.team_requirement
|
|
||||||
$el.find("label.team-requirement").addClass("selected")
|
|
||||||
else
|
|
||||||
$el.find("label.team-requirement").removeClass("selected")
|
|
||||||
if us.client_requirement
|
|
||||||
$el.find("label.client-requirement").addClass("selected")
|
|
||||||
else
|
|
||||||
$el.find("label.client-requirement").removeClass("selected")
|
|
||||||
|
|
||||||
$scope.createEditUsOpen = true
|
|
||||||
|
|
||||||
lightboxService.open $el, () ->
|
|
||||||
$scope.createEditUsOpen = false
|
|
||||||
|
|
||||||
createAttachments = (obj) ->
|
|
||||||
promises = _.map attachmentsToAdd.toJS(), (attachment) ->
|
|
||||||
attachmentsService.upload(attachment.file, obj.id, $scope.us.project, 'us')
|
|
||||||
|
|
||||||
return $q.all(promises)
|
|
||||||
|
|
||||||
deleteAttachments = (obj) ->
|
|
||||||
promises = _.map attachmentsToDelete.toJS(), (attachment) ->
|
|
||||||
return attachmentsService.delete("us", attachment.id)
|
|
||||||
|
|
||||||
return $q.all(promises)
|
|
||||||
|
|
||||||
submit = debounce 2000, (event) =>
|
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
form = $el.find("form").checksley()
|
|
||||||
if not form.validate()
|
|
||||||
return
|
|
||||||
|
|
||||||
currentLoading = $loading()
|
|
||||||
.target(submitButton)
|
|
||||||
.start()
|
|
||||||
|
|
||||||
params = {
|
|
||||||
include_attachments: true,
|
|
||||||
include_tasks: true
|
|
||||||
}
|
|
||||||
|
|
||||||
if $scope.isNew
|
|
||||||
promise = $repo.create("userstories", $scope.us)
|
|
||||||
broadcastEvent = "usform:new:success"
|
|
||||||
else
|
|
||||||
promise = $repo.save($scope.us, true)
|
|
||||||
broadcastEvent = "usform:edit:success"
|
|
||||||
|
|
||||||
promise.then (data) ->
|
|
||||||
deleteAttachments(data)
|
|
||||||
.then () => createAttachments(data)
|
|
||||||
.then () =>
|
|
||||||
currentLoading.finish()
|
|
||||||
lightboxService.close($el)
|
|
||||||
|
|
||||||
$rs.userstories.getByRef(data.project, data.ref, params).then (us) ->
|
|
||||||
$rootScope.$broadcast(broadcastEvent, us)
|
|
||||||
|
|
||||||
|
|
||||||
promise.then null, (data) ->
|
|
||||||
currentLoading.finish()
|
|
||||||
form.setErrors(data)
|
|
||||||
if data._error_message
|
|
||||||
$confirm.notify("error", data._error_message)
|
|
||||||
|
|
||||||
submitButton = $el.find(".submit-button")
|
|
||||||
|
|
||||||
close = () =>
|
|
||||||
if !$scope.us.isModified()
|
|
||||||
lightboxService.close($el)
|
|
||||||
$scope.$apply ->
|
|
||||||
$scope.us.revert()
|
|
||||||
else
|
|
||||||
$confirm.ask($translate.instant("LIGHTBOX.CREATE_EDIT_US.CONFIRM_CLOSE")).then (result) ->
|
|
||||||
lightboxService.close($el)
|
|
||||||
$scope.us.revert()
|
|
||||||
result.finish()
|
|
||||||
|
|
||||||
$el.on "submit", "form", submit
|
|
||||||
|
|
||||||
$el.find('.close').on "click", (event) ->
|
|
||||||
event.preventDefault()
|
|
||||||
event.stopPropagation()
|
|
||||||
close()
|
|
||||||
|
|
||||||
$el.keydown (event) ->
|
|
||||||
event.stopPropagation()
|
|
||||||
code = if event.keyCode then event.keyCode else event.which
|
|
||||||
if code == 27
|
|
||||||
close()
|
|
||||||
|
|
||||||
$scope.$on "$destroy", ->
|
|
||||||
$el.find('.close').off()
|
|
||||||
$el.off()
|
|
||||||
|
|
||||||
return {link: link}
|
|
||||||
|
|
||||||
module.directive("tgLbCreateEditUserstory", [
|
|
||||||
"$tgRepo",
|
|
||||||
"$tgModel",
|
|
||||||
"$tgResources",
|
|
||||||
"$rootScope",
|
|
||||||
"lightboxService",
|
|
||||||
"$tgLoading",
|
|
||||||
"$translate",
|
|
||||||
"$tgConfirm",
|
|
||||||
"$q",
|
|
||||||
"tgAttachmentsService"
|
|
||||||
CreateEditUserstoryDirective
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
## Creare Bulk Userstories Lightbox Directive
|
## Creare Bulk Userstories Lightbox Directive
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
@ -938,6 +707,17 @@ SetDueDateDirective = (lightboxService, $loading, $translate, $confirm, $modelTr
|
||||||
.target($el.find(".submit-button"))
|
.target($el.find(".submit-button"))
|
||||||
.start()
|
.start()
|
||||||
|
|
||||||
|
if $scope.notAutoSave
|
||||||
|
new_due_date = $('.due-date').val()
|
||||||
|
$scope.object.due_date = if (new_due_date) \
|
||||||
|
then moment(new_due_date, prettyDate).format("YYYY-MM-DD") \
|
||||||
|
else null
|
||||||
|
|
||||||
|
$scope.$apply()
|
||||||
|
currentLoading.finish()
|
||||||
|
lightboxService.close($el)
|
||||||
|
return
|
||||||
|
|
||||||
transform = $modelTransform.save (object) ->
|
transform = $modelTransform.save (object) ->
|
||||||
new_due_date = $('.due-date').val()
|
new_due_date = $('.due-date').val()
|
||||||
object.due_date = if (new_due_date) \
|
object.due_date = if (new_due_date) \
|
||||||
|
@ -968,6 +748,10 @@ SetDueDateDirective = (lightboxService, $loading, $translate, $confirm, $modelTr
|
||||||
askResponse.finish()
|
askResponse.finish()
|
||||||
$('.due-date').val(null)
|
$('.due-date').val(null)
|
||||||
$scope.object.due_date_reason = null
|
$scope.object.due_date_reason = null
|
||||||
|
if $scope.notAutoSave
|
||||||
|
$scope.object.due_date = null
|
||||||
|
lightboxService.close($el)
|
||||||
|
else
|
||||||
save()
|
save()
|
||||||
|
|
||||||
$el.on "click", ".delete-due-date", (event) ->
|
$el.on "click", ".delete-due-date", (event) ->
|
||||||
|
@ -982,3 +766,328 @@ SetDueDateDirective = (lightboxService, $loading, $translate, $confirm, $modelTr
|
||||||
|
|
||||||
module.directive("tgLbSetDueDate", ["lightboxService", "$tgLoading", "$translate", "$tgConfirm"
|
module.directive("tgLbSetDueDate", ["lightboxService", "$tgLoading", "$translate", "$tgConfirm"
|
||||||
"$tgQueueModelTransformation", SetDueDateDirective])
|
"$tgQueueModelTransformation", SetDueDateDirective])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## Create/Edit Lightbox Directive
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
CreateEditDirective = (
|
||||||
|
$log, $repo, $model, $rs, $rootScope, lightboxService, $loading, $translate,
|
||||||
|
$confirm, $q, attachmentsService) ->
|
||||||
|
link = ($scope, $el, attrs) ->
|
||||||
|
form = null
|
||||||
|
schemas = {
|
||||||
|
us: {
|
||||||
|
objName: 'User Story',
|
||||||
|
model: 'userstories',
|
||||||
|
params: { include_attachments: true, include_tasks: true },
|
||||||
|
requiredAttrs: ['project'],
|
||||||
|
initialData: (data) ->
|
||||||
|
return {
|
||||||
|
project: data.project.id
|
||||||
|
points : {}
|
||||||
|
status: data.project.default_us_status
|
||||||
|
is_archived: false
|
||||||
|
tags: []
|
||||||
|
subject: ""
|
||||||
|
description: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task: {
|
||||||
|
objName: 'Task',
|
||||||
|
model: 'tasks',
|
||||||
|
params: { include_attachments: true },
|
||||||
|
requiredAttrs: ['project', 'sprintId', 'usId'],
|
||||||
|
initialData: (data) ->
|
||||||
|
return {
|
||||||
|
project: data.project.id
|
||||||
|
milestone: data.sprintId
|
||||||
|
user_story: data.usId
|
||||||
|
is_archived: false
|
||||||
|
status: data.project.default_task_status
|
||||||
|
assigned_to: null
|
||||||
|
tags: [],
|
||||||
|
subject: "",
|
||||||
|
description: "",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
issue: {
|
||||||
|
objName: 'Issue',
|
||||||
|
model: 'issues',
|
||||||
|
params: { include_attachments: true },
|
||||||
|
requiredAttrs: ['project', 'typeList', 'typeById', 'severityList', 'priorityList'],
|
||||||
|
initialData: (data) ->
|
||||||
|
return {
|
||||||
|
project: data.project.id
|
||||||
|
subject: ""
|
||||||
|
status: data.project.default_issue_status
|
||||||
|
type: data.project.default_issue_type
|
||||||
|
priority: data.project.default_priority
|
||||||
|
severity: data.project.default_severity
|
||||||
|
tags: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
attachmentsToAdd = Immutable.List()
|
||||||
|
attachmentsToDelete = Immutable.List()
|
||||||
|
|
||||||
|
$scope.$on "genericform:new", (ctx, data) ->
|
||||||
|
if beforeMount('new', data, ['objType', 'statusList', ])
|
||||||
|
mountCreateForm(data)
|
||||||
|
afterMount()
|
||||||
|
|
||||||
|
$scope.$on "genericform:edit", (ctx, data) ->
|
||||||
|
if beforeMount('edit', data, ['objType', 'statusList', 'obj', 'attachments'])
|
||||||
|
mountUpdateForm(data)
|
||||||
|
afterMount()
|
||||||
|
|
||||||
|
beforeMount = (mode, data, requiredAttrs) ->
|
||||||
|
form.reset() if form
|
||||||
|
$el.find(".tag-input").val("")
|
||||||
|
|
||||||
|
# Get form schema
|
||||||
|
if !data.objType || !schemas[data.objType]
|
||||||
|
return $log.error(
|
||||||
|
"Invalid objType `#{data.objType}` for `genericform:#{mode}` event")
|
||||||
|
$scope.schema = schemas[data.objType]
|
||||||
|
|
||||||
|
# Get required attrs for creation from objType schema
|
||||||
|
if mode == 'new'
|
||||||
|
requiredAttrs = $scope.schema.requiredAttrs.concat(requiredAttrs)
|
||||||
|
|
||||||
|
# Check if required attrs for creating are present
|
||||||
|
getAttrs(mode, data, requiredAttrs)
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
mountCreateForm = (data) ->
|
||||||
|
$scope.obj = $model.make_model($scope.schema.model, $scope.schema.initialData(data))
|
||||||
|
$scope.isNew = true
|
||||||
|
$scope.attachments = Immutable.List()
|
||||||
|
|
||||||
|
# Update texts for creation
|
||||||
|
$el.find(".button-green").html($translate.instant("COMMON.CREATE"))
|
||||||
|
$el.find(".title").html($translate.instant(
|
||||||
|
"LIGHTBOX.CREATE_EDIT.NEW", { objName: $scope.schema.objName }))
|
||||||
|
$el.find(".blocked-note").addClass("hidden")
|
||||||
|
|
||||||
|
mountUpdateForm = (data) ->
|
||||||
|
$scope.isNew = false
|
||||||
|
$scope.attachments = Immutable.fromJS($scope.attachments)
|
||||||
|
|
||||||
|
# Update texts for edition
|
||||||
|
$el.find(".button-green").html($translate.instant("COMMON.SAVE"))
|
||||||
|
$el.find(".title").html($translate.instant(
|
||||||
|
"LIGHTBOX.CREATE_EDIT.EDIT", { objName: $scope.schema.objName }))
|
||||||
|
|
||||||
|
afterMount = () ->
|
||||||
|
resetAttachments()
|
||||||
|
setStatus($scope.obj.status)
|
||||||
|
$scope.createEditOpen = true
|
||||||
|
lightboxService.open $el, () ->
|
||||||
|
$scope.createEditOpen = false
|
||||||
|
|
||||||
|
getAttrs = (mode, data, attrs) ->
|
||||||
|
for attr in attrs
|
||||||
|
if !data[attr]
|
||||||
|
return $log.error "`#{attr}` attribute required in `genericform:#{mode}` event"
|
||||||
|
$scope[attr] = data[attr]
|
||||||
|
|
||||||
|
resetAttachments = () ->
|
||||||
|
attachmentsToAdd = Immutable.List()
|
||||||
|
attachmentsToDelete = Immutable.List()
|
||||||
|
|
||||||
|
$scope.addAttachment = (attachment) ->
|
||||||
|
attachmentsToAdd = attachmentsToAdd.push(attachment)
|
||||||
|
|
||||||
|
$scope.deleteAttachment = (attachment) ->
|
||||||
|
attachmentsToAdd = attachmentsToAdd.filter (it) ->
|
||||||
|
return it.get('name') != attachment.get('name')
|
||||||
|
|
||||||
|
if attachment.get("id")
|
||||||
|
attachmentsToDelete = attachmentsToDelete.push(attachment)
|
||||||
|
|
||||||
|
$scope.addTag = (tag, color) ->
|
||||||
|
value = trim(tag.toLowerCase())
|
||||||
|
|
||||||
|
tags = $scope.project.tags
|
||||||
|
projectTags = $scope.project.tags_colors
|
||||||
|
|
||||||
|
tags = [] if not tags?
|
||||||
|
projectTags = {} if not projectTags?
|
||||||
|
|
||||||
|
if value not in tags
|
||||||
|
tags.push(value)
|
||||||
|
|
||||||
|
projectTags[tag] = color || null
|
||||||
|
|
||||||
|
$scope.project.tags = tags
|
||||||
|
|
||||||
|
itemtags = _.clone($scope.obj.tags)
|
||||||
|
|
||||||
|
inserted = _.find itemtags, (it) -> it[0] == value
|
||||||
|
|
||||||
|
if !inserted
|
||||||
|
itemtags.push([value , color])
|
||||||
|
$scope.obj.tags = itemtags
|
||||||
|
|
||||||
|
$scope.deleteTag = (tag) ->
|
||||||
|
value = trim(tag[0].toLowerCase())
|
||||||
|
|
||||||
|
tags = $scope.project.tags
|
||||||
|
itemtags = _.clone($scope.obj.tags)
|
||||||
|
|
||||||
|
_.remove itemtags, (tag) -> tag[0] == value
|
||||||
|
|
||||||
|
$scope.obj.tags = itemtags
|
||||||
|
|
||||||
|
_.pull($scope.obj.tags, value)
|
||||||
|
|
||||||
|
|
||||||
|
createAttachments = (obj) ->
|
||||||
|
promises = _.map attachmentsToAdd.toJS(), (attachment) ->
|
||||||
|
attachmentsService.upload(
|
||||||
|
attachment.file, obj.id, $scope.obj.project, $scope.objType)
|
||||||
|
|
||||||
|
return $q.all(promises)
|
||||||
|
|
||||||
|
deleteAttachments = (obj) ->
|
||||||
|
promises = _.map attachmentsToDelete.toJS(), (attachment) ->
|
||||||
|
return attachmentsService.delete($scope.objType, attachment.id)
|
||||||
|
|
||||||
|
return $q.all(promises)
|
||||||
|
|
||||||
|
submit = debounce 2000, (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
form = $el.find("form").checksley()
|
||||||
|
if not form.validate()
|
||||||
|
return
|
||||||
|
|
||||||
|
currentLoading = $loading().target(submitButton).start()
|
||||||
|
|
||||||
|
if $scope.isNew
|
||||||
|
promise = $repo.create($scope.schema.model, $scope.obj)
|
||||||
|
broadcastEvent = "#{$scope.objType}form:new:success"
|
||||||
|
else
|
||||||
|
promise = $repo.save($scope.obj, true)
|
||||||
|
broadcastEvent = "#{$scope.objType}form:edit:success"
|
||||||
|
|
||||||
|
promise.then (data) ->
|
||||||
|
deleteAttachments(data)
|
||||||
|
.then () -> createAttachments(data)
|
||||||
|
.then () ->
|
||||||
|
currentLoading.finish()
|
||||||
|
lightboxService.close($el)
|
||||||
|
|
||||||
|
$rs[$scope.schema.model].getByRef(
|
||||||
|
data.project, data.ref, $scope.schema.params).then (obj) ->
|
||||||
|
$rootScope.$broadcast(broadcastEvent, obj)
|
||||||
|
|
||||||
|
promise.then null, (data) ->
|
||||||
|
currentLoading.finish()
|
||||||
|
form.setErrors(data)
|
||||||
|
if data._error_message
|
||||||
|
$confirm.notify("error", data._error_message)
|
||||||
|
|
||||||
|
submitButton = $el.find(".submit-button")
|
||||||
|
|
||||||
|
close = () ->
|
||||||
|
if !$scope.obj.isModified()
|
||||||
|
lightboxService.close($el)
|
||||||
|
$scope.$apply ->
|
||||||
|
$scope.obj.revert()
|
||||||
|
else
|
||||||
|
$confirm.ask(
|
||||||
|
$translate.instant("LIGHTBOX.CREATE_EDIT.CONFIRM_CLOSE")).then (result) ->
|
||||||
|
lightboxService.close($el)
|
||||||
|
$scope.obj.revert()
|
||||||
|
result.finish()
|
||||||
|
|
||||||
|
$el.on "submit", "form", submit
|
||||||
|
|
||||||
|
$el.find('.close').on "click", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
close()
|
||||||
|
|
||||||
|
$el.keydown (event) ->
|
||||||
|
event.stopPropagation()
|
||||||
|
code = if event.keyCode then event.keyCode else event.which
|
||||||
|
if code == 27
|
||||||
|
close()
|
||||||
|
|
||||||
|
$scope.$on "$destroy", ->
|
||||||
|
$el.find('.close').off()
|
||||||
|
$el.off()
|
||||||
|
|
||||||
|
$scope.$watch "obj", ->
|
||||||
|
if !$scope.obj
|
||||||
|
return
|
||||||
|
setStatus($scope.obj.status)
|
||||||
|
|
||||||
|
$el.on "click", ".status-dropdown", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
$el.find(".pop-status").popover().open()
|
||||||
|
|
||||||
|
$el.on "click", ".status", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
setStatus(angular.element(event.currentTarget).data("status-id"))
|
||||||
|
$scope.$apply()
|
||||||
|
$scope.$broadcast("status:changed", $scope.obj.status)
|
||||||
|
$el.find(".pop-status").popover().close()
|
||||||
|
|
||||||
|
$el.on "click", ".users-dropdown", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
$el.find(".pop-users").popover().open()
|
||||||
|
|
||||||
|
$el.on "click", ".team-requirement", (event) ->
|
||||||
|
$scope.obj.team_requirement = not $scope.obj.team_requirement
|
||||||
|
$scope.$apply()
|
||||||
|
|
||||||
|
$el.on "click", ".client-requirement", (event) ->
|
||||||
|
$scope.obj.client_requirement = not $scope.obj.client_requirement
|
||||||
|
$scope.$apply()
|
||||||
|
|
||||||
|
$el.on "click", ".is-blocked", (event) ->
|
||||||
|
$scope.obj.is_blocked = not $scope.obj.is_blocked
|
||||||
|
$scope.$apply()
|
||||||
|
|
||||||
|
$el.on "click", ".iocaine", (event) ->
|
||||||
|
$scope.obj.is_iocaine = not $scope.obj.is_iocaine
|
||||||
|
$scope.$broadcast("isiocaine:changed", $scope.obj)
|
||||||
|
|
||||||
|
setStatus = (id) ->
|
||||||
|
$scope.obj.status = id
|
||||||
|
$scope.selectedStatus = _.find $scope.statusList, (item) -> item.id == id
|
||||||
|
|
||||||
|
$scope.isTeamRequirement = () ->
|
||||||
|
return $scope.obj?.team_requirement
|
||||||
|
|
||||||
|
$scope.isClientRequirement = () ->
|
||||||
|
return $scope.obj?.client_requirement
|
||||||
|
|
||||||
|
return {
|
||||||
|
link: link
|
||||||
|
}
|
||||||
|
|
||||||
|
module.directive("tgLbCreateEdit", [
|
||||||
|
"$log",
|
||||||
|
"$tgRepo",
|
||||||
|
"$tgModel",
|
||||||
|
"$tgResources",
|
||||||
|
"$rootScope",
|
||||||
|
"lightboxService",
|
||||||
|
"$tgLoading",
|
||||||
|
"$translate",
|
||||||
|
"$tgConfirm",
|
||||||
|
"$q",
|
||||||
|
"tgAttachmentsService"
|
||||||
|
CreateEditDirective
|
||||||
|
])
|
|
@ -355,10 +355,12 @@ IssueTypeButtonDirective = ($rootScope, $repo, $confirm, $loading, $modelTransfo
|
||||||
template = $template.get("issue/issue-type-button.html", true)
|
template = $template.get("issue/issue-type-button.html", true)
|
||||||
|
|
||||||
link = ($scope, $el, $attrs, $model) ->
|
link = ($scope, $el, $attrs, $model) ->
|
||||||
|
notAutoSave = $scope.$eval($attrs.notAutoSave)
|
||||||
|
|
||||||
isEditable = ->
|
isEditable = ->
|
||||||
return $scope.project.my_permissions.indexOf("modify_issue") != -1
|
return $scope.project.my_permissions.indexOf("modify_issue") != -1
|
||||||
|
|
||||||
render = (issue) =>
|
render = (issue) ->
|
||||||
type = $scope.typeById[issue.type]
|
type = $scope.typeById[issue.type]
|
||||||
|
|
||||||
html = template({
|
html = template({
|
||||||
|
@ -374,6 +376,11 @@ IssueTypeButtonDirective = ($rootScope, $repo, $confirm, $loading, $modelTransfo
|
||||||
save = (type) ->
|
save = (type) ->
|
||||||
$.fn.popover().closeAll()
|
$.fn.popover().closeAll()
|
||||||
|
|
||||||
|
if notAutoSave
|
||||||
|
$model.$modelValue.type = type
|
||||||
|
$scope.$apply()
|
||||||
|
return
|
||||||
|
|
||||||
currentLoading = $loading()
|
currentLoading = $loading()
|
||||||
.target($el.find(".level-name"))
|
.target($el.find(".level-name"))
|
||||||
.start()
|
.start()
|
||||||
|
@ -445,10 +452,12 @@ IssueSeverityButtonDirective = ($rootScope, $repo, $confirm, $loading, $modelTra
|
||||||
template = $template.get("issue/issue-severity-button.html", true)
|
template = $template.get("issue/issue-severity-button.html", true)
|
||||||
|
|
||||||
link = ($scope, $el, $attrs, $model) ->
|
link = ($scope, $el, $attrs, $model) ->
|
||||||
|
notAutoSave = $scope.$eval($attrs.notAutoSave)
|
||||||
|
|
||||||
isEditable = ->
|
isEditable = ->
|
||||||
return $scope.project.my_permissions.indexOf("modify_issue") != -1
|
return $scope.project.my_permissions.indexOf("modify_issue") != -1
|
||||||
|
|
||||||
render = (issue) =>
|
render = (issue) ->
|
||||||
severity = $scope.severityById[issue.severity]
|
severity = $scope.severityById[issue.severity]
|
||||||
|
|
||||||
html = template({
|
html = template({
|
||||||
|
@ -464,6 +473,11 @@ IssueSeverityButtonDirective = ($rootScope, $repo, $confirm, $loading, $modelTra
|
||||||
save = (severity) ->
|
save = (severity) ->
|
||||||
$.fn.popover().closeAll()
|
$.fn.popover().closeAll()
|
||||||
|
|
||||||
|
if notAutoSave
|
||||||
|
$model.$modelValue.severity = severity
|
||||||
|
$scope.$apply()
|
||||||
|
return
|
||||||
|
|
||||||
currentLoading = $loading()
|
currentLoading = $loading()
|
||||||
.target($el.find(".level-name"))
|
.target($el.find(".level-name"))
|
||||||
.start()
|
.start()
|
||||||
|
@ -536,10 +550,12 @@ IssuePriorityButtonDirective = ($rootScope, $repo, $confirm, $loading, $modelTra
|
||||||
template = $template.get("issue/issue-priority-button.html", true)
|
template = $template.get("issue/issue-priority-button.html", true)
|
||||||
|
|
||||||
link = ($scope, $el, $attrs, $model) ->
|
link = ($scope, $el, $attrs, $model) ->
|
||||||
|
notAutoSave = $scope.$eval($attrs.notAutoSave)
|
||||||
|
|
||||||
isEditable = ->
|
isEditable = ->
|
||||||
return $scope.project.my_permissions.indexOf("modify_issue") != -1
|
return $scope.project.my_permissions.indexOf("modify_issue") != -1
|
||||||
|
|
||||||
render = (issue) =>
|
render = (issue) ->
|
||||||
priority = $scope.priorityById[issue.priority]
|
priority = $scope.priorityById[issue.priority]
|
||||||
|
|
||||||
html = template({
|
html = template({
|
||||||
|
@ -555,6 +571,11 @@ IssuePriorityButtonDirective = ($rootScope, $repo, $confirm, $loading, $modelTra
|
||||||
save = (priority) ->
|
save = (priority) ->
|
||||||
$.fn.popover().closeAll()
|
$.fn.popover().closeAll()
|
||||||
|
|
||||||
|
if notAutoSave
|
||||||
|
$model.$modelValue.priority = priority
|
||||||
|
$scope.$apply()
|
||||||
|
return
|
||||||
|
|
||||||
currentLoading = $loading()
|
currentLoading = $loading()
|
||||||
.target($el.find(".level-name"))
|
.target($el.find(".level-name"))
|
||||||
.start()
|
.start()
|
||||||
|
|
|
@ -29,131 +29,6 @@ trim = @.taiga.trim
|
||||||
|
|
||||||
module = angular.module("taigaIssues")
|
module = angular.module("taigaIssues")
|
||||||
|
|
||||||
#############################################################################
|
|
||||||
## Issue Create Lightbox Directive
|
|
||||||
#############################################################################
|
|
||||||
|
|
||||||
CreateIssueDirective = ($repo, $confirm, $rootscope, lightboxService, $loading, $q, attachmentsService) ->
|
|
||||||
link = ($scope, $el, $attrs) ->
|
|
||||||
form = $el.find("form").checksley()
|
|
||||||
$scope.issue = {}
|
|
||||||
$scope.attachments = Immutable.List()
|
|
||||||
|
|
||||||
$scope.$on "issueform:new", (ctx, project)->
|
|
||||||
form.reset()
|
|
||||||
|
|
||||||
resetAttachments()
|
|
||||||
|
|
||||||
$el.find(".tag-input").val("")
|
|
||||||
lightboxService.open $el, () ->
|
|
||||||
$scope.createIssueOpen = false
|
|
||||||
|
|
||||||
$scope.issue = {
|
|
||||||
project: project.id
|
|
||||||
subject: ""
|
|
||||||
status: project.default_issue_status
|
|
||||||
type: project.default_issue_type
|
|
||||||
priority: project.default_priority
|
|
||||||
severity: project.default_severity
|
|
||||||
tags: []
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.createIssueOpen = true
|
|
||||||
|
|
||||||
$scope.$on "$destroy", ->
|
|
||||||
$el.off()
|
|
||||||
|
|
||||||
createAttachments = (obj) ->
|
|
||||||
promises = _.map attachmentsToAdd.toJS(), (attachment) ->
|
|
||||||
return attachmentsService.upload(attachment.file, obj.id, $scope.issue.project, 'issue')
|
|
||||||
|
|
||||||
return $q.all(promises)
|
|
||||||
|
|
||||||
attachmentsToAdd = Immutable.List()
|
|
||||||
|
|
||||||
resetAttachments = () ->
|
|
||||||
attachmentsToAdd = Immutable.List()
|
|
||||||
$scope.attachments = Immutable.List()
|
|
||||||
|
|
||||||
$scope.addAttachment = (attachment) ->
|
|
||||||
attachmentsToAdd = attachmentsToAdd.push(attachment)
|
|
||||||
|
|
||||||
$scope.deleteAttachment = (attachment) ->
|
|
||||||
attachmentsToAdd = attachmentsToAdd.filter (it) ->
|
|
||||||
return it.get('name') != attachment.get('name')
|
|
||||||
|
|
||||||
$scope.addTag = (tag, color) ->
|
|
||||||
value = trim(tag.toLowerCase())
|
|
||||||
|
|
||||||
tags = $scope.project.tags
|
|
||||||
projectTags = $scope.project.tags_colors
|
|
||||||
|
|
||||||
tags = [] if not tags?
|
|
||||||
projectTags = {} if not projectTags?
|
|
||||||
|
|
||||||
if value not in tags
|
|
||||||
tags.push(value)
|
|
||||||
|
|
||||||
projectTags[tag] = color || null
|
|
||||||
|
|
||||||
$scope.project.tags = tags
|
|
||||||
|
|
||||||
itemtags = _.clone($scope.issue.tags)
|
|
||||||
|
|
||||||
inserted = _.find itemtags, (it) -> it[0] == value
|
|
||||||
|
|
||||||
if !inserted
|
|
||||||
itemtags.push([tag , color])
|
|
||||||
$scope.issue.tags = itemtags
|
|
||||||
|
|
||||||
$scope.deleteTag = (tag) ->
|
|
||||||
value = trim(tag[0].toLowerCase())
|
|
||||||
|
|
||||||
tags = $scope.project.tags
|
|
||||||
itemtags = _.clone($scope.issue.tags)
|
|
||||||
|
|
||||||
_.remove itemtags, (tag) -> tag[0] == value
|
|
||||||
|
|
||||||
$scope.issue.tags = itemtags
|
|
||||||
|
|
||||||
_.pull($scope.issue.tags, value)
|
|
||||||
|
|
||||||
submit = debounce 2000, (event) =>
|
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
if not form.validate()
|
|
||||||
return
|
|
||||||
|
|
||||||
currentLoading = $loading()
|
|
||||||
.target(submitButton)
|
|
||||||
.start()
|
|
||||||
|
|
||||||
promise = $repo.create("issues", $scope.issue)
|
|
||||||
|
|
||||||
promise.then (data) ->
|
|
||||||
return createAttachments(data)
|
|
||||||
|
|
||||||
promise.then (data) ->
|
|
||||||
currentLoading.finish()
|
|
||||||
$rootscope.$broadcast("issueform:new:success", data)
|
|
||||||
lightboxService.close($el)
|
|
||||||
$confirm.notify("success")
|
|
||||||
|
|
||||||
promise.then null, ->
|
|
||||||
currentLoading.finish()
|
|
||||||
$confirm.notify("error")
|
|
||||||
|
|
||||||
submitButton = $el.find(".submit-button")
|
|
||||||
|
|
||||||
$el.on "submit", "form", submit
|
|
||||||
|
|
||||||
|
|
||||||
return {link:link}
|
|
||||||
|
|
||||||
module.directive("tgLbCreateIssue", ["$tgRepo", "$tgConfirm", "$rootScope", "lightboxService", "$tgLoading",
|
|
||||||
"$q", "tgAttachmentsService", CreateIssueDirective])
|
|
||||||
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
## Issue Bulk Create Lightbox Directive
|
## Issue Bulk Create Lightbox Directive
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
|
@ -367,7 +367,16 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
||||||
|
|
||||||
# Functions used from templates
|
# Functions used from templates
|
||||||
addNewIssue: ->
|
addNewIssue: ->
|
||||||
@rootscope.$broadcast("issueform:new", @scope.project)
|
project = @projectService.project.toJS()
|
||||||
|
@rootscope.$broadcast("genericform:new", {
|
||||||
|
'objType': 'issue',
|
||||||
|
'statusList': @scope.issueStatusList,
|
||||||
|
'project': project,
|
||||||
|
'severityList': @scope.severityList,
|
||||||
|
'priorityList': @scope.priorityList,
|
||||||
|
'typeById': groupBy(project.issue_types, (x) -> x.id),
|
||||||
|
'typeList': _.sortBy(project.issue_types, "order")
|
||||||
|
})
|
||||||
|
|
||||||
addIssuesInBulk: ->
|
addIssuesInBulk: ->
|
||||||
@rootscope.$broadcast("issueform:bulk", @scope.projectId)
|
@rootscope.$broadcast("issueform:bulk", @scope.projectId)
|
||||||
|
|
|
@ -164,8 +164,12 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
||||||
|
|
||||||
addNewUs: (type, statusId) ->
|
addNewUs: (type, statusId) ->
|
||||||
switch type
|
switch type
|
||||||
when "standard" then @rootscope.$broadcast("usform:new",
|
when "standard" then @rootscope.$broadcast("genericform:new",
|
||||||
@scope.projectId, statusId, @scope.usStatusList)
|
{
|
||||||
|
'objType': 'us',
|
||||||
|
'project': @scope.project,
|
||||||
|
'statusList': @scope.usStatusList
|
||||||
|
})
|
||||||
when "bulk" then @rootscope.$broadcast("usform:bulk",
|
when "bulk" then @rootscope.$broadcast("usform:bulk",
|
||||||
@scope.projectId, statusId)
|
@scope.projectId, statusId)
|
||||||
|
|
||||||
|
@ -176,8 +180,14 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi
|
||||||
|
|
||||||
@rs.userstories.getByRef(us.getIn(['model', 'project']), us.getIn(['model', 'ref']))
|
@rs.userstories.getByRef(us.getIn(['model', 'project']), us.getIn(['model', 'ref']))
|
||||||
.then (editingUserStory) =>
|
.then (editingUserStory) =>
|
||||||
@rs2.attachments.list("us", us.get('id'), us.getIn(['model', 'project'])).then (attachments) =>
|
@rs2.attachments.list(
|
||||||
@rootscope.$broadcast("usform:edit", editingUserStory, attachments.toJS())
|
"us", us.get('id'), us.getIn(['model', 'project'])).then (attachments) =>
|
||||||
|
@rootscope.$broadcast("genericform:edit", {
|
||||||
|
'objType': 'us',
|
||||||
|
'obj': editingUserStory,
|
||||||
|
'statusList': @scope.usStatusList,
|
||||||
|
'attachments': attachments.toJS()
|
||||||
|
})
|
||||||
|
|
||||||
us = us.set('loading-edit', false)
|
us = us.set('loading-edit', false)
|
||||||
@kanbanUserstoriesService.replace(us)
|
@kanbanUserstoriesService.replace(us)
|
||||||
|
|
|
@ -27,196 +27,6 @@ bindOnce = @.taiga.bindOnce
|
||||||
debounce = @.taiga.debounce
|
debounce = @.taiga.debounce
|
||||||
trim = @.taiga.trim
|
trim = @.taiga.trim
|
||||||
|
|
||||||
CreateEditTaskDirective = ($repo, $model, $rs, $rootscope, $loading, lightboxService, $translate, $q, $confirm, attachmentsService) ->
|
|
||||||
link = ($scope, $el, attrs) ->
|
|
||||||
$scope.isNew = true
|
|
||||||
|
|
||||||
attachmentsToAdd = Immutable.List()
|
|
||||||
attachmentsToDelete = Immutable.List()
|
|
||||||
|
|
||||||
resetAttachments = () ->
|
|
||||||
attachmentsToAdd = Immutable.List()
|
|
||||||
attachmentsToDelete = Immutable.List()
|
|
||||||
|
|
||||||
$scope.addAttachment = (attachment) ->
|
|
||||||
attachmentsToAdd = attachmentsToAdd.push(attachment)
|
|
||||||
|
|
||||||
$scope.deleteAttachment = (attachment) ->
|
|
||||||
attachmentsToAdd = attachmentsToAdd.filter (it) ->
|
|
||||||
return it.get('name') != attachment.get('name')
|
|
||||||
|
|
||||||
if attachment.get("id")
|
|
||||||
attachmentsToDelete = attachmentsToDelete.push(attachment)
|
|
||||||
|
|
||||||
createAttachments = (obj) ->
|
|
||||||
promises = _.map attachmentsToAdd.toJS(), (attachment) ->
|
|
||||||
attachmentsService.upload(attachment.file, obj.id, $scope.task.project, 'task')
|
|
||||||
|
|
||||||
return $q.all(promises)
|
|
||||||
|
|
||||||
deleteAttachments = (obj) ->
|
|
||||||
promises = _.map attachmentsToDelete.toJS(), (attachment) ->
|
|
||||||
return attachmentsService.delete("task", attachment.id)
|
|
||||||
|
|
||||||
return $q.all(promises)
|
|
||||||
|
|
||||||
tagsToAdd = []
|
|
||||||
|
|
||||||
$scope.addTag = (tag, color) ->
|
|
||||||
value = trim(tag.toLowerCase())
|
|
||||||
|
|
||||||
tags = $scope.project.tags
|
|
||||||
projectTags = $scope.project.tags_colors
|
|
||||||
|
|
||||||
tags = [] if not tags?
|
|
||||||
projectTags = {} if not projectTags?
|
|
||||||
|
|
||||||
if value not in tags
|
|
||||||
tags.push(value)
|
|
||||||
|
|
||||||
projectTags[tag] = color || null
|
|
||||||
|
|
||||||
$scope.project.tags = tags
|
|
||||||
|
|
||||||
itemtags = _.clone($scope.task.tags)
|
|
||||||
|
|
||||||
inserted = _.find itemtags, (it) -> it[0] == value
|
|
||||||
|
|
||||||
if !inserted
|
|
||||||
itemtags.push([tag , color])
|
|
||||||
$scope.task.tags = itemtags
|
|
||||||
|
|
||||||
|
|
||||||
$scope.deleteTag = (tag) ->
|
|
||||||
value = trim(tag[0].toLowerCase())
|
|
||||||
|
|
||||||
tags = $scope.project.tags
|
|
||||||
itemtags = _.clone($scope.task.tags)
|
|
||||||
|
|
||||||
_.remove itemtags, (tag) -> tag[0] == value
|
|
||||||
|
|
||||||
$scope.task.tags = itemtags
|
|
||||||
|
|
||||||
_.pull($scope.task.tags, value)
|
|
||||||
|
|
||||||
$scope.$on "taskform:new", (ctx, sprintId, usId) ->
|
|
||||||
$scope.task = $model.make_model('tasks', {
|
|
||||||
project: $scope.projectId
|
|
||||||
milestone: sprintId
|
|
||||||
user_story: usId
|
|
||||||
is_archived: false
|
|
||||||
status: $scope.project.default_task_status
|
|
||||||
assigned_to: null
|
|
||||||
tags: [],
|
|
||||||
subject: "",
|
|
||||||
description: "",
|
|
||||||
})
|
|
||||||
$scope.isNew = true
|
|
||||||
$scope.attachments = Immutable.List()
|
|
||||||
|
|
||||||
resetAttachments()
|
|
||||||
|
|
||||||
# Update texts for creation
|
|
||||||
create = $translate.instant("COMMON.CREATE")
|
|
||||||
$el.find(".button-green").html(create)
|
|
||||||
|
|
||||||
newTask = $translate.instant("LIGHTBOX.CREATE_EDIT_TASK.TITLE")
|
|
||||||
$el.find(".title").html(newTask + " ")
|
|
||||||
|
|
||||||
$el.find(".tag-input").val("")
|
|
||||||
lightboxService.open $el, () ->
|
|
||||||
$scope.createEditTaskOpen = false
|
|
||||||
|
|
||||||
$scope.createEditTaskOpen = true
|
|
||||||
|
|
||||||
$scope.$on "taskform:edit", (ctx, task, attachments) ->
|
|
||||||
$scope.task = task
|
|
||||||
$scope.isNew = false
|
|
||||||
|
|
||||||
$scope.attachments = Immutable.fromJS(attachments)
|
|
||||||
|
|
||||||
resetAttachments()
|
|
||||||
|
|
||||||
# Update texts for edition
|
|
||||||
save = $translate.instant("COMMON.SAVE")
|
|
||||||
edit = $translate.instant("LIGHTBOX.CREATE_EDIT_TASK.ACTION_EDIT")
|
|
||||||
|
|
||||||
$el.find(".button-green").html(save)
|
|
||||||
$el.find(".title").html(edit + " ")
|
|
||||||
|
|
||||||
$el.find(".tag-input").val("")
|
|
||||||
lightboxService.open $el, () ->
|
|
||||||
$scope.createEditTaskOpen = false
|
|
||||||
|
|
||||||
$scope.createEditTaskOpen = true
|
|
||||||
|
|
||||||
|
|
||||||
submitButton = $el.find(".submit-button")
|
|
||||||
|
|
||||||
submit = debounce 2000, (event) =>
|
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
form = $el.find("form").checksley()
|
|
||||||
if not form.validate()
|
|
||||||
return
|
|
||||||
|
|
||||||
params = {
|
|
||||||
include_attachments: true,
|
|
||||||
include_tasks: true
|
|
||||||
}
|
|
||||||
|
|
||||||
if $scope.isNew
|
|
||||||
promise = $repo.create("tasks", $scope.task)
|
|
||||||
broadcastEvent = "taskform:new:success"
|
|
||||||
else
|
|
||||||
promise = $repo.save($scope.task)
|
|
||||||
broadcastEvent = "taskform:edit:success"
|
|
||||||
|
|
||||||
promise.then (data) ->
|
|
||||||
deleteAttachments(data)
|
|
||||||
.then () => createAttachments(data)
|
|
||||||
.then () =>
|
|
||||||
$rs.tasks.getByRef(data.project, data.ref, params).then (task) ->
|
|
||||||
$rootscope.$broadcast(broadcastEvent, task)
|
|
||||||
|
|
||||||
currentLoading = $loading()
|
|
||||||
.target(submitButton)
|
|
||||||
.start()
|
|
||||||
|
|
||||||
promise.then (data) ->
|
|
||||||
currentLoading.finish()
|
|
||||||
lightboxService.close($el)
|
|
||||||
|
|
||||||
$el.on "submit", "form", submit
|
|
||||||
|
|
||||||
close = () =>
|
|
||||||
if !$scope.task.isModified()
|
|
||||||
lightboxService.close($el)
|
|
||||||
$scope.$apply ->
|
|
||||||
$scope.task.revert()
|
|
||||||
else
|
|
||||||
$confirm.ask($translate.instant("LIGHTBOX.CREATE_EDIT_TASK.CONFIRM_CLOSE")).then (result) ->
|
|
||||||
lightboxService.close($el)
|
|
||||||
$scope.task.revert()
|
|
||||||
result.finish()
|
|
||||||
|
|
||||||
$el.find('.close').on "click", (event) ->
|
|
||||||
event.preventDefault()
|
|
||||||
event.stopPropagation()
|
|
||||||
close()
|
|
||||||
|
|
||||||
$el.keydown (event) ->
|
|
||||||
event.stopPropagation()
|
|
||||||
code = if event.keyCode then event.keyCode else event.which
|
|
||||||
if code == 27
|
|
||||||
close()
|
|
||||||
|
|
||||||
$scope.$on "$destroy", ->
|
|
||||||
$el.find('.close').off()
|
|
||||||
$el.off()
|
|
||||||
|
|
||||||
return {link: link}
|
|
||||||
|
|
||||||
|
|
||||||
CreateBulkTasksDirective = ($repo, $rs, $rootscope, $loading, lightboxService, $model) ->
|
CreateBulkTasksDirective = ($repo, $rs, $rootscope, $loading, lightboxService, $model) ->
|
||||||
link = ($scope, $el, attrs) ->
|
link = ($scope, $el, attrs) ->
|
||||||
|
@ -248,7 +58,6 @@ CreateBulkTasksDirective = ($repo, $rs, $rootscope, $loading, lightboxService, $
|
||||||
# TODO: error handling
|
# TODO: error handling
|
||||||
promise.then null, ->
|
promise.then null, ->
|
||||||
currentLoading.finish()
|
currentLoading.finish()
|
||||||
console.log "FAIL"
|
|
||||||
|
|
||||||
$scope.$on "taskform:bulk", (ctx, sprintId, usId)->
|
$scope.$on "taskform:bulk", (ctx, sprintId, usId)->
|
||||||
lightboxService.open($el)
|
lightboxService.open($el)
|
||||||
|
@ -266,20 +75,6 @@ CreateBulkTasksDirective = ($repo, $rs, $rootscope, $loading, lightboxService, $
|
||||||
|
|
||||||
module = angular.module("taigaTaskboard")
|
module = angular.module("taigaTaskboard")
|
||||||
|
|
||||||
module.directive("tgLbCreateEditTask", [
|
|
||||||
"$tgRepo",
|
|
||||||
"$tgModel",
|
|
||||||
"$tgResources",
|
|
||||||
"$rootScope",
|
|
||||||
"$tgLoading",
|
|
||||||
"lightboxService",
|
|
||||||
"$translate",
|
|
||||||
"$q",
|
|
||||||
"$tgConfirm",
|
|
||||||
"tgAttachmentsService",
|
|
||||||
CreateEditTaskDirective
|
|
||||||
])
|
|
||||||
|
|
||||||
module.directive("tgLbCreateBulkTasks", [
|
module.directive("tgLbCreateBulkTasks", [
|
||||||
"$tgRepo",
|
"$tgRepo",
|
||||||
"$tgResources",
|
"$tgResources",
|
||||||
|
|
|
@ -439,9 +439,17 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin, taiga
|
||||||
task = task.set('loading-edit', true)
|
task = task.set('loading-edit', true)
|
||||||
@taskboardTasksService.replace(task)
|
@taskboardTasksService.replace(task)
|
||||||
|
|
||||||
@rs.tasks.getByRef(task.getIn(['model', 'project']), task.getIn(['model', 'ref'])).then (editingTask) =>
|
@rs.tasks.getByRef(task.getIn(['model', 'project']), task.getIn(['model', 'ref']))
|
||||||
@rs2.attachments.list("task", task.get('id'), task.getIn(['model', 'project'])).then (attachments) =>
|
.then (editingTask) =>
|
||||||
@rootscope.$broadcast("taskform:edit", editingTask, attachments.toJS())
|
@rs2.attachments.list("task", task.get('id'), task.getIn(['model', 'project']))
|
||||||
|
.then (attachments) =>
|
||||||
|
@rootscope.$broadcast("genericform:edit", {
|
||||||
|
'objType': 'task',
|
||||||
|
'obj': editingTask,
|
||||||
|
'statusList': @scope.taskStatusList,
|
||||||
|
'attachments': attachments.toJS()
|
||||||
|
})
|
||||||
|
|
||||||
task = task.set('loading', false)
|
task = task.set('loading', false)
|
||||||
@taskboardTasksService.replace(task)
|
@taskboardTasksService.replace(task)
|
||||||
|
|
||||||
|
@ -496,7 +504,15 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin, taiga
|
||||||
## Template actions
|
## Template actions
|
||||||
addNewTask: (type, us) ->
|
addNewTask: (type, us) ->
|
||||||
switch type
|
switch type
|
||||||
when "standard" then @rootscope.$broadcast("taskform:new", @scope.sprintId, us?.id)
|
when "standard" then @rootscope.$broadcast("genericform:new",
|
||||||
|
{
|
||||||
|
'objType': 'task',
|
||||||
|
'project': @scope.project,
|
||||||
|
'sprintId': @scope.sprintId,
|
||||||
|
'usId': us?.id,
|
||||||
|
'status': @scope.project.default_task_status,
|
||||||
|
'statusList': @scope.taskStatusList
|
||||||
|
})
|
||||||
when "bulk" then @rootscope.$broadcast("taskform:bulk", @scope.sprintId, us?.id)
|
when "bulk" then @rootscope.$broadcast("taskform:bulk", @scope.sprintId, us?.id)
|
||||||
|
|
||||||
toggleFold: (id) ->
|
toggleFold: (id) ->
|
||||||
|
|
|
@ -150,7 +150,9 @@
|
||||||
"VOTES": "Votes",
|
"VOTES": "Votes",
|
||||||
"SPRINT": "Sprint",
|
"SPRINT": "Sprint",
|
||||||
"DUE_DATE": "Due date",
|
"DUE_DATE": "Due date",
|
||||||
"DUE_DATE_REASON": "Due date reason"
|
"DUE_DATE_REASON": "Due date reason",
|
||||||
|
"CLIENT_REQUIREMENT": "Client requirement",
|
||||||
|
"TEAM_REQUIREMENT": "Team requirement"
|
||||||
},
|
},
|
||||||
"ROLES": {
|
"ROLES": {
|
||||||
"ALL": "All"
|
"ALL": "All"
|
||||||
|
@ -1091,6 +1093,12 @@
|
||||||
"EDIT_US": "Edit user story",
|
"EDIT_US": "Edit user story",
|
||||||
"CONFIRM_CLOSE": "You have not saved changes.\nAre you sure you want to close the form?"
|
"CONFIRM_CLOSE": "You have not saved changes.\nAre you sure you want to close the form?"
|
||||||
},
|
},
|
||||||
|
"CREATE_EDIT": {
|
||||||
|
"PLACEHOLDER_DESCRIPTION": "Please add descriptive text to help others better understand this {{ objName }}",
|
||||||
|
"NEW": "New {{ objName }}",
|
||||||
|
"EDIT": "Edit {{ objName }}",
|
||||||
|
"CONFIRM_CLOSE": "You have not saved changes.\nAre you sure you want to close the form?"
|
||||||
|
},
|
||||||
"DELETE_DUE_DATE": {
|
"DELETE_DUE_DATE": {
|
||||||
"TITLE": "Delete due date",
|
"TITLE": "Delete due date",
|
||||||
"SUBTITLE": "Are you sure you want to delete this due date?"
|
"SUBTITLE": "Are you sure you want to delete this due date?"
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
.card-statistics
|
.card-statistics
|
||||||
tg-due-date.statistic.card-due-date(
|
tg-due-date.statistic.card-due-date(
|
||||||
due-date="vm.item.getIn(['model', 'due_date'])"
|
due-date="vm.item.getIn(['model', 'due_date'])"
|
||||||
due-date-status="vm.item.getIn(['model', 'due_date_status'])"
|
|
||||||
is-closed="vm.item.getIn(['model', 'is_closed'])"
|
is-closed="vm.item.getIn(['model', 'is_closed'])"
|
||||||
)
|
)
|
||||||
.statistic.card-iocaine(
|
.statistic.card-iocaine(
|
||||||
|
|
|
@ -21,9 +21,8 @@
|
||||||
tg-svg.detail-edit.e2e-detail-edit(svg-icon="icon-edit")
|
tg-svg.detail-edit.e2e-detail-edit(svg-icon="icon-edit")
|
||||||
tg-due-date(
|
tg-due-date(
|
||||||
due-date="vm.item.due_date"
|
due-date="vm.item.due_date"
|
||||||
due-date-status="vm.item.due_date_status"
|
|
||||||
ng-if="vm.item.due_date"
|
|
||||||
is-closed="vm.item.is_closed"
|
is-closed="vm.item.is_closed"
|
||||||
|
ng-if="vm.item.due_date"
|
||||||
)
|
)
|
||||||
.edit-title-wrapper(ng-if="vm.editMode")
|
.edit-title-wrapper(ng-if="vm.editMode")
|
||||||
input.edit-title-input.e2e-title-input(
|
input.edit-title-input.e2e-title-input(
|
||||||
|
|
|
@ -21,9 +21,10 @@ class DueDateController
|
||||||
@.$inject = [
|
@.$inject = [
|
||||||
"$translate"
|
"$translate"
|
||||||
"tgLightboxFactory"
|
"tgLightboxFactory"
|
||||||
|
"tgProjectService"
|
||||||
]
|
]
|
||||||
|
|
||||||
constructor: (@translate, @tgLightboxFactory) ->
|
constructor: (@translate, @tgLightboxFactory, @projectService) ->
|
||||||
|
|
||||||
visible: () ->
|
visible: () ->
|
||||||
return @.format == 'button' or @.dueDate?
|
return @.format == 'button' or @.dueDate?
|
||||||
|
@ -37,17 +38,35 @@ class DueDateController
|
||||||
'due_soon': 'due-soon',
|
'due_soon': 'due-soon',
|
||||||
'past_due': 'past-due',
|
'past_due': 'past-due',
|
||||||
'set': 'due-set',
|
'set': 'due-set',
|
||||||
|
'not_set': 'not-set',
|
||||||
}
|
}
|
||||||
return colors[@.dueDateStatus] or ''
|
return colors[@status()] or ''
|
||||||
|
|
||||||
title: () ->
|
title: () ->
|
||||||
if @.format == 'button'
|
if @.dueDate
|
||||||
return if @.dueDate then @._formatTitle() else 'Edit due date'
|
|
||||||
|
|
||||||
return @._formatTitle()
|
return @._formatTitle()
|
||||||
|
else if @.format == 'button'
|
||||||
|
return @translate.instant('COMMON.DUE_DATE.TITLE_ACTION_SET_DUE_DATE')
|
||||||
|
return ''
|
||||||
|
|
||||||
|
status: () ->
|
||||||
|
if !@.dueDate
|
||||||
|
return 'not_set'
|
||||||
|
|
||||||
|
project = @projectService.project.toJS()
|
||||||
|
project.due_soon_threshold = 14 # TODO get value from taiga-back
|
||||||
|
dueDate = moment(@.dueDate)
|
||||||
|
now = moment()
|
||||||
|
|
||||||
|
if @.isClosed
|
||||||
|
return 'no_longer_applicable'
|
||||||
|
else if now > dueDate
|
||||||
|
return 'past_due'
|
||||||
|
else if now.add(moment.duration(project.due_soon_threshold, "days")) >= dueDate
|
||||||
|
return 'due_soon'
|
||||||
|
return 'set'
|
||||||
|
|
||||||
_formatTitle: () ->
|
_formatTitle: () ->
|
||||||
dueDateStatus = 'closed'
|
|
||||||
titles = {
|
titles = {
|
||||||
'no_longer_applicable': 'COMMON.DUE_DATE.NO_LONGER_APPLICABLE',
|
'no_longer_applicable': 'COMMON.DUE_DATE.NO_LONGER_APPLICABLE',
|
||||||
'due_soon': 'COMMON.DUE_DATE.DUE_SOON',
|
'due_soon': 'COMMON.DUE_DATE.DUE_SOON',
|
||||||
|
@ -56,16 +75,17 @@ class DueDateController
|
||||||
prettyDate = @translate.instant("COMMON.PICKERDATE.FORMAT")
|
prettyDate = @translate.instant("COMMON.PICKERDATE.FORMAT")
|
||||||
formatedDate = moment(@.dueDate).format(prettyDate)
|
formatedDate = moment(@.dueDate).format(prettyDate)
|
||||||
|
|
||||||
if not titles[@.dueDateStatus]
|
status = @status()
|
||||||
|
if not titles[status]
|
||||||
return formatedDate
|
return formatedDate
|
||||||
return "#{formatedDate} (#{@translate.instant(titles[@.dueDateStatus])})"
|
return "#{formatedDate} (#{@translate.instant(titles[status])})"
|
||||||
|
|
||||||
setDueDate: () ->
|
setDueDate: () ->
|
||||||
return if @.disabled()
|
return if @.disabled()
|
||||||
@tgLightboxFactory.create(
|
@tgLightboxFactory.create(
|
||||||
"tg-lb-set-due-date",
|
"tg-lb-set-due-date",
|
||||||
{"class": "lightbox lightbox-set-due-date"},
|
{"class": "lightbox lightbox-set-due-date"},
|
||||||
{"object": @.item}
|
{"object": @.item, "notAutoSave": @.notAutoSave}
|
||||||
)
|
)
|
||||||
|
|
||||||
angular.module('taigaComponents').controller('DueDate', DueDateController)
|
angular.module('taigaComponents').controller('DueDateCtrl', DueDateController)
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
###
|
||||||
|
# Copyright (C) 2014-2018 Taiga Agile LLC <taiga@taiga.io>
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
# File: due-date.directive.coffee
|
||||||
|
###
|
||||||
|
|
||||||
|
module = angular.module("taigaComponents")
|
||||||
|
|
||||||
|
dueDatePopoverDirective = ($translate, datePickerConfigService) ->
|
||||||
|
return {
|
||||||
|
link: (scope, el, attrs, ctrl) ->
|
||||||
|
prettyDate = $translate.instant("COMMON.PICKERDATE.FORMAT")
|
||||||
|
if ctrl.dueDate
|
||||||
|
ctrl.dueDate = moment(ctrl.dueDate, prettyDate)
|
||||||
|
|
||||||
|
el.on "click", ".date-picker-popover-trigger", (event) ->
|
||||||
|
if ctrl.disabled()
|
||||||
|
return
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
el.find(".date-picker-popover").popover().open()
|
||||||
|
|
||||||
|
el.on "click", ".date-picker-clean", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
ctrl.dueDate = null
|
||||||
|
scope.$apply()
|
||||||
|
el.find(".date-picker-popover").popover().close()
|
||||||
|
|
||||||
|
datePickerConfig = datePickerConfigService.get()
|
||||||
|
_.merge(datePickerConfig, {
|
||||||
|
field: el.find('input.due-date')[0]
|
||||||
|
container: el.find('.date-picker-container')[0]
|
||||||
|
bound: false
|
||||||
|
onSelect: () ->
|
||||||
|
ctrl.dueDate = this.getMoment().format('YYYY-MM-DD')
|
||||||
|
el.find(".date-picker-popover").popover().close()
|
||||||
|
scope.$apply()
|
||||||
|
})
|
||||||
|
|
||||||
|
el.picker = new Pikaday(datePickerConfig)
|
||||||
|
|
||||||
|
controller: "DueDateCtrl",
|
||||||
|
controllerAs: "vm",
|
||||||
|
bindToController: true,
|
||||||
|
templateUrl: "components/due-date/due-date-popover.html",
|
||||||
|
scope: {
|
||||||
|
dueDate: '=',
|
||||||
|
isClosed: '=',
|
||||||
|
item: '=',
|
||||||
|
format: '@',
|
||||||
|
notAutoSave: '='
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.directive('tgDueDatePopover', ['$translate', 'tgDatePickerConfigService', dueDatePopoverDirective])
|
|
@ -0,0 +1,16 @@
|
||||||
|
.due-date-button-wrapper
|
||||||
|
label.due-date-button.button-gray.is-editable.date-picker-popover-trigger(
|
||||||
|
ng-disabled="vm.disabled()"
|
||||||
|
ng-class="vm.color()"
|
||||||
|
ng-attr-title="{{ vm.title() }}"
|
||||||
|
)
|
||||||
|
tg-svg(svg-icon="icon-clock")
|
||||||
|
input.due-date.no-focus(
|
||||||
|
type="hidden"
|
||||||
|
picker-value="{{ vm.dueDate }}"
|
||||||
|
)
|
||||||
|
div.date-picker-popover
|
||||||
|
div.date-picker-container
|
||||||
|
div.date-picker-popover-footer(ng-if="vm.dueDate")
|
||||||
|
a.date-picker-clean(href="", title="{{'LIGHTBOX.SET_DUE_DATE.TITLE_ACTION_DELETE_DUE_DATE' | translate}}")
|
||||||
|
tg-svg(svg-icon="icon-trash")
|
|
@ -19,25 +19,60 @@
|
||||||
|
|
||||||
module = angular.module("taigaComponents")
|
module = angular.module("taigaComponents")
|
||||||
|
|
||||||
dueDateDirective = () ->
|
dueDateDirective = ($translate, datePickerConfigService) ->
|
||||||
templateUrl = (el, attrs) ->
|
templateUrl = (el, attrs) ->
|
||||||
if attrs.format
|
if attrs.format
|
||||||
return "components/due-date/due-date-" + attrs.format + ".html"
|
return "components/due-date/due-date-" + attrs.format + ".html"
|
||||||
return "components/due-date/due-date-icon.html"
|
return "components/due-date/due-date-icon.html"
|
||||||
|
|
||||||
return {
|
return {
|
||||||
link: (scope) ->
|
link: (scope, el, attrs, ctrl) ->
|
||||||
controller: "DueDate",
|
renderDatePicker = () ->
|
||||||
|
prettyDate = $translate.instant("COMMON.PICKERDATE.FORMAT")
|
||||||
|
if ctrl.dueDate
|
||||||
|
ctrl.dueDate = moment(ctrl.dueDate, prettyDate)
|
||||||
|
|
||||||
|
el.on "click", ".date-picker-popover-trigger", (event) ->
|
||||||
|
if ctrl.disabled()
|
||||||
|
return
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
el.find(".date-picker-popover").popover().open()
|
||||||
|
|
||||||
|
el.on "click", ".date-picker-clean", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
ctrl.dueDate = null
|
||||||
|
scope.$apply()
|
||||||
|
el.find(".date-picker-popover").popover().close()
|
||||||
|
|
||||||
|
datePickerConfig = datePickerConfigService.get()
|
||||||
|
_.merge(datePickerConfig, {
|
||||||
|
field: el.find('input.due-date')[0]
|
||||||
|
container: el.find('.date-picker-container')[0]
|
||||||
|
bound: false
|
||||||
|
onSelect: () ->
|
||||||
|
ctrl.dueDate = this.getMoment().format('YYYY-MM-DD')
|
||||||
|
el.find(".date-picker-popover").popover().close()
|
||||||
|
scope.$apply()
|
||||||
|
})
|
||||||
|
|
||||||
|
el.picker = new Pikaday(datePickerConfig)
|
||||||
|
|
||||||
|
if attrs.format == 'button-popover'
|
||||||
|
renderDatePicker()
|
||||||
|
|
||||||
|
controller: "DueDateCtrl",
|
||||||
controllerAs: "vm",
|
controllerAs: "vm",
|
||||||
bindToController: true,
|
bindToController: true,
|
||||||
templateUrl: templateUrl,
|
templateUrl: templateUrl,
|
||||||
scope: {
|
scope: {
|
||||||
dueDate: '=',
|
dueDate: '=',
|
||||||
dueDateStatus: '=',
|
|
||||||
isClosed: '=',
|
isClosed: '=',
|
||||||
item: '=',
|
item: '=',
|
||||||
format: '@'
|
format: '@',
|
||||||
|
notAutoSave: '='
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.directive('tgDueDate', dueDateDirective)
|
module.directive('tgDueDate', ['$translate', 'tgDatePickerConfigService', dueDateDirective])
|
|
@ -6,17 +6,25 @@
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
transition: background .2s linear;
|
transition: background .2s linear;
|
||||||
transition-delay: .1s;
|
transition-delay: .1s;
|
||||||
&.closed {
|
&.closed,
|
||||||
|
&.text-button.closed:hover {
|
||||||
background: $gray-lighter;
|
background: $gray-lighter;
|
||||||
|
border-color: $gray-lighter;
|
||||||
}
|
}
|
||||||
&.due-set {
|
&.due-set,
|
||||||
|
&.text-button.due-set:hover {
|
||||||
background: $yellow-green;
|
background: $yellow-green;
|
||||||
|
border-color: $yellow-green;
|
||||||
}
|
}
|
||||||
&.due-soon {
|
&.due-soon,
|
||||||
|
&.text-button.due-soon:hover {
|
||||||
background: $my-sin;
|
background: $my-sin;
|
||||||
|
border-color: $my-sin;
|
||||||
}
|
}
|
||||||
&.past-due {
|
&.past-due,
|
||||||
|
&.text-button.past-due:hover {
|
||||||
background: $red-light;
|
background: $red-light;
|
||||||
|
border-color: $red-light;
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $gray;
|
background: $gray;
|
||||||
|
@ -24,6 +32,17 @@
|
||||||
&.editable {
|
&.editable {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
&.text-button {
|
||||||
|
color: $white;
|
||||||
|
margin: 0;
|
||||||
|
padding: .5rem;
|
||||||
|
&.not-set:hover {
|
||||||
|
color: $white;
|
||||||
|
}
|
||||||
|
&.not-set {
|
||||||
|
color: $gray;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.due-date-icon {
|
.due-date-icon {
|
||||||
|
@ -66,3 +85,39 @@
|
||||||
width: .9rem;
|
width: .9rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.due-date-button-wrapper {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-picker-container {
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-picker-popover {
|
||||||
|
background: $white;
|
||||||
|
border: 1px solid $gray;
|
||||||
|
display: none;
|
||||||
|
left: 0;
|
||||||
|
overflow: visible;
|
||||||
|
position: absolute;
|
||||||
|
top: 56px;
|
||||||
|
width: auto;
|
||||||
|
.pika-single {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-picker-popover-footer {
|
||||||
|
padding: .2rem .5rem;
|
||||||
|
text-align: right;
|
||||||
|
svg {
|
||||||
|
fill: $gray;
|
||||||
|
height: 1rem;
|
||||||
|
width: 1rem;
|
||||||
|
}
|
||||||
|
a:hover svg {
|
||||||
|
fill: $red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -123,8 +123,8 @@ div.wrapper(tg-backlog, ng-controller="BacklogController as ctrl",
|
||||||
sidebar.menu-secondary.sidebar
|
sidebar.menu-secondary.sidebar
|
||||||
include ../includes/modules/sprints
|
include ../includes/modules/sprints
|
||||||
|
|
||||||
div.lightbox.lightbox-generic-form.lb-create-edit-userstory(tg-lb-create-edit-userstory)
|
div.lightbox.lightbox-generic-form.lightbox-create-edit(tg-lb-create-edit)
|
||||||
include ../includes/modules/lightbox-us-create-edit
|
include ../includes/modules/lightbox-create-edit/lb-create-edit-us
|
||||||
|
|
||||||
div.lightbox.lightbox-generic-bulk(tg-lb-create-bulk-userstories)
|
div.lightbox.lightbox-generic-bulk(tg-lb-create-bulk-userstories)
|
||||||
include ../includes/modules/lightbox-us-bulk
|
include ../includes/modules/lightbox-us-bulk
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
.user-avatar(ng-class!="{ 'is-iocaine': isIocaine }")
|
||||||
|
img(
|
||||||
|
style="background-color: {{ bg }}"
|
||||||
|
src="{{ avatar.url }}"
|
||||||
|
alt="{{ fullName }}"
|
||||||
|
)
|
||||||
|
.iocaine-symbol(
|
||||||
|
ng-if="isIocaine"
|
||||||
|
title="{{ 'TASK.TITLE_ACTION_IOCAINE' | translate }}"
|
||||||
|
)
|
||||||
|
tg-svg(svg-icon="icon-iocaine")
|
||||||
|
|
||||||
|
|
||||||
|
.assigned-to
|
||||||
|
.assigned-to-options
|
||||||
|
span.assigned-name(
|
||||||
|
ng-if="!isEditable && fullNameVisible"
|
||||||
|
) {{ fullName }}
|
||||||
|
|
||||||
|
span.users-dropdown.user-assigned(
|
||||||
|
title="{{ 'COMMON.ASSIGNED_TO.TITLE_ACTION_EDIT_ASSIGNMENT'|translate }}"
|
||||||
|
ng-class="{ 'editable': isEditable }"
|
||||||
|
ng-if="isEditable"
|
||||||
|
)
|
||||||
|
span.assigned-name
|
||||||
|
span(ng-if="fullNameVisible") {{ fullName }}
|
||||||
|
|
||||||
|
div.pop-users.popover
|
||||||
|
input.users-search(
|
||||||
|
type="text"
|
||||||
|
data-maxlength="500"
|
||||||
|
placeholder="{{'LIGHTBOX.ASSIGNED_TO.SEARCH' | translate}}"
|
||||||
|
ng-model="usersSearch"
|
||||||
|
)
|
||||||
|
a.user-list-single(
|
||||||
|
href=""
|
||||||
|
data-user-id="{{ user.id }}"
|
||||||
|
title="{{ user.full_name_display }}"
|
||||||
|
ng-repeat="user in users"
|
||||||
|
)
|
||||||
|
img.user-list-avatar(
|
||||||
|
style="background: {{user.avatar.bg }}"
|
||||||
|
src="{{ user.avatar.url }}"
|
||||||
|
)
|
||||||
|
span.user-list-name(
|
||||||
|
href=""
|
||||||
|
title="{{ user.full_name_display }}"
|
||||||
|
) {{ user.full_name_display }}
|
||||||
|
.show-more(ng-if="showMore")
|
||||||
|
span(translate="COMMON.ASSIGNED_TO.TOO_MANY")
|
||||||
|
|
||||||
|
span(translate="COMMON.OR", ng-if="isUnassigned")
|
||||||
|
div(ng-if="isUnassigned")
|
||||||
|
a.assign-to-me(
|
||||||
|
href="#"
|
||||||
|
title="{{'COMMON.ASSIGNED_TO.SELF' | translate}}"
|
||||||
|
)
|
||||||
|
span {{ "COMMON.ASSIGNED_TO.SELF" | translate }}
|
||||||
|
|
||||||
|
tg-svg.remove-user(
|
||||||
|
ng-if="isEditable && !isUnassigned"
|
||||||
|
svg-icon="icon-close",
|
||||||
|
title="{{'COMMON.ASSIGNED_TO.DELETE_ASSIGNMENT' | translate}}"
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
div(ng-if="isAssigned")
|
||||||
|
.user-list(ng-if="assignedUsers.length > 1")
|
||||||
|
.user-list-item(ng-repeat="assignedUser in assignedUsers")
|
||||||
|
img(
|
||||||
|
tg-avatar="assignedUser"
|
||||||
|
title="{{assignedUser.full_name_display}}"
|
||||||
|
alt="{{assignedUser.full_name_display}}"
|
||||||
|
)
|
||||||
|
.user-list-item.counter(ng-if="hiddenUsers")
|
||||||
|
span +{{ hiddenUsers }}
|
||||||
|
|
||||||
|
.ticket-assigned-to.single-assign(ng-if="assignedUsers.length == 1")
|
||||||
|
.user-avatar
|
||||||
|
img(
|
||||||
|
tg-avatar="assignedUsers[0]"
|
||||||
|
title="{{assignedUsers[0].full_name_display}}"
|
||||||
|
alt="{{assignedUsers[0].full_name_display}}"
|
||||||
|
)
|
||||||
|
.assigned-to
|
||||||
|
.assigned-users-options
|
||||||
|
span.user-assigned {{ assignedUsers[0].full_name_display }}
|
||||||
|
tg-svg.remove-user(
|
||||||
|
svg-icon="icon-close",
|
||||||
|
title="{{'COMMON.ASSIGNED_TO.DELETE_ASSIGNMENT' | translate}}"
|
||||||
|
data-user-id="{{ assignedUsers[0].id }}"
|
||||||
|
)
|
||||||
|
|
||||||
|
div.add-assigned
|
||||||
|
a.users-dropdown.tg-add-assigned(
|
||||||
|
href=""
|
||||||
|
ng-click="openAssignedUsers()"
|
||||||
|
)
|
||||||
|
tg-svg.add-assigned(
|
||||||
|
data-assigned-user-id="{{assignedUser.id}}",
|
||||||
|
svg-icon="icon-add",
|
||||||
|
title="{{'COMMON.ASSIGNED_USERS.ADD_ASSIGNED' | translate}}"
|
||||||
|
)
|
||||||
|
span {{ "COMMON.ASSIGNED_USERS.ADD_ASSIGNED" | translate }}
|
||||||
|
|
||||||
|
|
||||||
|
.ticket-assigned-to(ng-if="!isAssigned")
|
||||||
|
.user-avatar
|
||||||
|
img(
|
||||||
|
tg-avatar=""
|
||||||
|
alt="{{ 'COMMON.ASSIGNED_TO.ASSIGN' | translate }}"
|
||||||
|
)
|
||||||
|
.assigned-to
|
||||||
|
.assigned-users-options
|
||||||
|
a.users-dropdown.user-assigned(
|
||||||
|
href=""
|
||||||
|
title="{{ 'COMMON.ASSIGNED_TO.TITLE_ACTION_EDIT_ASSIGNMENT'|translate }}"
|
||||||
|
class="user-assigned"
|
||||||
|
)
|
||||||
|
span.assigned-name {{ "COMMON.ASSIGNED_TO.ASSIGN" | translate }}
|
||||||
|
|
|
||||||
|
span(translate="COMMON.OR")
|
||||||
|
|
|
||||||
|
a.assign-to-me(
|
||||||
|
href="#"
|
||||||
|
title="{{'COMMON.ASSIGNED_TO.SELF' | translate}}"
|
||||||
|
)
|
||||||
|
span {{ "COMMON.ASSIGNED_TO.SELF" | translate }}
|
||||||
|
|
||||||
|
div.pop-users.popover(ng-class="{'multiple': assignedUsers.length > 0}")
|
||||||
|
input.users-search(
|
||||||
|
type="text"
|
||||||
|
data-maxlength="500"
|
||||||
|
placeholder="{{'LIGHTBOX.ASSIGNED_TO.SEARCH' | translate}}"
|
||||||
|
ng-model="usersSearch"
|
||||||
|
)
|
||||||
|
a.user-list-single.selected(
|
||||||
|
href=""
|
||||||
|
data-user-id="{{ user.id }}"
|
||||||
|
title="{{ user.full_name_display }}"
|
||||||
|
ng-repeat="user in selected"
|
||||||
|
ng-class="{'selected': selected.indexOf(user) == -1 }"
|
||||||
|
)
|
||||||
|
img.user-list-avatar(
|
||||||
|
style="background: {{user.avatar.bg }}"
|
||||||
|
src="{{ user.avatar.url }}"
|
||||||
|
)
|
||||||
|
span.user-list-name(
|
||||||
|
href=""
|
||||||
|
title="{{ user.full_name_display }}"
|
||||||
|
) {{ user.full_name_display }}
|
||||||
|
tg-svg.remove(
|
||||||
|
href=""
|
||||||
|
data-user-id="{{ user.id }}"
|
||||||
|
ng-if="selected.indexOf(user) > -1"
|
||||||
|
svg-icon="icon-close",
|
||||||
|
title="{{'COMMON.ASSIGNED_TO.DELETE_ASSIGNMENT' | translate}}"
|
||||||
|
)
|
||||||
|
|
||||||
|
a.user-list-single(
|
||||||
|
href=""
|
||||||
|
data-user-id="{{ user.id }}"
|
||||||
|
title="{{ user.full_name_display }}"
|
||||||
|
ng-repeat="user in users"
|
||||||
|
)
|
||||||
|
img.user-list-avatar(
|
||||||
|
style="background: {{user.avatar.bg }}"
|
||||||
|
src="{{ user.avatar.url }}"
|
||||||
|
)
|
||||||
|
span.user-list-name(
|
||||||
|
href=""
|
||||||
|
title="{{ user.full_name_display }}"
|
||||||
|
) {{ user.full_name_display }}
|
||||||
|
tg-svg.remove(
|
||||||
|
href=""
|
||||||
|
data-user-id="{{ user.id }}"
|
||||||
|
ng-if="selected.indexOf(user) > -1"
|
||||||
|
svg-icon="icon-close",
|
||||||
|
title="{{'COMMON.ASSIGNED_TO.DELETE_ASSIGNMENT' | translate}}"
|
||||||
|
)
|
||||||
|
|
||||||
|
.show-more(ng-if="showMore")
|
||||||
|
span(translate="COMMON.ASSIGNED_TO.TOO_MANY")
|
|
@ -40,5 +40,6 @@ form
|
||||||
a.delete-due-date(
|
a.delete-due-date(
|
||||||
href=""
|
href=""
|
||||||
title="{{'LIGHTBOX.SET_DUE_DATE.TITLE_ACTION_DELETE_DUE_DATE' | translate}}"
|
title="{{'LIGHTBOX.SET_DUE_DATE.TITLE_ACTION_DELETE_DUE_DATE' | translate}}"
|
||||||
|
v-if="new_due_date"
|
||||||
)
|
)
|
||||||
tg-svg(svg-icon="icon-trash")
|
tg-svg(svg-icon="icon-trash")
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
span(ng-bind-html="us.subject | emojify")
|
span(ng-bind-html="us.subject | emojify")
|
||||||
tg-due-date(
|
tg-due-date(
|
||||||
due-date="us.due_date"
|
due-date="us.due_date"
|
||||||
due-date-status="us.due_date_status"
|
is-closed="us.is_closed"
|
||||||
ng-if="us.due_date"
|
ng-if="us.due_date"
|
||||||
)
|
)
|
||||||
tg-belong-to-epics(
|
tg-belong-to-epics(
|
||||||
|
|
|
@ -56,7 +56,7 @@ section.issues-table.basic-table(ng-class="{empty: !issues.length}")
|
||||||
span(ng-bind-html="issue.subject | emojify")
|
span(ng-bind-html="issue.subject | emojify")
|
||||||
tg-due-date(
|
tg-due-date(
|
||||||
due-date="issue.due_date"
|
due-date="issue.due_date"
|
||||||
due-date-status="issue.due_date_status"
|
is-closed="us.is_closed"
|
||||||
ng-if="issue.due_date"
|
ng-if="issue.due_date"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
extends lb-create-edit
|
||||||
|
|
||||||
|
block options
|
||||||
|
section.ticket-assigned-to(
|
||||||
|
tg-assigned-to-inline
|
||||||
|
ng-model="obj"
|
||||||
|
required-perm="modify_{{ objType }}"
|
||||||
|
)
|
||||||
|
div.ticket-data-container
|
||||||
|
tg-issue-type-button.ticket-status(
|
||||||
|
autosave="false"
|
||||||
|
ng-model="obj"
|
||||||
|
)
|
||||||
|
tg-issue-severity-button.ticket-status(
|
||||||
|
autosave="false"
|
||||||
|
ng-model="obj"
|
||||||
|
)
|
||||||
|
tg-issue-priority-button.ticket-status(
|
||||||
|
autosave="false"
|
||||||
|
ng-model="obj"
|
||||||
|
)
|
||||||
|
|
||||||
|
div.ticket-detail-settings
|
||||||
|
tg-due-date-popover(
|
||||||
|
due-date="obj.due_date"
|
||||||
|
is-closed="obj.is_closed"
|
||||||
|
item="obj"
|
||||||
|
not-auto-save="true"
|
||||||
|
)
|
||||||
|
div
|
||||||
|
label.button-gray.is-blocked(
|
||||||
|
title="{{ 'COMMON.BLOCK_TITLE' | translate }}"
|
||||||
|
ng-class="{ 'button-red item-unblock': obj.is_blocked, 'item-block': !obj.is_blocked }"
|
||||||
|
)
|
||||||
|
tg-svg(svg-icon="icon-lock")
|
||||||
|
|
||||||
|
tg-blocking-message-input(
|
||||||
|
watch="obj.is_blocked"
|
||||||
|
ng-model="obj.blocked_note"
|
||||||
|
)
|
|
@ -0,0 +1,40 @@
|
||||||
|
extends lb-create-edit
|
||||||
|
|
||||||
|
block options
|
||||||
|
section.ticket-assigned-to(
|
||||||
|
tg-assigned-to-inline
|
||||||
|
ng-model="obj"
|
||||||
|
required-perm="modify_{{ objType }}"
|
||||||
|
)
|
||||||
|
div.ticket-detail-settings
|
||||||
|
tg-due-date-popover(
|
||||||
|
due-date="obj.due_date"
|
||||||
|
is-closed="obj.is_closed"
|
||||||
|
item="obj"
|
||||||
|
not-auto-save="true"
|
||||||
|
)
|
||||||
|
div
|
||||||
|
fieldset.iocaine-flag(title="{{ 'TASK.TITLE_ACTION_IOCAINE' | translate }}")
|
||||||
|
label.button-gray.iocaine(
|
||||||
|
for="is-iocaine"
|
||||||
|
ng-class="{'active': obj.is_iocaine}"
|
||||||
|
)
|
||||||
|
tg-svg(svg-icon="icon-iocaine")
|
||||||
|
input(
|
||||||
|
type="checkbox"
|
||||||
|
id="is-iocaine"
|
||||||
|
name="is-iocaine"
|
||||||
|
ng-model="obj.is_iocaine"
|
||||||
|
ng-value="true"
|
||||||
|
)
|
||||||
|
div
|
||||||
|
label.button-gray.is-blocked(
|
||||||
|
title="{{ 'COMMON.BLOCK_TITLE' | translate }}"
|
||||||
|
ng-class="{ 'button-red item-unblock': obj.is_blocked, 'item-block': !obj.is_blocked }"
|
||||||
|
)
|
||||||
|
tg-svg(svg-icon="icon-lock")
|
||||||
|
|
||||||
|
tg-blocking-message-input(
|
||||||
|
watch="obj.is_blocked"
|
||||||
|
ng-model="obj.blocked_note"
|
||||||
|
)
|
|
@ -0,0 +1,44 @@
|
||||||
|
extends lb-create-edit
|
||||||
|
|
||||||
|
block options
|
||||||
|
section.ticket-assigned-to.multiple-assign(
|
||||||
|
tg-assigned-users-inline
|
||||||
|
ng-model="obj"
|
||||||
|
required-perm="modify_{{ objType }}"
|
||||||
|
)
|
||||||
|
div.ticket-estimation
|
||||||
|
tg-lb-us-estimation(ng-model="obj")
|
||||||
|
|
||||||
|
div.ticket-detail-settings
|
||||||
|
tg-due-date-popover(
|
||||||
|
due-date="obj.due_date"
|
||||||
|
is-closed="obj.is_closed"
|
||||||
|
item="obj"
|
||||||
|
not-auto-save="true"
|
||||||
|
)
|
||||||
|
div
|
||||||
|
label.button-gray.team-requirement(
|
||||||
|
for="team-requirement"
|
||||||
|
title="{{ 'COMMON.TEAM_REQUIREMENT' | translate }}"
|
||||||
|
ng-class="{ 'active': isTeamRequirement() }"
|
||||||
|
)
|
||||||
|
tg-svg(svg-icon="icon-team-requirement")
|
||||||
|
div
|
||||||
|
label.button-gray.client-requirement(
|
||||||
|
for="client-requirement"
|
||||||
|
title="{{ 'COMMON.CLIENT_REQUIREMENT' | translate }}"
|
||||||
|
ng-class="{ 'active': isClientRequirement() }"
|
||||||
|
)
|
||||||
|
tg-svg(svg-icon="icon-client-requirement")
|
||||||
|
|
||||||
|
div
|
||||||
|
label.button-gray.is-blocked(
|
||||||
|
title="{{ 'COMMON.BLOCK_TITLE' | translate }}"
|
||||||
|
ng-class="{ 'button-red item-unblock': obj.is_blocked, 'item-block': !obj.is_blocked }"
|
||||||
|
)
|
||||||
|
tg-svg(svg-icon="icon-lock")
|
||||||
|
|
||||||
|
tg-blocking-message-input(
|
||||||
|
watch="obj.is_blocked"
|
||||||
|
ng-model="obj.blocked_note"
|
||||||
|
)
|
|
@ -0,0 +1,66 @@
|
||||||
|
tg-lightbox-close
|
||||||
|
|
||||||
|
form
|
||||||
|
h2.title(translate="LIGHTBOX.CREATE_EDIT.TITLE_NEW")
|
||||||
|
div.form-wrapper
|
||||||
|
main
|
||||||
|
fieldset
|
||||||
|
input(
|
||||||
|
type="text"
|
||||||
|
name="subject"
|
||||||
|
ng-model-options="{ debounce: 200 }"
|
||||||
|
ng-model="obj.subject"
|
||||||
|
placeholder="{{'COMMON.FIELDS.SUBJECT' | translate}}"
|
||||||
|
data-required="true"
|
||||||
|
data-maxlength="500"
|
||||||
|
)
|
||||||
|
|
||||||
|
fieldset
|
||||||
|
tg-tag-line-common.tags-block(
|
||||||
|
ng-if="project && createEditOpen"
|
||||||
|
project="project"
|
||||||
|
tags="obj.tags"
|
||||||
|
permissions="add_{{objType}}"
|
||||||
|
on-add-tag="addTag(name, color)"
|
||||||
|
on-delete-tag="deleteTag(tag)"
|
||||||
|
)
|
||||||
|
|
||||||
|
fieldset
|
||||||
|
textarea.description(
|
||||||
|
rows=7
|
||||||
|
name="description"
|
||||||
|
ng-model="obj.description"
|
||||||
|
ng-model-options="{ debounce: 200 }"
|
||||||
|
ng-attr-placeholder="{{'LIGHTBOX.CREATE_EDIT.PLACEHOLDER_DESCRIPTION' | translate}}"
|
||||||
|
)
|
||||||
|
fieldset
|
||||||
|
section
|
||||||
|
tg-attachments-simple(
|
||||||
|
attachments="attachments",
|
||||||
|
on-add="addAttachment(attachment)"
|
||||||
|
on-delete="deleteAttachment(attachment)"
|
||||||
|
)
|
||||||
|
|
||||||
|
sidebar.sidebar.ticket-data
|
||||||
|
fieldset.status-button
|
||||||
|
div.status-dropdown.editable(style="background-color:{{ selectedStatus.color }}")
|
||||||
|
span.status-text {{ selectedStatus.name }}
|
||||||
|
tg-svg(svg-icon="icon-arrow-down")
|
||||||
|
|
||||||
|
ul.pop-status.popover
|
||||||
|
li(ng-repeat="s in statusList")
|
||||||
|
a.status(
|
||||||
|
href=""
|
||||||
|
title="{{ s.name }}"
|
||||||
|
data-status-id="{{ s.id }}"
|
||||||
|
) {{ s.name }}
|
||||||
|
|
||||||
|
block options
|
||||||
|
|
||||||
|
button.button-green.submit-button(
|
||||||
|
type="submit"
|
||||||
|
title="{{'COMMON.CREATE' | translate}}"
|
||||||
|
translate="COMMON.CREATE"
|
||||||
|
)
|
||||||
|
|
||||||
|
div.lightbox.lightbox-select-user(tg-lb-assignedto)
|
|
@ -1,60 +0,0 @@
|
||||||
tg-lightbox-close
|
|
||||||
|
|
||||||
form
|
|
||||||
h2.title(translate="LIGHTBOX.CREATE_ISSUE.TITLE")
|
|
||||||
fieldset
|
|
||||||
input(
|
|
||||||
type="text"
|
|
||||||
ng-model="issue.subject"
|
|
||||||
ng-attr-placeholder="{{'COMMON.FIELDS.SUBJECT' | translate}}"
|
|
||||||
ng-model-options="{ debounce: 200 }"
|
|
||||||
data-required="true"
|
|
||||||
data-maxlength="500"
|
|
||||||
)
|
|
||||||
.fieldset-row
|
|
||||||
fieldset
|
|
||||||
select.type(
|
|
||||||
ng-model="issue.type"
|
|
||||||
ng-options="t.id as t.name for t in issueTypes"
|
|
||||||
)
|
|
||||||
fieldset
|
|
||||||
select.priority(
|
|
||||||
ng-model="issue.priority"
|
|
||||||
ng-options="p.id as p.name for p in priorityList"
|
|
||||||
)
|
|
||||||
fieldset
|
|
||||||
select.severity(
|
|
||||||
ng-model="issue.severity"
|
|
||||||
ng-options="s.id as s.name for s in severityList"
|
|
||||||
)
|
|
||||||
|
|
||||||
fieldset
|
|
||||||
tg-tag-line-common.tags-block(
|
|
||||||
ng-if="project && createIssueOpen"
|
|
||||||
project="project"
|
|
||||||
tags="issue.tags"
|
|
||||||
permissions="add_issue"
|
|
||||||
on-add-tag="addTag(name, color)"
|
|
||||||
on-delete-tag="deleteTag(tag)"
|
|
||||||
)
|
|
||||||
|
|
||||||
fieldset
|
|
||||||
section
|
|
||||||
tg-attachments-simple(
|
|
||||||
attachments="attachments",
|
|
||||||
on-add="addAttachment(attachment)"
|
|
||||||
on-delete="deleteAttachment(attachment)"
|
|
||||||
)
|
|
||||||
|
|
||||||
fieldset
|
|
||||||
textarea.description(
|
|
||||||
ng-attr-placeholder="{{'COMMON.FIELDS.DESCRIPTION' | translate}}"
|
|
||||||
ng-model="issue.description"
|
|
||||||
)
|
|
||||||
|
|
||||||
// include lightbox-attachments
|
|
||||||
button.button-green.submit-button(
|
|
||||||
type="submit"
|
|
||||||
title="{{'COMMON.CREATE' | translate}}"
|
|
||||||
translate="COMMON.CREATE"
|
|
||||||
)
|
|
|
@ -1,92 +0,0 @@
|
||||||
tg-lightbox-close
|
|
||||||
form
|
|
||||||
h2.title(translate="LIGHTBOX.CREATE_EDIT_TASK.TITLE")
|
|
||||||
fieldset
|
|
||||||
input(
|
|
||||||
type="text"
|
|
||||||
ng-model="task.subject"
|
|
||||||
ng-attr-placeholder="{{'LIGHTBOX.CREATE_EDIT_TASK.PLACEHOLDER_SUBJECT' | translate}}"
|
|
||||||
ng-model-options="{ debounce: 200 }"
|
|
||||||
data-required="true"
|
|
||||||
data-maxlength="500"
|
|
||||||
)
|
|
||||||
|
|
||||||
fieldset
|
|
||||||
select(
|
|
||||||
ng-model="task.status"
|
|
||||||
ng-options="s.id as s.name for s in taskStatusList"
|
|
||||||
placeholder="{{'LIGHTBOX.CREATE_EDIT_TASK.PLACEHOLDER_STATUS' | translate}}"
|
|
||||||
)
|
|
||||||
|
|
||||||
fieldset
|
|
||||||
select(
|
|
||||||
ng-model="task.assigned_to"
|
|
||||||
ng-options="s.id as s.full_name_display for s in users"
|
|
||||||
placeholder="{{'Assigned to'}}"
|
|
||||||
)
|
|
||||||
option(
|
|
||||||
value=""
|
|
||||||
translate="LIGHTBOX.CREATE_EDIT_TASK.OPTION_UNASSIGNED"
|
|
||||||
)
|
|
||||||
|
|
||||||
fieldset
|
|
||||||
tg-tag-line-common.tags-block(
|
|
||||||
ng-if="project && createEditTaskOpen"
|
|
||||||
project="project"
|
|
||||||
tags="task.tags"
|
|
||||||
permissions="add_task"
|
|
||||||
on-add-tag="addTag(name, color)"
|
|
||||||
on-delete-tag="deleteTag(tag)"
|
|
||||||
)
|
|
||||||
|
|
||||||
fieldset
|
|
||||||
section
|
|
||||||
tg-attachments-simple(
|
|
||||||
attachments="attachments",
|
|
||||||
on-add="addAttachment(attachment)"
|
|
||||||
on-delete="deleteAttachment(attachment)"
|
|
||||||
)
|
|
||||||
|
|
||||||
fieldset
|
|
||||||
textarea.description(
|
|
||||||
ng-attr-placeholder="{{'LIGHTBOX.CREATE_EDIT_TASK.PLACEHOLDER_SHORT_DESCRIPTION' | translate}}"
|
|
||||||
ng-model="task.description"
|
|
||||||
ng-model-options="{ debounce: 200 }"
|
|
||||||
)
|
|
||||||
|
|
||||||
div.settings
|
|
||||||
fieldset.iocaine-flag(title="{{'COMMON.IOCAINE_TEXT' | translate}}")
|
|
||||||
input(
|
|
||||||
type="checkbox"
|
|
||||||
ng-model="task.is_iocaine"
|
|
||||||
name="iocaine-task"
|
|
||||||
id="iocaine-task"
|
|
||||||
ng-value="true"
|
|
||||||
)
|
|
||||||
label.iocaine.trans-button(for="iocaine-task")
|
|
||||||
tg-svg(svg-icon="icon-iocaine")
|
|
||||||
span Iocaine
|
|
||||||
|
|
||||||
fieldset.blocking-flag
|
|
||||||
input(
|
|
||||||
type="checkbox"
|
|
||||||
ng-model="task.is_blocked"
|
|
||||||
name="blocked-task"
|
|
||||||
id="blocked-task"
|
|
||||||
ng-value="true"
|
|
||||||
)
|
|
||||||
label.blocked.trans-button(
|
|
||||||
for="blocked-task"
|
|
||||||
translate="COMMON.BLOCKED"
|
|
||||||
)
|
|
||||||
|
|
||||||
tg-blocking-message-input(
|
|
||||||
watch="task.is_blocked"
|
|
||||||
ng-model="task.blocked_note"
|
|
||||||
)
|
|
||||||
|
|
||||||
button.button-green.submit-button(
|
|
||||||
type="submit"
|
|
||||||
title="{{'COMMON.CREATE' | translate}}"
|
|
||||||
translate="COMMON.CREATE"
|
|
||||||
)
|
|
|
@ -1,100 +0,0 @@
|
||||||
tg-lightbox-close
|
|
||||||
|
|
||||||
form
|
|
||||||
h2.title(translate="LIGHTBOX.CREATE_EDIT_US.TITLE")
|
|
||||||
fieldset
|
|
||||||
input(
|
|
||||||
type="text"
|
|
||||||
name="subject"
|
|
||||||
ng-model-options="{ debounce: 200 }"
|
|
||||||
ng-model="us.subject"
|
|
||||||
placeholder="{{'COMMON.FIELDS.SUBJECT' | translate}}"
|
|
||||||
data-required="true"
|
|
||||||
data-maxlength="500"
|
|
||||||
)
|
|
||||||
|
|
||||||
fieldset.ticket-estimation
|
|
||||||
tg-lb-us-estimation(ng-model="us")
|
|
||||||
|
|
||||||
fieldset
|
|
||||||
select(
|
|
||||||
name="status"
|
|
||||||
ng-model="us.status"
|
|
||||||
ng-options="s.id as s.name for s in usStatusList"
|
|
||||||
)
|
|
||||||
|
|
||||||
fieldset
|
|
||||||
tg-tag-line-common.tags-block(
|
|
||||||
ng-if="project && createEditUsOpen"
|
|
||||||
project="project"
|
|
||||||
tags="us.tags"
|
|
||||||
permissions="add_us"
|
|
||||||
on-add-tag="addTag(name, color)"
|
|
||||||
on-delete-tag="deleteTag(tag)"
|
|
||||||
)
|
|
||||||
|
|
||||||
fieldset
|
|
||||||
textarea.description(
|
|
||||||
name="description"
|
|
||||||
ng-model="us.description"
|
|
||||||
ng-model-options="{ debounce: 200 }"
|
|
||||||
ng-attr-placeholder="{{'LIGHTBOX.CREATE_EDIT_US.PLACEHOLDER_DESCRIPTION' | translate}}"
|
|
||||||
)
|
|
||||||
fieldset
|
|
||||||
section
|
|
||||||
tg-attachments-simple(
|
|
||||||
attachments="attachments",
|
|
||||||
on-add="addAttachment(attachment)"
|
|
||||||
on-delete="deleteAttachment(attachment)"
|
|
||||||
)
|
|
||||||
|
|
||||||
div.settings
|
|
||||||
fieldset.team-requirement
|
|
||||||
input(
|
|
||||||
type="checkbox"
|
|
||||||
name="team_requirement"
|
|
||||||
ng-model="us.team_requirement"
|
|
||||||
id="team-requirement"
|
|
||||||
ng-value="true"
|
|
||||||
)
|
|
||||||
label.requirement.trans-button(
|
|
||||||
for="team-requirement"
|
|
||||||
translate="US.FIELDS.TEAM_REQUIREMENT"
|
|
||||||
)
|
|
||||||
|
|
||||||
fieldset.client-requirement
|
|
||||||
input(
|
|
||||||
type="checkbox"
|
|
||||||
name="client_requirement"
|
|
||||||
ng-model="us.client_requirement",
|
|
||||||
id="client-requirement"
|
|
||||||
ng-value="true"
|
|
||||||
)
|
|
||||||
label.requirement.trans-button(
|
|
||||||
for="client-requirement"
|
|
||||||
translate="US.FIELDS.CLIENT_REQUIREMENT"
|
|
||||||
)
|
|
||||||
|
|
||||||
fieldset.blocking-flag
|
|
||||||
input(
|
|
||||||
type="checkbox"
|
|
||||||
name="is_blocked"
|
|
||||||
ng-model="us.is_blocked"
|
|
||||||
id="blocked-us"
|
|
||||||
ng-value="true"
|
|
||||||
)
|
|
||||||
label.blocked.trans-button(
|
|
||||||
for="blocked-us"
|
|
||||||
translate="COMMON.BLOCKED"
|
|
||||||
)
|
|
||||||
|
|
||||||
tg-blocking-message-input(
|
|
||||||
watch="us.is_blocked"
|
|
||||||
ng-model="us.blocked_note"
|
|
||||||
)
|
|
||||||
|
|
||||||
button.button-green.submit-button(
|
|
||||||
type="submit"
|
|
||||||
title="{{'COMMON.CREATE' | translate}}"
|
|
||||||
translate="COMMON.CREATE"
|
|
||||||
)
|
|
|
@ -114,12 +114,11 @@ div.wrapper(
|
||||||
|
|
||||||
section.ticket-detail-settings
|
section.ticket-detail-settings
|
||||||
tg-due-date(
|
tg-due-date(
|
||||||
tg-check-permission="modify_issue"
|
|
||||||
due-date="issue.due_date"
|
due-date="issue.due_date"
|
||||||
due-date-status="issue.due_date_status"
|
format="button"
|
||||||
is-closed="issue.is_closed"
|
is-closed="issue.is_closed"
|
||||||
item="issue"
|
item="issue"
|
||||||
format="button"
|
tg-check-permission="modify_issue"
|
||||||
)
|
)
|
||||||
tg-promote-issue-to-us-button(
|
tg-promote-issue-to-us-button(
|
||||||
tg-check-permission="add_us",
|
tg-check-permission="add_us",
|
||||||
|
|
|
@ -33,8 +33,8 @@ div.wrapper.issues.lightbox-generic-form(
|
||||||
|
|
||||||
div.lightbox.lightbox-select-user(tg-lb-assignedto)
|
div.lightbox.lightbox-select-user(tg-lb-assignedto)
|
||||||
|
|
||||||
div.lightbox.lightbox-create-issue(tg-lb-create-issue)
|
div.lightbox.lightbox-generic-form.lightbox-create-edit(tg-lb-create-edit)
|
||||||
include ../includes/modules/lightbox-create-issue
|
include ../includes/modules/lightbox-create-edit/lb-create-edit-issue
|
||||||
|
|
||||||
div.lightbox.lightbox-generic-bulk(tg-lb-create-bulk-issues)
|
div.lightbox.lightbox-generic-bulk(tg-lb-create-bulk-issues)
|
||||||
include ../includes/modules/lightbox-issue-bulk
|
include ../includes/modules/lightbox-issue-bulk
|
||||||
|
|
|
@ -40,8 +40,8 @@ div.wrapper(
|
||||||
|
|
||||||
include ../includes/modules/kanban-table
|
include ../includes/modules/kanban-table
|
||||||
|
|
||||||
div.lightbox.lightbox-generic-form.lb-create-edit-userstory(tg-lb-create-edit-userstory)
|
div.lightbox.lightbox-generic-form.lightbox-create-edit(tg-lb-create-edit)
|
||||||
include ../includes/modules/lightbox-us-create-edit
|
include ../includes/modules/lightbox-create-edit/lb-create-edit-us
|
||||||
|
|
||||||
div.lightbox.lightbox-generic-bulk(tg-lb-create-bulk-userstories)
|
div.lightbox.lightbox-generic-bulk(tg-lb-create-bulk-userstories)
|
||||||
include ../includes/modules/lightbox-us-bulk
|
include ../includes/modules/lightbox-us-bulk
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
span(ng-non-bindable) <%= emojify(task.subject) %>
|
span(ng-non-bindable) <%= emojify(task.subject) %>
|
||||||
tg-due-date(
|
tg-due-date(
|
||||||
due-date="task.due_date"
|
due-date="task.due_date"
|
||||||
due-date-status="task.due_date_status"
|
|
||||||
ng-if="task.due_date"
|
ng-if="task.due_date"
|
||||||
)
|
)
|
||||||
.task-settings
|
.task-settings
|
||||||
|
|
|
@ -103,12 +103,11 @@ div.wrapper(
|
||||||
|
|
||||||
section.ticket-detail-settings
|
section.ticket-detail-settings
|
||||||
tg-due-date(
|
tg-due-date(
|
||||||
tg-check-permission="modify_task"
|
|
||||||
due-date="task.due_date"
|
due-date="task.due_date"
|
||||||
due-date-status="task.due_date_status"
|
format="button"
|
||||||
is-closed="task.is_closed"
|
is-closed="task.is_closed"
|
||||||
item="task"
|
item="task"
|
||||||
format="button"
|
tg-check-permission="modify_task"
|
||||||
)
|
)
|
||||||
tg-task-is-iocaine-button(ng-model="task")
|
tg-task-is-iocaine-button(ng-model="task")
|
||||||
tg-block-button(tg-check-permission="modify_task", ng-model="task")
|
tg-block-button(tg-check-permission="modify_task", ng-model="task")
|
||||||
|
|
|
@ -47,8 +47,8 @@ div.wrapper(
|
||||||
|
|
||||||
include ../includes/modules/taskboard-table
|
include ../includes/modules/taskboard-table
|
||||||
|
|
||||||
div.lightbox.lightbox-generic-form(tg-lb-create-edit-task)
|
div.lightbox.lightbox-generic-form.lightbox-create-edit(tg-lb-create-edit)
|
||||||
include ../includes/modules/lightbox-task-create-edit
|
include ../includes/modules/lightbox-create-edit/lb-create-edit-task
|
||||||
|
|
||||||
div.lightbox.lightbox-generic-bulk.lightbox-task-bulk(tg-lb-create-bulk-tasks)
|
div.lightbox.lightbox-generic-bulk.lightbox-task-bulk(tg-lb-create-bulk-tasks)
|
||||||
include ../includes/modules/lightbox-task-bulk
|
include ../includes/modules/lightbox-task-bulk
|
||||||
|
|
|
@ -128,12 +128,11 @@ div.wrapper(
|
||||||
|
|
||||||
section.ticket-detail-settings
|
section.ticket-detail-settings
|
||||||
tg-due-date(
|
tg-due-date(
|
||||||
tg-check-permission="modify_us"
|
|
||||||
due-date="us.due_date"
|
due-date="us.due_date"
|
||||||
due-date-status="us.due_date_status"
|
format="button"
|
||||||
is-closed="us.is_closed"
|
is-closed="us.is_closed"
|
||||||
item="us"
|
item="us"
|
||||||
format="button"
|
tg-check-permission="modify_us"
|
||||||
)
|
)
|
||||||
tg-us-team-requirement-button(ng-model="us")
|
tg-us-team-requirement-button(ng-model="us")
|
||||||
tg-us-client-requirement-button(ng-model="us")
|
tg-us-client-requirement-button(ng-model="us")
|
||||||
|
|
|
@ -600,3 +600,229 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.lightbox-create-edit {
|
||||||
|
z-index: 9998;
|
||||||
|
$control-height: 30px;
|
||||||
|
$spacing: 15px;
|
||||||
|
$width: 700px;
|
||||||
|
$pop-width: 203px;
|
||||||
|
$sidebar-width: 220px;
|
||||||
|
form {
|
||||||
|
flex-basis: $width;
|
||||||
|
max-width: $width;
|
||||||
|
width: $width;
|
||||||
|
}
|
||||||
|
.form-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-basis: $width;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-grow: 0;
|
||||||
|
margin-bottom: $spacing*2;
|
||||||
|
main {
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-right: $spacing;
|
||||||
|
}
|
||||||
|
.sidebar {
|
||||||
|
border-left: 2px solid $whitish;
|
||||||
|
padding-left: $spacing;
|
||||||
|
width: $sidebar-width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.status-button {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.status-dropdown {
|
||||||
|
align-content: center;
|
||||||
|
color: $white;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-basis: 100%;
|
||||||
|
height: $control-height;
|
||||||
|
padding: .25rem .5rem;
|
||||||
|
.status-text {
|
||||||
|
flex-grow: 1;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
fill: $white;
|
||||||
|
height: .9rem;
|
||||||
|
width: .9rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover {
|
||||||
|
a {
|
||||||
|
color: $white;
|
||||||
|
display: block;
|
||||||
|
padding: .5rem 1rem;
|
||||||
|
text-align: left;
|
||||||
|
&:hover,
|
||||||
|
&.active {
|
||||||
|
color: $primary-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-assigned-to {
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
&.single-assign {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
&.multiple-assign {
|
||||||
|
align-items: start;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.assigned-to-options {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.remove-user {
|
||||||
|
top: 1.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-list {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
$item-size: 44.75px;
|
||||||
|
.user-list-item {
|
||||||
|
margin-right: .5rem;
|
||||||
|
width: $item-size;
|
||||||
|
img {
|
||||||
|
height: $item-size;
|
||||||
|
width: $item-size;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
&.counter {
|
||||||
|
background: $gray-lighter;
|
||||||
|
color: $gray-light;
|
||||||
|
font-weight: 400;
|
||||||
|
height: $item-size;
|
||||||
|
line-height: $item-size;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tg-add-assigned {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
margin: .25rem 0 .75rem;
|
||||||
|
.add-assigned {
|
||||||
|
fill: $gray;
|
||||||
|
opacity: 1;
|
||||||
|
right: .5rem;
|
||||||
|
top: 2rem;
|
||||||
|
&:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
fill: $red;
|
||||||
|
transition: fill .2s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
@include font-size(small);
|
||||||
|
@include font-type(light);
|
||||||
|
color: $gray;
|
||||||
|
margin: .2rem .5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.users-dropdown {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pop-status {
|
||||||
|
@include popover($pop-width, $control-height - 2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pop-users {
|
||||||
|
@include popover($pop-width, 60px, 0, '', '', 16px, -7px, ($pop-width / 3));
|
||||||
|
&.multiple {
|
||||||
|
top: 84px;
|
||||||
|
&:after {
|
||||||
|
left: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ul {
|
||||||
|
margin-bottom: .5rem;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
border-bottom: 1px solid $gray-light;
|
||||||
|
&:last-child {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.user-list-single {
|
||||||
|
align-content: center;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-grow: 0;
|
||||||
|
padding: .5rem 0;
|
||||||
|
&.selected {
|
||||||
|
color: $primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.user-list-avatar {
|
||||||
|
height: 32px;
|
||||||
|
margin-right: .5rem;
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
.user-list-name {
|
||||||
|
@include font-type(text);
|
||||||
|
flex-grow: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove svg {
|
||||||
|
fill: $whitish;
|
||||||
|
height: .8rem;
|
||||||
|
width: .8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-more {
|
||||||
|
border-top: 1px solid $gray-light;
|
||||||
|
padding-top: .5rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-data-container {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 0 .1rem;
|
||||||
|
.ticket-status .priority-data {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-estimation .points-per-role {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-detail-settings {
|
||||||
|
height: 52px;
|
||||||
|
justify-content: left;
|
||||||
|
margin: 1rem 0 0;
|
||||||
|
label {
|
||||||
|
border: 0;
|
||||||
|
padding: 12px 13px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
.item-block,
|
||||||
|
.item-unblock {
|
||||||
|
display: block;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.blocked-note {
|
||||||
|
margin-top: .5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue