diff --git a/app/coffee/modules/resources/tasks.coffee b/app/coffee/modules/resources/tasks.coffee index 77198cdf..fffee166 100644 --- a/app/coffee/modules/resources/tasks.coffee +++ b/app/coffee/modules/resources/tasks.coffee @@ -22,7 +22,7 @@ taiga = @.taiga -resourceProvider = ($repo) -> +resourceProvider = ($repo, $http, $urls) -> service = {} service.list = (projectId, sprintId=null) -> @@ -30,9 +30,14 @@ resourceProvider = ($repo) -> params.milestone = sprintId if sprintId return $repo.queryMany("tasks", params) + service.bulkCreate = (projectId, usId, data) -> + url = $urls.resolve("bulk-create-tasks") + params = {projectId: projectId, usId: usId, bulkTasks: data} + return $http.post(url, params) + return (instance) -> instance.tasks = service module = angular.module("taigaResources") -module.factory("$tgTasksResourcesProvider", ["$tgRepo", resourceProvider]) +module.factory("$tgTasksResourcesProvider", ["$tgRepo", "$tgHttp", "$tgUrls", resourceProvider]) diff --git a/app/coffee/modules/taskboard/lightboxes.coffee b/app/coffee/modules/taskboard/lightboxes.coffee new file mode 100644 index 00000000..8721ba09 --- /dev/null +++ b/app/coffee/modules/taskboard/lightboxes.coffee @@ -0,0 +1,167 @@ +### +# 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/taskboard/lightboxes.coffee +### + +taiga = @.taiga +bindOnce = @.taiga.bindOnce + +CreateEditTaskDirective = ($repo, $model, $rs, $rootScope) -> + editDescription = ($scope, $el) -> + $el.find('.markdown-preview a').removeClass("active") + $el.find('.markdown-preview a.edit').addClass("active") + descriptionDOM = $el.find("textarea.description") + descriptionPreviewDOM = $el.find(".description-preview") + descriptionDOM.show() + descriptionPreviewDOM.hide() + + previewDescription = ($scope, $el) -> + $el.find('.markdown-preview a').removeClass("active") + $el.find('.markdown-preview a.preview').addClass("active") + descriptionDOM = $el.find("textarea.description") + descriptionPreviewDOM = $el.find(".description-preview") + $rs.mdrender.render($scope.projectId, $scope.task.description).then (data) -> + descriptionDOM.hide() + descriptionPreviewDOM.html(data.data) + descriptionPreviewDOM.show() + + link = ($scope, $el, attrs) -> + isNew = true + + $scope.$on "taskform:new", (ctx, sprintId, usId) -> + $scope.task = { + project: $scope.projectId + milestone: sprintId + user_story: usId + is_archived: false + status: $scope.project.default_task_status + } + isNew = true + editDescription($scope, $el) + # Update texts for creation + $el.find(".button-green span").html("Create") #TODO: i18n + $el.find(".title").html("New task ") #TODO: i18n + $el.removeClass("hidden") + + $scope.$on "taskform:edit", (ctx, task) -> + $scope.task = task + isNew = false + editDescription($scope, $el) + # Update texts for edition + $el.find(".button-green span").html("Save") #TODO: i18n + $el.find(".title").html("Edit task ") #TODO: i18n + $el.removeClass("hidden") + + # Update requirement info (team, client or blocked) + if task.is_blocked + $el.find(".blocked-note").show() + $el.find("label.blocked").addClass("selected") + if task.is_iocaine + $el.find("label.iocaine").addClass("selected") + + $scope.$on "$destroy", -> + $el.off() + + # Dom Event Handlers + + $el.on "click", ".markdown-preview a.edit", (event) -> + event.preventDefault() + editDescription($scope, $el) + + $el.on "click", ".markdown-preview a.preview", (event) -> + event.preventDefault() + previewDescription($scope, $el) + + $el.on "click", ".close", (event) -> + event.preventDefault() + $el.addClass("hidden") + + $el.on "click", ".button-green", (event) -> + event.preventDefault() + + form = $el.find("form").checksley() + if not form.validate() + return + + if isNew + promise = $repo.create("tasks", $scope.task) + broadcastEvent = "taskform:new:success" + else + promise = $repo.save($scope.task) + broadcastEvent = "taskform:edit:success" + + promise.then (data) -> + $el.addClass("hidden") + $rootScope.$broadcast(broadcastEvent, data) + + $el.on "click", "label.blocked", (event) -> + event.preventDefault() + target = angular.element(event.currentTarget) + target.toggleClass("selected") + $scope.us.is_blocked = not $scope.us.is_blocked + $el.find(".blocked-note").toggle(400) + + $el.on "click", "label.iocaine", (event) -> + event.preventDefault() + angular.element(event.currentTarget).toggleClass("selected") + $scope.task.is_iocaine = not $scope.task.is_iocaine + + $scope.$on "$destroy", -> + $el.off() + + return {link: link} + +CreateBulkTasksDirective = ($repo, $rs, $rootscope) -> + link = ($scope, $el, attrs) -> + $scope.form = {data: "", usId: null} + + $scope.$on "taskform:bulk", (ctx, usId)-> + $el.removeClass("hidden") + $scope.form = {data: "", usId: usId} + + $el.on "click", ".close", (event) -> + event.preventDefault() + $el.addClass("hidden") + + $el.on "click", ".button-green", (event) -> + event.preventDefault() + + form = $el.find("form").checksley() + if not form.validate() + return + + data = $scope.form.data + projectId = $scope.projectId + usId = $scope.form.usId + + $rs.tasks.bulkCreate(projectId, usId, data).then (result) -> + $rootscope.$broadcast("taskform:bulk:success", result) + $el.addClass("hidden") + + $scope.$on "$destroy", -> + $el.off() + + return {link: link} + + +module = angular.module("taigaTaskboard") +module.directive("tgLbCreateEditTask", ["$tgRepo", "$tgModel", "$tgResources", "$rootScope", + CreateEditTaskDirective]) +module.directive("tgLbCreateBulkTasks", ["$tgRepo", "$tgResources", "$rootScope", + CreateBulkTasksDirective]) diff --git a/app/coffee/modules/taskboard/main.coffee b/app/coffee/modules/taskboard/main.coffee index a6be5370..f40263bf 100644 --- a/app/coffee/modules/taskboard/main.coffee +++ b/app/coffee/modules/taskboard/main.coffee @@ -51,6 +51,13 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin) promise.then null, -> console.log "FAIL" #TODO + @scope.$on "taskform:new:success", => + @.loadTaskboard() + @scope.$on "taskform:bulk:success", => + @.loadTaskboard() + @scope.$on "taskform:edit:success", => + @.loadTaskboard() + loadSprintStats: -> return @rs.sprints.stats(@scope.projectId, @scope.sprintId).then (stats) => totalPointsSum =_.reduce(_.values(stats.total_points), ((res, n) -> res + n), 0) @@ -127,6 +134,16 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin) .then(=> @.loadUsersAndRoles()) .then(=> @.loadTaskboard()) + ## Template actions + + addNewTask: (type, us) -> + switch type + when "standard" then @rootscope.$broadcast("taskform:new", @scope.sprintId, us?.id) + when "bulk" then @rootscope.$broadcast("taskform:bulk", us.id) + + editTask: (task) -> + @rootscope.$broadcast("taskform:edit", task) + module.controller("TaskboardController", TaskboardController) diff --git a/app/partials/taskboard.jade b/app/partials/taskboard.jade index 0c41e6f7..4dee4fb6 100644 --- a/app/partials/taskboard.jade +++ b/app/partials/taskboard.jade @@ -14,3 +14,8 @@ block content include views/components/sprint-summary include views/modules/burndown include views/modules/taskboard-table + + div.lightbox.lightbox_add-new-us.hidden(tg-lb-create-edit-task) + include views/modules/lightbox_add-edit-task + div.lightbox.lightbox_add-bulk.hidden(tg-lb-create-bulk-tasks) + include views/modules/lightbox_add-task-bulk diff --git a/app/partials/views/components/addnewtask.jade b/app/partials/views/components/addnewtask.jade index 3635aa76..c7760fec 100644 --- a/app/partials/views/components/addnewtask.jade +++ b/app/partials/views/components/addnewtask.jade @@ -1,5 +1,7 @@ div.new-task - a.button.button-green(href="", ng-click="ctrl.addNewTask('standard', us)", title="Add new task") + a.button.button-green(href="", ng-click="ctrl.addNewTask('standard', us)", + title="Add new task") span.text + Add new Task - a.button.button-bulk(href="", ng-click="ctrl.addNewTask('bulk', us)", title="Add new tasks in bulk") + a.button.button-bulk(href="", ng-click="ctrl.addNewTask('bulk', us)", ng-if="us", + title="Add new tasks in bulk") span.icon.icon-bulk diff --git a/app/partials/views/components/taskboard-task.jade b/app/partials/views/components/taskboard-task.jade index c76f777d..96c92878 100644 --- a/app/partials/views/components/taskboard-task.jade +++ b/app/partials/views/components/taskboard-task.jade @@ -9,5 +9,5 @@ div.taskboard-task(ng-repeat="task in usTasks[us.id][st.id] track by task.id") p.taskboard-text span.task-num(ng-bind="task.ref") span.task-name(ng-bind="task.subject") - a.icon.icon-edit(href="", title="Edit") + a.icon.icon-edit(href="", title="Edit", ng-click="ctrl.editTask(task)") a.icon.icon-drag-h(href="", title="Drag&Drop") diff --git a/app/partials/views/modules/lightbox_add-edit-task.jade b/app/partials/views/modules/lightbox_add-edit-task.jade new file mode 100644 index 00000000..5e630048 --- /dev/null +++ b/app/partials/views/modules/lightbox_add-edit-task.jade @@ -0,0 +1,34 @@ +a.close(href="", title="close") + span.icon.icon-delete +form + h2.title(tg-i18n="task.title-new") + fieldset + input(type="text", ng-model="task.subject", placeholder="A task subject", data-required="true") + fieldset + select(ng-model="task.status", ng-options="s.id as s.name for s in taskStatusList", + placeholder="Task status") + // TODO: Assigned to + //fieldset + // select(ng-model="task.assigned_to", ng-options="s.id as s.full_name for s in userList", + // placeholder="Assigned to") + // option(value)------- + fieldset + input(type="text", placeholder="Tags", tg-tags, ng-model="task.tags") + fieldset + div.markdown-preview + a.edit.active(href="", title="Edit") Edit + a.preview(href="", title="Preview") Preview + textarea.description(placeholder="Type a short description", ng-model="task.description") + div.description-preview.hidden + div.new-us-settings + fieldset + label.iocaine(for="iocaine-task icon-iocaine" data-icon="r") Iocaine + input(type="checkbox", ng-model="task.is_iocaine", name="iocaine-task", id="iocaine-task") + fieldset + label.blocked(for="blocked-task") Blocked + input(type="checkbox", ng-model="task.is_blocked", name="blocked-task", id="blocked-task") + fieldset.blocked-note.hidden + textarea(placeholder="Why is this task blocked?", ng-model="task.blocked_note") + + a.button.button-green(href="", title="Save") + span Create diff --git a/app/partials/views/modules/lightbox_add-task-bulk.jade b/app/partials/views/modules/lightbox_add-task-bulk.jade new file mode 100644 index 00000000..c0ef989d --- /dev/null +++ b/app/partials/views/modules/lightbox_add-task-bulk.jade @@ -0,0 +1,8 @@ +a.close(href="", title="close") + span.icon.icon-delete +form + h2.title(tg-i18n="common.new-bulk") + fieldset + textarea(tg-i18n="placeholder:common.one-item-line", ng-model="form.data", data-required="true") + a.button.button-green(href="", tg-i18n="title:common.save") + span(tg-i18n="common.save") diff --git a/app/styles/modules/lightbox.scss b/app/styles/modules/lightbox.scss index 7e2f1053..6a48f1b3 100644 --- a/app/styles/modules/lightbox.scss +++ b/app/styles/modules/lightbox.scss @@ -96,7 +96,7 @@ cursor: pointer; display: block; } - .requirement { + .requirement, .iocaine { &:hover { @include transition(all .2s ease-in); background: $fresh-taiga;