diff --git a/app/coffee/modules/common.coffee b/app/coffee/modules/common.coffee index 51853f07..798628b0 100644 --- a/app/coffee/modules/common.coffee +++ b/app/coffee/modules/common.coffee @@ -26,276 +26,6 @@ typeIsArray = @.taiga.typeIsArray module = angular.module("taigaCommon", []) - -############################################################################# -## Change (comment and history mode) directive -############################################################################# - -ChangesDirective = -> - containerTemplate = _.template(""" -
- <% if (showMoreEnabled){ %> - - + Show previous comments (<%- howManyMore %> more) - - <% } %> -
- """) # TODO: i18n - commentBaseTemplate = _.template(""" -
-
- - <%- userFullName %> - -
-
- - <%- userFullName %> - - <% if(hasChanges){ %> - - <% } %> - -
- <%= comment %> -
-
- <%- creationDate %> -
-
-
- """) - changeBaseTemplate = _.template(""" -
-
- - <%- userFullName %> - -
-
-
- - <%- userFullName %> - - - <%- creationDate %> - -
-
- <%= comment %> -
-
-
- """) - standardChangeFromToTemplate = _.template(""" -
-
- <%- name %> -
-
-

- from
- <%= from %> -

-

- to
- <%= to %> -

-
-
- """) # TODO: i18n - descriptionChangeTemplate = _.template(""" -
-
- <%- name %> -
-
-

- <%= diff %> -

-
-
- """) - pointsChangeTemplate = _.template(""" - <% _.each(points, function(point, name) { %> -
-
- <%- name %> points -
-
-

- from
- <%= point[0] %> -

-

- to
- <%= point[1] %> -

-
-
- <% }); %> - """) # TODO: i18n - attachmentTemplate = _.template(""" -
-
- <%- name %> -
-
- <%- description %> -
-
- """) - 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 ############################################################################# diff --git a/app/coffee/modules/common/history.coffee b/app/coffee/modules/common/history.coffee new file mode 100644 index 00000000..534239a9 --- /dev/null +++ b/app/coffee/modules/common/history.coffee @@ -0,0 +1,385 @@ +### +# Copyright (C) 2014 Andrey Antukh +# Copyright (C) 2014 Jesús Espino Garcia +# Copyright (C) 2014 David Barragán Merino +# +# 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 . +# +# 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(""" +
+
+ <%- name %> +
+
+

+ <%= diff %> +

+
+
+ """) + + templateChangePoints = _.template(""" + <% _.each(points, function(point, name) { %> +
+
+ points (<%- name.toLowerCase() %>) +
+
+

+ from
+ <%= point[0] %> +

+

+ to
+ <%= point[1] %> +

+
+
+ <% }); %> + """) + + templateChangeGeneric = _.template(""" +
+
+ <%- name %> +
+
+

+ from
+ <%= from %> +

+

+ to
+ <%= to %> +

