commit
4306ad9b08
|
@ -26,276 +26,6 @@ typeIsArray = @.taiga.typeIsArray
|
||||||
|
|
||||||
module = angular.module("taigaCommon", [])
|
module = angular.module("taigaCommon", [])
|
||||||
|
|
||||||
|
|
||||||
#############################################################################
|
|
||||||
## Change (comment and history mode) directive
|
|
||||||
#############################################################################
|
|
||||||
|
|
||||||
ChangesDirective = ->
|
|
||||||
containerTemplate = _.template("""
|
|
||||||
<div>
|
|
||||||
<% if (showMoreEnabled){ %>
|
|
||||||
<a href="" title="Show more" class="show-more show-more-comments">
|
|
||||||
+ Show previous comments (<%- howManyMore %> more)
|
|
||||||
</a>
|
|
||||||
<% } %>
|
|
||||||
</div>
|
|
||||||
""") # TODO: i18n
|
|
||||||
commentBaseTemplate = _.template("""
|
|
||||||
<div class="entry comment-single <% if(hidden){ %>hidden<% }%>">
|
|
||||||
<div class="comment-user activity-comment">
|
|
||||||
<a class="avatar" href="" title="<%- userFullName %>">
|
|
||||||
<img src="<%- avatar %>" alt="<%- userFullName %>">
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="comment-content">
|
|
||||||
<a class="username" href="" title="<%- userFullName %>">
|
|
||||||
<%- userFullName %>
|
|
||||||
</a>
|
|
||||||
<% if(hasChanges){ %>
|
|
||||||
<div class="us-activity">
|
|
||||||
<a class="activity-title" href="" title="Show activity">
|
|
||||||
<span>
|
|
||||||
<%- changesText %>
|
|
||||||
</span>
|
|
||||||
<span class="icon icon-arrow-up">
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<div class="comment wysiwyg">
|
|
||||||
<%= comment %>
|
|
||||||
</div>
|
|
||||||
<div class="date">
|
|
||||||
<%- creationDate %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
""")
|
|
||||||
changeBaseTemplate = _.template("""
|
|
||||||
<div class="entry activity-single <% if(hidden){ %>hidden<% }%>">
|
|
||||||
<div class="activity-user">
|
|
||||||
<a class="avatar" href="" title="<%- userFullName %>">
|
|
||||||
<img src="<%- avatar %>" alt="<%- userFullName %>">
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="activity-content">
|
|
||||||
<div class="activity-username">
|
|
||||||
<a class="username" href="" title="<%- userFullName %>">
|
|
||||||
<%- userFullName %>
|
|
||||||
</a>
|
|
||||||
<span class="date">
|
|
||||||
<%- creationDate %>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="comment wysiwyg">
|
|
||||||
<%= comment %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
""")
|
|
||||||
standardChangeFromToTemplate = _.template("""
|
|
||||||
<div class="activity-inner">
|
|
||||||
<div class="activity-changed">
|
|
||||||
<span><%- name %></span>
|
|
||||||
</div>
|
|
||||||
<div class="activity-fromto">
|
|
||||||
<p>
|
|
||||||
<strong> from </strong> <br />
|
|
||||||
<span><%= from %></span>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong> to </strong> <br />
|
|
||||||
<span><%= to %></span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
""") # TODO: i18n
|
|
||||||
descriptionChangeTemplate = _.template("""
|
|
||||||
<div class="activity-inner">
|
|
||||||
<div class="activity-changed">
|
|
||||||
<span><%- name %></span>
|
|
||||||
</div>
|
|
||||||
<div class="activity-fromto">
|
|
||||||
<p>
|
|
||||||
<span><%= diff %></span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
""")
|
|
||||||
pointsChangeTemplate = _.template("""
|
|
||||||
<% _.each(points, function(point, name) { %>
|
|
||||||
<div class="activity-inner">
|
|
||||||
<div class="activity-changed">
|
|
||||||
<span><%- name %> points</span>
|
|
||||||
</div>
|
|
||||||
<div class="activity-fromto">
|
|
||||||
<p>
|
|
||||||
<strong> from </strong> <br />
|
|
||||||
<span><%= point[0] %></span>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong> to </strong> <br />
|
|
||||||
<span><%= point[1] %></span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<% }); %>
|
|
||||||
""") # TODO: i18n
|
|
||||||
attachmentTemplate = _.template("""
|
|
||||||
<div class="activity-inner">
|
|
||||||
<div class="activity-changed">
|
|
||||||
<span><%- name %></span>
|
|
||||||
</div>
|
|
||||||
<div class="activity-fromto">
|
|
||||||
<%- description %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
""")
|
|
||||||
link = ($scope, $el, $attrs, $model) ->
|
|
||||||
$.uncollapsedEntries = null
|
|
||||||
countChanges = (comment) ->
|
|
||||||
return _.keys(comment.values_diff).length
|
|
||||||
|
|
||||||
buildChangesText = (comment) ->
|
|
||||||
size = countChanges(comment)
|
|
||||||
if size == 1
|
|
||||||
return "Made #{size} change" # TODO: i18n
|
|
||||||
return "Made #{size} changes" # TODO: i18n
|
|
||||||
|
|
||||||
renderEntries = (change, parentDomNode) ->
|
|
||||||
_.each change.values_diff, (modification, name) ->
|
|
||||||
if name == "description"
|
|
||||||
parentDomNode.append(descriptionChangeTemplate({
|
|
||||||
name: name
|
|
||||||
diff: modification[1]
|
|
||||||
}))
|
|
||||||
else if name == "points"
|
|
||||||
parentDomNode.append(pointsChangeTemplate({
|
|
||||||
points: modification
|
|
||||||
}))
|
|
||||||
else if name == "attachments"
|
|
||||||
_.each modification, (attachmentChanges, attachmentType) ->
|
|
||||||
if attachmentType == "new"
|
|
||||||
_.each attachmentChanges, (attachmentChange) ->
|
|
||||||
parentDomNode.append(attachmentTemplate({
|
|
||||||
name: "New attachment" # TODO: i18n
|
|
||||||
description: attachmentChange.filename
|
|
||||||
}))
|
|
||||||
else if attachmentType == "deleted" # TODO: i18n
|
|
||||||
_.each attachmentChanges, (attachmentChange) ->
|
|
||||||
parentDomNode.append(attachmentTemplate({
|
|
||||||
name: "Deleted attachment"
|
|
||||||
description: attachmentChange.filename
|
|
||||||
}))
|
|
||||||
else
|
|
||||||
name = "Updated attachment"
|
|
||||||
_.each attachmentChanges, (attachmentChange) ->
|
|
||||||
parentDomNode.append(attachmentTemplate({
|
|
||||||
name: "Updated attachment" # TODO: i18n
|
|
||||||
description: attachmentChange[0].filename
|
|
||||||
}))
|
|
||||||
else if name == "assigned_to"
|
|
||||||
parentDomNode.append(standardChangeFromToTemplate({
|
|
||||||
name: name
|
|
||||||
from: prettyPrintModification(modification[0]) ? "Unassigned" # TODO: i18n
|
|
||||||
to: prettyPrintModification(modification[1]) ? "Unassigned" # TODO: i18n
|
|
||||||
}))
|
|
||||||
else
|
|
||||||
parentDomNode.append(standardChangeFromToTemplate({
|
|
||||||
name: name
|
|
||||||
from: prettyPrintModification(modification[0])
|
|
||||||
to: prettyPrintModification(modification[1])
|
|
||||||
}))
|
|
||||||
|
|
||||||
renderComment = (comment, containerDomNode, hidden) ->
|
|
||||||
html = commentBaseTemplate({
|
|
||||||
avatar: getUserAvatar(comment.user.pk)
|
|
||||||
userFullName: getUserFullName(comment.user.pk)
|
|
||||||
creationDate: moment(comment.created_at).format("DD MMM YYYY HH:mm")
|
|
||||||
comment: comment.comment_html
|
|
||||||
changesText: buildChangesText(comment)
|
|
||||||
hasChanges: countChanges(comment) > 0
|
|
||||||
hidden: hidden
|
|
||||||
})
|
|
||||||
entryDomNode = $(html)
|
|
||||||
activityContentDom = entryDomNode.find(".comment-content .us-activity")
|
|
||||||
renderEntries(comment, activityContentDom)
|
|
||||||
containerDomNode.append(entryDomNode)
|
|
||||||
|
|
||||||
renderChange = (change, containerDomNode, hidden) ->
|
|
||||||
html = changeBaseTemplate({
|
|
||||||
avatar: getUserAvatar(change.user.pk)
|
|
||||||
userFullName: getUserFullName(change.user.pk)
|
|
||||||
creationDate: moment(change.created_at).format("DD MMM YYYY HH:mm")
|
|
||||||
comment: change.comment_html
|
|
||||||
hidden: hidden
|
|
||||||
})
|
|
||||||
entryDomNode = $(html)
|
|
||||||
activityContentDom = entryDomNode.find(".activity-content")
|
|
||||||
renderEntries(change, activityContentDom)
|
|
||||||
containerDomNode.append(entryDomNode)
|
|
||||||
|
|
||||||
getUserFullName = (userId) ->
|
|
||||||
return $scope.usersById[userId]?.full_name_display
|
|
||||||
|
|
||||||
getUserAvatar = (userId) ->
|
|
||||||
return $scope.usersById[userId]?.photo
|
|
||||||
|
|
||||||
prettyPrintModification = (value) ->
|
|
||||||
if typeIsArray(value)
|
|
||||||
if value.length == 0
|
|
||||||
#TODO i18n
|
|
||||||
return "None" # TODO: i18n
|
|
||||||
return value.join(", ")
|
|
||||||
|
|
||||||
if value == ""
|
|
||||||
#TODO i18n
|
|
||||||
return "None" # TODO: i18n
|
|
||||||
|
|
||||||
return value
|
|
||||||
|
|
||||||
$scope.$watch $attrs.ngModel, (changes) ->
|
|
||||||
if not changes?
|
|
||||||
return
|
|
||||||
|
|
||||||
showMoreEnabled = $.uncollapsedEntries == null and changes.length > 2
|
|
||||||
howManyMore = changes.length - 2
|
|
||||||
html = containerTemplate({
|
|
||||||
showMoreEnabled: showMoreEnabled
|
|
||||||
howManyMore: howManyMore
|
|
||||||
})
|
|
||||||
|
|
||||||
containerDomNode = $(html)
|
|
||||||
_.each changes, (change, index) ->
|
|
||||||
hidden = showMoreEnabled and index < howManyMore
|
|
||||||
if $attrs.mode == "comment"
|
|
||||||
renderComment(change, containerDomNode, hidden)
|
|
||||||
else
|
|
||||||
renderChange(change, containerDomNode, hidden)
|
|
||||||
|
|
||||||
$el.html(containerDomNode)
|
|
||||||
|
|
||||||
$el.on "click", ".activity-title", (event) ->
|
|
||||||
event.preventDefault()
|
|
||||||
$el.find(".activity-inner").toggleClass("active")
|
|
||||||
|
|
||||||
$el.on "click", ".show-more", (event) ->
|
|
||||||
event.preventDefault()
|
|
||||||
target = angular.element(event.currentTarget)
|
|
||||||
target.hide()
|
|
||||||
$el.find(".entry.hidden").removeClass("hidden")
|
|
||||||
$.uncollapsedEntries = true
|
|
||||||
|
|
||||||
$scope.$on "$destroy", ->
|
|
||||||
$el.off()
|
|
||||||
|
|
||||||
return {link:link, require:"ngModel"}
|
|
||||||
|
|
||||||
module.directive("tgChanges", ChangesDirective)
|
|
||||||
|
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
## Permission directive, hide elements when necessary
|
## Permission directive, hide elements when necessary
|
||||||
#############################################################################
|
#############################################################################
|
||||||
|
|
|
@ -0,0 +1,385 @@
|
||||||
|
###
|
||||||
|
# Copyright (C) 2014 Andrey Antukh <niwi@niwi.be>
|
||||||
|
# Copyright (C) 2014 Jesús Espino Garcia <jespinog@gmail.com>
|
||||||
|
# Copyright (C) 2014 David Barragán Merino <bameda@dbarragan.com>
|
||||||
|
#
|
||||||
|
# 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: modules/common/history.coffee
|
||||||
|
###
|
||||||
|
|
||||||
|
taiga = @.taiga
|
||||||
|
trim = @.taiga.trim
|
||||||
|
bindOnce = @.taiga.bindOnce
|
||||||
|
|
||||||
|
module = angular.module("taigaCommon")
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
## History Directive (Main)
|
||||||
|
#############################################################################
|
||||||
|
|
||||||
|
class HistoryController extends taiga.Controller
|
||||||
|
@.$inject = ["$scope", "$tgRepo"]
|
||||||
|
|
||||||
|
constructor: (@scope, @repo) ->
|
||||||
|
|
||||||
|
# TODO: possible move to resources
|
||||||
|
getHistory: (type, objectId) ->
|
||||||
|
return @repo.queryOneRaw("history/#{type}", objectId)
|
||||||
|
|
||||||
|
loadHistory: (type, objectId) ->
|
||||||
|
return @.getHistory(type, objectId).then (history) =>
|
||||||
|
for historyResult in history
|
||||||
|
# If description was modified take only the description_html field
|
||||||
|
if historyResult.values_diff.description?
|
||||||
|
historyResult.values_diff.description = historyResult.values_diff.description_diff
|
||||||
|
|
||||||
|
delete historyResult.values_diff.description_html
|
||||||
|
delete historyResult.values_diff.description_diff
|
||||||
|
|
||||||
|
@scope.history = history
|
||||||
|
@scope.comments = _.filter(history, (item) -> item.comment != "")
|
||||||
|
|
||||||
|
|
||||||
|
HistoryDirective = ($log) ->
|
||||||
|
templateChangeDiff = _.template("""
|
||||||
|
<div class="change-entry">
|
||||||
|
<div class="activity-changed">
|
||||||
|
<span><%- name %></span>
|
||||||
|
</div>
|
||||||
|
<div class="activity-fromto">
|
||||||
|
<p>
|
||||||
|
<span><%= diff %></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
""")
|
||||||
|
|
||||||
|
templateChangePoints = _.template("""
|
||||||
|
<% _.each(points, function(point, name) { %>
|
||||||
|
<div class="change-entry">
|
||||||
|
<div class="activity-changed">
|
||||||
|
<span>points (<%- name.toLowerCase() %>)</span>
|
||||||
|
</div>
|
||||||
|
<div class="activity-fromto">
|
||||||
|
<p>
|
||||||
|
<strong> from </strong> <br />
|
||||||
|
<span><%= point[0] %></span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong> to </strong> <br />
|
||||||
|
<span><%= point[1] %></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% }); %>
|
||||||
|
""")
|
||||||
|
|
||||||
|
templateChangeGeneric = _.template("""
|
||||||
|
<div class="change-entry">
|
||||||
|
<div class="activity-changed">
|
||||||
|
<span><%- name %></span>
|
||||||
|
</div>
|
||||||
|
<div class="activity-fromto">
|
||||||
|
<p>
|
||||||
|
<strong> from </strong> <br />
|
||||||
|
<span><%= from %></span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong> to </strong> <br />
|
||||||
|
<span><%= to %></span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
""")
|
||||||
|
|
||||||
|
templateActivity = _.template("""
|
||||||
|
<div class="activity-single <%- mode %>">
|
||||||
|
<div class="activity-user">
|
||||||
|
<a class="avatar" href="" title="<%- userFullName %>">
|
||||||
|
<img src="<%- avatar %>" alt="<%- userFullName %>">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="activity-content">
|
||||||
|
<div class="activity-username">
|
||||||
|
<a class="username" href="" title="<%- userFullName %>">
|
||||||
|
<%- userFullName %>
|
||||||
|
</a>
|
||||||
|
<span class="date">
|
||||||
|
<%- creationDate %>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<% if (comment.length > 0) { %>
|
||||||
|
<div class="comment wysiwyg">
|
||||||
|
<%= comment %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if(changes.length > 0) { %>
|
||||||
|
<div class="changes">
|
||||||
|
<% if (mode != "activity") { %>
|
||||||
|
<a class="changes-title" href="" title="Show activity">
|
||||||
|
<span><%- changesText %></span>
|
||||||
|
<span class="icon icon-arrow-up"></span>
|
||||||
|
</a>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% _.each(changes, function(change) { %>
|
||||||
|
<%= change %>
|
||||||
|
<% }) %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
""")
|
||||||
|
|
||||||
|
templateBaseEntries = _.template("""
|
||||||
|
<% if (showMore > 0) { %>
|
||||||
|
<a href="" title="Show more" class="show-more show-more-comments">
|
||||||
|
+ Show previous entries (<%- showMore %> more)
|
||||||
|
</a>
|
||||||
|
<% } %>
|
||||||
|
<% _.each(entries, function(entry) { %>
|
||||||
|
<%= entry %>
|
||||||
|
<% }) %>
|
||||||
|
""")
|
||||||
|
|
||||||
|
templateBase = _.template("""
|
||||||
|
<section class="history">
|
||||||
|
<ul class="history-tabs">
|
||||||
|
<li>
|
||||||
|
<a href="#" class="active">
|
||||||
|
<span class="icon icon-comment"></span>
|
||||||
|
<span class="tab-title">Comments</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#">
|
||||||
|
<span class="icon icon-issues"></span>
|
||||||
|
<span class="tab-title">Activity</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<section class="history-comments">
|
||||||
|
<div class="comments-list"></div>
|
||||||
|
<div tg-check-permission tg-toggle-comment permission="modify_<%- type %>" class="add-comment">
|
||||||
|
<textarea placeholder="Write here a new commet"
|
||||||
|
ng-model="<%- ngmodel %>.comment" tg-markitup="tg-markitup">
|
||||||
|
</textarea>
|
||||||
|
<% if (mode !== "edit") { %>
|
||||||
|
<a href="" title="Comment" class="button button-green save-comment">Comment</a>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="history-activity hidden">
|
||||||
|
<div class="changes-list"></div>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
""")
|
||||||
|
|
||||||
|
link = ($scope, $el, $attrs, $ctrl) ->
|
||||||
|
# Bootstraping
|
||||||
|
type = $attrs.type
|
||||||
|
objectId = null
|
||||||
|
|
||||||
|
showAllComments = false
|
||||||
|
showAllActivity = false
|
||||||
|
|
||||||
|
bindOnce $scope, $attrs.ngModel, (model) ->
|
||||||
|
type = $attrs.type
|
||||||
|
objectId = model.id
|
||||||
|
$ctrl.loadHistory(type, objectId)
|
||||||
|
|
||||||
|
# Helpers
|
||||||
|
|
||||||
|
getUserFullName = (userId) ->
|
||||||
|
return $scope.usersById[userId]?.full_name_display
|
||||||
|
|
||||||
|
getUserAvatar = (userId) ->
|
||||||
|
return $scope.usersById[userId]?.photo
|
||||||
|
|
||||||
|
countChanges = (comment) ->
|
||||||
|
return _.keys(comment.values_diff).length
|
||||||
|
|
||||||
|
formatChange = (change) ->
|
||||||
|
if _.isArray(change)
|
||||||
|
if change.length == 0
|
||||||
|
return "nil"
|
||||||
|
return change.join(", ")
|
||||||
|
|
||||||
|
if change == ""
|
||||||
|
return "nil"
|
||||||
|
|
||||||
|
return change
|
||||||
|
|
||||||
|
# Render into string (operations without mutability)
|
||||||
|
|
||||||
|
renderAttachmentEntry = (field, value) ->
|
||||||
|
attachments = _.map value, (changes, type) ->
|
||||||
|
if type == "new"
|
||||||
|
return _.map changes, (change) ->
|
||||||
|
return templateChangeDiff({name: "New attachment", diff: change.filename})
|
||||||
|
else if type == "deleted"
|
||||||
|
return _.map changes, (change) ->
|
||||||
|
return templateChangeDiff({name: "Deleted attachment", diff: change.filename})
|
||||||
|
else
|
||||||
|
return _.map changes, (change) ->
|
||||||
|
return templateChangeDiff({name: "Updated attachment", diff: change[0].filename})
|
||||||
|
|
||||||
|
return _.flatten(attachments).join("\n")
|
||||||
|
|
||||||
|
renderChangeEntry = (field, value) ->
|
||||||
|
if field == "description"
|
||||||
|
return templateChangeDiff({name: field, diff: value[1]})
|
||||||
|
else if field == "points"
|
||||||
|
return templateChangePoints({points: value})
|
||||||
|
else if field == "attachments"
|
||||||
|
return renderAttachmentEntry(field, value)
|
||||||
|
else if field == "assigned_to"
|
||||||
|
from = formatChange(value[0] or "Unassigned")
|
||||||
|
to = formatChange(value[1] or "Unassigned")
|
||||||
|
return templateChangeGeneric({name:field, from:from, to: to})
|
||||||
|
else
|
||||||
|
from = formatChange(value[0])
|
||||||
|
to = formatChange(value[1])
|
||||||
|
return templateChangeGeneric({name:field, from:from, to: to})
|
||||||
|
|
||||||
|
renderChangeEntries = (change, join=true) ->
|
||||||
|
entries = _.map(change.values_diff, (value, field) -> renderChangeEntry(field, value))
|
||||||
|
if join
|
||||||
|
return entries.join("\n")
|
||||||
|
return entries
|
||||||
|
|
||||||
|
renderChangesHelperText = (change) ->
|
||||||
|
size = countChanges(change)
|
||||||
|
if size == 1
|
||||||
|
return "Made #{size} change" # TODO: i18n
|
||||||
|
return "Made #{size} changes" # TODO: i18n
|
||||||
|
|
||||||
|
renderComment = (comment) ->
|
||||||
|
return templateActivity({
|
||||||
|
avatar: getUserAvatar(comment.user.pk)
|
||||||
|
userFullName: getUserFullName(comment.user.pk)
|
||||||
|
creationDate: moment(comment.created_at).format("DD MMM YYYY HH:mm")
|
||||||
|
comment: comment.comment_html
|
||||||
|
changesText: renderChangesHelperText(comment)
|
||||||
|
changes: renderChangeEntries(comment, false)
|
||||||
|
mode: "comment"
|
||||||
|
})
|
||||||
|
|
||||||
|
renderChange = (change) ->
|
||||||
|
return templateActivity({
|
||||||
|
avatar: getUserAvatar(change.user.pk)
|
||||||
|
userFullName: getUserFullName(change.user.pk)
|
||||||
|
creationDate: moment(change.created_at).format("DD MMM YYYY HH:mm")
|
||||||
|
comment: change.comment_html
|
||||||
|
changes: renderChangeEntries(change, false)
|
||||||
|
changesText: ""
|
||||||
|
mode: "activity"
|
||||||
|
})
|
||||||
|
|
||||||
|
renderHistory = (entries, totalEntries) ->
|
||||||
|
if entries.length == totalEntries
|
||||||
|
showMore = 0
|
||||||
|
else
|
||||||
|
showMore = totalEntries - entries.length
|
||||||
|
|
||||||
|
return templateBaseEntries({entries: entries, showMore:showMore})
|
||||||
|
|
||||||
|
# Render into DOM (operations with dom mutability)
|
||||||
|
|
||||||
|
renderComments = ->
|
||||||
|
comments = $scope.comments or []
|
||||||
|
totalComments = comments.length
|
||||||
|
if not showAllComments
|
||||||
|
comments = _.last(comments, 4)
|
||||||
|
|
||||||
|
comments = _.map(comments, (x) -> renderComment(x))
|
||||||
|
html = renderHistory(comments, totalComments)
|
||||||
|
$el.find(".comments-list").html(html)
|
||||||
|
|
||||||
|
renderActivity = ->
|
||||||
|
changes = $scope.history or []
|
||||||
|
totalChanges = changes.length
|
||||||
|
if not showAllActivity
|
||||||
|
changes = _.last(changes, 4)
|
||||||
|
|
||||||
|
changes = _.map(changes, (x) -> renderChange(x))
|
||||||
|
html = renderHistory(changes, totalChanges)
|
||||||
|
$el.find(".changes-list").html(html)
|
||||||
|
|
||||||
|
# Watchers
|
||||||
|
|
||||||
|
$scope.$watch("comments", renderComments)
|
||||||
|
$scope.$watch("history", renderActivity)
|
||||||
|
|
||||||
|
$scope.$on "history:reload", ->
|
||||||
|
renderComments()
|
||||||
|
renderActivity()
|
||||||
|
|
||||||
|
# Events
|
||||||
|
|
||||||
|
$el.on "click", ".add-comment a.button-green", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
$el.find(".comment-list").addClass("activeanimation")
|
||||||
|
onSuccess = ->
|
||||||
|
$ctrl.loadHistory(type, objectId)
|
||||||
|
|
||||||
|
onError = ->
|
||||||
|
$confirm.notify("error")
|
||||||
|
|
||||||
|
model = $scope.$eval($attrs.ngModel)
|
||||||
|
$ctrl.repo.save(model).then(onSuccess, onError)
|
||||||
|
|
||||||
|
$el.on "click", ".show-more", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
if target.parent().is(".changes-list")
|
||||||
|
showAllActivity = not showAllActivity
|
||||||
|
renderActivity()
|
||||||
|
else
|
||||||
|
showAllComments = not showAllComments
|
||||||
|
renderComments()
|
||||||
|
|
||||||
|
$el.on "click", ".changes-title", (event) ->
|
||||||
|
event.preventDefault()
|
||||||
|
target = angular.element(event.currentTarget)
|
||||||
|
target.parent().find(".change-entry").toggleClass("active")
|
||||||
|
|
||||||
|
$el.on "focus", ".add-comment textarea", (event) ->
|
||||||
|
$(this).addClass('active')
|
||||||
|
|
||||||
|
$el.on "click", ".history-tabs li a", (event) ->
|
||||||
|
$el.find(".history-tabs li a").toggleClass("active")
|
||||||
|
$el.find(".history section").toggleClass("hidden")
|
||||||
|
|
||||||
|
$scope.$on "$destroy", ->
|
||||||
|
$el.off()
|
||||||
|
|
||||||
|
templateFn = ($el, $attrs) ->
|
||||||
|
return templateBase({ngmodel: $attrs.ngModel, type: $attrs.type, mode: $attrs.mode})
|
||||||
|
|
||||||
|
return {
|
||||||
|
controller: HistoryController
|
||||||
|
template: templateFn
|
||||||
|
restrict: "AE"
|
||||||
|
link: link
|
||||||
|
# require: ["ngModel", "tgHistory"]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.directive("tgHistory", ["$log", HistoryDirective])
|
|
@ -67,9 +67,9 @@ class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin, tai
|
||||||
@location.replace()
|
@location.replace()
|
||||||
return @q.reject(xhr)
|
return @q.reject(xhr)
|
||||||
|
|
||||||
@scope.$on("attachment:create", => @.loadHistory())
|
@scope.$on("attachment:create", => @rootscope.$broadcast("history:reload"))
|
||||||
@scope.$on("attachment:edit", => @.loadHistory())
|
@scope.$on("attachment:edit", => @rootscope.$broadcast("history:reload"))
|
||||||
@scope.$on("attachment:delete", => @.loadHistory())
|
@scope.$on("attachment:delete", => @rootscope.$broadcast("history:reload"))
|
||||||
|
|
||||||
loadProject: ->
|
loadProject: ->
|
||||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||||
|
@ -105,19 +105,6 @@ class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin, tai
|
||||||
}
|
}
|
||||||
@scope.nextUrl = @navUrls.resolve("project-issues-detail", ctx)
|
@scope.nextUrl = @navUrls.resolve("project-issues-detail", ctx)
|
||||||
|
|
||||||
loadHistory: =>
|
|
||||||
return @rs.issues.history(@scope.issueId).then (history) =>
|
|
||||||
for historyResult in history
|
|
||||||
# If description was modified take only the description_html field
|
|
||||||
if historyResult.values_diff.description?
|
|
||||||
historyResult.values_diff.description = historyResult.values_diff.description_diff
|
|
||||||
|
|
||||||
delete historyResult.values_diff.description_html
|
|
||||||
delete historyResult.values_diff.description_diff
|
|
||||||
|
|
||||||
@scope.history = history
|
|
||||||
@scope.comments = _.filter(history, (item) -> item.comment != "")
|
|
||||||
|
|
||||||
loadInitialData: ->
|
loadInitialData: ->
|
||||||
params = {
|
params = {
|
||||||
pslug: @params.pslug
|
pslug: @params.pslug
|
||||||
|
@ -132,8 +119,7 @@ class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin, tai
|
||||||
return promise.then(=> @.loadProject())
|
return promise.then(=> @.loadProject())
|
||||||
.then(=> @.loadUsersAndRoles())
|
.then(=> @.loadUsersAndRoles())
|
||||||
.then(=> @q.all([@.loadIssue(),
|
.then(=> @q.all([@.loadIssue(),
|
||||||
@.loadAttachments(@scope.issueId),
|
@.loadAttachments(@scope.issueId)]))
|
||||||
@.loadHistory()]))
|
|
||||||
|
|
||||||
block: ->
|
block: ->
|
||||||
@rootscope.$broadcast("block", @scope.issue)
|
@rootscope.$broadcast("block", @scope.issue)
|
||||||
|
@ -188,26 +174,6 @@ IssueDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $loading) ->
|
||||||
$loading.start(target)
|
$loading.start(target)
|
||||||
$tgrepo.save($scope.issue).then(onSuccess, onError)
|
$tgrepo.save($scope.issue).then(onSuccess, onError)
|
||||||
|
|
||||||
$el.on "click", ".add-comment a.button-green", (event) ->
|
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
$el.find(".comment-list").addClass("activeanimation")
|
|
||||||
|
|
||||||
onSuccess = ->
|
|
||||||
$ctrl.loadHistory()
|
|
||||||
|
|
||||||
onError = ->
|
|
||||||
$confirm.notify("error")
|
|
||||||
|
|
||||||
$tgrepo.save($scope.issue).then(onSuccess, onError)
|
|
||||||
|
|
||||||
$el.on "focus", ".add-comment textarea", (event) ->
|
|
||||||
$(this).addClass('active')
|
|
||||||
|
|
||||||
$el.on "click", ".us-activity-tabs li a", (event) ->
|
|
||||||
$el.find(".us-activity-tabs li a").toggleClass("active")
|
|
||||||
$el.find(".us-activity section").toggleClass("hidden")
|
|
||||||
|
|
||||||
return {link:link}
|
return {link:link}
|
||||||
|
|
||||||
module.directive("tgIssueDetail", ["$tgRepo", "$log", "$tgLocation", "$tgConfirm", "$tgNavUrls",
|
module.directive("tgIssueDetail", ["$tgRepo", "$log", "$tgLocation", "$tgConfirm", "$tgNavUrls",
|
||||||
|
|
|
@ -82,7 +82,7 @@ urls = {
|
||||||
"severities": "/api/v1/severities"
|
"severities": "/api/v1/severities"
|
||||||
|
|
||||||
# History
|
# History
|
||||||
"history/userstory": "/api/v1/history/userstory"
|
"history/us": "/api/v1/history/userstory"
|
||||||
"history/issue": "/api/v1/history/issue"
|
"history/issue": "/api/v1/history/issue"
|
||||||
"history/task": "/api/v1/history/task"
|
"history/task": "/api/v1/history/task"
|
||||||
"history/wiki": "/api/v1/history/wiki"
|
"history/wiki": "/api/v1/history/wiki"
|
||||||
|
|
|
@ -52,9 +52,6 @@ resourceProvider = ($repo, $http, $urls, $storage, $q) ->
|
||||||
service.filtersData = (projectId) ->
|
service.filtersData = (projectId) ->
|
||||||
return $repo.queryOneRaw("projects", "#{projectId}/issue_filters_data")
|
return $repo.queryOneRaw("projects", "#{projectId}/issue_filters_data")
|
||||||
|
|
||||||
service.history = (issueId) ->
|
|
||||||
return $repo.queryOneRaw("history/issue", issueId)
|
|
||||||
|
|
||||||
service.listValues = (projectId, type) ->
|
service.listValues = (projectId, type) ->
|
||||||
params = {"project": projectId}
|
params = {"project": projectId}
|
||||||
service.storeQueryParams(projectId, params)
|
service.storeQueryParams(projectId, params)
|
||||||
|
|
|
@ -46,9 +46,6 @@ resourceProvider = ($repo, $http, $urls, $storage) ->
|
||||||
return $http.post(url, params).then (result) ->
|
return $http.post(url, params).then (result) ->
|
||||||
return result.data
|
return result.data
|
||||||
|
|
||||||
service.history = (taskId) ->
|
|
||||||
return $repo.queryOneRaw("history/task", taskId)
|
|
||||||
|
|
||||||
service.listValues = (projectId, type) ->
|
service.listValues = (projectId, type) ->
|
||||||
params = {"project": projectId}
|
params = {"project": projectId}
|
||||||
return $repo.queryMany(type, params)
|
return $repo.queryMany(type, params)
|
||||||
|
|
|
@ -54,9 +54,6 @@ resourceProvider = ($repo, $http, $urls, $storage) ->
|
||||||
params = {project_id: projectId, bulk_stories: data}
|
params = {project_id: projectId, bulk_stories: data}
|
||||||
return $http.post(url, params)
|
return $http.post(url, params)
|
||||||
|
|
||||||
service.history = (usId) ->
|
|
||||||
return $repo.queryOneRaw("history/userstory", usId)
|
|
||||||
|
|
||||||
service.listValues = (projectId, type) ->
|
service.listValues = (projectId, type) ->
|
||||||
params = {"project": projectId}
|
params = {"project": projectId}
|
||||||
service.storeQueryParams(projectId, params)
|
service.storeQueryParams(projectId, params)
|
||||||
|
|
|
@ -59,9 +59,10 @@ class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin, taig
|
||||||
promise.then null, ->
|
promise.then null, ->
|
||||||
console.log "FAIL" #TODO
|
console.log "FAIL" #TODO
|
||||||
|
|
||||||
@scope.$on "attachment:create", @loadHistory
|
|
||||||
@scope.$on "attachment:edit", @loadHistory
|
@scope.$on("attachment:create", => @rootscope.$broadcast("history:reload"))
|
||||||
@scope.$on "attachment:delete", @loadHistory
|
@scope.$on("attachment:edit", => @rootscope.$broadcast("history:reload"))
|
||||||
|
@scope.$on("attachment:delete", => @rootscope.$broadcast("history:reload"))
|
||||||
|
|
||||||
loadProject: ->
|
loadProject: ->
|
||||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||||
|
@ -91,22 +92,6 @@ class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin, taig
|
||||||
}
|
}
|
||||||
@scope.nextUrl = @navUrls.resolve("project-tasks-detail", ctx)
|
@scope.nextUrl = @navUrls.resolve("project-tasks-detail", ctx)
|
||||||
|
|
||||||
loadHistory: =>
|
|
||||||
return @rs.tasks.history(@scope.taskId).then (history) =>
|
|
||||||
_.each history, (historyResult) ->
|
|
||||||
#If description was modified take only the description_html field
|
|
||||||
if historyResult.values_diff.description?
|
|
||||||
historyResult.values_diff.description = historyResult.values_diff.description_diff
|
|
||||||
|
|
||||||
if historyResult.values_diff.is_iocaine
|
|
||||||
historyResult.values_diff.is_iocaine = _.map(historyResult.values_diff.is_iocaine, (v) -> {true: 'Yes', false: 'No'}[v])
|
|
||||||
|
|
||||||
delete historyResult.values_diff.description_html
|
|
||||||
delete historyResult.values_diff.description_diff
|
|
||||||
|
|
||||||
@scope.history = history
|
|
||||||
@scope.comments = _.filter(history, (historyEntry) -> historyEntry.comment != "")
|
|
||||||
|
|
||||||
loadInitialData: ->
|
loadInitialData: ->
|
||||||
params = {
|
params = {
|
||||||
pslug: @params.pslug
|
pslug: @params.pslug
|
||||||
|
@ -126,7 +111,6 @@ class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin, taig
|
||||||
.then(=> @.loadUsersAndRoles())
|
.then(=> @.loadUsersAndRoles())
|
||||||
.then(=> @.loadTask())
|
.then(=> @.loadTask())
|
||||||
.then(=> @.loadAttachments(@scope.taskId))
|
.then(=> @.loadAttachments(@scope.taskId))
|
||||||
.then(=> @.loadHistory())
|
|
||||||
|
|
||||||
block: ->
|
block: ->
|
||||||
@rootscope.$broadcast("block", @scope.task)
|
@rootscope.$broadcast("block", @scope.task)
|
||||||
|
@ -181,26 +165,6 @@ TaskDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $loading) ->
|
||||||
$loading.start(target)
|
$loading.start(target)
|
||||||
$tgrepo.save($scope.task).then(onSuccess, onError)
|
$tgrepo.save($scope.task).then(onSuccess, onError)
|
||||||
|
|
||||||
$el.on "click", ".add-comment a.button-green", (event) ->
|
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
$el.find(".comment-list").addClass("activeanimation")
|
|
||||||
|
|
||||||
onSuccess = ->
|
|
||||||
$ctrl.loadHistory()
|
|
||||||
|
|
||||||
onError = ->
|
|
||||||
$confirm.notify("error")
|
|
||||||
|
|
||||||
$tgrepo.save($scope.task).then(onSuccess, onError)
|
|
||||||
|
|
||||||
$el.on "focus", ".add-comment textarea", (event) ->
|
|
||||||
$(this).addClass('active')
|
|
||||||
|
|
||||||
$el.on "click", ".us-activity-tabs li a", (event) ->
|
|
||||||
$el.find(".us-activity-tabs li a").toggleClass("active")
|
|
||||||
$el.find(".us-activity section").toggleClass("hidden")
|
|
||||||
|
|
||||||
return {link:link}
|
return {link:link}
|
||||||
|
|
||||||
module.directive("tgTaskDetail", ["$tgRepo", "$log", "$tgLocation", "$tgConfirm", "$tgNavUrls",
|
module.directive("tgTaskDetail", ["$tgRepo", "$log", "$tgLocation", "$tgConfirm", "$tgNavUrls",
|
||||||
|
|
|
@ -64,9 +64,9 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin,
|
||||||
@location.replace()
|
@location.replace()
|
||||||
return @q.reject(xhr)
|
return @q.reject(xhr)
|
||||||
|
|
||||||
@scope.$on("attachment:create", => @loadHistory())
|
@scope.$on("attachment:create", => @rootscope.$broadcast("history:reload"))
|
||||||
@scope.$on("attachment:edit", => @loadHistory())
|
@scope.$on("attachment:edit", => @rootscope.$broadcast("history:reload"))
|
||||||
@scope.$on("attachment:delete", => @loadHistory())
|
@scope.$on("attachment:delete", => @rootscope.$broadcast("history:reload"))
|
||||||
|
|
||||||
loadProject: ->
|
loadProject: ->
|
||||||
return @rs.projects.get(@scope.projectId).then (project) =>
|
return @rs.projects.get(@scope.projectId).then (project) =>
|
||||||
|
@ -106,26 +106,6 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin,
|
||||||
@scope.tasks = tasks
|
@scope.tasks = tasks
|
||||||
return tasks
|
return tasks
|
||||||
|
|
||||||
loadHistory: =>
|
|
||||||
return @rs.userstories.history(@scope.usId).then (history) =>
|
|
||||||
for historyResult in history
|
|
||||||
# If description was modified take only the description_html field
|
|
||||||
if historyResult.values_diff.description?
|
|
||||||
historyResult.values_diff.description = historyResult.values_diff.description_diff
|
|
||||||
|
|
||||||
if historyResult.values_diff.client_requirement
|
|
||||||
historyResult.values_diff.client_requirement = _.map(historyResult.values_diff.client_requirement, (v) -> {true: 'Yes', false: 'No'}[v])
|
|
||||||
|
|
||||||
if historyResult.values_diff.team_requirement
|
|
||||||
historyResult.values_diff.team_requirement = _.map(historyResult.values_diff.team_requirement, (v) -> {true: 'Yes', false: 'No'}[v])
|
|
||||||
|
|
||||||
delete historyResult.values_diff.description_html
|
|
||||||
delete historyResult.values_diff.description_diff
|
|
||||||
|
|
||||||
@scope.history = history
|
|
||||||
@scope.comments = _.filter(history, (historyEntry) -> historyEntry.comment != "")
|
|
||||||
return history
|
|
||||||
|
|
||||||
loadInitialData: ->
|
loadInitialData: ->
|
||||||
params = {
|
params = {
|
||||||
pslug: @params.pslug
|
pslug: @params.pslug
|
||||||
|
@ -141,8 +121,7 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin,
|
||||||
.then(=> @.loadUsersAndRoles())
|
.then(=> @.loadUsersAndRoles())
|
||||||
.then(=> @q.all([@.loadUs(),
|
.then(=> @q.all([@.loadUs(),
|
||||||
@.loadTasks(),
|
@.loadTasks(),
|
||||||
@.loadAttachments(@scope.usId),
|
@.loadAttachments(@scope.usId)]))
|
||||||
@.loadHistory()]))
|
|
||||||
block: ->
|
block: ->
|
||||||
@rootscope.$broadcast("block", @scope.us)
|
@rootscope.$broadcast("block", @scope.us)
|
||||||
|
|
||||||
|
@ -198,26 +177,6 @@ UsDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $loading) ->
|
||||||
$loading.start(target)
|
$loading.start(target)
|
||||||
$tgrepo.save($scope.us).then(onSuccess, onError)
|
$tgrepo.save($scope.us).then(onSuccess, onError)
|
||||||
|
|
||||||
$el.on "click", ".add-comment a.button-green", (event) ->
|
|
||||||
event.preventDefault()
|
|
||||||
|
|
||||||
$el.find(".comment-list").addClass("activeanimation")
|
|
||||||
|
|
||||||
onSuccess = ->
|
|
||||||
$ctrl.loadHistory()
|
|
||||||
|
|
||||||
onError = ->
|
|
||||||
$confirm.notify("error")
|
|
||||||
|
|
||||||
$tgrepo.save($scope.us).then(onSuccess, onError)
|
|
||||||
|
|
||||||
$el.on "focus", ".add-comment textarea", (event) ->
|
|
||||||
$(this).addClass('active')
|
|
||||||
|
|
||||||
$el.on "click", ".us-activity-tabs li a", (event) ->
|
|
||||||
$el.find(".us-activity-tabs li a").toggleClass("active")
|
|
||||||
$el.find(".us-activity section").toggleClass("hidden")
|
|
||||||
|
|
||||||
return {link:link}
|
return {link:link}
|
||||||
|
|
||||||
module.directive("tgUsDetail", ["$tgRepo", "$log", "$tgLocation", "$tgConfirm", "$tgNavUrls", "$tgLoading", UsDirective])
|
module.directive("tgUsDetail", ["$tgRepo", "$log", "$tgLocation", "$tgConfirm", "$tgNavUrls", "$tgLoading", UsDirective])
|
||||||
|
|
|
@ -32,22 +32,7 @@ block content
|
||||||
- var permissionSuffix = "issue"
|
- var permissionSuffix = "issue"
|
||||||
include views/modules/attachments
|
include views/modules/attachments
|
||||||
|
|
||||||
section.us-activity
|
tg-history(ng-model="issue", type="issue", mode="edit")
|
||||||
ul.us-activity-tabs
|
|
||||||
li
|
|
||||||
a.active(href="#")
|
|
||||||
span.icon.icon-bulk
|
|
||||||
span.tab-title Comments
|
|
||||||
|
|
||||||
li
|
|
||||||
a(href="#")
|
|
||||||
span.icon.icon-issues
|
|
||||||
span.tab-title Activity
|
|
||||||
|
|
||||||
- var commentModel = "us"
|
|
||||||
- var noSaveButton = true
|
|
||||||
include views/modules/comments
|
|
||||||
include views/modules/activity
|
|
||||||
|
|
||||||
sidebar.menu-secondary.sidebar
|
sidebar.menu-secondary.sidebar
|
||||||
section.us-status(tg-issue-status, ng-model="issue", editable="true")
|
section.us-status(tg-issue-status, ng-model="issue", editable="true")
|
||||||
|
|
|
@ -32,21 +32,7 @@ block content
|
||||||
- var permissionSuffix = "issue"
|
- var permissionSuffix = "issue"
|
||||||
include views/modules/attachments
|
include views/modules/attachments
|
||||||
|
|
||||||
section.us-activity
|
tg-history(ng-model="issue", type="issue")
|
||||||
ul.us-activity-tabs
|
|
||||||
li
|
|
||||||
a.active(href="#")
|
|
||||||
span.icon.icon-comment
|
|
||||||
span.tab-title Comments
|
|
||||||
|
|
||||||
li
|
|
||||||
a(href="#")
|
|
||||||
span.icon.icon-issues
|
|
||||||
span.tab-title Activity
|
|
||||||
|
|
||||||
- var commentModel = "issue"
|
|
||||||
include views/modules/comments
|
|
||||||
include views/modules/activity
|
|
||||||
|
|
||||||
sidebar.menu-secondary.sidebar
|
sidebar.menu-secondary.sidebar
|
||||||
section.us-status(tg-issue-status, ng-model="issue")
|
section.us-status(tg-issue-status, ng-model="issue")
|
||||||
|
|
|
@ -32,22 +32,7 @@ block content
|
||||||
- var permissionSuffix = "task"
|
- var permissionSuffix = "task"
|
||||||
include views/modules/attachments
|
include views/modules/attachments
|
||||||
|
|
||||||
section.us-activity
|
tg-history(ng-model="task", type="task", mode="edit")
|
||||||
ul.us-activity-tabs
|
|
||||||
li
|
|
||||||
a.active(href="#")
|
|
||||||
span.icon.icon-bulk
|
|
||||||
span.tab-title Comments
|
|
||||||
|
|
||||||
li
|
|
||||||
a(href="#")
|
|
||||||
span.icon.icon-issues
|
|
||||||
span.tab-title Activity
|
|
||||||
|
|
||||||
- var commentModel = "task"
|
|
||||||
- var noSaveButton = true
|
|
||||||
include views/modules/comments
|
|
||||||
include views/modules/activity
|
|
||||||
|
|
||||||
sidebar.menu-secondary.sidebar
|
sidebar.menu-secondary.sidebar
|
||||||
section.us-status(tg-task-status, ng-model="task", editable="true")
|
section.us-status(tg-task-status, ng-model="task", editable="true")
|
||||||
|
|
|
@ -32,21 +32,7 @@ block content
|
||||||
- var permissionSuffix = "task"
|
- var permissionSuffix = "task"
|
||||||
include views/modules/attachments
|
include views/modules/attachments
|
||||||
|
|
||||||
section.us-activity
|
tg-history(ng-model="task", type="task")
|
||||||
ul.us-activity-tabs
|
|
||||||
li
|
|
||||||
a.active(href="#")
|
|
||||||
span.icon.icon-bulk
|
|
||||||
span.tab-title Comments
|
|
||||||
|
|
||||||
li
|
|
||||||
a(href="#")
|
|
||||||
span.icon.icon-issues
|
|
||||||
span.tab-title Activity
|
|
||||||
|
|
||||||
- var commentModel = "task"
|
|
||||||
include views/modules/comments
|
|
||||||
include views/modules/activity
|
|
||||||
|
|
||||||
sidebar.menu-secondary.sidebar
|
sidebar.menu-secondary.sidebar
|
||||||
section.us-status(tg-task-status, ng-model="task")
|
section.us-status(tg-task-status, ng-model="task")
|
||||||
|
|
|
@ -32,22 +32,7 @@ block content
|
||||||
- var permissionSuffix = "us"
|
- var permissionSuffix = "us"
|
||||||
include views/modules/attachments
|
include views/modules/attachments
|
||||||
|
|
||||||
section.us-activity
|
tg-history(ng-model="us", type="us", mode="edit")
|
||||||
ul.us-activity-tabs
|
|
||||||
li
|
|
||||||
a.active(href="#")
|
|
||||||
span.icon.icon-bulk
|
|
||||||
span.tab-title Comments
|
|
||||||
|
|
||||||
li
|
|
||||||
a(href="#")
|
|
||||||
span.icon.icon-issues
|
|
||||||
span.tab-title Activity
|
|
||||||
|
|
||||||
- var commentModel = "us"
|
|
||||||
- var noSaveButton = true
|
|
||||||
include views/modules/comments
|
|
||||||
include views/modules/activity
|
|
||||||
|
|
||||||
sidebar.menu-secondary.sidebar
|
sidebar.menu-secondary.sidebar
|
||||||
section.us-status(tg-us-status-detail, ng-model="us", editable="true")
|
section.us-status(tg-us-status-detail, ng-model="us", editable="true")
|
||||||
|
|
|
@ -36,21 +36,7 @@ block content
|
||||||
- var permissionSuffix = "us"
|
- var permissionSuffix = "us"
|
||||||
include views/modules/attachments
|
include views/modules/attachments
|
||||||
|
|
||||||
section.us-activity
|
tg-history(ng-model="us", type="us")
|
||||||
ul.us-activity-tabs
|
|
||||||
li
|
|
||||||
a.active(href="#")
|
|
||||||
span.icon.icon-bulk
|
|
||||||
span.tab-title Comments
|
|
||||||
|
|
||||||
li
|
|
||||||
a(href="#")
|
|
||||||
span.icon.icon-issues
|
|
||||||
span.tab-title Activity
|
|
||||||
|
|
||||||
- var commentModel = "us"
|
|
||||||
include views/modules/comments
|
|
||||||
include views/modules/activity
|
|
||||||
|
|
||||||
sidebar.menu-secondary.sidebar
|
sidebar.menu-secondary.sidebar
|
||||||
section.us-status(tg-us-status-detail, ng-model="us")
|
section.us-status(tg-us-status-detail, ng-model="us")
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
section.us-activity.hidden
|
|
||||||
//- modules/common.coffee - ChangeDirective
|
|
||||||
div.activity-list(tg-changes, ng-model="history", mode="activity")
|
|
||||||
|
|
||||||
//- TODO
|
|
||||||
//- a.more-activity(href="", title="show more comments")
|
|
||||||
//- span show previous activity
|
|
||||||
//- span.prev-activity-num (3 more)
|
|
|
@ -1,19 +0,0 @@
|
||||||
//- NOTE: You must to define 'var commentModel' with the object model
|
|
||||||
//- You must to define 'var noSaveButton = true' if save button is not necessary
|
|
||||||
|
|
||||||
section.us-comments
|
|
||||||
//- modules/common.coffee - ChangeDirective
|
|
||||||
div.comment-list(tg-changes, mode="comment", ng-model="comments")
|
|
||||||
|
|
||||||
div.comment-single
|
|
||||||
|
|
||||||
//- TODO
|
|
||||||
//- a.more-comments(href="", title="show more comments")
|
|
||||||
//- span show previous comments
|
|
||||||
//- span.prev-comments-num (3 more)
|
|
||||||
|
|
||||||
div.add-comment(tg-check-permission, tg-toggle-comment, permission="modify_"+commentModel)
|
|
||||||
textarea(placeholder="Write here a new commet", ng-model="commentModel.comment", tg-markitup)
|
|
||||||
|
|
||||||
unless noSaveButton
|
|
||||||
a.button.button-green.save-comment(href="", title="Comment") Comment
|
|
|
@ -114,34 +114,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.us-activity-tabs {
|
|
||||||
@extend %title;
|
|
||||||
border-bottom: 3px solid $gray-light;
|
|
||||||
padding: .5rem 0;
|
|
||||||
li {
|
|
||||||
@extend %large;
|
|
||||||
display: inline-block;
|
|
||||||
&:first-child {
|
|
||||||
border-right: 1px solid $gray-light;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
@include transition(color .2s ease-in);
|
|
||||||
color: $gray-light;
|
|
||||||
padding: 0 2rem;
|
|
||||||
&.active {
|
|
||||||
color: $grayer;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
@include transition(color .2s ease-in);
|
|
||||||
color: $green-taiga;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
margin-right: .5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-list {
|
.comment-list {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,10 +60,8 @@ $prefix-for-spec: true;
|
||||||
@import 'modules/common/colors-table';
|
@import 'modules/common/colors-table';
|
||||||
@import 'modules/common/category-config';
|
@import 'modules/common/category-config';
|
||||||
@import 'modules/common/attachments';
|
@import 'modules/common/attachments';
|
||||||
@import 'modules/common/comments';
|
|
||||||
@import 'modules/common/comment-activity';
|
|
||||||
@import 'modules/common/activity';
|
|
||||||
@import 'modules/common/related-tasks';
|
@import 'modules/common/related-tasks';
|
||||||
|
@import 'modules/common/history';
|
||||||
|
|
||||||
//Project modules
|
//Project modules
|
||||||
@import 'modules/home-projects-list';
|
@import 'modules/home-projects-list';
|
||||||
|
|
|
@ -1,51 +0,0 @@
|
||||||
.activity-single {
|
|
||||||
@include table-flex;
|
|
||||||
border-bottom: 2px solid $gray-light;
|
|
||||||
padding: 2rem 0;
|
|
||||||
position: relative;
|
|
||||||
&:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
.username {
|
|
||||||
color: $green-taiga;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
.activity-user {
|
|
||||||
@include table-flex-child(1, 50px, 0);
|
|
||||||
img {
|
|
||||||
max-width: 70px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.activity-username {
|
|
||||||
border-bottom: 1px dotted $gray-light;
|
|
||||||
color: $green-taiga;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
.activity-content {
|
|
||||||
@include table-flex-child(20, 150px, 0);
|
|
||||||
}
|
|
||||||
.us-activity {
|
|
||||||
background: $whitish;
|
|
||||||
.activity-inner {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.date {
|
|
||||||
@extend %small;
|
|
||||||
color: $gray-light;
|
|
||||||
margin-left: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.more-activity {
|
|
||||||
@extend %small;
|
|
||||||
border-bottom: 1px solid $gray-light;
|
|
||||||
color: $gray-light;
|
|
||||||
display: block;
|
|
||||||
padding: 1rem;
|
|
||||||
.prev-activity-num {
|
|
||||||
color: $green-taiga;
|
|
||||||
margin-left: .5rem;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
.us-activity {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
padding: 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.activity-title {
|
|
||||||
display: block;
|
|
||||||
padding: .5rem;
|
|
||||||
&:hover {
|
|
||||||
.icon {
|
|
||||||
@include transform(rotate(180deg));
|
|
||||||
@include transition(all.2s linear);
|
|
||||||
color: $green-taiga;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.icon {
|
|
||||||
@include transform(rotate(0));
|
|
||||||
@include transition(all.2s linear);
|
|
||||||
color: $grayer;
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.activity-inner {
|
|
||||||
@include table-flex;
|
|
||||||
border-bottom: 1px solid $gray-light;
|
|
||||||
padding: 1rem 0;
|
|
||||||
&:last-child {
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
.activity-changed,
|
|
||||||
.activity-fromto {
|
|
||||||
@include table-flex-child(1, 50px, 0);
|
|
||||||
}
|
|
||||||
.activity-changed {
|
|
||||||
@extend %bold;
|
|
||||||
}
|
|
||||||
.activity-fromto {
|
|
||||||
@extend %small;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +1,74 @@
|
||||||
|
.history {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding: 0 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.changes-title {
|
||||||
|
display: block;
|
||||||
|
padding: .5rem;
|
||||||
|
&:hover {
|
||||||
|
.icon {
|
||||||
|
@include transform(rotate(180deg));
|
||||||
|
@include transition(all.2s linear);
|
||||||
|
color: $green-taiga;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
@include transform(rotate(0));
|
||||||
|
@include transition(all.2s linear);
|
||||||
|
color: $grayer;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.change-entry {
|
||||||
|
@include table-flex;
|
||||||
|
border-bottom: 1px solid $gray-light;
|
||||||
|
padding: .5rem;
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
.activity-changed,
|
||||||
|
.activity-fromto {
|
||||||
|
@include table-flex-child(1, 50px, 0);
|
||||||
|
}
|
||||||
|
.activity-changed {
|
||||||
|
@extend %bold;
|
||||||
|
}
|
||||||
|
.activity-fromto {
|
||||||
|
@extend %small;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-tabs {
|
||||||
|
@extend %title;
|
||||||
|
border-bottom: 3px solid $gray-light;
|
||||||
|
padding: .5rem 0;
|
||||||
|
li {
|
||||||
|
@extend %large;
|
||||||
|
display: inline-block;
|
||||||
|
&:first-child {
|
||||||
|
border-right: 1px solid $gray-light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
@include transition(color .2s ease-in);
|
||||||
|
color: $gray-light;
|
||||||
|
padding: 0 2rem;
|
||||||
|
&.active {
|
||||||
|
color: $grayer;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
@include transition(color .2s ease-in);
|
||||||
|
color: $green-taiga;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
margin-right: .5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.add-comment {
|
.add-comment {
|
||||||
@include clearfix;
|
@include clearfix;
|
||||||
textarea {
|
textarea {
|
||||||
|
@ -37,66 +108,6 @@ a.show-more-comments {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-single {
|
|
||||||
@include table-flex;
|
|
||||||
border-bottom: 2px solid $gray-light;
|
|
||||||
padding: 1rem 0;
|
|
||||||
position: relative;
|
|
||||||
&:hover {
|
|
||||||
.delete-comment {
|
|
||||||
opacity: 1;
|
|
||||||
@include transition(opacity .2s linear);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
&:last-child {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
.username {
|
|
||||||
color: $green-taiga;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
.comment-user {
|
|
||||||
@include table-flex-child(1, 50px, 0);
|
|
||||||
img {
|
|
||||||
max-width: 70px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.comment-content {
|
|
||||||
@include table-flex-child(20, 150px, 0);
|
|
||||||
}
|
|
||||||
.us-activity {
|
|
||||||
background: $whitish;
|
|
||||||
.activity-inner {
|
|
||||||
display: none;
|
|
||||||
&.active {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.date {
|
|
||||||
@extend %small;
|
|
||||||
color: $gray-light;
|
|
||||||
}
|
|
||||||
.delete-comment {
|
|
||||||
@include transition(all .2s linear);
|
|
||||||
bottom: 2rem;
|
|
||||||
color: $grayer;
|
|
||||||
opacity: 0;
|
|
||||||
position: absolute;
|
|
||||||
right: 1.5rem;
|
|
||||||
&:hover {
|
|
||||||
@include transition(color .2s linear);
|
|
||||||
color: $red;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.more-comments {
|
.more-comments {
|
||||||
@extend %small;
|
@extend %small;
|
||||||
border-bottom: 1px solid $gray-light;
|
border-bottom: 1px solid $gray-light;
|
||||||
|
@ -108,6 +119,7 @@ a.show-more-comments {
|
||||||
margin-left: .5rem;
|
margin-left: .5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-list {
|
.comment-list {
|
||||||
&.activeanimation {
|
&.activeanimation {
|
||||||
.comment-single.ng-enter:last-child,
|
.comment-single.ng-enter:last-child,
|
||||||
|
@ -124,3 +136,70 @@ a.show-more-comments {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.activity-single {
|
||||||
|
@include table-flex;
|
||||||
|
border-bottom: 2px solid $gray-light;
|
||||||
|
padding: 2rem 0;
|
||||||
|
position: relative;
|
||||||
|
&:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.username {
|
||||||
|
color: $green-taiga;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
.activity-user {
|
||||||
|
@include table-flex-child(1, 50px, 0);
|
||||||
|
img {
|
||||||
|
max-width: 70px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.activity-username {
|
||||||
|
color: $green-taiga;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-content {
|
||||||
|
@include table-flex-child(20, 150px, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.changes {
|
||||||
|
background: $whitish;
|
||||||
|
.change-entry {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.date {
|
||||||
|
@extend %small;
|
||||||
|
color: $gray-light;
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wysiwyg {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.activity {
|
||||||
|
.change-entry {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.more-activity {
|
||||||
|
@extend %small;
|
||||||
|
border-bottom: 1px solid $gray-light;
|
||||||
|
color: $gray-light;
|
||||||
|
display: block;
|
||||||
|
padding: 1rem;
|
||||||
|
.prev-activity-num {
|
||||||
|
color: $green-taiga;
|
||||||
|
margin-left: .5rem;
|
||||||
|
}
|
||||||
|
}
|
|
@ -114,7 +114,7 @@ gulp.task "scsslint", ->
|
||||||
config: "scsslint.yml"
|
config: "scsslint.yml"
|
||||||
}))
|
}))
|
||||||
|
|
||||||
gulp.task "sass", ->
|
gulp.task "sass", ["scsslint"], ->
|
||||||
gulp.src(paths.sassStylesMain)
|
gulp.src(paths.sassStylesMain)
|
||||||
.pipe(plumber())
|
.pipe(plumber())
|
||||||
.pipe(sass())
|
.pipe(sass())
|
||||||
|
@ -126,12 +126,12 @@ gulp.task "css", ->
|
||||||
.pipe(concat("vendor.css"))
|
.pipe(concat("vendor.css"))
|
||||||
.pipe(gulp.dest(paths.distStylesPath))
|
.pipe(gulp.dest(paths.distStylesPath))
|
||||||
|
|
||||||
gulp.task "csslint-vendor", ->
|
gulp.task "csslint-vendor", ["css"], ->
|
||||||
gulp.src(paths.css)
|
gulp.src(paths.css)
|
||||||
.pipe(csslint("csslintrc.json"))
|
.pipe(csslint("csslintrc.json"))
|
||||||
.pipe(csslint.reporter())
|
.pipe(csslint.reporter())
|
||||||
|
|
||||||
gulp.task "csslint-app", ->
|
gulp.task "csslint-app", ["css", "sass"], ->
|
||||||
gulp.src(paths.distStylesPath + "/app.css")
|
gulp.src(paths.distStylesPath + "/app.css")
|
||||||
.pipe(csslint("csslintrc.json"))
|
.pipe(csslint("csslintrc.json"))
|
||||||
.pipe(csslint.reporter())
|
.pipe(csslint.reporter())
|
||||||
|
|
Loading…
Reference in New Issue