### # 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/issues/detail.coffee ### taiga = @.taiga mixOf = @.taiga.mixOf toString = @.taiga.toString joinStr = @.taiga.joinStr groupBy = @.taiga.groupBy bindOnce = @.taiga.bindOnce module = angular.module("taigaIssues") ############################################################################# ## Issue Detail Controller ############################################################################# class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin) @.$inject = [ "$scope", "$rootScope", "$tgRepo", "$tgConfirm", "$tgResources", "$routeParams", "$q", "$tgLocation", "$log", "$appTitle", "$tgNavUrls" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @log, @appTitle, @navUrls) -> @scope.issueRef = @params.issueref @scope.sectionName = "Issue Details" promise = @.loadInitialData() # On Success promise.then => @appTitle.set(@scope.issue.subject + " - " + @scope.project.name) # On Error promise.then null, (xhr) => if xhr and xhr.status == 404 @location.path(@navUrls.resolve("not-found")) @location.replace() return @q.reject(xhr) @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) => @scope.project = project @scope.$emit('project:loaded', project) @scope.statusList = project.issue_statuses @scope.statusById = groupBy(project.issue_statuses, (x) -> x.id) @scope.typeById = groupBy(project.issue_types, (x) -> x.id) @scope.typeList = _.sortBy(project.issue_types, "order") @scope.severityList = project.severities @scope.severityById = groupBy(project.severities, (x) -> x.id) @scope.priorityList = project.priorities @scope.priorityById = groupBy(project.priorities, (x) -> x.id) @scope.membersById = groupBy(project.memberships, (x) -> x.user) return project loadIssue: -> return @rs.issues.get(@scope.projectId, @scope.issueId).then (issue) => @scope.issue = issue @scope.commentModel = issue if @scope.issue.neighbors.previous.ref? ctx = { project: @scope.project.slug ref: @scope.issue.neighbors.previous.ref } @scope.previousUrl = @navUrls.resolve("project-issues-detail", ctx) if @scope.issue.neighbors.next.ref? ctx = { project: @scope.project.slug ref: @scope.issue.neighbors.next.ref } @scope.nextUrl = @navUrls.resolve("project-issues-detail", ctx) loadInitialData: -> params = { pslug: @params.pslug issueref: @params.issueref } promise = @repo.resolve(params).then (data) => @scope.projectId = data.project @scope.issueId = data.issue return data return promise.then(=> @.loadProject()) .then(=> @.loadUsersAndRoles()) .then(=> @.loadIssue()) block: -> @rootscope.$broadcast("block", @scope.issue) unblock: -> @rootscope.$broadcast("unblock", @scope.issue) delete: -> # TODO: i18n title = "Delete Issue" subtitle = @scope.issue.subject @confirm.ask(title, subtitle).then (finish) => promise = @.repo.remove(@scope.issue) promise.then => finish() @location.path(@navUrls.resolve("project-issues", {project: @scope.project.slug})) promise.then null, => finish(false) @confirm.notify("error") module.controller("IssueDetailController", IssueDetailController) ############################################################################# ## Issue Main Directive ############################################################################# IssueDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $loading) -> linkSidebar = ($scope, $el, $attrs, $ctrl) -> link = ($scope, $el, $attrs) -> $ctrl = $el.controller() linkSidebar($scope, $el, $attrs, $ctrl) if $el.is("form") form = $el.checksley() $el.on "click", ".save-issue", (event) -> if not form.validate() return onSuccess = -> $loading.finish(target) $confirm.notify("success") ctx = { project: $scope.project.slug ref: $scope.issue.ref } $location.path($navUrls.resolve("project-issues-detail", ctx)) onError = -> $loading.finish(target) $confirm.notify("error") target = angular.element(event.currentTarget) $loading.start(target) $tgrepo.save($scope.issue).then(onSuccess, onError) return {link:link} module.directive("tgIssueDetail", ["$tgRepo", "$log", "$tgLocation", "$tgConfirm", "$tgNavUrls", "$tgLoading", IssueDirective]) ############################################################################# ## Issue status directive ############################################################################# IssueStatusDirective = () -> # TODO: i18n template = _.template("""

<% if (status.is_closed) { %> Closed <% } else { %> Open <% } %> <%= status.name %>

<%- owner.full_name_display %>
Created by <%- owner.full_name_display %> <%- date %>
<%= type.name %> <% if (editable) { %> <% } %> type
<%= severity.name %> <% if (editable) { %> <% } %> severity
<%= priority.name %> <% if (editable) { %> <% } %> priority
<%= status.name %> <% if (editable) { %> <% } %> status
""") selectionTypeTemplate = _.template(""" """) selectionSeverityTemplate = _.template(""" """) selectionPriorityTemplate = _.template(""" """) selectionStatusTemplate = _.template(""" """) link = ($scope, $el, $attrs, $model) -> editable = $attrs.editable? renderIssuestatus = (issue) -> owner = $scope.usersById?[issue.owner] date = moment(issue.created_date).format("DD MMM YYYY HH:mm") type = $scope.typeById[issue.type] status = $scope.statusById[issue.status] severity = $scope.severityById[issue.severity] priority = $scope.priorityById[issue.priority] html = template({ owner: owner date: date editable: editable status: status severity: severity priority: priority type: type }) $el.html(html) $el.find(".type-data").append(selectionTypeTemplate({types:$scope.typeList})) $el.find(".severity-data").append(selectionSeverityTemplate({severities:$scope.severityList})) $el.find(".priority-data").append(selectionPriorityTemplate({priorities:$scope.priorityList})) $el.find(".status-data").append(selectionStatusTemplate({statuses:$scope.statusList})) $scope.$watch $attrs.ngModel, (issue) -> if issue? renderIssuestatus(issue) if editable $el.on "click", ".type-data", (event) -> event.preventDefault() event.stopPropagation() $el.find(".pop-type").popover().open() $el.on "click", ".type", (event) -> event.preventDefault() event.stopPropagation() target = angular.element(event.currentTarget) $model.$modelValue.type = target.data("type-id") renderIssuestatus($model.$modelValue) $.fn.popover().closeAll() $el.on "click", ".severity-data", (event) -> event.preventDefault() event.stopPropagation() $el.find(".pop-severity").popover().open() $el.on "click", ".severity", (event) -> event.preventDefault() event.stopPropagation() target = angular.element(event.currentTarget) $model.$modelValue.severity = target.data("severity-id") renderIssuestatus($model.$modelValue) $.fn.popover().closeAll() $el.on "click", ".priority-data", (event) -> event.preventDefault() event.stopPropagation() $el.find(".pop-priority").popover().open() $el.on "click", ".priority", (event) -> event.preventDefault() event.stopPropagation() target = angular.element(event.currentTarget) $model.$modelValue.priority = target.data("priority-id") renderIssuestatus($model.$modelValue) $.fn.popover().closeAll() $el.on "click", ".status-data", (event) -> event.preventDefault() event.stopPropagation() $el.find(".pop-status").popover().open() $el.on "click", ".status", (event) -> event.preventDefault() event.stopPropagation() target = angular.element(event.currentTarget) $model.$modelValue.status = target.data("status-id") renderIssuestatus($model.$modelValue) $.fn.popover().closeAll() return {link:link, require:"ngModel"} module.directive("tgIssueStatus", IssueStatusDirective)