+
+
+ """) + + templateActivity = _.template(""" +
+
+ + <%- userFullName %> + +
+
+
+ + <%- userFullName %> + + + <%- creationDate %> + +
+ + <% if (comment.length > 0) { %> +
+ <%= comment %> +
+ <% } %> + + <% if(changes.length > 0) { %> +
+ <% if (mode != "activity") { %> + + <%- changesText %> + + + <% } %> + + <% _.each(changes, function(change) { %> + <%= change %> + <% }) %> +
+ <% } %> +
+
+ """) + + templateBaseEntries = _.template(""" + <% if (showMore > 0) { %> + + + Show previous entries (<%- showMore %> more) + + <% } %> + <% _.each(entries, function(entry) { %> + <%= entry %> + <% }) %> + """) + + templateBase = _.template(""" +
+ +
+
+
+ + <% if (mode !== "edit") { %> + Comment + <% } %> +
+
+ +
+ """) + + 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]) diff --git a/app/coffee/modules/issues/detail.coffee b/app/coffee/modules/issues/detail.coffee index f855a733..35a06c0e 100644 --- a/app/coffee/modules/issues/detail.coffee +++ b/app/coffee/modules/issues/detail.coffee @@ -67,9 +67,9 @@ class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin, tai @location.replace() return @q.reject(xhr) - @scope.$on("attachment:create", => @.loadHistory()) - @scope.$on("attachment:edit", => @.loadHistory()) - @scope.$on("attachment:delete", => @.loadHistory()) + @scope.$on("attachment:create", => @rootscope.$broadcast("history:reload")) + @scope.$on("attachment:edit", => @rootscope.$broadcast("history:reload")) + @scope.$on("attachment:delete", => @rootscope.$broadcast("history:reload")) loadProject: -> 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) - 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: -> params = { pslug: @params.pslug @@ -132,8 +119,7 @@ class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin, tai return promise.then(=> @.loadProject()) .then(=> @.loadUsersAndRoles()) .then(=> @q.all([@.loadIssue(), - @.loadAttachments(@scope.issueId), - @.loadHistory()])) + @.loadAttachments(@scope.issueId)])) block: -> @rootscope.$broadcast("block", @scope.issue) @@ -188,26 +174,6 @@ IssueDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $loading) -> $loading.start(target) $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} module.directive("tgIssueDetail", ["$tgRepo", "$log", "$tgLocation", "$tgConfirm", "$tgNavUrls", diff --git a/app/coffee/modules/resources.coffee b/app/coffee/modules/resources.coffee index d56d499d..a886a157 100644 --- a/app/coffee/modules/resources.coffee +++ b/app/coffee/modules/resources.coffee @@ -82,7 +82,7 @@ urls = { "severities": "/api/v1/severities" # History - "history/userstory": "/api/v1/history/userstory" + "history/us": "/api/v1/history/userstory" "history/issue": "/api/v1/history/issue" "history/task": "/api/v1/history/task" "history/wiki": "/api/v1/history/wiki" diff --git a/app/coffee/modules/resources/issues.coffee b/app/coffee/modules/resources/issues.coffee index 696d5757..fca4caa3 100644 --- a/app/coffee/modules/resources/issues.coffee +++ b/app/coffee/modules/resources/issues.coffee @@ -52,9 +52,6 @@ resourceProvider = ($repo, $http, $urls, $storage, $q) -> service.filtersData = (projectId) -> return $repo.queryOneRaw("projects", "#{projectId}/issue_filters_data") - service.history = (issueId) -> - return $repo.queryOneRaw("history/issue", issueId) - service.listValues = (projectId, type) -> params = {"project": projectId} service.storeQueryParams(projectId, params) diff --git a/app/coffee/modules/resources/tasks.coffee b/app/coffee/modules/resources/tasks.coffee index e390a421..76883117 100644 --- a/app/coffee/modules/resources/tasks.coffee +++ b/app/coffee/modules/resources/tasks.coffee @@ -46,9 +46,6 @@ resourceProvider = ($repo, $http, $urls, $storage) -> return $http.post(url, params).then (result) -> return result.data - service.history = (taskId) -> - return $repo.queryOneRaw("history/task", taskId) - service.listValues = (projectId, type) -> params = {"project": projectId} return $repo.queryMany(type, params) diff --git a/app/coffee/modules/resources/userstories.coffee b/app/coffee/modules/resources/userstories.coffee index cdb252ba..caeda114 100644 --- a/app/coffee/modules/resources/userstories.coffee +++ b/app/coffee/modules/resources/userstories.coffee @@ -54,9 +54,6 @@ resourceProvider = ($repo, $http, $urls, $storage) -> params = {project_id: projectId, bulk_stories: data} return $http.post(url, params) - service.history = (usId) -> - return $repo.queryOneRaw("history/userstory", usId) - service.listValues = (projectId, type) -> params = {"project": projectId} service.storeQueryParams(projectId, params) diff --git a/app/coffee/modules/tasks/detail.coffee b/app/coffee/modules/tasks/detail.coffee index 2fd76fb1..c1f08250 100644 --- a/app/coffee/modules/tasks/detail.coffee +++ b/app/coffee/modules/tasks/detail.coffee @@ -59,9 +59,10 @@ class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin, taig promise.then null, -> console.log "FAIL" #TODO - @scope.$on "attachment:create", @loadHistory - @scope.$on "attachment:edit", @loadHistory - @scope.$on "attachment:delete", @loadHistory + + @scope.$on("attachment:create", => @rootscope.$broadcast("history:reload")) + @scope.$on("attachment:edit", => @rootscope.$broadcast("history:reload")) + @scope.$on("attachment:delete", => @rootscope.$broadcast("history:reload")) loadProject: -> 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) - 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: -> params = { pslug: @params.pslug @@ -126,7 +111,6 @@ class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin, taig .then(=> @.loadUsersAndRoles()) .then(=> @.loadTask()) .then(=> @.loadAttachments(@scope.taskId)) - .then(=> @.loadHistory()) block: -> @rootscope.$broadcast("block", @scope.task) @@ -181,26 +165,6 @@ TaskDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $loading) -> $loading.start(target) $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} module.directive("tgTaskDetail", ["$tgRepo", "$log", "$tgLocation", "$tgConfirm", "$tgNavUrls", diff --git a/app/coffee/modules/userstories/detail.coffee b/app/coffee/modules/userstories/detail.coffee index 43bce3f3..a4f6c344 100644 --- a/app/coffee/modules/userstories/detail.coffee +++ b/app/coffee/modules/userstories/detail.coffee @@ -64,9 +64,9 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin, @location.replace() return @q.reject(xhr) - @scope.$on("attachment:create", => @loadHistory()) - @scope.$on("attachment:edit", => @loadHistory()) - @scope.$on("attachment:delete", => @loadHistory()) + @scope.$on("attachment:create", => @rootscope.$broadcast("history:reload")) + @scope.$on("attachment:edit", => @rootscope.$broadcast("history:reload")) + @scope.$on("attachment:delete", => @rootscope.$broadcast("history:reload")) loadProject: -> return @rs.projects.get(@scope.projectId).then (project) => @@ -106,26 +106,6 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin, @scope.tasks = 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: -> params = { pslug: @params.pslug @@ -141,8 +121,7 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin, .then(=> @.loadUsersAndRoles()) .then(=> @q.all([@.loadUs(), @.loadTasks(), - @.loadAttachments(@scope.usId), - @.loadHistory()])) + @.loadAttachments(@scope.usId)])) block: -> @rootscope.$broadcast("block", @scope.us) @@ -198,26 +177,6 @@ UsDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $loading) -> $loading.start(target) $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} module.directive("tgUsDetail", ["$tgRepo", "$log", "$tgLocation", "$tgConfirm", "$tgNavUrls", "$tgLoading", UsDirective]) diff --git a/app/partials/issues-detail-edit.jade b/app/partials/issues-detail-edit.jade index 39d1f067..48fc3138 100644 --- a/app/partials/issues-detail-edit.jade +++ b/app/partials/issues-detail-edit.jade @@ -32,22 +32,7 @@ block content - var permissionSuffix = "issue" include views/modules/attachments - section.us-activity - 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 + tg-history(ng-model="issue", type="issue", mode="edit") sidebar.menu-secondary.sidebar section.us-status(tg-issue-status, ng-model="issue", editable="true") diff --git a/app/partials/issues-detail.jade b/app/partials/issues-detail.jade index 1c25f4fe..849208af 100644 --- a/app/partials/issues-detail.jade +++ b/app/partials/issues-detail.jade @@ -32,21 +32,7 @@ block content - var permissionSuffix = "issue" include views/modules/attachments - section.us-activity - 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 + tg-history(ng-model="issue", type="issue") sidebar.menu-secondary.sidebar section.us-status(tg-issue-status, ng-model="issue") diff --git a/app/partials/task-detail-edit.jade b/app/partials/task-detail-edit.jade index d55ce906..f88c134e 100644 --- a/app/partials/task-detail-edit.jade +++ b/app/partials/task-detail-edit.jade @@ -32,22 +32,7 @@ block content - var permissionSuffix = "task" include views/modules/attachments - section.us-activity - 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 + tg-history(ng-model="task", type="task", mode="edit") sidebar.menu-secondary.sidebar section.us-status(tg-task-status, ng-model="task", editable="true") diff --git a/app/partials/task-detail.jade b/app/partials/task-detail.jade index fcbcc5cb..199d5dc4 100644 --- a/app/partials/task-detail.jade +++ b/app/partials/task-detail.jade @@ -32,21 +32,7 @@ block content - var permissionSuffix = "task" include views/modules/attachments - section.us-activity - 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 + tg-history(ng-model="task", type="task") sidebar.menu-secondary.sidebar section.us-status(tg-task-status, ng-model="task") diff --git a/app/partials/us-detail-edit.jade b/app/partials/us-detail-edit.jade index e1ea9592..161a2f12 100644 --- a/app/partials/us-detail-edit.jade +++ b/app/partials/us-detail-edit.jade @@ -32,22 +32,7 @@ block content - var permissionSuffix = "us" include views/modules/attachments - section.us-activity - 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 + tg-history(ng-model="us", type="us", mode="edit") sidebar.menu-secondary.sidebar section.us-status(tg-us-status-detail, ng-model="us", editable="true") diff --git a/app/partials/us-detail.jade b/app/partials/us-detail.jade index cfe263e3..857277f1 100644 --- a/app/partials/us-detail.jade +++ b/app/partials/us-detail.jade @@ -36,21 +36,7 @@ block content - var permissionSuffix = "us" include views/modules/attachments - section.us-activity - 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 + tg-history(ng-model="us", type="us") sidebar.menu-secondary.sidebar section.us-status(tg-us-status-detail, ng-model="us") diff --git a/app/partials/views/modules/activity.jade b/app/partials/views/modules/activity.jade deleted file mode 100644 index f68ddc3e..00000000 --- a/app/partials/views/modules/activity.jade +++ /dev/null @@ -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) diff --git a/app/partials/views/modules/comments.jade b/app/partials/views/modules/comments.jade deleted file mode 100644 index 78fe0a38..00000000 --- a/app/partials/views/modules/comments.jade +++ /dev/null @@ -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 diff --git a/app/styles/layout/us-detail.scss b/app/styles/layout/us-detail.scss index 2b29554e..2f9f7809 100644 --- a/app/styles/layout/us-detail.scss +++ b/app/styles/layout/us-detail.scss @@ -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 { padding: 1rem; } diff --git a/app/styles/main.scss b/app/styles/main.scss index 1c90000c..f117b6f8 100755 --- a/app/styles/main.scss +++ b/app/styles/main.scss @@ -60,10 +60,8 @@ $prefix-for-spec: true; @import 'modules/common/colors-table'; @import 'modules/common/category-config'; @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/history'; //Project modules @import 'modules/home-projects-list'; diff --git a/app/styles/modules/common/activity.scss b/app/styles/modules/common/activity.scss deleted file mode 100644 index 711f9b6b..00000000 --- a/app/styles/modules/common/activity.scss +++ /dev/null @@ -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; - } -} diff --git a/app/styles/modules/common/comment-activity.scss b/app/styles/modules/common/comment-activity.scss deleted file mode 100644 index 6042878a..00000000 --- a/app/styles/modules/common/comment-activity.scss +++ /dev/null @@ -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; - } -} diff --git a/app/styles/modules/common/comments.scss b/app/styles/modules/common/history.scss similarity index 54% rename from app/styles/modules/common/comments.scss rename to app/styles/modules/common/history.scss index 59c2fc85..bde6d604 100644 --- a/app/styles/modules/common/comments.scss +++ b/app/styles/modules/common/history.scss @@ -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 { @include clearfix; 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 { @extend %small; border-bottom: 1px solid $gray-light; @@ -108,6 +119,7 @@ a.show-more-comments { margin-left: .5rem; } } + .comment-list { &.activeanimation { .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; + } +} diff --git a/gulpfile.coffee b/gulpfile.coffee index 8b20a89b..e9b075a8 100644 --- a/gulpfile.coffee +++ b/gulpfile.coffee @@ -114,7 +114,7 @@ gulp.task "scsslint", -> config: "scsslint.yml" })) -gulp.task "sass", -> +gulp.task "sass", ["scsslint"], -> gulp.src(paths.sassStylesMain) .pipe(plumber()) .pipe(sass()) @@ -126,12 +126,12 @@ gulp.task "css", -> .pipe(concat("vendor.css")) .pipe(gulp.dest(paths.distStylesPath)) -gulp.task "csslint-vendor", -> +gulp.task "csslint-vendor", ["css"], -> gulp.src(paths.css) .pipe(csslint("csslintrc.json")) .pipe(csslint.reporter()) -gulp.task "csslint-app", -> +gulp.task "csslint-app", ["css", "sass"], -> gulp.src(paths.distStylesPath + "/app.css") .pipe(csslint("csslintrc.json")) .pipe(csslint.reporter())