From 0f32cbe23767676deb04fe6399e58bf18ea15cec Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 18 Nov 2014 10:14:33 +0100 Subject: [PATCH 01/66] User story points are undefined if the task points are undefined --- app/coffee/modules/backlog/main.coffee | 5 +++-- app/coffee/modules/common/estimation.coffee | 11 ++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/coffee/modules/backlog/main.coffee b/app/coffee/modules/backlog/main.coffee index 080f5d1e..87ae636a 100644 --- a/app/coffee/modules/backlog/main.coffee +++ b/app/coffee/modules/backlog/main.coffee @@ -828,8 +828,9 @@ UsPointsDirective = ($repo) -> dom = $el.find("a > span.points-value") if roleId == null or numberOfRoles == 1 - dom.text(us.total_points) - dom.parent().prop("title", us.total_points) + totalPoints = if us.total_points? then us.total_points else "?" + dom.text(totalPoints) + dom.parent().prop("title", totalPoints) else pointId = us.points[roleId] pointObj = $scope.pointsById[pointId] diff --git a/app/coffee/modules/common/estimation.coffee b/app/coffee/modules/common/estimation.coffee index 48474107..6449fe5e 100644 --- a/app/coffee/modules/common/estimation.coffee +++ b/app/coffee/modules/common/estimation.coffee @@ -210,7 +210,7 @@ UsEstimationDirective = ($rootScope, $repo, $confirm) -> return $scope.project.my_permissions.indexOf("modify_us") != -1 render = (us) -> - totalPoints = us.total_points or 0 + totalPoints = if us.total_points? then us.total_points else "?" computableRoles = _.filter($scope.project.roles, "computable") roles = _.map computableRoles, (role) -> @@ -254,10 +254,15 @@ UsEstimationDirective = ($rootScope, $repo, $confirm) -> $el.find(".pop-points-open").show() calculateTotalPoints = (us) -> - values = _.map(us.points, (v, k) -> $scope.pointsById[v]?.value or 0) + values = _.map(us.points, (v, k) -> $scope.pointsById[v]?.value) if values.length == 0 return "0" - return _.reduce(values, (acc, num) -> acc + num) + + notNullValues = _.filter(values, (v) -> v?) + if notNullValues.length == 0 + return "?" + + return _.reduce(notNullValues, (acc, num) -> acc + num) $el.on "click", ".total.clickable", (event) -> event.preventDefault() From 87e76e6c588635686649a0138a625f4152afd835 Mon Sep 17 00:00:00 2001 From: Juanfran Date: Wed, 19 Nov 2014 18:03:05 +0100 Subject: [PATCH 02/66] fix #1622 refresh tags colors after create an US with a new tag --- app/coffee/modules/common/tags.coffee | 2 +- app/coffee/modules/kanban/main.coffee | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/coffee/modules/common/tags.coffee b/app/coffee/modules/common/tags.coffee index 97aa8fd6..3e910882 100644 --- a/app/coffee/modules/common/tags.coffee +++ b/app/coffee/modules/common/tags.coffee @@ -111,7 +111,7 @@ LbTagLineDirective = ($rs) -> # Tags template (rendered manually using lodash) templateTags = _.template(""" <% _.each(tags, function(tag) { %> - + style="border-left: 5px solid <%- tag.color %>;"<% } %>> <%- tag.name %> diff --git a/app/coffee/modules/kanban/main.coffee b/app/coffee/modules/kanban/main.coffee index 32acbd99..d8ba9db5 100644 --- a/app/coffee/modules/kanban/main.coffee +++ b/app/coffee/modules/kanban/main.coffee @@ -83,13 +83,17 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi initializeEventHandlers: -> @scope.$on "usform:new:success", => @.loadUserstories() + @.refreshTagsColors() @analytics.trackEvent("userstory", "create", "create userstory on kanban", 1) @scope.$on "usform:bulk:success", => @.loadUserstories() @analytics.trackEvent("userstory", "create", "bulk create userstory on kanban", 1) - @scope.$on("usform:edit:success", @.loadUserstories) + @scope.$on "usform:edit:success", => + @.loadUserstories() + @.refreshTagsColors() + @scope.$on("assigned-to:added", @.onAssignedToChanged) @scope.$on("kanban:us:move", @.moveUs) From 18a4e82c36b877a52a37a2c23b10d172413d331f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Wed, 19 Nov 2014 18:48:02 +0100 Subject: [PATCH 03/66] Fix broken video icon --- app/fonts/taiga.eot | Bin 7828 -> 7940 bytes app/fonts/taiga.svg | 1 + app/fonts/taiga.ttf | Bin 7672 -> 7784 bytes app/fonts/taiga.woff | Bin 5608 -> 5680 bytes app/styles/layout/typography.scss | 4 +++- 5 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/fonts/taiga.eot b/app/fonts/taiga.eot index 3993e361c0af9cdb41f1e4a970425f34a4692824..8abe260c89ae6ed7ff47d62b2d700dbe8ffd7a97 100644 GIT binary patch delta 419 zcmYk0u}d3q9L3-FF1cRFg*G&a;hH;*30KLg&jG#+pinh7OswM&prNj< zW>iaWj`I;9lmckkTv}OmesfxYasuEB2U|Sesj=_*s^B6DJLw6&%iBL3`Y93 z45iY^a3bKR)7t}Cd)CuDl{L-j5t~-bB}p!-h#s;vxr5+i%hF_9)^0CdQl%ofY|-Np j*<9!k4YO$_M#Icf)<|d9$~#K3oT^Zq)zl~Md-wkVT7+hh delta 309 zcmYj~JxfAy9EG3X^`*cemq5@fZ9xi=Lxf~B^x_hdLS+bf(W?!bH`K6NTiTMp;8LH$ z+JYQhLIfRJqMZ5wAp}hs4nYSF&v4*5S8I)kv*Cwtz3yDL_qyR|eZ82meoWBc0N?h; z<`zkupg#h0vBY91_MUnIIRN%DMZ=QaK?*cCNIY+pt??Ke==Z>MzHpwK>fbzrtqmUg zv1w$rrJAYSGH<2}rHpa;Q5}IT3mg`Wn#CDSkd?{XiBUB7@8YxI?SPzGrEOyop_Q!0u!#Kcol diff --git a/app/fonts/taiga.svg b/app/fonts/taiga.svg index f347cfdc..7732be66 100644 --- a/app/fonts/taiga.svg +++ b/app/fonts/taiga.svg @@ -48,4 +48,5 @@ + diff --git a/app/fonts/taiga.ttf b/app/fonts/taiga.ttf index a41437dd495b43a16038c8eaf56cead78a73da3d..1f7c068fca3842558f300f9a7cd3ce1e9b7d7075 100644 GIT binary patch delta 493 zcmXw$OK1}T6h+UQapHtdw8f-`aT@H00ZoFC#MolfRU0>!mMDHoP{$e@NMlD@QBg=x za4Fcq&&IvbWi~<=%|hHNXi-6N(}j?=AVNDbk-W|2!F}9&cz;g+nrt9IgeEHU#p3x{ z_wlDqNSp<%Gt)Cg76?Hi1st6_cOoN|+L)rxaNnV#JQz61GcweqZCRjx0uEIJQ%9vug@3Y6>4J(s(@1Q`!< zZ#nhK#n+`#uyP=`-Idif?UmMqp*O(8E`vb&TWIU*!O7qBDFpLz{mHeSu1i7E-jr+$ zUcZu-d2dQtlT@pv^oe4Ox7w-}Z*H&#$;pfxoICe+}<#4TZ`!JW-@FTVX5g6>DZ=E{7|!Ln;p~M+YTGGni1~k zk%$f$yy!LuLBl}2uSb5$g!k4;%7nLL-I27nFm!n)8#sI)rRzQb#JhOGu98C72mD74 OzR8Cx@Bj9=d-@N|wrh+4 delta 363 zcmXw#Jxf9X6o#L3uT~&^ERmoW8Y6{BD59((%38!S=?keYdecGkh8k8wt!>pEoca|O zEkO+uR75qj)z;7~1ksRj4bSp&IPg52_cQoCc7Oow9HKH83dO>v`D=jo26$(trbDdI z0@@YO8(A0#MBd}qAj`mFBCDG+{}KnK3nZG-^Jcw{3fei)mdfmIwmu){eBr!p>nYeHVF9;II*)}&GpDwm2&6sS~Hr`sCx x)+Au{X+8;9F|8t0)#wgFPFqckiXfV%;=cNHIk1Nax(UGlVc`_r^G^AEzYQ#k+t diff --git a/app/fonts/taiga.woff b/app/fonts/taiga.woff index 383aba436ebe9c4b575f060a1d18c44e54eb87c1..27eb9460b92f9f1638876ac0fb9b4991b700dd39 100644 GIT binary patch delta 5434 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 Date: Wed, 19 Nov 2014 18:57:55 +0100 Subject: [PATCH 04/66] Fix manage members page bug on very small resolutions --- app/styles/modules/admin/admin-membership-table.scss | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/styles/modules/admin/admin-membership-table.scss b/app/styles/modules/admin/admin-membership-table.scss index 1c354b20..6e15db4d 100644 --- a/app/styles/modules/admin/admin-membership-table.scss +++ b/app/styles/modules/admin/admin-membership-table.scss @@ -78,11 +78,13 @@ .row-role, .header-member, .header-role { - @include table-flex-child(4, 0, 0); + @include table-flex-child(3, 0, 0); + min-width: 210px; } .row-admin, .header-admin { @include table-flex-child(1, 0, 0); + min-width: 70px; } .row-status, .header-status { From c970adbec21602141d4df353818c3eca969599c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Wed, 19 Nov 2014 18:29:21 +0100 Subject: [PATCH 05/66] Fix admin layout in safari and other browsers --- app/coffee/modules/admin/roles.coffee | 3 ++- app/coffee/modules/common/lightboxes.coffee | 1 - app/styles/modules/admin/admin-roles.scss | 6 +++--- app/styles/modules/common/category-config.scss | 16 +++++++++------- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/app/coffee/modules/admin/roles.coffee b/app/coffee/modules/admin/roles.coffee index 3a9111c2..99bae6e1 100644 --- a/app/coffee/modules/admin/roles.coffee +++ b/app/coffee/modules/admin/roles.coffee @@ -251,7 +251,8 @@ RolePermissionsDirective = ($rootscope, $repo, $confirm) ->
<% _.each(category.permissions, function(permission) { %> -
<%- permission.description %> +
+ <%- permission.description %>
checked="checked"<% } %>/>
diff --git a/app/coffee/modules/common/lightboxes.coffee b/app/coffee/modules/common/lightboxes.coffee index a8c33c7b..59b06a7d 100644 --- a/app/coffee/modules/common/lightboxes.coffee +++ b/app/coffee/modules/common/lightboxes.coffee @@ -44,7 +44,6 @@ class LightboxService extends taiga.Service docEl = angular.element(document) docEl.off(".lightbox") docEl.off(".keyboard-navigation") # Hack: to fix problems in the WYSIWYG textareas when press ENTER - $el.one "transitionend", => $el.removeAttr('style') $el.removeClass("open").removeClass('close') diff --git a/app/styles/modules/admin/admin-roles.scss b/app/styles/modules/admin/admin-roles.scss index 29199cc9..5992dc79 100644 --- a/app/styles/modules/admin/admin-roles.scss +++ b/app/styles/modules/admin/admin-roles.scss @@ -39,9 +39,9 @@ padding: .5rem; } .general-category { - align-items: center; - display: flex; - justify-content: flex-end; + @include display(flex); + @include align-items(center); + @include justify-content(flex-end); padding-bottom: 2rem; .check { margin-left: .5rem; diff --git a/app/styles/modules/common/category-config.scss b/app/styles/modules/common/category-config.scss index cd1e831a..0eac6075 100644 --- a/app/styles/modules/common/category-config.scss +++ b/app/styles/modules/common/category-config.scss @@ -4,13 +4,14 @@ border-top: 1px solid $gray-light; } .resume { - @include table-flex($align-items: center); + @include display(flex); + @include align-items(space-between); cursor: pointer; padding: 1rem; position: relative; } .resume-title { - @include table-flex-child(1, 280px, 0); + width: 280px; } .count { color: $gray-light; @@ -18,7 +19,8 @@ padding-right: 5px; } .summary-role { - @include table-flex-child(3, 280px, 0); + @include flex(1); + width: 280px; .role-summary-single { background: $gray-light; display: inline-block; @@ -34,7 +36,7 @@ } } .icon { - @include table-flex-child(1, 0, 0); + @include flex(1); @extend %xlarge; text-align: right; } @@ -47,10 +49,10 @@ } } .category-item { - align-items: center; + @include display(flex); + @include justify-content(space-between); + @include align-items(center); border-bottom: 1px solid $very-light-gray; - display: flex; - justify-content: space-between; padding: .5rem .5rem .5rem 2rem; &:last-child { border-bottom: 0; From c344152f32ce312e4a1bdac455a6ad8f4d0d569f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Wed, 19 Nov 2014 18:00:48 +0100 Subject: [PATCH 06/66] Change show/hide to add/removeClass in meetup button --- app/coffee/modules/admin/project-profile.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/coffee/modules/admin/project-profile.coffee b/app/coffee/modules/admin/project-profile.coffee index 3c1b3505..499452cb 100644 --- a/app/coffee/modules/admin/project-profile.coffee +++ b/app/coffee/modules/admin/project-profile.coffee @@ -165,9 +165,9 @@ ProjectModulesDirective = ($repo, $confirm, $loading) -> $scope.$watch "isVideoconferenceActivated", (isVideoconferenceActivated) -> if isVideoconferenceActivated - $el.find(".videoconference-attributes").show() + $el.find(".videoconference-attributes").removeClass("hidden") else - $el.find(".videoconference-attributes").hide() + $el.find(".videoconference-attributes").addClass("hidden") $scope.project.videoconferences = null $scope.project.videoconferences_salt = "" From cc177430451dc48656c0c8f4cd71afbffbc04a60 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 19 Nov 2014 19:34:03 +0100 Subject: [PATCH 07/66] Add the ability to disable events and use relative url in config. --- app/coffee/modules/events.coffee | 14 +++++++++++++- app/coffee/utils.coffee | 3 +++ conf/main.example.json | 4 ++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/app/coffee/modules/events.coffee b/app/coffee/modules/events.coffee index 08445607..f167fcfe 100644 --- a/app/coffee/modules/events.coffee +++ b/app/coffee/modules/events.coffee @@ -20,6 +20,7 @@ ### taiga = @.taiga +startswith = @.taiga.startswith module = angular.module("taigaEvents", []) @@ -41,7 +42,18 @@ class EventsService setupConnection: -> @.stopExistingConnection() - url = @config.get("eventsUrl", "ws://localhost:8888/events") + url = @config.get("eventsUrl") + + # This allows disable events in case + # url is not found on the configuration. + return if not url + + # This allows relative urls in configuration. + if not startswith(url, "ws:") and not startswith(url, "wss:") + loc = @win.location + scheme = if loc.protocol == "https:" then "wss:" else "ws:" + path = _.str.ltrim(url, "/") + url = "#{scheme}//#{loc.host}/#{path}" @.ws = new @win.WebSocket(url) @.ws.addEventListener("open", @.onOpen) diff --git a/app/coffee/utils.coffee b/app/coffee/utils.coffee index b7150637..455211bf 100644 --- a/app/coffee/utils.coffee +++ b/app/coffee/utils.coffee @@ -23,6 +23,7 @@ nl2br = (str) => breakTag = '
' return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2') + bindOnce = (scope, attr, continuation) => val = scope.$eval(attr) if val != undefined @@ -106,9 +107,11 @@ joinStr = (str, coll) -> debounce = (wait, func) -> return _.debounce(func, wait, {leading: true, trailing: false}) + debounceLeading = (wait, func) -> return _.debounce(func, wait, {leading: false, trailing: true}) + startswith = (str1, str2) -> return _.str.startsWith(str1, str2) diff --git a/conf/main.example.json b/conf/main.example.json index e40d5dcd..181dc694 100644 --- a/conf/main.example.json +++ b/conf/main.example.json @@ -1,7 +1,7 @@ { "api": "http://localhost:8000/api/v1/", - "eventsUrl": "ws://localhost:8888/events", - "debug": "true", + "eventsUrl": null, + "debug": true, "publicRegisterEnabled": true, "feedbackEnabled": true, "privacyPolicyUrl": null, From e43a4205e726f9f0c9ca41791a53b4b03f233753 Mon Sep 17 00:00:00 2001 From: Florian Bezagu Date: Wed, 26 Nov 2014 21:19:04 +0100 Subject: [PATCH 08/66] Catch submit event of form to create and edit task MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows to use « enter » to create or edit a task because there is a new event caught, the submit one. --- app/coffee/modules/taskboard/lightboxes.coffee | 12 +++++++++--- .../views/modules/lightbox-task-create-edit.jade | 1 + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/coffee/modules/taskboard/lightboxes.coffee b/app/coffee/modules/taskboard/lightboxes.coffee index 6a1c09f0..68ac79c5 100644 --- a/app/coffee/modules/taskboard/lightboxes.coffee +++ b/app/coffee/modules/taskboard/lightboxes.coffee @@ -54,6 +54,15 @@ CreateEditTaskDirective = ($repo, $model, $rs, $rootscope, lightboxService) -> lightboxService.open($el) $el.on "click", ".button-green", debounce 2000, (event) -> + formSubmitted event + + $el.on "submit", "form", debounce 2000, (event) -> + formSubmitted event + + $scope.$on "$destroy", -> + $el.off() + + formSubmitted = (event) -> event.preventDefault() form = $el.find("form").checksley() @@ -72,9 +81,6 @@ CreateEditTaskDirective = ($repo, $model, $rs, $rootscope, lightboxService) -> lightboxService.close($el) $rootscope.$broadcast(broadcastEvent, data) - $scope.$on "$destroy", -> - $el.off() - return {link: link} diff --git a/app/partials/views/modules/lightbox-task-create-edit.jade b/app/partials/views/modules/lightbox-task-create-edit.jade index 96772bd8..bc363077 100644 --- a/app/partials/views/modules/lightbox-task-create-edit.jade +++ b/app/partials/views/modules/lightbox-task-create-edit.jade @@ -34,5 +34,6 @@ form tg-blocking-message-input(watch="task.is_blocked", ng-model="task.blocked_note") + button(title="Save" style="display: none;") a.button.button-green(href="", title="Save") span Create From 2b61b88564a4b8381623cfb51d21a8ef83cd981f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Thu, 27 Nov 2014 10:14:20 +0100 Subject: [PATCH 09/66] Add help icon --- app/fonts/taiga.eot | Bin 7940 -> 9080 bytes app/fonts/taiga.svg | 5 +++++ app/fonts/taiga.ttf | Bin 7784 -> 8924 bytes app/fonts/taiga.woff | Bin 5680 -> 6500 bytes app/styles/layout/typography.scss | 3 +++ 5 files changed, 8 insertions(+) diff --git a/app/fonts/taiga.eot b/app/fonts/taiga.eot index 8abe260c89ae6ed7ff47d62b2d700dbe8ffd7a97..23a31f5b8f977c8eef56e25b0a2b1b9ac014bbe3 100644 GIT binary patch delta 1488 zcmY*ZO^g&p6n?L&x~h7nyLxthx_4)~XLq}2y7}8->DlQf!CfFKxL!yEl>`!8U;&Y3 zm#hdTgt-_EN0b-p5tM`)k zrRtrjKezCc0l*LbS)Q;P^QRx4-88rF{9h*k{F?yaZhh|gEwBeTfd4T7jBMM!Hs1E* z?ymrFCjh*%Z*FE`?R#Ti0uUDfUphFmxbWx^PyqjZ0FVcdynW#A>+PQb=yw3_twXaj z`^nD56TJd@-4C@p0C*JujvSfaH*@*hk2V3&1pqiOH*<0UPQiHqT%YwlIx{!>>c#ED z03#Ow@Yurq;+uS<_A7v20DyM^0kZw@^!$xI)-!)VodlM%hJD!!OLHVT=@HSB|+>L88zEA(9D{>L)~6wTTpEAyII>DC*j!f@JIx8`erf z2+Sy6FH%HSl#(;VQJdvli|YoLejucwbIZ*!*QJb0Sp;AJFx{7oLJfu?1t_&UfmZ33 z1rJ93D4fK0rR>-nFiw+63@SmVSsCq2q{#+cK4ZuBupK-0^>gQN+Ek^b-6dt-)CAwn zg;skJn@eD-(terCUC!m?{*p5BdgI=ilBtwgI@97p(*$odn`e$5Et#s7mr}}nx1~%# z*Z~ATBLL3=q&x~cNgAfMV>@Jv(wpUrYSgF_hw6c}5m#)kC9(YWwa2!reew zS9?b%Ll_W_0u}MT+WPoQG7mBc^rteGEs5_WXr&;DX=~ng9CQd*1A*z8m8sIly?f9v zA!w&3tqHBY=Ry@rXk*=90&)h7&&;K))z_^W(9=LNV=db(aR}1na%Zi~ + + + + + diff --git a/app/fonts/taiga.ttf b/app/fonts/taiga.ttf index 1f7c068fca3842558f300f9a7cd3ce1e9b7d7075..1408dd80a3355622174e91fc0e37c37b83888f6a 100644 GIT binary patch delta 1542 zcmY*ZO^g&p7=2$=cU8?yclGT2bnnh~&qB{kH-bB?Jv-ebu#2dmYho~hN&?X=val)( zYf!<2IG!|I*@F^)A_>upF)9b5G0_;}!HXUwQNf>ti!oj_@t}!ddR8HJC0$>=_f>V* z_wv1;w_Mpi00FS^0yys9v19jr%P;?V90)%J;NN}M_8oW>0tnv(ux973jmggM_k9A; z9smzLwlu%I@ukU+0OkYqz@hnL%h#`i1K}$G)S<)A9sKU`-cJDk2JkN~F3cZbdyX9k za0NiRxVSKwH>MZ|s0N_Dxb*ai;;ZH*fZhXe`0&xk=Fffo`t1N;25@j`{=_m);$?s~ zAW^qaQx%Z21EvhWz>JwKKD; zGdnYTnr0|jnWamGIRLv6ptDkAll0)q9qbu%vb%BWw(}n|MV9r8y~#dj|Dg8+=P&Z7 zMh6UYxQ8y#xA5^SP}MX+ZZAobye4Hynz>%S-A%JJb9+hV=5QKEaXQF`X!My?AR6zFu2V`j0?8YW zZE9_)qSN5wDpO2o#~Cqlyr9geTb7C@BVLr+X>eo2aV)_EtBy1BYfLbuRngaC%u>9) zVX|dPYfNarP$~yKb!}qx%l&Sy*fH?*RaExOD z8Bp!@TV{PwlcKdYjH4Oq)oY%+nUXA>p;o=s@6^}!r?Yf3t-ce_4XBrR?uFB*Y0lQw zYx}C&{?wFWpOEJGz0|n|TUQULV)0zDs18)MO&8jiPgQNL?dqwnkftd`x6?UwhcR+xyUk4ldoCYvD#PT)AZJ=T6tXf`f^Z4?S N&;QEjoBnrZ_8&Ke;2i(} delta 369 zcmY+APbhamr zqjIENcP)iYwNGLQuYVO>gfqMjS4F!TBrg4C~ z9q@$5I=aIzu?vtXU?P#xO^JTRKsiC8DSgHK{ze0L3s99xuPr(scJDyDga*?{>I*6` zdImfLy@rw8(ruke191W^MkZIN-n7?)oB;FbY(igu-EITT0Ad-vV6w^qNMEJUlAcLU zmZQz!>H%3cvnx6Kp}h!=$H2z#I04_2<6^F^|AQJu1vmSp_#dlMd|w8{XAR1|V7Zh} zBG$0V+kbVZm#RumAGPHMtL%B#y6{_jO>L^nZ=E;g#b2K9_4!W K>hph8DgFbE3RVpO diff --git a/app/fonts/taiga.woff b/app/fonts/taiga.woff index 27eb9460b92f9f1638876ac0fb9b4991b700dd39..64897ab71fd47de3e91f2e45a8c303e300e4e1fe 100644 GIT binary patch delta 6304 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 W004NLV_;@L28;{`XaE2JjsOL77v4eu delta 5450 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 Date: Wed, 26 Nov 2014 11:56:26 +0100 Subject: [PATCH 10/66] angular1.3 --- app/coffee/app.coffee | 28 +++++++++++-------- app/coffee/modules/admin/memberships.coffee | 3 +- app/coffee/modules/admin/roles.coffee | 3 +- app/coffee/modules/admin/third-parties.coffee | 3 +- app/coffee/modules/backlog/main.coffee | 4 ++- app/coffee/modules/base/repository.coffee | 1 + app/coffee/modules/common/attachments.coffee | 3 +- app/coffee/modules/common/confirm.coffee | 4 +-- app/coffee/modules/events.coffee | 3 +- app/coffee/modules/kanban/main.coffee | 5 +++- app/coffee/modules/taskboard/main.coffee | 3 +- app/coffee/utils.coffee | 11 ++++++++ app/partials/issues-detail.jade | 2 +- bower.json | 13 +++++---- 14 files changed, 57 insertions(+), 29 deletions(-) diff --git a/app/coffee/app.coffee b/app/coffee/app.coffee index 0b014ad3..76af3789 100644 --- a/app/coffee/app.coffee +++ b/app/coffee/app.coffee @@ -134,7 +134,7 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven {templateUrl: "/partials/permission-denied.html"}) $routeProvider.otherwise({redirectTo: '/not-found'}) - $locationProvider.html5Mode(true) + $locationProvider.html5Mode({enabled: true, requireBase: false}) defaultHeaders = { "Content-Type": "application/json" @@ -154,20 +154,24 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven # Add next param when user try to access to a secction need auth permissions. authHttpIntercept = ($q, $location, $confirm, $navUrls, $lightboxService) -> - return (promise) -> - return promise.then null, (response) -> - if response.status == 0 - $lightboxService.closeAll() - $location.path($navUrls.resolve("error")) - $location.replace() - else if response.status == 401 - nextPath = $location.path() - $location.url($navUrls.resolve("login")).search("next=#{nextPath}") - return $q.reject(response) + httpResponseError = (response) -> + if response.status == 0 + $lightboxService.closeAll() + $location.path($navUrls.resolve("error")) + $location.replace() + else if response.status == 401 + nextPath = $location.path() + $location.url($navUrls.resolve("login")).search("next=#{nextPath}") + return $q.reject(response) + + return { + responseError: httpResponseError + } $provide.factory("authHttpIntercept", ["$q", "$location", "$tgConfirm", "$tgNavUrls", "lightboxService", authHttpIntercept]) - $httpProvider.responseInterceptors.push('authHttpIntercept') + + $httpProvider.interceptors.push('authHttpIntercept'); window.checksley.updateValidators({ linewidth: (val, width) -> diff --git a/app/coffee/modules/admin/memberships.coffee b/app/coffee/modules/admin/memberships.coffee index c337fbbe..631feb50 100644 --- a/app/coffee/modules/admin/memberships.coffee +++ b/app/coffee/modules/admin/memberships.coffee @@ -22,6 +22,7 @@ taiga = @.taiga mixOf = @.taiga.mixOf +bindMethods = @.taiga.bindMethods module = angular.module("taigaAdmin") @@ -47,7 +48,7 @@ class MembershipsController extends mixOf(taiga.Controller, taiga.PageMixin, tai constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @analytics, @appTitle) -> - _.bindAll(@) + bindMethods(@) @scope.sectionName = "Manage Members" #i18n @scope.project = {} diff --git a/app/coffee/modules/admin/roles.coffee b/app/coffee/modules/admin/roles.coffee index 99bae6e1..6174e69e 100644 --- a/app/coffee/modules/admin/roles.coffee +++ b/app/coffee/modules/admin/roles.coffee @@ -24,6 +24,7 @@ taiga = @.taiga mixOf = @.taiga.mixOf bindOnce = @.taiga.bindOnce debounce = @.taiga.debounce +bindMethods = @.taiga.bindMethods module = angular.module("taigaAdmin") @@ -47,7 +48,7 @@ class RolesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fil ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @appTitle) -> - _.bindAll(@) + bindMethods(@) @scope.sectionName = "Permissions" #i18n @scope.project = {} diff --git a/app/coffee/modules/admin/third-parties.coffee b/app/coffee/modules/admin/third-parties.coffee index 44c4782c..c8aa1b3d 100644 --- a/app/coffee/modules/admin/third-parties.coffee +++ b/app/coffee/modules/admin/third-parties.coffee @@ -22,6 +22,7 @@ taiga = @.taiga mixOf = @.taiga.mixOf +bindMethods = @.taiga.bindMethods module = angular.module("taigaAdmin") @@ -40,7 +41,7 @@ class GithubController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi ] constructor: (@scope, @repo, @rs, @params, @appTitle) -> - _.bindAll(@) + bindMethods(@) @scope.sectionName = "Github" #i18n @scope.project = {} diff --git a/app/coffee/modules/backlog/main.coffee b/app/coffee/modules/backlog/main.coffee index 87ae636a..2cca43de 100644 --- a/app/coffee/modules/backlog/main.coffee +++ b/app/coffee/modules/backlog/main.coffee @@ -27,6 +27,7 @@ scopeDefer = @.taiga.scopeDefer bindOnce = @.taiga.bindOnce groupBy = @.taiga.groupBy timeout = @.taiga.timeout +bindMethods = @.taiga.bindMethods module = angular.module("taigaBacklog") @@ -53,7 +54,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @appTitle, @navUrls, @events, @analytics, tgLoader) -> - _.bindAll(@) + bindMethods(@) @scope.sectionName = "Backlog" @showTags = false @@ -444,6 +445,7 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F return obj plainStatuses = _.map(@scope.userstories, "status") + plainStatuses = _.filter plainStatuses, (status) => if status return status diff --git a/app/coffee/modules/base/repository.coffee b/app/coffee/modules/base/repository.coffee index 9241975a..0cbf7348 100644 --- a/app/coffee/modules/base/repository.coffee +++ b/app/coffee/modules/base/repository.coffee @@ -143,6 +143,7 @@ class RepositoryService extends taiga.Service queryMany: (name, params, options={}) -> url = @urls.resolve(name) httpOptions = {headers: {}} + if not options.enablePagination httpOptions.headers["x-disable-pagination"] = "1" diff --git a/app/coffee/modules/common/attachments.coffee b/app/coffee/modules/common/attachments.coffee index 05951831..2a082259 100644 --- a/app/coffee/modules/common/attachments.coffee +++ b/app/coffee/modules/common/attachments.coffee @@ -22,6 +22,7 @@ taiga = @.taiga sizeFormat = @.taiga.sizeFormat bindOnce = @.taiga.bindOnce +bindMethods = @.taiga.bindMethods module = angular.module("taigaCommon") @@ -30,7 +31,7 @@ class AttachmentsController extends taiga.Controller @.$inject = ["$scope", "$rootScope", "$tgRepo", "$tgResources", "$tgConfirm", "$q"] constructor: (@scope, @rootscope, @repo, @rs, @confirm, @q) -> - _.bindAll(@) + bindMethods(@) @.type = null @.objectId = null @.projectId = null diff --git a/app/coffee/modules/common/confirm.coffee b/app/coffee/modules/common/confirm.coffee index 81679f42..ce93c707 100644 --- a/app/coffee/modules/common/confirm.coffee +++ b/app/coffee/modules/common/confirm.coffee @@ -23,7 +23,7 @@ taiga = @.taiga timeout = @.taiga.timeout cancelTimeout = @.taiga.cancelTimeout debounce = @.taiga.debounce - +bindMethods = @.taiga.bindMethods NOTIFICATION_MSG = { "success": @@ -42,7 +42,7 @@ class ConfirmService extends taiga.Service @.$inject = ["$q", "lightboxService", "$tgLoading"] constructor: (@q, @lightboxService, @loading) -> - _.bindAll(@) + bindMethods(@) hide: (el)-> if el diff --git a/app/coffee/modules/events.coffee b/app/coffee/modules/events.coffee index f167fcfe..bd8923c1 100644 --- a/app/coffee/modules/events.coffee +++ b/app/coffee/modules/events.coffee @@ -21,13 +21,14 @@ taiga = @.taiga startswith = @.taiga.startswith +bindMethods = @.taiga.bindMethods module = angular.module("taigaEvents", []) class EventsService constructor: (@win, @log, @config, @auth) -> - _.bindAll(@) + bindMethods(@) initialize: (sessionId) -> @.sessionId = sessionId diff --git a/app/coffee/modules/kanban/main.coffee b/app/coffee/modules/kanban/main.coffee index d8ba9db5..7f64a924 100644 --- a/app/coffee/modules/kanban/main.coffee +++ b/app/coffee/modules/kanban/main.coffee @@ -27,6 +27,7 @@ scopeDefer = @.taiga.scopeDefer bindOnce = @.taiga.bindOnce groupBy = @.taiga.groupBy timeout = @.taiga.timeout +bindMethods = @.taiga.bindMethods module = angular.module("taigaKanban") @@ -66,7 +67,9 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @appTitle, @navUrls, @events, @analytics, tgLoader) -> - _.bindAll(@) + + bindMethods(@) + @scope.sectionName = "Kanban" @scope.statusViewModes = {} @.initializeEventHandlers() diff --git a/app/coffee/modules/taskboard/main.coffee b/app/coffee/modules/taskboard/main.coffee index 331a69b2..f1b46ccc 100644 --- a/app/coffee/modules/taskboard/main.coffee +++ b/app/coffee/modules/taskboard/main.coffee @@ -26,6 +26,7 @@ groupBy = @.taiga.groupBy bindOnce = @.taiga.bindOnce scopeDefer = @.taiga.scopeDefer timeout = @.taiga.timeout +bindMethods = @.taiga.bindMethods module = angular.module("taigaTaskboard") @@ -53,7 +54,7 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin) constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @appTitle, @location, @navUrls, @events, @analytics, tgLoader) -> - _.bindAll(@) + bindMethods(@) @scope.sectionName = "Taskboard" @.initializeEventHandlers() diff --git a/app/coffee/utils.coffee b/app/coffee/utils.coffee index 455211bf..dc399ab8 100644 --- a/app/coffee/utils.coffee +++ b/app/coffee/utils.coffee @@ -23,6 +23,16 @@ nl2br = (str) => breakTag = '
' return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2') +bindMethods = (object) => + dependencies = _.keys(object) + + methods = [] + + _.forIn object, (value, key) => + if key not in dependencies + methods.push(key) + + _.bindAll(object, methods) bindOnce = (scope, attr, continuation) => val = scope.$eval(attr) @@ -133,6 +143,7 @@ sizeFormat = (input, precision=1) -> taiga = @.taiga taiga.nl2br = nl2br +taiga.bindMethods = bindMethods taiga.bindOnce = bindOnce taiga.mixOf = mixOf taiga.trim = trim diff --git a/app/partials/issues-detail.jade b/app/partials/issues-detail.jade index 971daecf..9fa95b0e 100644 --- a/app/partials/issues-detail.jade +++ b/app/partials/issues-detail.jade @@ -16,7 +16,7 @@ block content span.us-number(tg-bo-ref="issue.ref") span.us-name(tg-editable-subject, ng-model="issue", required-perm="modify_issue") - p.us-related-task(ng-if="issue.generated_user_stories") This issue has been promoted to US: + p.us-related-task(ng-if="issue.generated_user_stories.length") This issue has been promoted to US: a(ng-repeat="us in issue.generated_user_stories", tg-check-permission="view_us", href="", tg-bo-title="'#' + us.ref + ' ' + us.subject", diff --git a/bower.json b/bower.json index 10a70219..12d69091 100644 --- a/bower.json +++ b/bower.json @@ -50,11 +50,11 @@ "lodash": "~2.4.1", "emoticons": "~0.1.7", "jquery-flot": "~0.8.2", - "angular": "1.2.21", - "angular-route": "1.2.21", - "angular-animate": "1.2.21", - "angular-sanitize": "1.2.21", - "angular-mocks": "1.2.21", + "angular": "1.3.4", + "angular-route": "1.3.4", + "angular-animate": "1.3.4", + "angular-sanitize": "1.3.4", + "angular-mocks": "1.3.4", "kalendae": "~0.4.1", "checksley": "~0.6.0", "i18next": "~1.7.1", @@ -78,7 +78,8 @@ "resolutions": { "lodash": "~2.4.1", "moment": "~2.6.0", - "jquery": "~2.1.1" + "jquery": "~2.1.1", + "angular": "1.3.4" }, "private": true } From 8af84eaa8b9e7547526dbf74c15912aefd66eb0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Thu, 27 Nov 2014 10:30:30 +0100 Subject: [PATCH 11/66] Changelog update --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed667b3a..8e76f6bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog # +## 1.4.0 Unknown (Unknown) + +### Features +- Upgrade to AngularJS 1.3 +- Use enter to submit lightboxes forms + +### Misc +- Lots of small and not so small bugfixes. + ## 1.3.0 Dryas hookeriana (2014-11-18) ### Features From bd777721351b11728148af3f9fc4ce17811c63f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Thu, 27 Nov 2014 10:57:39 +0100 Subject: [PATCH 12/66] Add help button in WYSIWYG and markdown syntax --- app/coffee/modules/common/components.coffee | 4 ++++ app/coffee/modules/wiki/main.coffee | 7 +++++-- app/styles/layout/us-detail.scss | 18 ++++++++++++++++++ app/styles/layout/wiki.scss | 20 +++++++++++++++++--- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/app/coffee/modules/common/components.coffee b/app/coffee/modules/common/components.coffee index f6a57961..6a7057fe 100644 --- a/app/coffee/modules/common/components.coffee +++ b/app/coffee/modules/common/components.coffee @@ -564,6 +564,10 @@ EditableDescriptionDirective = ($window, $document, $rootscope, $repo, $confirm, + + + Markdown syntax help + diff --git a/app/coffee/modules/wiki/main.coffee b/app/coffee/modules/wiki/main.coffee index 0163e25a..4bac5f28 100644 --- a/app/coffee/modules/wiki/main.coffee +++ b/app/coffee/modules/wiki/main.coffee @@ -215,14 +215,17 @@ EditableWikiContentDirective = ($window, $document, $repo, $confirm, $loading, $ $analytics) -> template = """
-
+
diff --git a/app/styles/modules/common/history.scss b/app/styles/modules/common/history.scss index 920d4582..4ff86a64 100644 --- a/app/styles/modules/common/history.scss +++ b/app/styles/modules/common/history.scss @@ -73,6 +73,10 @@ @include transition(height .3s ease-in); height: 6rem; } + .help-markdown { + @include transition(opacity .3s linear); + opacity: 1; + } .preview-icon { opacity: 1; position: absolute; @@ -86,6 +90,25 @@ margin-bottom: .5rem; min-height: inherit; } + .help-markdown { + @extend %small; + color: $gray-light; + opacity: 0; + &:hover { + span { + @include transition(color .2s linear); + color: $grayer; + } + .icon { + @include transition(color .2s linear); + color: $fresh-taiga; + } + } + .icon { + color: $gray-light; + margin-right: .2rem; + } + } .save-comment { color: $white; float: right; From bb5eaa86330749e55d589747fbcecb19def83b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Thu, 27 Nov 2014 13:42:03 +0100 Subject: [PATCH 16/66] Markdown help SCSS refactor --- app/styles/components/markdown-help.scss | 18 ++++++++++++++++++ app/styles/layout/us-detail.scss | 18 ------------------ app/styles/layout/wiki.scss | 18 ++---------------- app/styles/modules/common/history.scss | 18 +----------------- main-sass.js | 1 + 5 files changed, 22 insertions(+), 51 deletions(-) create mode 100644 app/styles/components/markdown-help.scss diff --git a/app/styles/components/markdown-help.scss b/app/styles/components/markdown-help.scss new file mode 100644 index 00000000..270a7e38 --- /dev/null +++ b/app/styles/components/markdown-help.scss @@ -0,0 +1,18 @@ +a.help-markdown { + @extend %small; + color: $gray-light; + &:hover { + span { + @include transition(color .2s linear); + color: $grayer; + } + .icon { + @include transition(color .2s linear); + color: $fresh-taiga; + } + } + .icon { + color: $gray-light; + margin-right: .2rem; + } +} diff --git a/app/styles/layout/us-detail.scss b/app/styles/layout/us-detail.scss index db453178..f93c8199 100644 --- a/app/styles/layout/us-detail.scss +++ b/app/styles/layout/us-detail.scss @@ -216,24 +216,6 @@ right: 2.5rem; top: .4rem; } - .help-markdown { - @extend %small; - color: $gray-light; - &:hover { - span { - @include transition(color .2s linear); - color: $grayer; - } - .icon { - @include transition(color .2s linear); - color: $fresh-taiga; - } - } - .icon { - color: $gray-light; - margin-right: .2rem; - } - } } } diff --git a/app/styles/layout/wiki.scss b/app/styles/layout/wiki.scss index 03215f2b..05ead45c 100644 --- a/app/styles/layout/wiki.scss +++ b/app/styles/layout/wiki.scss @@ -1,6 +1,5 @@ .wiki { - .remove, - .help-markdown { + .remove { @extend %small; color: $gray-light; &:hover { @@ -10,6 +9,7 @@ } .icon { @include transition(color .2s linear); + color: $red; } } .icon { @@ -17,20 +17,6 @@ margin-right: .2rem; } } - .remove { - &:hover { - .icon { - color: $red; - } - } - } - .help-markdown { - &:hover { - .icon { - color: $fresh-taiga; - } - } - } } .wiki-content { diff --git a/app/styles/modules/common/history.scss b/app/styles/modules/common/history.scss index e383fd55..62a43676 100644 --- a/app/styles/modules/common/history.scss +++ b/app/styles/modules/common/history.scss @@ -85,28 +85,12 @@ } textarea { background: $white; - margin-bottom: .5rem; height: 5rem; + margin-bottom: .5rem; min-height: 41px; } .help-markdown { - @extend %small; - color: $gray-light; opacity: 0; - &:hover { - span { - @include transition(color .2s linear); - color: $grayer; - } - .icon { - @include transition(color .2s linear); - color: $fresh-taiga; - } - } - .icon { - color: $gray-light; - margin-right: .2rem; - } } .save-comment { color: $white; diff --git a/main-sass.js b/main-sass.js index af5a6cda..2693462e 100644 --- a/main-sass.js +++ b/main-sass.js @@ -54,6 +54,7 @@ exports.files = function () { 'components/help-notion-button', 'components/beta', 'components/markitup', + 'components/markdown-help', //################################################# From 33c427b0721957ecf2c082ed0159b2e613c42f0c Mon Sep 17 00:00:00 2001 From: Juanfran Date: Thu, 27 Nov 2014 13:55:14 +0100 Subject: [PATCH 17/66] unify form submit --- app/coffee/modules/admin/lightboxes.coffee | 15 ++- .../modules/admin/project-profile.coffee | 60 +++++++++--- .../modules/admin/project-values.coffee | 2 +- app/coffee/modules/admin/third-parties.coffee | 21 ++--- app/coffee/modules/auth.coffee | 91 +++++++------------ app/coffee/modules/backlog/lightboxes.coffee | 17 ++-- app/coffee/modules/common/lightboxes.coffee | 30 +++--- app/coffee/modules/feedback.coffee | 20 ++-- app/coffee/modules/issues/lightboxes.coffee | 37 +++++--- app/coffee/modules/projects/lightboxes.coffee | 18 ++-- app/coffee/modules/search.coffee | 13 ++- .../modules/taskboard/lightboxes.coffee | 44 ++++++--- .../user-settings/change-password.coffee | 46 ++++++---- app/coffee/modules/user-settings/main.coffee | 10 +- .../admin-project-default-values.jade | 2 +- app/partials/admin-project-modules.jade | 4 +- app/partials/admin-project-profile.jade | 4 +- app/partials/admin-third-parties-github.jade | 4 +- app/partials/user-change-password.jade | 4 +- app/partials/user-profile.jade | 4 +- .../views/modules/admin/default-values.jade | 4 +- .../views/modules/cancel-account-form.jade | 4 +- .../views/modules/change-email-form.jade | 4 +- .../change-password-from-recovery-form.jade | 6 +- app/partials/views/modules/forgot-form.jade | 4 +- .../views/modules/invitation-login-form.jade | 4 +- .../modules/invitation-register-form.jade | 4 +- .../views/modules/lightbox-add-member.jade | 6 +- .../views/modules/lightbox-create-issue.jade | 4 +- .../views/modules/lightbox-feedback.jade | 4 +- .../views/modules/lightbox-issue-bulk.jade | 5 +- .../views/modules/lightbox-search.jade | 5 +- .../modules/lightbox-sprint-add-edit.jade | 3 +- .../views/modules/lightbox-task-bulk.jade | 5 +- .../modules/lightbox-task-create-edit.jade | 4 +- .../views/modules/lightbox-us-bulk.jade | 5 +- .../modules/lightbox-us-create-edit.jade | 4 +- app/partials/views/modules/login-form.jade | 4 +- app/partials/views/modules/register-form.jade | 4 +- .../views/modules/wizard-create-project.jade | 4 +- 40 files changed, 312 insertions(+), 221 deletions(-) diff --git a/app/coffee/modules/admin/lightboxes.coffee b/app/coffee/modules/admin/lightboxes.coffee index bf30904a..6ad67d99 100644 --- a/app/coffee/modules/admin/lightboxes.coffee +++ b/app/coffee/modules/admin/lightboxes.coffee @@ -30,7 +30,7 @@ MAX_MEMBERSHIP_FIELDSETS = 4 ## Create Members Lightbox Directive ############################################################################# -CreateMembersDirective = ($rs, $rootScope, $confirm, lightboxService) -> +CreateMembersDirective = ($rs, $rootScope, $confirm, $loading ,lightboxService) -> extraTextTemplate = """
@@ -103,15 +103,19 @@ CreateMembersDirective = ($rs, $rootScope, $confirm, lightboxService) -> $el.find(".add-member-wrapper fieldset:last > a").removeClass("icon-plus add-fieldset") .addClass("icon-delete delete-fieldset") - $el.on "click", ".button-green", debounce 2000, (event) -> + submit = debounce 2000, (event) => event.preventDefault() + $loading.start(submitButton) + onSuccess = (data) -> + $loading.finish(submitButton) lightboxService.close($el) $confirm.notify("success") $rootScope.$broadcast("membersform:new:success") onError = (data) -> + $loading.finish(submitButton) lightboxService.close($el) $confirm.notify("error") $rootScope.$broadcast("membersform:new:error") @@ -143,7 +147,12 @@ CreateMembersDirective = ($rs, $rootScope, $confirm, lightboxService) -> $rs.memberships.bulkCreateMemberships($scope.project.id, invitations, invitation_extra_text).then(onSuccess, onError) + submitButton = $el.find(".submit-button") + + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit + return {link: link} -module.directive("tgLbCreateMembers", ["$tgResources", "$rootScope", "$tgConfirm", "lightboxService", +module.directive("tgLbCreateMembers", ["$tgResources", "$rootScope", "$tgConfirm", "$tgLoading", "lightboxService", CreateMembersDirective]) diff --git a/app/coffee/modules/admin/project-profile.coffee b/app/coffee/modules/admin/project-profile.coffee index 499452cb..9b00f527 100644 --- a/app/coffee/modules/admin/project-profile.coffee +++ b/app/coffee/modules/admin/project-profile.coffee @@ -27,6 +27,7 @@ toString = @.taiga.toString joinStr = @.taiga.joinStr groupBy = @.taiga.groupBy bindOnce = @.taiga.bindOnce +debounce = @.taiga.debounce module = angular.module("taigaAdmin") @@ -95,14 +96,16 @@ module.controller("ProjectProfileController", ProjectProfileController) ProjectProfileDirective = ($repo, $confirm, $loading, $navurls, $location) -> link = ($scope, $el, $attrs) -> form = $el.find("form").checksley({"onlyOneErrorElement": true}) - submit = (target) => + submit = debounce 2000, (event) => + event.preventDefault() + return if not form.validate() - $loading.start(target) + $loading.start(submitButton) promise = $repo.save($scope.project) promise.then -> - $loading.finish(target) + $loading.finish(submitButton) $confirm.notify("success") newUrl = $navurls.resolve("project-admin-project-profile-details", {project: $scope.project.slug}) $location.path(newUrl) @@ -114,24 +117,51 @@ ProjectProfileDirective = ($repo, $confirm, $loading, $navurls, $location) -> if data._error_message $confirm.notify("error", data._error_message) - $el.on "submit", "form", (event) -> - event.preventDefault() - submit() + submitButton = $el.find(".submit-button"); - $el.on "click", ".default-values a.button-green", (event) -> - event.preventDefault() - target = angular.element(event.currentTarget) - submit(target) - - $el.on "click", ".project-details a.button-green", (event) -> - event.preventDefault() - target = angular.element(event.currentTarget) - submit(target) + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit return {link:link} module.directive("tgProjectProfile", ["$tgRepo", "$tgConfirm", "$tgLoading", "$tgNavUrls", "$tgLocation", ProjectProfileDirective]) +############################################################################# +## Project Default Values Directive +############################################################################# + +ProjectDefaultValuesDirective = ($repo, $confirm, $loading) -> + link = ($scope, $el, $attrs) -> + form = $el.find("form").checksley({"onlyOneErrorElement": true}) + submit = debounce 2000, (event) => + event.preventDefault() + + return if not form.validate() + + $loading.start(submitButton) + + promise = $repo.save($scope.project) + promise.then -> + $loading.finish(submitButton) + $confirm.notify("success") + + promise.then null, (data) -> + $loading.finish(target) + form.setErrors(data) + if data._error_message + $confirm.notify("error", data._error_message) + + submitButton = $el.find(".submit-button") + + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit + + $scope.$on "$destroy", -> + $el.off() + + return {link:link} + +module.directive("tgProjectDefaultValues", ["$tgRepo", "$tgConfirm", "$tgLoading", ProjectDefaultValuesDirective]) ############################################################################# ## Project Modules Directive diff --git a/app/coffee/modules/admin/project-values.coffee b/app/coffee/modules/admin/project-values.coffee index f721a992..8f70c0ce 100644 --- a/app/coffee/modules/admin/project-values.coffee +++ b/app/coffee/modules/admin/project-values.coffee @@ -208,7 +208,7 @@ ProjectValuesDirective = ($log, $repo, $confirm, $location, animationFrame) -> animationFrame.add () -> goToBottomList() - $el.find(".new-value").hide() + $el.find(".new-value").addClass("hidden") initializeNewValue() promise.then null, (data) -> diff --git a/app/coffee/modules/admin/third-parties.coffee b/app/coffee/modules/admin/third-parties.coffee index c8aa1b3d..842652e8 100644 --- a/app/coffee/modules/admin/third-parties.coffee +++ b/app/coffee/modules/admin/third-parties.coffee @@ -23,6 +23,7 @@ taiga = @.taiga mixOf = @.taiga.mixOf bindMethods = @.taiga.bindMethods +debounce = @.taiga.debounce module = angular.module("taigaAdmin") @@ -94,30 +95,28 @@ module.directive("tgSelectInputText", SelectInputText) GithubWebhooksDirective = ($repo, $confirm, $loading) -> link = ($scope, $el, $attrs) -> form = $el.find("form").checksley({"onlyOneErrorElement": true}) - submit = (target) => + submit = debounce 2000, (event) => + event.preventDefault() + return if not form.validate() - $loading.start(target) + $loading.start(submitButton) promise = $repo.saveAttribute($scope.github, "github") promise.then -> - $loading.finish(target) + $loading.finish(submitButton) $confirm.notify("success") promise.then null, (data) -> - $loading.finish(target) + $loading.finish(submitButton) form.setErrors(data) if data._error_message $confirm.notify("error", data._error_message) - $el.on "click", "a.button-green", (event) -> - event.preventDefault() - target = angular.element(event.currentTarget) - submit(target) + submitButton = $el.find(".submit-button") - $el.on "submit", "form", (event) -> - event.preventDefault() - submit() + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit return {link:link} diff --git a/app/coffee/modules/auth.coffee b/app/coffee/modules/auth.coffee index 42a8ce12..173e38fd 100644 --- a/app/coffee/modules/auth.coffee +++ b/app/coffee/modules/auth.coffee @@ -189,7 +189,9 @@ LoginDirective = ($auth, $confirm, $location, $config, $routeParams, $navUrls, $ onError = (response) -> $confirm.notify("light-error", "According to our Oompa Loompas, your username/email or password are incorrect.") #TODO: i18n - submit = -> + submit = debounce 2000, (event) => + event.preventDefault() + form = new checksley.Form($el.find("form.login-form")) if not form.validate() return @@ -202,13 +204,8 @@ LoginDirective = ($auth, $confirm, $location, $config, $routeParams, $navUrls, $ promise = $auth.login(data) return promise.then(onSuccess, onError) - $el.on "click", "a.button-login", (event) -> - event.preventDefault() - submit() - - $el.on "submit", "form", (event) -> - event.preventDefault() - submit() + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit return {link:link} @@ -239,20 +236,17 @@ RegisterDirective = ($auth, $confirm, $location, $navUrls, $config, $analytics) form.setErrors(response.data) - submit = debounce 2000, => + submit = debounce 2000, (event) => + event.preventDefault() + if not form.validate() return promise = $auth.register($scope.data) promise.then(onSuccessSubmit, onErrorSubmit) - $el.on "submit", (event) -> - event.preventDefault() - submit() - - $el.on "click", "a.button-register", (event) -> - event.preventDefault() - submit() + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit return {link:link} @@ -279,20 +273,17 @@ ForgotPasswordDirective = ($auth, $confirm, $location, $navUrls) -> $confirm.notify("light-error", "According to our Oompa Loompas, your are not registered yet.") #TODO: i18n - submit = debounce 2000, => + submit = debounce 2000, (event) => + event.preventDefault() + if not form.validate() return promise = $auth.forgotPassword($scope.data) promise.then(onSuccessSubmit, onErrorSubmit) - $el.on "submit", (event) -> - event.preventDefault() - submit() - - $el.on "click", "a.button-forgot", (event) -> - event.preventDefault() - submit() + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit return {link:link} @@ -324,20 +315,17 @@ ChangePasswordFromRecoveryDirective = ($auth, $confirm, $location, $params, $nav $confirm.notify("light-error", "One of our Oompa Loompas say '#{response.data._error_message}'.") #TODO: i18n - submit = debounce 2000, => + submit = debounce 2000, (event) => + event.preventDefault() + if not form.validate() return promise = $auth.changePasswordFromRecovery($scope.data) promise.then(onSuccessSubmit, onErrorSubmit) - $el.on "submit", (event) -> - event.preventDefault() - submit() - - $el.on "click", "a.button-change-password", (event) -> - event.preventDefault() - submit() + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit return {link:link} @@ -375,20 +363,17 @@ InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics $confirm.notify("light-error", "According to our Oompa Loompas, your are not registered yet or typed an invalid password.") #TODO: i18n - submitLogin = debounce 2000, => + submitLogin = debounce 2000, (event) => + event.preventDefault() + if not loginForm.validate() return promise = $auth.acceptInvitiationWithExistingUser($scope.dataLogin) promise.then(onSuccessSubmitLogin, onErrorSubmitLogin) - $el.on "submit", "form.login-form", (event) -> - event.preventDefault() - submitLogin() - - $el.on "click", "a.button-login", (event) -> - event.preventDefault() - submitLogin() + $el.on "submit", "form.login-form", submitLogin + $el.on "click", ".button-login", submitLogin # Register form $scope.dataRegister = {token: token} @@ -404,20 +389,17 @@ InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics $confirm.notify("light-error", "According to our Oompa Loompas, that username or email is already in use.") #TODO: i18n - submitRegister = debounce 2000, => + submitRegister = debounce 2000, (event) => + event.preventDefault() + if not registerForm.validate() return promise = $auth.acceptInvitiationWithNewUser($scope.dataRegister) promise.then(onSuccessSubmitRegister, onErrorSubmitRegister) - $el.on "submit", "form.register-form", (event) -> - event.preventDefault() - submitRegister - - $el.on "click", "a.button-register", (event) -> - event.preventDefault() - submitRegister() + $el.on "submit", "form.register-form", submitRegister + $el.on "click", ".button-register", submitRegister return {link:link} @@ -483,20 +465,17 @@ CancelAccountDirective = ($repo, $model, $auth, $confirm, $location, $params, $n $confirm.notify("error", "One of our Oompa Loompas says '#{response.data._error_message}'.") #TODO: i18n - submit = -> + submit = debounce 2000, (event) => + event.preventDefault() + if not form.validate() return promise = $auth.cancelAccount($scope.data) promise.then(onSuccessSubmit, onErrorSubmit) - $el.on "submit", (event) -> - event.preventDefault() - submit() - - $el.on "click", "a.button-cancel-account", (event) -> - event.preventDefault() - submit() + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit return {link:link} diff --git a/app/coffee/modules/backlog/lightboxes.coffee b/app/coffee/modules/backlog/lightboxes.coffee index 52e1d416..d9a6a5b4 100644 --- a/app/coffee/modules/backlog/lightboxes.coffee +++ b/app/coffee/modules/backlog/lightboxes.coffee @@ -41,7 +41,9 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading) estimated_finish: null } - submit = (event) -> + submit = debounce 2000, (event) => + event.preventDefault() + target = angular.element(event.currentTarget) form = $el.find("form").checksley() @@ -65,17 +67,17 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading) promise = $repo.save(newSprint) broadcastEvent = "sprintform:edit:success" - $loading.start(target) + $loading.start(submitButton) promise.then (data) -> - $loading.finish(target) + $loading.finish(submitButton) $scope.sprintsCounter += 1 if createSprint $rootscope.$broadcast(broadcastEvent, data) lightboxService.close($el) promise.then null, (data) -> - $loading.finish(target) + $loading.finish(submitButton) form.setErrors(data) if data._error_message @@ -152,9 +154,10 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading) else $el.find(".last-sprint-name").removeClass("disappear") - $el.on "click", ".button-green", debounce 2000, (event) -> - event.preventDefault() - submit(event) + submitButton = $el.find(".submit-button") + + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit $el.on "click", ".delete-sprint .icon-delete", (event) -> event.preventDefault() diff --git a/app/coffee/modules/common/lightboxes.coffee b/app/coffee/modules/common/lightboxes.coffee index 59b06a7d..fd07cb7a 100644 --- a/app/coffee/modules/common/lightboxes.coffee +++ b/app/coffee/modules/common/lightboxes.coffee @@ -285,15 +285,14 @@ CreateEditUserstoryDirective = ($repo, $model, $rs, $rootScope, lightboxService, lightboxService.open($el) - $el.on "click", ".button-green", debounce 2000, (event) -> + submit = debounce 2000, (event) => event.preventDefault() - form = $el.find("form").checksley() - target = angular.element(event.currentTarget) + form = $el.find("form").checksley() if not form.validate() return - $loading.start(target) + $loading.start(submitButton) if $scope.isNew promise = $repo.create("userstories", $scope.us) @@ -303,16 +302,21 @@ CreateEditUserstoryDirective = ($repo, $model, $rs, $rootScope, lightboxService, broadcastEvent = "usform:edit:success" promise.then (data) -> - $loading.finish(target) + $loading.finish(submitButton) lightboxService.close($el) $rootScope.$broadcast(broadcastEvent, data) promise.then null, (data) -> - $loading.finish(target) + $loading.finish(submitButton) form.setErrors(data) if data._error_message $confirm.notify("error", data._error_message) + submitButton = $el.find(".submit-button") + + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit + $el.on "click", ".close", (event) -> event.preventDefault() $scope.$apply -> @@ -356,28 +360,32 @@ CreateBulkUserstoriesDirective = ($repo, $rs, $rootscope, lightboxService, $load } lightboxService.open($el) - $el.on "click", ".button-green", debounce 2000, (event) -> + submit = debounce 2000, (event) => event.preventDefault() - target = angular.element(event.currentTarget) form = $el.find("form").checksley({onlyOneErrorElement: true}) if not form.validate() return - $loading.start(target) + $loading.start(submitButton) promise = $rs.userstories.bulkCreate($scope.new.projectId, $scope.new.statusId, $scope.new.bulk) promise.then (result) -> - $loading.finish(target) + $loading.finish(submitButton) $rootscope.$broadcast("usform:bulk:success", result) lightboxService.close($el) promise.then null, (data) -> - $loading.finish(target) + $loading.finish(submitButton) form.setErrors(data) if data._error_message $confirm.notify("error", data._error_message) + submitButton = $el.find(".submit-button") + + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit + $scope.$on "$destroy", -> $el.off() diff --git a/app/coffee/modules/feedback.coffee b/app/coffee/modules/feedback.coffee index 17add8e7..781f6ddc 100644 --- a/app/coffee/modules/feedback.coffee +++ b/app/coffee/modules/feedback.coffee @@ -29,29 +29,33 @@ trim = @.taiga.trim module = angular.module("taigaFeedback", []) -FeedbackDirective = ($lightboxService, $repo, $confirm)-> +FeedbackDirective = ($lightboxService, $repo, $confirm, $loading)-> link = ($scope, $el, $attrs) -> form = $el.find("form").checksley() - submit = debounce 2000, -> + submit = debounce 2000, (event) => + event.preventDefault() + if not form.validate() return + $loading.start(submitButton) + promise = $repo.create("feedback", $scope.feedback) promise.then (data) -> + $loading.finish(submitButton) $lightboxService.close($el) $confirm.notify("success", "\\o/ we'll be happy to read your") promise.then null, -> + $loading.finish(submitButton) $confirm.notify("error") - $el.on "submit", (event) -> - submit() + submitButton = $el.find(".submit-button") - $el.on "click", ".button-green", (event) -> - event.preventDefault() - submit() + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit $scope.$on "feedback:show", -> $scope.$apply -> @@ -65,4 +69,4 @@ FeedbackDirective = ($lightboxService, $repo, $confirm)-> return {link:link} -module.directive("tgLbFeedback", ["lightboxService", "$tgRepo", "$tgConfirm", FeedbackDirective]) +module.directive("tgLbFeedback", ["lightboxService", "$tgRepo", "$tgConfirm", "$tgLoading", FeedbackDirective]) diff --git a/app/coffee/modules/issues/lightboxes.coffee b/app/coffee/modules/issues/lightboxes.coffee index 4daab182..70cd6f90 100644 --- a/app/coffee/modules/issues/lightboxes.coffee +++ b/app/coffee/modules/issues/lightboxes.coffee @@ -29,7 +29,7 @@ module = angular.module("taigaIssues") ## Issue Create Lightbox Directive ############################################################################# -CreateIssueDirective = ($repo, $confirm, $rootscope, lightboxService) -> +CreateIssueDirective = ($repo, $confirm, $rootscope, lightboxService, $loading) -> link = ($scope, $el, $attrs) -> form = $el.find("form").checksley() $scope.issue = {} @@ -50,31 +50,35 @@ CreateIssueDirective = ($repo, $confirm, $rootscope, lightboxService) -> $scope.$on "$destroy", -> $el.off() - submit = debounce 2000, -> + submit = debounce 2000, (event) => + event.preventDefault() + if not form.validate() return + $loading.start(submitButton) promise = $repo.create("issues", $scope.issue) promise.then (data) -> + $loading.finish(submitButton) $rootscope.$broadcast("issueform:new:success", data) lightboxService.close($el) $confirm.notify("success") promise.then null, -> + $loading.finish(submitButton) $confirm.notify("error") - $el.on "click", ".button-green", (event) -> - event.preventDefault() - submit() - $el.on "submit", "form", (event) -> - event.preventDefault() - submit() + submitButton = $el.find(".submit-button") + + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit + return {link:link} -module.directive("tgLbCreateIssue", ["$tgRepo", "$tgConfirm", "$rootScope", "lightboxService", +module.directive("tgLbCreateIssue", ["$tgRepo", "$tgConfirm", "$rootScope", "lightboxService", "$tgLoading", CreateIssueDirective]) @@ -82,7 +86,7 @@ module.directive("tgLbCreateIssue", ["$tgRepo", "$tgConfirm", "$rootScope", "lig ## Issue Bulk Create Lightbox Directive ############################################################################# -CreateBulkIssuesDirective = ($repo, $rs, $confirm, $rootscope, lightboxService) -> +CreateBulkIssuesDirective = ($repo, $rs, $confirm, $rootscope, $loading, lightboxService) -> link = ($scope, $el, attrs) -> $scope.$on "issueform:bulk", (ctx, projectId, status)-> lightboxService.open($el) @@ -91,29 +95,38 @@ CreateBulkIssuesDirective = ($repo, $rs, $confirm, $rootscope, lightboxService) bulk: "" } - $el.on "click", ".button-green", debounce 2000, (event) -> + submit = debounce 2000, (event) => event.preventDefault() form = $el.find("form").checksley() if not form.validate() return + $loading.start(submitButton) + data = $scope.new.bulk projectId = $scope.new.projectId promise = $rs.issues.bulkCreate(projectId, data) promise.then (result) -> + $loading.finish(submitButton) $rootscope.$broadcast("issueform:new:success", result) lightboxService.close($el) $confirm.notify("success") promise.then null, -> + $loading.finish(submitButton) $confirm.notify("error") + submitButton = $el.find(".submit-button") + + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit + $scope.$on "$destroy", -> $el.off() return {link: link} -module.directive("tgLbCreateBulkIssues", ["$tgRepo", "$tgResources", "$tgConfirm", "$rootScope", +module.directive("tgLbCreateBulkIssues", ["$tgRepo", "$tgResources", "$tgConfirm", "$rootScope", "$tgLoading", "lightboxService", CreateBulkIssuesDirective]) diff --git a/app/coffee/modules/projects/lightboxes.coffee b/app/coffee/modules/projects/lightboxes.coffee index 9d6cb8c0..74cceb73 100644 --- a/app/coffee/modules/projects/lightboxes.coffee +++ b/app/coffee/modules/projects/lightboxes.coffee @@ -26,7 +26,7 @@ debounce = @.taiga.debounce module = angular.module("taigaProject") -CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $projectUrl, lightboxService, $cacheFactory) -> +CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $projectUrl, $loading, lightboxService, $cacheFactory) -> link = ($scope, $el, attrs) -> $scope.data = {} $scope.templates = [] @@ -39,12 +39,14 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project # than another deleted in the same session $cacheFactory.get('$http').removeAll() + $loading.finish(submitButton) $rootscope.$broadcast("projects:reload") $confirm.notify("success", "Success") #TODO: i18n $location.url($projectUrl.get(response)) lightboxService.close($el) onErrorSubmit = (response) -> + $loading.finish(submitButton) form.setErrors(response) selectors = [] for error_field in _.keys(response) @@ -54,10 +56,14 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project error_step.addClass("active") $el.find('.progress-bar').removeClass().addClass('progress-bar').addClass(error_step.data("step")) - submit = -> + submit = (event) => + event.preventDefault() + if not form.validate() return + $loading.start(submitButton) + promise = $repo.create("projects", $scope.data) promise.then(onSuccessSubmit, onErrorSubmit) @@ -109,10 +115,10 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project step = prev.data('step') $el.find('.progress-bar').removeClass().addClass('progress-bar').addClass(step) + submitButton = $el.find(".submit-button") - $el.on "click", ".button-submit", debounce 2000, (event) -> - event.preventDefault() - submit() + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit $el.on "click", ".close", (event) -> event.preventDefault() @@ -121,7 +127,7 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project return {link:link} module.directive("tgLbCreateProject", ["$rootScope", "$tgRepo", "$tgConfirm", "$location", "$tgNavUrls", - "$tgResources", "$projectUrl", "lightboxService", "$cacheFactory", CreateProject]) + "$tgResources", "$projectUrl", "$tgLoading", "lightboxService", "$cacheFactory", CreateProject]) ############################################################################# diff --git a/app/coffee/modules/search.coffee b/app/coffee/modules/search.coffee index e22c787d..1aa77b20 100644 --- a/app/coffee/modules/search.coffee +++ b/app/coffee/modules/search.coffee @@ -26,6 +26,7 @@ bindOnce = @.taiga.bindOnce mixOf = @.taiga.mixOf debounceLeading = @.taiga.debounceLeading trim = @.taiga.trim +debounce = @.taiga.debounce module = angular.module("taigaSearch", []) @@ -111,7 +112,9 @@ SearchBoxDirective = ($lightboxService, $navurls, $location, $route)-> link = ($scope, $el, $attrs) -> project = null - submit = -> + submit = debounce 2000, (event) => + event.preventDefault() + form = $el.find("form").checksley() if not form.validate() return @@ -131,12 +134,8 @@ SearchBoxDirective = ($lightboxService, $navurls, $location, $route)-> $lightboxService.open($el) $el.find("#search-text").val("") - $el.on "submit", (event) -> - submit() - - $el.on "click", ".button-green", (event) -> - event.preventDefault() - submit() + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit return {link:link} diff --git a/app/coffee/modules/taskboard/lightboxes.coffee b/app/coffee/modules/taskboard/lightboxes.coffee index 68ac79c5..97399f1a 100644 --- a/app/coffee/modules/taskboard/lightboxes.coffee +++ b/app/coffee/modules/taskboard/lightboxes.coffee @@ -23,7 +23,7 @@ taiga = @.taiga bindOnce = @.taiga.bindOnce debounce = @.taiga.debounce -CreateEditTaskDirective = ($repo, $model, $rs, $rootscope, lightboxService) -> +CreateEditTaskDirective = ($repo, $model, $rs, $rootscope, $loading, lightboxService) -> link = ($scope, $el, attrs) -> $scope.isNew = true @@ -53,16 +53,10 @@ CreateEditTaskDirective = ($repo, $model, $rs, $rootscope, lightboxService) -> $el.find(".title").html("Edit task ") #TODO: i18n lightboxService.open($el) - $el.on "click", ".button-green", debounce 2000, (event) -> - formSubmitted event - $el.on "submit", "form", debounce 2000, (event) -> - formSubmitted event + submitButton = $el.find(".submit-button") - $scope.$on "$destroy", -> - $el.off() - - formSubmitted = (event) -> + submit = debounce 2000, (event) => event.preventDefault() form = $el.find("form").checksley() @@ -76,29 +70,36 @@ CreateEditTaskDirective = ($repo, $model, $rs, $rootscope, lightboxService) -> promise = $repo.save($scope.task) broadcastEvent = "taskform:edit:success" + $loading.start(submitButton) + # FIXME: error handling? promise.then (data) -> + $loading.finish(submitButton) lightboxService.close($el) $rootscope.$broadcast(broadcastEvent, data) + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit + + $scope.$on "$destroy", -> + $el.off() + return {link: link} -CreateBulkTasksDirective = ($repo, $rs, $rootscope, lightboxService) -> +CreateBulkTasksDirective = ($repo, $rs, $rootscope, $loading, lightboxService) -> link = ($scope, $el, attrs) -> $scope.form = {data: "", usId: null} - $scope.$on "taskform:bulk", (ctx, sprintId, usId)-> - lightboxService.open($el) - $scope.form = {data: "", sprintId: sprintId, usId: usId} - - $el.on "click", ".button-green", debounce 2000, (event) -> + submit = debounce 2000, (event) => event.preventDefault() form = $el.find("form").checksley() if not form.validate() return + $loading.start(submitButton) + data = $scope.form.data projectId = $scope.projectId sprintId = $scope.form.sprintId @@ -106,13 +107,24 @@ CreateBulkTasksDirective = ($repo, $rs, $rootscope, lightboxService) -> promise = $rs.tasks.bulkCreate(projectId, sprintId, usId, data) promise.then (result) -> + $loading.finish(submitButton) $rootscope.$broadcast("taskform:bulk:success", result) lightboxService.close($el) # TODO: error handling promise.then null, -> + $loading.finish(submitButton) console.log "FAIL" + $scope.$on "taskform:bulk", (ctx, sprintId, usId)-> + lightboxService.open($el) + $scope.form = {data: "", sprintId: sprintId, usId: usId} + + submitButton = $el.find(".submit-button") + + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit + $scope.$on "$destroy", -> $el.off() @@ -126,6 +138,7 @@ module.directive("tgLbCreateEditTask", [ "$tgModel", "$tgResources", "$rootScope", + "$tgLoading", "lightboxService", CreateEditTaskDirective ]) @@ -134,6 +147,7 @@ module.directive("tgLbCreateBulkTasks", [ "$tgRepo", "$tgResources", "$rootScope", + "$tgLoading", "lightboxService", CreateBulkTasksDirective ]) diff --git a/app/coffee/modules/user-settings/change-password.coffee b/app/coffee/modules/user-settings/change-password.coffee index 54aeb0de..4dc9fa28 100644 --- a/app/coffee/modules/user-settings/change-password.coffee +++ b/app/coffee/modules/user-settings/change-password.coffee @@ -22,6 +22,7 @@ taiga = @.taiga mixOf = @.taiga.mixOf +debounce = @.taiga.debounce module = angular.module("taigaUserSettings") @@ -66,18 +67,6 @@ class UserChangePasswordController extends mixOf(taiga.Controller, taiga.PageMix return promise.then(=> @.loadProject()) - save: -> - if @scope.newPassword1 != @scope.newPassword2 - @confirm.notify('error', "The passwords dosn't match") - return - - promise = @rs.userSettings.changePassword(@scope.currentPassword, @scope.newPassword1) - promise.then => - @confirm.notify('success') - promise.then null, (response) => - @confirm.notify('error', response.data._error_message) - - module.controller("UserChangePasswordController", UserChangePasswordController) @@ -85,11 +74,36 @@ module.controller("UserChangePasswordController", UserChangePasswordController) ## User ChangePassword Directive ############################################################################# -UserChangePasswordDirective = () -> - link = ($scope, $el, $attrs) -> +UserChangePasswordDirective = ($rs, $confirm, $loading) -> + link = ($scope, $el, $attrs, ctrl) -> + submit = debounce 2000, (event) => + event.preventDefault() + + if $scope.newPassword1 != $scope.newPassword2 + $confirm.notify('error', "The passwords dosn't match") + return + + $loading.start(submitButton) + + promise = $rs.userSettings.changePassword($scope.currentPassword, $scope.newPassword1) + promise.then => + $loading.finish(submitButton) + $confirm.notify('success') + + promise.then null, (response) => + $loading.finish(submitButton) + $confirm.notify('error', response.data._error_message) + + submitButton = $el.find(".submit-button") + + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit + $scope.$on "$destroy", -> $el.off() - return {link:link} + return { + link:link + } -module.directive("tgUserChangePassword", UserChangePasswordDirective) +module.directive("tgUserChangePassword", ["$tgResources", "$tgConfirm", "$tgLoading", UserChangePasswordDirective]) diff --git a/app/coffee/modules/user-settings/main.coffee b/app/coffee/modules/user-settings/main.coffee index 5b49708e..dbfffe35 100644 --- a/app/coffee/modules/user-settings/main.coffee +++ b/app/coffee/modules/user-settings/main.coffee @@ -23,7 +23,7 @@ taiga = @.taiga mixOf = @.taiga.mixOf sizeFormat = @.taiga.sizeFormat module = angular.module("taigaUserSettings") - +debounce = @.taiga.debounce ############################################################################# ## User settings Controller @@ -82,7 +82,9 @@ module.controller("UserSettingsController", UserSettingsController) UserProfileDirective = ($confirm, $auth, $repo) -> link = ($scope, $el, $attrs) -> - $el.on "click", ".user-profile form .save-profile", (event) -> + submit = debounce 2000, (event) => + event.preventDefault() + form = $el.find("form").checksley() return if not form.validate() @@ -103,6 +105,10 @@ UserProfileDirective = ($confirm, $auth, $repo) -> $repo.save($scope.user).then(onSuccess, onError) + $el.on "submit", "form", submit + + $el.on "click", ".submit-button", submit + $scope.$on "$destroy", -> $el.off() diff --git a/app/partials/admin-project-default-values.jade b/app/partials/admin-project-default-values.jade index e56f9089..59afdbca 100644 --- a/app/partials/admin-project-default-values.jade +++ b/app/partials/admin-project-default-values.jade @@ -4,7 +4,7 @@ block head title Taiga Your agile, free, and open source project management tool block content - div.wrapper(tg-project-profile, ng-controller="ProjectProfileController as ctrl", + div.wrapper(tg-project-default-values, ng-controller="ProjectProfileController as ctrl", ng-init="section='admin'; sectionName='Default values'") sidebar.menu-secondary.sidebar(tg-admin-navigation="project-profile") include views/modules/admin-menu diff --git a/app/partials/admin-project-modules.jade b/app/partials/admin-project-modules.jade index 93b00df4..deea51d6 100644 --- a/app/partials/admin-project-modules.jade +++ b/app/partials/admin-project-modules.jade @@ -93,5 +93,5 @@ block content option(value="") Select a videoconference system input(type="text", ng-model="project.videoconferences_salt", placeholder="If you want you can append a salt code to the name of the chat room") - input(type="submit", class="hidden") - a.button.button-green(href="") Save + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Save") Save diff --git a/app/partials/admin-project-profile.jade b/app/partials/admin-project-profile.jade index cf4c7917..7a94aed4 100644 --- a/app/partials/admin-project-profile.jade +++ b/app/partials/admin-project-profile.jade @@ -54,8 +54,8 @@ block content p All projects are private during Taiga's beta period. - input(type="submit", class="hidden") - a.button.button-green(href="") Save + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Save") Save a.delete-project(href="", title="Delete this project", ng-click="ctrl.openDeleteLightbox()") Delete this project div.lightbox.lightbox-delete-project(tg-lb-delete-project) diff --git a/app/partials/admin-third-parties-github.jade b/app/partials/admin-third-parties-github.jade index 4f84553e..0a900b61 100644 --- a/app/partials/admin-third-parties-github.jade +++ b/app/partials/admin-third-parties-github.jade @@ -27,8 +27,8 @@ block content .icon.icon-copy .help-copy Copy to clipboard: Ctrl+C - input(type="submit", class="hidden") - a.button.button-green(href="") Save + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Save") Save .help diff --git a/app/partials/user-change-password.jade b/app/partials/user-change-password.jade index 9196c655..988989a9 100644 --- a/app/partials/user-change-password.jade +++ b/app/partials/user-change-password.jade @@ -25,5 +25,5 @@ block content label(for="retype-password") Retype Password input(type="password", placeholder="Retype Password", id="retype-password", ng-model="newPassword2") fieldset - input(type="submit", class="hidden") - a.button.button-green(href="", ng-click="ctrl.save()") Save + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Save") Save diff --git a/app/partials/user-profile.jade b/app/partials/user-profile.jade index 894479b5..92c10968 100644 --- a/app/partials/user-profile.jade +++ b/app/partials/user-profile.jade @@ -55,8 +55,8 @@ block content ng-model="user.bio") fieldset.submit - input(type="submit", class="hidden") - a.button.button-green.save-profile(href="") Save + button(type="submit", title="Save", class="hidden") + a.button.button-green.save-profile.submit-button(href="") Save a.delete-account(href="", title="Delete Taiga account", ng-click="ctrl.openDeleteLightbox()") Delete Taiga account diff --git a/app/partials/views/modules/admin/default-values.jade b/app/partials/views/modules/admin/default-values.jade index 8a041342..c2d74b2c 100644 --- a/app/partials/views/modules/admin/default-values.jade +++ b/app/partials/views/modules/admin/default-values.jade @@ -36,5 +36,5 @@ section.default-values ng-options="s.id as s.name for s in issueStatusList") fieldset - input(type="submit", class="hidden") - a.button.button-green(href="", title="Save") Save + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Save") Save diff --git a/app/partials/views/modules/cancel-account-form.jade b/app/partials/views/modules/cancel-account-form.jade index 99108c2b..5e99a94b 100644 --- a/app/partials/views/modules/cancel-account-form.jade +++ b/app/partials/views/modules/cancel-account-form.jade @@ -3,10 +3,10 @@ div.change-email-form-container(tg-cancel-account) strong Cancel your account
span We're sorry you are leaving the taiga, we hope you enjoyed your stay :) - form(ng-submit="ctrl.submit()") + form fieldset input(type="hidden", name="cancel_token", ng-model="data.cancel_token", data-required="true", placeholder="cancel account token") a.button.button-cancel-account.button-gray(href="", title="Yes, I'm leaving") Yes, I'm leaving! - input(type="submit", style="display:none") + button(type="submit", class="hidden") diff --git a/app/partials/views/modules/change-email-form.jade b/app/partials/views/modules/change-email-form.jade index ccfbd79a..4acd78fb 100644 --- a/app/partials/views/modules/change-email-form.jade +++ b/app/partials/views/modules/change-email-form.jade @@ -3,10 +3,10 @@ div.change-email-form-container(tg-change-email) strong Change your email
span One click more and your email will be updated! - form(ng-submit="ctrl.submit()") + form fieldset input(type="hidden", name="email_token", ng-model="data.email_token", data-required="true", placeholder="change email token") a.button.button-change-email.button-gray(href="", title="Change email") Change email - input(type="submit", style="display:none") + button(type="submit", class="hidden") diff --git a/app/partials/views/modules/change-password-from-recovery-form.jade b/app/partials/views/modules/change-password-from-recovery-form.jade index 98904a7e..8a2e36a7 100644 --- a/app/partials/views/modules/change-password-from-recovery-form.jade +++ b/app/partials/views/modules/change-password-from-recovery-form.jade @@ -3,7 +3,7 @@ div.change-password-form-container(tg-change-password-from-recovery) strong Create a new Taiga pass
span And hey, you may want to eat some more iron-rich food, it's good for your brain :P - form(ng-submit="ctrl.submit()") + form fieldset.token-change-password(ng-hide="tokenInParams") input(type="text", name="token", ng-model="data.token", data-required="true", placeholder="Recover password token") @@ -16,5 +16,5 @@ div.change-password-form-container(tg-change-password-from-recovery) input(type="password", name="password2", id="password2", ng-model="data.password2", data-required="true", data-equalto="#password", placeholder="Re-type new password") fieldset - a.button.button-change-password.button-gray(href="", title="Reset Password") Reset Password - input(type="submit", style="display:none") + a.button.button-change-password.button-gray.submit-button(href="", title="Reset Password") Reset Password + button(type="submit", class="hidden") diff --git a/app/partials/views/modules/forgot-form.jade b/app/partials/views/modules/forgot-form.jade index 492e4d2b..074a4051 100644 --- a/app/partials/views/modules/forgot-form.jade +++ b/app/partials/views/modules/forgot-form.jade @@ -10,7 +10,7 @@ div.forgot-form-container(tg-forgot-password) input(type="text", name="username", ng-model="data.username", data-required="true", placeholder="Username or email") fieldset - a.button.button-forgot.button-gray(href="", title="Reset Password") Reset Password - input(type="submit", style="display:none") + button(type="submit", class="hidden") + a.button.button-gray.submit-button.button-forgot(href="", title="Reset Password") Reset Password a(href="", title="Login", tg-nav="login") Nah, take me back. I think I remember it. diff --git a/app/partials/views/modules/invitation-login-form.jade b/app/partials/views/modules/invitation-login-form.jade index 8a0b50b5..d6f35ebd 100644 --- a/app/partials/views/modules/invitation-login-form.jade +++ b/app/partials/views/modules/invitation-login-form.jade @@ -8,7 +8,7 @@ form.login-form placeholder="Password") a.forgot-pass(href="", tg-nav="forgot-password", title="Did you forgot your password?") Forgot it? fieldset - a.button.button-login.button-gray(href="", title="Log in") Enter - input(type="submit", style="display:none") + a.button.button-login.button-gray.submit-button(href="", title="Log in") Enter + button(type="submit", class="hidden") fieldset(tg-github-login-button) diff --git a/app/partials/views/modules/invitation-register-form.jade b/app/partials/views/modules/invitation-register-form.jade index 4005dc73..bfd4118e 100644 --- a/app/partials/views/modules/invitation-register-form.jade +++ b/app/partials/views/modules/invitation-register-form.jade @@ -20,7 +20,7 @@ form.register-form placeholder="Set a password") fieldset - a.button.button-register.button-gray(href="", title="Sign up") Sign up - input(type="submit", style="display:none") + button(type="submit", class="hidden") + a.button.button-register.button-gray.submit-button(href="", title="Sign up") Sign up tg-terms-notice diff --git a/app/partials/views/modules/lightbox-add-member.jade b/app/partials/views/modules/lightbox-add-member.jade index 8bff3b80..596c40d5 100644 --- a/app/partials/views/modules/lightbox-add-member.jade +++ b/app/partials/views/modules/lightbox-add-member.jade @@ -6,7 +6,9 @@ form //- Form is set in a directive .add-member-forms - a.button.button-green(href="", title="Save") - span Create + + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Create") + span Create p.help-text If users are already registered on Taiga, they will be added automatically. Otherwise they will receive an invitation. diff --git a/app/partials/views/modules/lightbox-create-issue.jade b/app/partials/views/modules/lightbox-create-issue.jade index 1dbe545d..54bf1234 100644 --- a/app/partials/views/modules/lightbox-create-issue.jade +++ b/app/partials/views/modules/lightbox-create-issue.jade @@ -20,6 +20,6 @@ form textarea.description(placeholder="Description", ng-model="issue.description") // include lightbox-attachments - input(type="submit", style="display:none") - a.button.button-green(href="", title="Save") + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Save") span Create diff --git a/app/partials/views/modules/lightbox-feedback.jade b/app/partials/views/modules/lightbox-feedback.jade index a59c4f56..7003e702 100644 --- a/app/partials/views/modules/lightbox-feedback.jade +++ b/app/partials/views/modules/lightbox-feedback.jade @@ -6,6 +6,6 @@ form textarea(ng-model="feedback.comment", data-required="true", placeholder="...a bug, some suggestions, something cool... or even your worst nightmare with Taiga") fieldset - input.hidden(type="submit") - a.button.button-green(href="", title="Send feedback") + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Send feedback") span Send feedback diff --git a/app/partials/views/modules/lightbox-issue-bulk.jade b/app/partials/views/modules/lightbox-issue-bulk.jade index 23dfe4bc..485fc429 100644 --- a/app/partials/views/modules/lightbox-issue-bulk.jade +++ b/app/partials/views/modules/lightbox-issue-bulk.jade @@ -4,5 +4,6 @@ form h2.title(tr="common.new-bulk") fieldset textarea(cols="200", wrap="off", tg-limit-line-length, tr="placeholder:common.one-item-line", ng-model="new.bulk", data-required="true", data-linewidth="200") - a.button.button-green(href="", tr="title:common.save") - span(tr="common.save") + + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Save") Save diff --git a/app/partials/views/modules/lightbox-search.jade b/app/partials/views/modules/lightbox-search.jade index 56a3418d..592d46ce 100644 --- a/app/partials/views/modules/lightbox-search.jade +++ b/app/partials/views/modules/lightbox-search.jade @@ -5,6 +5,5 @@ form fieldset input(type="text", name="text", id="search-text", placeholder="What are you looking for?", data-required="true") fieldset - input.hidden(type="submit") - a.button.button-green(href="", title="Accept") - span Search + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Search") Search \ No newline at end of file diff --git a/app/partials/views/modules/lightbox-sprint-add-edit.jade b/app/partials/views/modules/lightbox-sprint-add-edit.jade index 6ded594b..9fa21fcb 100644 --- a/app/partials/views/modules/lightbox-sprint-add-edit.jade +++ b/app/partials/views/modules/lightbox-sprint-add-edit.jade @@ -15,7 +15,8 @@ form input.date-end(type="text", name="estimated_finish", placeholder="Estimated End", ng-model="sprint.estimated_finish", data-required="true", tg-date-selector) - a.button.button-green(href="", title="Save") + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Create") span Create div(tg-check-permission="delete_milestone") diff --git a/app/partials/views/modules/lightbox-task-bulk.jade b/app/partials/views/modules/lightbox-task-bulk.jade index aa89505c..28b77204 100644 --- a/app/partials/views/modules/lightbox-task-bulk.jade +++ b/app/partials/views/modules/lightbox-task-bulk.jade @@ -4,5 +4,6 @@ form h2.title(tr="common.new-bulk") fieldset textarea(cols="200", wrap="off", tg-limit-line-length, tr="placeholder:common.one-item-line", ng-model="form.data", data-required="true") - a.button.button-green(href="", tr="title:common.save") - span(tr="common.save") + + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Save") Save diff --git a/app/partials/views/modules/lightbox-task-create-edit.jade b/app/partials/views/modules/lightbox-task-create-edit.jade index bc363077..770f66ac 100644 --- a/app/partials/views/modules/lightbox-task-create-edit.jade +++ b/app/partials/views/modules/lightbox-task-create-edit.jade @@ -34,6 +34,6 @@ form tg-blocking-message-input(watch="task.is_blocked", ng-model="task.blocked_note") - button(title="Save" style="display: none;") - a.button.button-green(href="", title="Save") + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Save") span Create diff --git a/app/partials/views/modules/lightbox-us-bulk.jade b/app/partials/views/modules/lightbox-us-bulk.jade index 23dfe4bc..8c92eeae 100644 --- a/app/partials/views/modules/lightbox-us-bulk.jade +++ b/app/partials/views/modules/lightbox-us-bulk.jade @@ -4,5 +4,6 @@ form h2.title(tr="common.new-bulk") fieldset textarea(cols="200", wrap="off", tg-limit-line-length, tr="placeholder:common.one-item-line", ng-model="new.bulk", data-required="true", data-linewidth="200") - a.button.button-green(href="", tr="title:common.save") - span(tr="common.save") + + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Save") Save \ No newline at end of file diff --git a/app/partials/views/modules/lightbox-us-create-edit.jade b/app/partials/views/modules/lightbox-us-create-edit.jade index 73d379c2..817b8f54 100644 --- a/app/partials/views/modules/lightbox-us-create-edit.jade +++ b/app/partials/views/modules/lightbox-us-create-edit.jade @@ -36,5 +36,5 @@ form tg-blocking-message-input(watch="us.is_blocked", ng-model="us.blocked_note") - a.button.button-green(href="", title="Save") - span Create + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Submit") Create diff --git a/app/partials/views/modules/login-form.jade b/app/partials/views/modules/login-form.jade index f5648eab..9174b672 100644 --- a/app/partials/views/modules/login-form.jade +++ b/app/partials/views/modules/login-form.jade @@ -10,8 +10,8 @@ div.login-form-container(tg-login) a.forgot-pass(href="", tg-nav="forgot-password", title="Did you forgot your password?") Forgot it? fieldset - a.button.button-login.button-gray(href="", title="Sign in") Sign in - input(type="submit", style="display:none") + button(type="submit", class="hidden") + a.button.button-login.button-gray.submit-button(href="", title="Sign in") Sign in fieldset(tg-github-login-button) diff --git a/app/partials/views/modules/register-form.jade b/app/partials/views/modules/register-form.jade index f6349c9e..6aa4cccd 100644 --- a/app/partials/views/modules/register-form.jade +++ b/app/partials/views/modules/register-form.jade @@ -21,8 +21,8 @@ div.register-form-container(tg-register) placeholder="Set a password (case sensitive)") fieldset - a.button.button-register.button-gray(href="", title="Sign up") Sign up - input(type="submit", class="hidden") + button(type="submit", class="hidden") + a.button.button-register.button-gray.submit-button(href="", title="Sign up") Sign up fieldset(tg-github-login-button) diff --git a/app/partials/views/modules/wizard-create-project.jade b/app/partials/views/modules/wizard-create-project.jade index c8008524..aef6fd90 100644 --- a/app/partials/views/modules/wizard-create-project.jade +++ b/app/partials/views/modules/wizard-create-project.jade @@ -28,7 +28,9 @@ form fieldset.wizard-action div a.button-prev.button.button-gray(href="", title="Prev") Prev - a.button-submit.button.button-green(href="", title="Create") Create + a.submit-button.button.button-green(href="", title="Create") Create + + button(type="submit", class="hidden") div.progress-bar div.progress-state From 6870b9a057b1840c4c6b119978c6a00380019d30 Mon Sep 17 00:00:00 2001 From: Juanfran Date: Thu, 27 Nov 2014 16:43:15 +0100 Subject: [PATCH 18/66] fix #1706 preserve navigation active in US and tasks --- app/coffee/modules/nav.coffee | 18 +++++++++++++++++- app/partials/task-detail.jade | 2 +- app/partials/us-detail.jade | 2 +- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/app/coffee/modules/nav.coffee b/app/coffee/modules/nav.coffee index adc7e401..7da65d7e 100644 --- a/app/coffee/modules/nav.coffee +++ b/app/coffee/modules/nav.coffee @@ -311,6 +311,22 @@ ProjectMenuDirective = ($log, $compile, $auth, $rootscope, $tgAuth, $location, $ """) + # If the last page was kanban or backlog and + # the new one is the task detail or the us details + # this method preserve the last section name. + getSectionName = ($el, sectionName, project) -> + oldSectionName = $el.find("a.active").parent().attr("id")?.replace("nav-", "") + + if sectionName == "backlog-kanban" + if oldSectionName in ["backlog", "kanban"] + sectionName = oldSectionName + else if project.is_backlog_activated && !project.is_kanban_activated + sectionName = "backlog" + else if !project.is_backlog_activated && project.is_kanban_activated + sectionName = "kanban" + + return sectionName + renderMainMenu = ($el) -> html = mainTemplate({}) $el.html(html) @@ -320,7 +336,7 @@ ProjectMenuDirective = ($log, $compile, $auth, $rootscope, $tgAuth, $location, $ # content loaded signal is raised using inner scope. renderMenuEntries = ($el, targetScope, project={}) -> container = $el.find(".menu-container") - sectionName = targetScope.section + sectionName = getSectionName($el, targetScope.section, project) ctx = { user: $auth.getUser(), diff --git a/app/partials/task-detail.jade b/app/partials/task-detail.jade index c9d4e80e..25cf5c73 100644 --- a/app/partials/task-detail.jade +++ b/app/partials/task-detail.jade @@ -5,7 +5,7 @@ block head block content div.wrapper(ng-controller="TaskDetailController as ctrl", - ng-init="section='backlog'") + ng-init="section='backlog-kanban'") div.main.us-detail div.us-detail-header.header-with-actions include views/components/mainTitle diff --git a/app/partials/us-detail.jade b/app/partials/us-detail.jade index 2bb65166..6685ae9a 100644 --- a/app/partials/us-detail.jade +++ b/app/partials/us-detail.jade @@ -5,7 +5,7 @@ block head block content div.wrapper(ng-controller="UserStoryDetailController as ctrl", - ng-init="section='backlog'") + ng-init="section='backlog-kanban'") div.main.us-detail div.us-detail-header.header-with-actions include views/components/mainTitle From 0c334d5828752be4ee522806935861982890efa2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Thu, 27 Nov 2014 16:54:16 +0100 Subject: [PATCH 19/66] Remove help from taiga set link instead --- app/partials/admin-third-parties-github.jade | 65 +------------------- app/styles/components/markdown-help.scss | 3 +- app/styles/modules/admin/third-parties.scss | 2 +- 3 files changed, 6 insertions(+), 64 deletions(-) diff --git a/app/partials/admin-third-parties-github.jade b/app/partials/admin-third-parties-github.jade index 0a900b61..53a3140a 100644 --- a/app/partials/admin-third-parties-github.jade +++ b/app/partials/admin-third-parties-github.jade @@ -31,65 +31,6 @@ block content a.button.button-green.submit-button(href="", title="Save") Save - .help - h2 How to use it - - h3 Configure Taiga - ol - li Fill - span Secret key - | or use the auto generated one - - li Copy the - span Payload URL field. - - h3 Configure Github - ol - li Go to your github repository. - li Click on - span Settings - | > - span Webhooks & Services - | > - span Add webhook - - li On that screen set the payload url with the payload url of this screen. - li Secret must be filled with the same content as the secret field of this screen. - li Content type must be - span application/json. - li Taiga currently listen for three different kind of events: - ol - li Push events: changing element status via commit message - li Issues: issues created in github appear automatically in Taiga - li Issue comment: issue comments created in github appear automatically in Taiga - - p Just check "send me everything" or just the events you want Taiga to listen for. - - .img - .alt-image Github Webhooke page - img(src="/images/github-help.png", alt="webhook") - - h2 Changing elements status via commit message - - p - | The status of any issue, task or user story can be changed via commit message. - | Just add to your commit message something like: - - code - | TG-REF #STATUS - - ul.code-info - li - span REF: - | US/Issue/Task reference of the element you want to modify - li - span STATUS: - | New status slug to set, you can find all of them in: - a(href="", tg-nav="project-admin-project-values-us-status:project=project.slug") US STATUSES. - - h3 An example please! - - code - | TG-123 #closed - - p In this example, 123 is an issue reference and with this command, the issue will change its status to closed. + a.help-button(href="https://taiga.io/support/github-integration/", target="_blank") + span.icon.icon-help + span Do you need help? Check out our support page! diff --git a/app/styles/components/markdown-help.scss b/app/styles/components/markdown-help.scss index 270a7e38..c3577a8a 100644 --- a/app/styles/components/markdown-help.scss +++ b/app/styles/components/markdown-help.scss @@ -1,4 +1,5 @@ -a.help-markdown { +a.help-markdown, +a.help-button { @extend %small; color: $gray-light; &:hover { diff --git a/app/styles/modules/admin/third-parties.scss b/app/styles/modules/admin/third-parties.scss index 1baf83ea..ede1fad1 100644 --- a/app/styles/modules/admin/third-parties.scss +++ b/app/styles/modules/admin/third-parties.scss @@ -1,6 +1,6 @@ .admin-third-parties { form { - margin-top: 1rem; + margin: 1rem 0; max-width: 700px; width: 100%; } From 8785a3ff8abe110b93c040dac04aadc8813ca0ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Thu, 6 Nov 2014 13:47:07 +0100 Subject: [PATCH 20/66] Created New Module Team --- app/coffee/app.coffee | 5 ++ app/coffee/modules/base.coffee | 7 ++- app/coffee/modules/nav.coffee | 6 +++ app/coffee/modules/team.coffee | 22 ++++++++ app/coffee/modules/team/main.coffee | 80 +++++++++++++++++++++++++++++ app/partials/views/team/team.jade | 8 +++ gulpfile.coffee | 1 + 7 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 app/coffee/modules/team.coffee create mode 100644 app/coffee/modules/team/main.coffee create mode 100644 app/partials/views/team/team.jade diff --git a/app/coffee/app.coffee b/app/coffee/app.coffee index 76af3789..1a5794c5 100644 --- a/app/coffee/app.coffee +++ b/app/coffee/app.coffee @@ -63,6 +63,10 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven $routeProvider.when("/project/:pslug/wiki/:slug", {templateUrl: "/partials/wiki.html", resolve: {loader: tgLoaderProvider.add()}}) + # Team + $routeProvider.when("/project/:pslug/team", + {templateUrl: "/partials/views/team/team.html", resolve: {loader: tgLoaderProvider.add()}}) + # Issues $routeProvider.when("/project/:pslug/issues", {templateUrl: "/partials/issues.html", resolve: {loader: tgLoaderProvider.add()}}) @@ -214,6 +218,7 @@ modules = [ "taigaIssues", "taigaUserStories", "taigaTasks", + "taigaTeam", "taigaWiki", "taigaSearch", "taigaAdmin", diff --git a/app/coffee/modules/base.coffee b/app/coffee/modules/base.coffee index 3aeb6e99..877bc907 100644 --- a/app/coffee/modules/base.coffee +++ b/app/coffee/modules/base.coffee @@ -72,8 +72,11 @@ urls = { "project-issues-detail": "/project/:project/issue/:ref" - "project-wiki": "/project/:project/wiki", - "project-wiki-page": "/project/:project/wiki/:slug", + "project-wiki": "/project/:project/wiki" + "project-wiki-page": "/project/:project/wiki/:slug" + + # Team + "project-team": "/project/:project/team" # Admin "project-admin-home": "/project/:project/admin/project-profile/details" diff --git a/app/coffee/modules/nav.coffee b/app/coffee/modules/nav.coffee index adc7e401..d76497c0 100644 --- a/app/coffee/modules/nav.coffee +++ b/app/coffee/modules/nav.coffee @@ -243,6 +243,12 @@ ProjectMenuDirective = ($log, $compile, $auth, $rootscope, $tgAuth, $location, $ <% } %> + <% if (project.videoconferences) { %>
- +
@@ -152,7 +171,7 @@ TeamMembersDirective = () -> """ return { link: (scope) -> - if !_.isArray(scope.memberships) + if not _.isArray(scope.memberships) scope.memberships = [scope.memberships] template: template @@ -160,7 +179,8 @@ TeamMembersDirective = () -> memberships: "=", filtersQ: "=filtersq", filtersRole: "=filtersrole", - currentUser: "@currentuser" + currentUser: "@currentuser", + stats: "=" } } From a1d09e75c497ace5a6ca983bbe3958ec7112ac16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Tue, 25 Nov 2014 12:40:00 +0100 Subject: [PATCH 26/66] Team statistics styles --- app/coffee/modules/team/main.coffee | 17 ++++++++++------- .../views/modules/team/team-table.jade | 18 +++++++++--------- app/styles/layout/typography.scss | 12 ++++++++++++ app/styles/modules/team/team-table.scss | 3 +++ 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee index 9818f64c..a8370063 100644 --- a/app/coffee/modules/team/main.coffee +++ b/app/coffee/modules/team/main.coffee @@ -80,10 +80,13 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) processStat: (stat) -> max = _.max(stat) + min = _.min(stat) singleStat = _.map stat, (value, key) -> if value == max return [key, 1] - return [key, (value * 0.3) / max] + else if value == min + return [key, 0.1] + return [key, (value * 0.5) / max] singleStat = _.object(singleStat) return singleStat @@ -150,22 +153,22 @@ TeamMembersDirective = () ->
- +
- +
- +
- +
- +
- 666 +
""" diff --git a/app/partials/views/modules/team/team-table.jade b/app/partials/views/modules/team/team-table.jade index 9566b943..166a615e 100644 --- a/app/partials/views/modules/team/team-table.jade +++ b/app/partials/views/modules/team/team-table.jade @@ -2,25 +2,25 @@ section.table-team.basic-table header.row.team-header div.username div.attribute.attribute-name - span Bug Killer + span Mr. Wolf div.popover.attribute-explanation - span Thanks to you, this project still steady! + span I see, you solve issues! div.attribute span Poison Drinker div.popover.attribute-explanation span Hey, are you a iocaine-holic? div.attribute - span Brown Dispatcher + span Cervantes div.popover.attribute-explanation - span Oh, stop dealing work! + span You have no fear to the blank page! div.attribute - Total Brown Eater + Total Bug Hunter div.popover.attribute-explanation - span Oh, poor devil, you are valuable! + span Thaks to you, this project still alive. div.attribute - span Chatter + span Night Shift div.popover.attribute-explanation - span This is not a chat... but I love your comments! + span Poor Devil, you work too much. div.attribute Total Power div.popover.attribute-explanation @@ -32,4 +32,4 @@ h2 span Team > span {{filtersRole.name || "All"}} -section.table-team.basic-table(tg-team-members, memberships="memberships", filtersq="filtersQ", filtersrole="filtersRole") +section.table-team.basic-table(tg-team-members, memberships="memberships", stats="stats", filtersq="filtersQ", filtersrole="filtersRole") diff --git a/app/styles/layout/typography.scss b/app/styles/layout/typography.scss index 664055ac..8808712b 100755 --- a/app/styles/layout/typography.scss +++ b/app/styles/layout/typography.scss @@ -255,3 +255,15 @@ a:visited { .icon-help:before { content: 'U'; } +.icon-bug:before { + content: 'Q'; +} +.icon-briefcase:before { + content: 'R'; +} +.icon-writer:before { + content: 'S'; +} +.icon-tasks:before { + content: 'T'; +} diff --git a/app/styles/modules/team/team-table.scss b/app/styles/modules/team/team-table.scss index 98d46076..e9e4f3e7 100644 --- a/app/styles/modules/team/team-table.scss +++ b/app/styles/modules/team/team-table.scss @@ -13,6 +13,9 @@ .points { @extend %xlarge; color: $grayer; + &.top { + color: $fresh-taiga; + } } .points { @extend %title; From a0b46d0cf8f0c8c3bf5eb97057a9e5488b3c36f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Wed, 26 Nov 2014 11:22:59 +0100 Subject: [PATCH 27/66] Add error handling on remove admin permissions of memberships panel --- app/coffee/modules/admin/memberships.coffee | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/coffee/modules/admin/memberships.coffee b/app/coffee/modules/admin/memberships.coffee index 631feb50..531d12cf 100644 --- a/app/coffee/modules/admin/memberships.coffee +++ b/app/coffee/modules/admin/memberships.coffee @@ -302,8 +302,10 @@ MembershipsRowAdminCheckboxDirective = ($log, $repo, $confirm) -> onSuccess = -> $confirm.notify("success") - onError = -> - $confirm.notify("error") + onError = (data) -> + member.revert() + $el.find(":checkbox").prop("checked", member.is_owner) + $confirm.notify("error", data.is_owner[0]) target = angular.element(event.currentTarget) member.is_owner = target.prop("checked") From e0694b2b76b9abef0e8ee25345d1d6669c91ec67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Wed, 26 Nov 2014 11:23:19 +0100 Subject: [PATCH 28/66] Add leave method to the projects resource --- app/coffee/modules/resources/projects.coffee | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/coffee/modules/resources/projects.coffee b/app/coffee/modules/resources/projects.coffee index 5e0e8515..ecffdd09 100644 --- a/app/coffee/modules/resources/projects.coffee +++ b/app/coffee/modules/resources/projects.coffee @@ -45,6 +45,9 @@ resourceProvider = ($repo) -> service.stats = (projectId) -> return $repo.queryOneRaw("projects", "#{projectId}/stats") + service.leave = (projectId) -> + return $repo.queryOneRaw("projects", "#{projectId}/leave") + service.memberStats = (projectId) -> return $repo.queryOneRaw("projects", "#{projectId}/member_stats") From b7f570ae53c4b0ac12d404078ff89056d5a21415 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Wed, 26 Nov 2014 12:11:16 +0100 Subject: [PATCH 29/66] Filtering memberships with owner in team members --- app/coffee/modules/resources/memberships.coffee | 7 +++++-- app/coffee/modules/team/main.coffee | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/coffee/modules/resources/memberships.coffee b/app/coffee/modules/resources/memberships.coffee index 6a2763b7..09443fd7 100644 --- a/app/coffee/modules/resources/memberships.coffee +++ b/app/coffee/modules/resources/memberships.coffee @@ -28,10 +28,13 @@ resourceProvider = ($repo, $http, $urls) -> service.get = (id) -> return $repo.queryOne("memberships", id) - service.list = (projectId, filters) -> + service.list = (projectId, filters, enablePagination=true) -> params = {project: projectId} params = _.extend({}, params, filters or {}) - return $repo.queryPaginated("memberships", params) + if enablePagination + return $repo.queryPaginated("memberships", params) + + return $repo.queryMany("memberships", params, options={enablePagination:enablePagination}) service.listByUser = (userId, filters) -> params = {user: userId} diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee index a8370063..c69e3714 100644 --- a/app/coffee/modules/team/main.coffee +++ b/app/coffee/modules/team/main.coffee @@ -48,6 +48,7 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) # On Success promise.then => + #TODO: i18n @appTitle.set("Team - " + @scope.project.name) tgLoader.pageLoaded() @@ -63,8 +64,8 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.filtersRole = "" loadMembers: -> - return @rs.memberships.list(@scope.projectId).then (data) => - @scope.memberships = data.models + return @rs.memberships.list(@scope.projectId, {}, false).then (data) => + @scope.memberships = _.filter(data, (membership) => membership.user?) return data loadProject: -> From 51087393f1bdcb25dc0e4ee9971f3709ed170931 Mon Sep 17 00:00:00 2001 From: Juanfran Date: Wed, 26 Nov 2014 13:17:54 +0100 Subject: [PATCH 30/66] create member-stats directive --- app/coffee/modules/team/main.coffee | 89 +++++++++++++------ .../views/modules/team/team-table.jade | 2 +- .../modules/admin/admin-membership-table.scss | 1 - app/styles/modules/team/team-table.scss | 4 + 4 files changed, 67 insertions(+), 29 deletions(-) diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee index c69e3714..09e00401 100644 --- a/app/coffee/modules/team/main.coffee +++ b/app/coffee/modules/team/main.coffee @@ -136,54 +136,91 @@ TeamFiltersDirective = () -> module.directive("tgTeamFilters", [TeamFiltersDirective]) +############################################################################# +## Team Member Stats Directive +############################################################################# + +TeamMemberStatsDirective = () -> + template = """ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ """ + return { + template: template + } + +module.directive("tgTeamMemberStats", TeamMemberStatsDirective) + +############################################################################# +## Team Member Directive +############################################################################# + +TeamMemberCurrentUserDirective = () -> + template = """ +
+
+
+ +
+ +
+
+
+
+
+
+ """ + return { + template: template + scope: { + currentUser: "=currentuser", + stats: "=" + } + } + +module.directive("tgTeamCurrentUser", TeamMemberCurrentUserDirective) + ############################################################################# ## Team Members Directive ############################################################################# TeamMembersDirective = () -> template = """ -
+
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
+
""" return { - link: (scope) -> - if not _.isArray(scope.memberships) - scope.memberships = [scope.memberships] - template: template scope: { memberships: "=", filtersQ: "=filtersq", filtersRole: "=filtersrole", - currentUser: "@currentuser", stats: "=" } } @@ -208,8 +245,6 @@ LeaveProjectDirective = ($repo, $confirm, $location) -> console.log "TODO" return { scope: {}, - restrict: "EA", - replace: true, template: template, link: link } diff --git a/app/partials/views/modules/team/team-table.jade b/app/partials/views/modules/team/team-table.jade index 166a615e..43056945 100644 --- a/app/partials/views/modules/team/team-table.jade +++ b/app/partials/views/modules/team/team-table.jade @@ -26,7 +26,7 @@ section.table-team.basic-table div.popover.attribute-explanation span How far did you go into this Taiga? - div.hero(tg-team-members, memberships="currentUser" currentuser=true) + div.hero(tg-team-current-user, currentuser="currentUser") h2 span Team > diff --git a/app/styles/modules/admin/admin-membership-table.scss b/app/styles/modules/admin/admin-membership-table.scss index 6e15db4d..adbadf9d 100644 --- a/app/styles/modules/admin/admin-membership-table.scss +++ b/app/styles/modules/admin/admin-membership-table.scss @@ -90,7 +90,6 @@ .header-status { @include table-flex-child(1, 50px, 0); } - .check { background-color: darken($whitish, 10%); border-radius: 2px; diff --git a/app/styles/modules/team/team-table.scss b/app/styles/modules/team/team-table.scss index e9e4f3e7..bed23da5 100644 --- a/app/styles/modules/team/team-table.scss +++ b/app/styles/modules/team/team-table.scss @@ -5,6 +5,10 @@ .username { @include table-flex-child(3, 0, 0); } + .member-stats { + @include table-flex(stretch, center, flex, row, wrap, flex-start); + @include table-flex-child(6, 0, 0); + } .attribute { @include table-flex-child(1, 0, 0); position: relative; From e6e7c43907241934bc2c8904321f62d8a17abc80 Mon Sep 17 00:00:00 2001 From: Juanfran Date: Wed, 26 Nov 2014 13:37:40 +0100 Subject: [PATCH 31/66] fix current user stats --- app/coffee/modules/team/main.coffee | 20 +++++++++++-------- .../views/modules/team/team-table.jade | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee index 09e00401..10c4402c 100644 --- a/app/coffee/modules/team/main.coffee +++ b/app/coffee/modules/team/main.coffee @@ -143,26 +143,30 @@ module.directive("tgTeamFilters", [TeamFiltersDirective]) TeamMemberStatsDirective = () -> template = """
- +
- +
- +
- +
- +
""" return { - template: template + template: template, + scope: { + "stats": "=", + "userId": "=user" + } } module.directive("tgTeamMemberStats", TeamMemberStatsDirective) @@ -183,7 +187,7 @@ TeamMemberCurrentUserDirective = () ->
-
+
""" return { @@ -212,7 +216,7 @@ TeamMembersDirective = () ->
-
+
""" return { diff --git a/app/partials/views/modules/team/team-table.jade b/app/partials/views/modules/team/team-table.jade index 43056945..eb2bc4c5 100644 --- a/app/partials/views/modules/team/team-table.jade +++ b/app/partials/views/modules/team/team-table.jade @@ -26,7 +26,7 @@ section.table-team.basic-table div.popover.attribute-explanation span How far did you go into this Taiga? - div.hero(tg-team-current-user, currentuser="currentUser") + div.hero(tg-team-current-user, stats="stats", currentuser="currentUser") h2 span Team > From 2a4680b5293a7c73e6cd93947ba4840f4d764875 Mon Sep 17 00:00:00 2001 From: Juanfran Date: Wed, 26 Nov 2014 14:57:33 +0100 Subject: [PATCH 32/66] add role to the current user & remove the user from the team list --- app/coffee/modules/team/main.coffee | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee index 10c4402c..f5fdf26a 100644 --- a/app/coffee/modules/team/main.coffee +++ b/app/coffee/modules/team/main.coffee @@ -55,8 +55,6 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) # On Error promise.then null, @.onInitialDataError.bind(@) - @scope.currentUser = @auth.getUser() - setRole: (role) -> if role @scope.filtersRole = role @@ -65,7 +63,15 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) loadMembers: -> return @rs.memberships.list(@scope.projectId, {}, false).then (data) => - @scope.memberships = _.filter(data, (membership) => membership.user?) + currentUser = @auth.getUser() + + @scope.currentUser = _.find data, (membership) => + return membership.user == currentUser.id + + @scope.memberships = _.filter data, (membership) => + if membership.user && membership.user != currentUser.id + return membership + return data loadProject: -> @@ -172,7 +178,7 @@ TeamMemberStatsDirective = () -> module.directive("tgTeamMemberStats", TeamMemberStatsDirective) ############################################################################# -## Team Member Directive +## Team Current User Directive ############################################################################# TeamMemberCurrentUserDirective = () -> @@ -180,14 +186,15 @@ TeamMemberCurrentUserDirective = () ->
- +
- + +
-
+
""" return { From b725b6c6e1ca60de9997f032ab5892ef60eabe8b Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Wed, 26 Nov 2014 15:49:45 +0100 Subject: [PATCH 33/66] Allowing leave project --- app/coffee/modules/resources/projects.coffee | 7 ++-- app/coffee/modules/team/main.coffee | 34 ++++++++++++++----- .../views/modules/team/team-table.jade | 2 +- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/app/coffee/modules/resources/projects.coffee b/app/coffee/modules/resources/projects.coffee index ecffdd09..ab506262 100644 --- a/app/coffee/modules/resources/projects.coffee +++ b/app/coffee/modules/resources/projects.coffee @@ -22,7 +22,7 @@ taiga = @.taiga -resourceProvider = ($repo) -> +resourceProvider = ($repo, $http, $urls) -> service = {} service.get = (id) -> @@ -46,7 +46,8 @@ resourceProvider = ($repo) -> return $repo.queryOneRaw("projects", "#{projectId}/stats") service.leave = (projectId) -> - return $repo.queryOneRaw("projects", "#{projectId}/leave") + url = "#{$urls.resolve("projects")}/#{projectId}/leave" + return $http.post(url) service.memberStats = (projectId) -> return $repo.queryOneRaw("projects", "#{projectId}/member_stats") @@ -59,4 +60,4 @@ resourceProvider = ($repo) -> module = angular.module("taigaResources") -module.factory("$tgProjectsResourcesProvider", ["$tgRepo", resourceProvider]) +module.factory("$tgProjectsResourcesProvider", ["$tgRepo", "$tgHttp", "$tgUrls", resourceProvider]) diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee index f5fdf26a..f91d6ec3 100644 --- a/app/coffee/modules/team/main.coffee +++ b/app/coffee/modules/team/main.coffee @@ -32,6 +32,7 @@ module = angular.module("taigaTeam") class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) @.$inject = [ "$scope", + "$rootScope", "$tgRepo", "$tgResources", "$routeParams", @@ -41,7 +42,7 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) "tgLoader" ] - constructor: (@scope, @repo, @rs, @params, @q, @appTitle, @auth, tgLoader) -> + constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @appTitle, @auth, tgLoader) -> @scope.sectionName = "Team" promise = @.loadInitialData() @@ -55,6 +56,12 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) # On Error promise.then null, @.onInitialDataError.bind(@) +<<<<<<< HEAD +======= + @scope.currentUser = @auth.getUser() + @scope.projectId = @rootscope.projectId + +>>>>>>> Allowing leave project setRole: (role) -> if role @scope.filtersRole = role @@ -190,7 +197,7 @@ TeamMemberCurrentUserDirective = () ->
-
+
@@ -200,6 +207,7 @@ TeamMemberCurrentUserDirective = () -> return { template: template scope: { + projectId: "=projectid", currentUser: "=currentuser", stats: "=" } @@ -242,22 +250,32 @@ module.directive("tgTeamMembers", TeamMembersDirective) ## Leave project Directive ############################################################################# -LeaveProjectDirective = ($repo, $confirm, $location) -> +LeaveProjectDirective = ($repo, $confirm, $location, $rs, $navurls) -> template= """ Leave this project """ #TODO: i18n - link = ($scope) -> + link = ($scope, $el, $attrs) -> $scope.leave = () -> - $confirm.ask("Leave this project", "Are you sure you want to leave the project?")#TODO: i18n - .then (finish) => - console.log "TODO" + #TODO: i18n + $confirm.ask("Leave this project", "Are you sure you want to leave the project?").then (finish) => + promise = $rs.projects.leave($attrs.projectid) + + promise.then => + finish() + $confirm.notify("success") + $location.path($navurls.resolve("home")) + + promise.then null, (response) -> + finish() + $confirm.notify('error', response.data._error_message) + return { scope: {}, template: template, link: link } -module.directive("tgLeaveProject", ["$tgRepo", "$tgConfirm", "$tgLocation", LeaveProjectDirective]) +module.directive("tgLeaveProject", ["$tgRepo", "$tgConfirm", "$tgLocation", "$tgResources", "$tgNavUrls", LeaveProjectDirective]) diff --git a/app/partials/views/modules/team/team-table.jade b/app/partials/views/modules/team/team-table.jade index eb2bc4c5..e4494541 100644 --- a/app/partials/views/modules/team/team-table.jade +++ b/app/partials/views/modules/team/team-table.jade @@ -26,7 +26,7 @@ section.table-team.basic-table div.popover.attribute-explanation span How far did you go into this Taiga? - div.hero(tg-team-current-user, stats="stats", currentuser="currentUser") + div.hero(tg-team-current-user, stats="stats", currentuser="currentUser", projectid="projectId") h2 span Team > From ddad02b3fcbc272ee24bada786395b3a6898f604 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Wed, 26 Nov 2014 15:55:04 +0100 Subject: [PATCH 34/66] Fixing scope --- app/coffee/modules/team/main.coffee | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee index f91d6ec3..4d37a0d7 100644 --- a/app/coffee/modules/team/main.coffee +++ b/app/coffee/modules/team/main.coffee @@ -56,12 +56,6 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) # On Error promise.then null, @.onInitialDataError.bind(@) -<<<<<<< HEAD -======= - @scope.currentUser = @auth.getUser() - @scope.projectId = @rootscope.projectId - ->>>>>>> Allowing leave project setRole: (role) -> if role @scope.filtersRole = role From f87d1b7534d1024ee3ef5e621ff9622e7ba65ef3 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Wed, 26 Nov 2014 16:15:03 +0100 Subject: [PATCH 35/66] Fixing team icons opacity --- app/coffee/modules/team/main.coffee | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee index 4d37a0d7..70da1714 100644 --- a/app/coffee/modules/team/main.coffee +++ b/app/coffee/modules/team/main.coffee @@ -90,10 +90,10 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) max = _.max(stat) min = _.min(stat) singleStat = _.map stat, (value, key) -> + if value == min + return [key, 0.1] if value == max return [key, 1] - else if value == min - return [key, 0.1] return [key, (value * 0.5) / max] singleStat = _.object(singleStat) return singleStat @@ -150,19 +150,19 @@ module.directive("tgTeamFilters", [TeamFiltersDirective]) TeamMemberStatsDirective = () -> template = """
- +
- +
- +
- +
- +
From 849e67d7a81dddddef3d760e1c6d7bdb1ff5b781 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Thu, 27 Nov 2014 12:57:37 +0100 Subject: [PATCH 36/66] Showing the power column --- app/coffee/modules/team/main.coffee | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee index 70da1714..66e6855f 100644 --- a/app/coffee/modules/team/main.coffee +++ b/app/coffee/modules/team/main.coffee @@ -65,14 +65,24 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) loadMembers: -> return @rs.memberships.list(@scope.projectId, {}, false).then (data) => currentUser = @auth.getUser() + if not currentUser.photo? + currentUser.photo = "/images/unnamed.png" @scope.currentUser = _.find data, (membership) => return membership.user == currentUser.id + @scope.totals = {} + _.forEach data, (membership) => + @scope.totals[membership.user] = 0 + @scope.memberships = _.filter data, (membership) => if membership.user && membership.user != currentUser.id return membership + for membership in @scope.memberships + if not membership.user.photo? + membership.user.photo = "/images/unnamed.png" + return data loadProject: -> @@ -84,7 +94,14 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) loadMemberStats: -> return @rs.projects.memberStats(@scope.projectId).then (stats) => - @scope.stats = @.processStats(stats) + totals = {} + _.forEach @scope.totals, (total, userId) => + vals = _.map(stats, (memberStats, statsKey) -> memberStats[userId]) + total = _.reduce(vals, (sum, el) -> sum + el) + @scope.totals[userId] = total + + @scope.stats = @.processStats(stats) + @scope.stats.totals = @scope.totals processStat: (stat) -> max = _.max(stat) @@ -165,7 +182,7 @@ TeamMemberStatsDirective = () ->
- +
""" return { @@ -187,7 +204,7 @@ TeamMemberCurrentUserDirective = () ->
- +
@@ -218,7 +235,7 @@ TeamMembersDirective = () ->
- +
From 9177f172f474f70e239e3ffe68932e0fbb70422e Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Thu, 27 Nov 2014 13:00:34 +0100 Subject: [PATCH 37/66] Showing team members only if there are team members --- app/partials/views/modules/team/team-table.jade | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/partials/views/modules/team/team-table.jade b/app/partials/views/modules/team/team-table.jade index e4494541..07f94379 100644 --- a/app/partials/views/modules/team/team-table.jade +++ b/app/partials/views/modules/team/team-table.jade @@ -28,7 +28,7 @@ section.table-team.basic-table div.hero(tg-team-current-user, stats="stats", currentuser="currentUser", projectid="projectId") -h2 +h2(ng-show="memberships") span Team > span {{filtersRole.name || "All"}} From 33bb54e453df761b07b3788657ee7c5bfb11af84 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Thu, 27 Nov 2014 13:26:56 +0100 Subject: [PATCH 38/66] Showing only columns related no enabled features --- app/coffee/modules/team/main.coffee | 31 +++++++++++++------ .../views/modules/team/team-table.jade | 14 ++++----- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee index 66e6855f..aa573e36 100644 --- a/app/coffee/modules/team/main.coffee +++ b/app/coffee/modules/team/main.coffee @@ -90,6 +90,10 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.project = project @scope.$emit('project:loaded', project) + @scope.issuesEnabled = project.is_issues_activated + @scope.tasksEnabled = project.is_kanban_activated or project.is_backlog_activated + @scope.wikiEnabled = project.is_wiki_activated + return project loadMemberStats: -> @@ -166,19 +170,19 @@ module.directive("tgTeamFilters", [TeamFiltersDirective]) TeamMemberStatsDirective = () -> template = """ -
+
-
+
-
+
-
+
-
+
@@ -188,8 +192,11 @@ TeamMemberStatsDirective = () -> return { template: template, scope: { - "stats": "=", - "userId": "=user" + stats: "=", + userId: "=user" + issuesEnabled: "=issuesenabled" + tasksEnabled: "=tasksenabled" + wikiEnabled: "=wikienabled" } } @@ -212,7 +219,7 @@ TeamMemberCurrentUserDirective = () ->
-
+
""" return { @@ -221,6 +228,9 @@ TeamMemberCurrentUserDirective = () -> projectId: "=projectid", currentUser: "=currentuser", stats: "=" + issuesEnabled: "=issuesenabled" + tasksEnabled: "=tasksenabled" + wikiEnabled: "=wikienabled" } } @@ -242,7 +252,7 @@ TeamMembersDirective = () ->
-
+
""" return { @@ -252,6 +262,9 @@ TeamMembersDirective = () -> filtersQ: "=filtersq", filtersRole: "=filtersrole", stats: "=" + issuesEnabled: "=issuesenabled" + tasksEnabled: "=tasksenabled" + wikiEnabled: "=wikienabled" } } diff --git a/app/partials/views/modules/team/team-table.jade b/app/partials/views/modules/team/team-table.jade index 07f94379..265325ad 100644 --- a/app/partials/views/modules/team/team-table.jade +++ b/app/partials/views/modules/team/team-table.jade @@ -1,23 +1,23 @@ section.table-team.basic-table header.row.team-header div.username - div.attribute.attribute-name + div.attribute.attribute-name(ng-if="issuesEnabled") span Mr. Wolf div.popover.attribute-explanation span I see, you solve issues! - div.attribute + div.attribute(ng-if="tasksEnabled") span Poison Drinker div.popover.attribute-explanation span Hey, are you a iocaine-holic? - div.attribute + div.attribute(ng-if="wikiEnabled") span Cervantes div.popover.attribute-explanation span You have no fear to the blank page! - div.attribute + div.attribute(ng-if="issuesEnabled") Total Bug Hunter div.popover.attribute-explanation span Thaks to you, this project still alive. - div.attribute + div.attribute(ng-if="tasksEnabled") span Night Shift div.popover.attribute-explanation span Poor Devil, you work too much. @@ -26,10 +26,10 @@ section.table-team.basic-table div.popover.attribute-explanation span How far did you go into this Taiga? - div.hero(tg-team-current-user, stats="stats", currentuser="currentUser", projectid="projectId") + div.hero(tg-team-current-user, stats="stats", currentuser="currentUser", projectid="projectId", issuesEnabled="issuesEnabled", tasksenabled="tasksEnabled", wikienabled="wikiEnabled") h2(ng-show="memberships") span Team > span {{filtersRole.name || "All"}} -section.table-team.basic-table(tg-team-members, memberships="memberships", stats="stats", filtersq="filtersQ", filtersrole="filtersRole") +section.table-team.basic-table(tg-team-members, memberships="memberships", stats="stats", filtersq="filtersQ", filtersrole="filtersRole", issuesEnabled="issuesEnabled", tasksenabled="tasksEnabled", wikienabled="wikiEnabled") From a13501cc58d2547b5c660d5cc9484eecd8e73a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Thu, 27 Nov 2014 15:30:39 +0100 Subject: [PATCH 39/66] Fix table columns layout in team members --- .../views/modules/team/team-table.jade | 49 ++++++++++--------- app/styles/dependencies/colors.scss | 2 +- app/styles/modules/team/team-table.scss | 15 ++++-- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/app/partials/views/modules/team/team-table.jade b/app/partials/views/modules/team/team-table.jade index 265325ad..f926f334 100644 --- a/app/partials/views/modules/team/team-table.jade +++ b/app/partials/views/modules/team/team-table.jade @@ -1,30 +1,31 @@ section.table-team.basic-table header.row.team-header div.username - div.attribute.attribute-name(ng-if="issuesEnabled") - span Mr. Wolf - div.popover.attribute-explanation - span I see, you solve issues! - div.attribute(ng-if="tasksEnabled") - span Poison Drinker - div.popover.attribute-explanation - span Hey, are you a iocaine-holic? - div.attribute(ng-if="wikiEnabled") - span Cervantes - div.popover.attribute-explanation - span You have no fear to the blank page! - div.attribute(ng-if="issuesEnabled") - Total Bug Hunter - div.popover.attribute-explanation - span Thaks to you, this project still alive. - div.attribute(ng-if="tasksEnabled") - span Night Shift - div.popover.attribute-explanation - span Poor Devil, you work too much. - div.attribute - Total Power - div.popover.attribute-explanation - span How far did you go into this Taiga? + div.member-stats + div.attribute.attribute-name(ng-if="issuesEnabled") + span Mr. Wolf + div.popover.attribute-explanation + span I see, you solve issues! + div.attribute(ng-if="tasksEnabled") + span Poison Drinker + div.popover.attribute-explanation + span Hey, are you a iocaine-holic? + div.attribute(ng-if="wikiEnabled") + span Cervantes + div.popover.attribute-explanation + span You have no fear to the blank page! + div.attribute(ng-if="issuesEnabled") + Total Bug Hunter + div.popover.attribute-explanation + span Thaks to you, this project still alive. + div.attribute(ng-if="tasksEnabled") + span Night Shift + div.popover.attribute-explanation + span Poor Devil, you work too much. + div.attribute + Total Power + div.popover.attribute-explanation + span How far did you go into this Taiga? div.hero(tg-team-current-user, stats="stats", currentuser="currentUser", projectid="projectId", issuesEnabled="issuesEnabled", tasksenabled="tasksEnabled", wikienabled="wikiEnabled") diff --git a/app/styles/dependencies/colors.scss b/app/styles/dependencies/colors.scss index 2efb3ae5..e5f37455 100755 --- a/app/styles/dependencies/colors.scss +++ b/app/styles/dependencies/colors.scss @@ -2,8 +2,8 @@ $black: #000; $blackish: #050505; -$gray: #555; $grayer: #444; +$gray: #555; $gray-light: #b8b8b8; $whitish: #f5f5f5; $very-light-gray: #fcfcfc; diff --git a/app/styles/modules/team/team-table.scss b/app/styles/modules/team/team-table.scss index bed23da5..a0a95283 100644 --- a/app/styles/modules/team/team-table.scss +++ b/app/styles/modules/team/team-table.scss @@ -3,14 +3,18 @@ padding: .5rem; } .username { - @include table-flex-child(3, 0, 0); + @include flex(5); + min-width: 300px; } .member-stats { - @include table-flex(stretch, center, flex, row, wrap, flex-start); - @include table-flex-child(6, 0, 0); + @include display(flex); + @include align-content(center); + @include align-items(center); + @include justify-content(flex-end); + @include flex(6); } .attribute { - @include table-flex-child(1, 0, 0); + @include flex(1); position: relative; text-align: center; .icon, @@ -36,8 +40,9 @@ } } .leave-project { + @extend %small; + color: $gray-light; display: block; - margin-top: .3rem; .icon { margin-right: .2rem; } From 66d00ba9f3613505b77d76a02ecc18cdda179b69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Thu, 27 Nov 2014 15:34:26 +0100 Subject: [PATCH 40/66] Improve layout styles to fit in window --- app/styles/modules/team/team-table.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/styles/modules/team/team-table.scss b/app/styles/modules/team/team-table.scss index a0a95283..31e59f1b 100644 --- a/app/styles/modules/team/team-table.scss +++ b/app/styles/modules/team/team-table.scss @@ -3,7 +3,7 @@ padding: .5rem; } .username { - @include flex(5); + @include flex(3); min-width: 300px; } .member-stats { From 8e53cee76877dbd9435d73361d6ee0d972bbab65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Fri, 28 Nov 2014 08:25:32 +0100 Subject: [PATCH 41/66] Small fixes for team members --- app/coffee/modules/team/main.coffee | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee index aa573e36..7e072cd2 100644 --- a/app/coffee/modules/team/main.coffee +++ b/app/coffee/modules/team/main.coffee @@ -37,12 +37,14 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) "$tgResources", "$routeParams", "$q", + "$location", + "$tgNavUrls", "$appTitle", - "$tgAuth" + "$tgAuth", "tgLoader" ] - constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @appTitle, @auth, tgLoader) -> + constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @location, @navUrls, @appTitle, @auth, tgLoader) -> @scope.sectionName = "Team" promise = @.loadInitialData() @@ -80,8 +82,8 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) return membership for membership in @scope.memberships - if not membership.user.photo? - membership.user.photo = "/images/unnamed.png" + if not membership.photo? + membership.photo = "/images/unnamed.png" return data From c0febab83758b7eecd1afeeba3a03a88e781a9cf Mon Sep 17 00:00:00 2001 From: Juanfran Date: Fri, 28 Nov 2014 09:00:04 +0100 Subject: [PATCH 42/66] fix #1710 select text in the wysiwyng preview actives edition mode --- app/coffee/modules/common.coffee | 15 +++++++++++++++ app/coffee/modules/common/components.coffee | 15 ++++----------- app/coffee/modules/common/wisiwyg.coffee | 16 +++++++++++----- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/app/coffee/modules/common.coffee b/app/coffee/modules/common.coffee index 594469a8..b9b31365 100644 --- a/app/coffee/modules/common.coffee +++ b/app/coffee/modules/common.coffee @@ -23,6 +23,21 @@ taiga = @.taiga module = angular.module("taigaCommon", []) +############################################################################# +## Get the selected text +############################################################################# +SelectedText = ($window, $document) -> + get = () -> + if $window.getSelection + return $window.getSelection().toString() + else if $document.selection + return $document.selection.createRange().text + return "" + + return {get: get} + +module.factory("$selectedText", ["$window", "$document", SelectedText]) + ############################################################################# ## Permission directive, hide elements when necessary ############################################################################# diff --git a/app/coffee/modules/common/components.coffee b/app/coffee/modules/common/components.coffee index 6a7057fe..f4a4b419 100644 --- a/app/coffee/modules/common/components.coffee +++ b/app/coffee/modules/common/components.coffee @@ -553,7 +553,7 @@ module.directive("tgEditableSubject", ["$rootScope", "$tgRepo", "$tgConfirm", "$ ## Editable subject directive ############################################################################# -EditableDescriptionDirective = ($window, $document, $rootscope, $repo, $confirm, $compile, $loading) -> +EditableDescriptionDirective = ($rootscope, $repo, $confirm, $compile, $loading, $selectedText) -> template = """
return $scope.project.my_permissions.indexOf($attrs.requiredPerm) != -1 - getSelectedText = -> - if $window.getSelection - return $window.getSelection().toString() - else if $document.selection - return $document.selection.createRange().text - return null - $el.on "mouseup", ".view-description", (event) -> # We want to dettect the a inside the div so we use the target and # not the currentTarget target = angular.element(event.target) return if not isEditable() return if target.is('a') - return if getSelectedText() + return if $selectedText.get().length $el.find('.edit-description').show() $el.find('.view-description').hide() @@ -654,8 +647,8 @@ EditableDescriptionDirective = ($window, $document, $rootscope, $repo, $confirm, template: template } -module.directive("tgEditableDescription", ["$window", "$document", "$rootScope", "$tgRepo", "$tgConfirm", - "$compile", "$tgLoading", EditableDescriptionDirective]) +module.directive("tgEditableDescription", ["$rootScope", "$tgRepo", "$tgConfirm", + "$compile", "$tgLoading", "$selectedText", EditableDescriptionDirective]) ############################################################################# diff --git a/app/coffee/modules/common/wisiwyg.coffee b/app/coffee/modules/common/wisiwyg.coffee index cb0f1443..e1ceeae2 100644 --- a/app/coffee/modules/common/wisiwyg.coffee +++ b/app/coffee/modules/common/wisiwyg.coffee @@ -28,7 +28,7 @@ module = angular.module("taigaCommon") ############################################################################# ## WYSIWYG markitup editor directive ############################################################################# -tgMarkitupDirective = ($rootscope, $rs, $tr) -> +tgMarkitupDirective = ($rootscope, $rs, $tr, $selectedText) -> previewTemplate = _.template("""
@@ -61,10 +61,16 @@ tgMarkitupDirective = ($rootscope, $rs, $tr) -> markdownDomNode.append(previewTemplate({data: data.data})) markItUpDomNode.hide() - # FIXME: Really `.parents()` is need? seems `.closest` - # function is better aproach for it - element.parents(".markdown").one "click", ".preview", (event) -> + markdown = element.closest(".markdown") + + markdown.on "mouseup.preview", ".preview", (event) -> event.preventDefault() + target = angular.element(event.target) + + if !target.is('a') and $selectedText.get().length + return + + markdown.off(".preview") closePreviewMode() markdownCaretPositon = false @@ -277,4 +283,4 @@ tgMarkitupDirective = ($rootscope, $rs, $tr) -> return {link:link, require:"ngModel"} -module.directive("tgMarkitup", ["$rootScope", "$tgResources", "$tgI18n", tgMarkitupDirective]) +module.directive("tgMarkitup", ["$rootScope", "$tgResources", "$tgI18n", "$selectedText", tgMarkitupDirective]) From 143f61749141d231ab63eb0837f9d66a0f21df8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Fri, 28 Nov 2014 09:03:04 +0100 Subject: [PATCH 43/66] Added team members to the changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e76f6bd..57b2167e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,9 @@ ## 1.4.0 Unknown (Unknown) ### Features -- Upgrade to AngularJS 1.3 -- Use enter to submit lightboxes forms +- Upgrade to AngularJS 1.3. +- Use enter to submit lightboxes forms. +- Added team members section. ### Misc - Lots of small and not so small bugfixes. From 15dea86392554be18f060b6d7977a82f2630a0c4 Mon Sep 17 00:00:00 2001 From: Juanfran Date: Fri, 28 Nov 2014 14:37:37 +0100 Subject: [PATCH 44/66] Partial fix #1714 taskboard order --- app/coffee/modules/taskboard/main.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/coffee/modules/taskboard/main.coffee b/app/coffee/modules/taskboard/main.coffee index f1b46ccc..7d0cf5d3 100644 --- a/app/coffee/modules/taskboard/main.coffee +++ b/app/coffee/modules/taskboard/main.coffee @@ -145,7 +145,7 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin) loadTasks: -> return @rs.tasks.list(@scope.projectId, @scope.sprintId).then (tasks) => - @scope.tasks = tasks + @scope.tasks = _.sortBy(tasks, 'taskboard_order') @scope.usTasks = {} # Iterate over all userstories and @@ -194,7 +194,7 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin) task.user_story = usId task.status = statusId - task.order = order + task.taskboard_order = order promise = @repo.save(task) promise.then => From 3733a86920f286b2b0b0ce06cbb8c9b2600c61a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Mon, 1 Dec 2014 15:01:51 +0100 Subject: [PATCH 45/66] :man: + :hocho: :wavy_dash: -> :boy: This reverts commit 95b75e9b1d2fa8c14321de0d84d2c55d28e0d3d6. Conflicts: app/partials/register.jade app/svg/logo.svg --- app/coffee/modules/nav.coffee | 30 ++++++++++++++---------------- app/partials/forgot-password.jade | 2 +- app/partials/login.jade | 2 +- app/partials/register.jade | 2 +- app/svg/logo.svg | 30 ++++++++++++++---------------- app/svg/logo_back.svg | 23 ----------------------- 6 files changed, 31 insertions(+), 58 deletions(-) delete mode 100644 app/svg/logo_back.svg diff --git a/app/coffee/modules/nav.coffee b/app/coffee/modules/nav.coffee index a80bf6d4..e9c8ee66 100644 --- a/app/coffee/modules/nav.coffee +++ b/app/coffee/modules/nav.coffee @@ -287,30 +287,28 @@ ProjectMenuDirective = ($log, $compile, $auth, $rootscope, $tgAuth, $location, $ mainTemplate = _.template(""" diff --git a/app/partials/forgot-password.jade b/app/partials/forgot-password.jade index 0fd58df7..f5504c25 100644 --- a/app/partials/forgot-password.jade +++ b/app/partials/forgot-password.jade @@ -8,7 +8,7 @@ block content div.wrapper div.login-main div.login-container - img.logo-svg(src="/svg/logo.svg", alt="TAIGA loves Movember!") + img.logo-svg(src="/svg/logo.svg", alt="TAIGA") h1.logo Taiga h2.tagline LOVE YOUR PROJECT diff --git a/app/partials/login.jade b/app/partials/login.jade index 96457b86..8883998b 100644 --- a/app/partials/login.jade +++ b/app/partials/login.jade @@ -8,7 +8,7 @@ block content div.wrapper div.login-main div.login-container - img.logo-svg(src="/svg/logo.svg", alt="TAIGA loves Movember!") + img.logo-svg(src="/svg/logo.svg", alt="TAIGA") h1.logo Taiga h2.tagline LOVE YOUR PROJECT diff --git a/app/partials/register.jade b/app/partials/register.jade index a42c56be..d35a733a 100644 --- a/app/partials/register.jade +++ b/app/partials/register.jade @@ -8,7 +8,7 @@ block content div.wrapper div.login-main div.login-container - img.logo-svg(src="/svg/logo.svg", alt="TAIGA loves Movember!") + img.logo-svg(src="/svg/logo.svg", alt="TAIGA") h1.logo Taiga h2.tagline LOVE YOUR PROJECT diff --git a/app/svg/logo.svg b/app/svg/logo.svg index 4ca67830..346d8115 100644 --- a/app/svg/logo.svg +++ b/app/svg/logo.svg @@ -1,25 +1,23 @@ - + - - - - - - - - - - - + + + + + + + + + + + + + - diff --git a/app/svg/logo_back.svg b/app/svg/logo_back.svg deleted file mode 100644 index 346d8115..00000000 --- a/app/svg/logo_back.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - From 382091c726a27da2aaf50fb8e86a69b4d3343f95 Mon Sep 17 00:00:00 2001 From: Juanfran Date: Tue, 2 Dec 2014 09:39:05 +0100 Subject: [PATCH 46/66] replace invalid q.all.apply calls --- app/coffee/modules/backlog/main.coffee | 6 +++--- app/coffee/modules/base/repository.coffee | 2 +- app/coffee/modules/common/attachments.coffee | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/coffee/modules/backlog/main.coffee b/app/coffee/modules/backlog/main.coffee index 2cca43de..59e059ac 100644 --- a/app/coffee/modules/backlog/main.coffee +++ b/app/coffee/modules/backlog/main.coffee @@ -390,14 +390,14 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F # Rehash userstories order field # and persist in bulk all changes. - promise = @q.all.apply(null, promises).then => + promise = @q.all(promises).then => items = @.resortUserStories(newSprint.user_stories, "sprint_order") data = @.prepareBulkUpdateData(items, "sprint_order") - return @rs.userstories.bulkUpdateSprintOrder(project, data).then => + @rs.userstories.bulkUpdateSprintOrder(project, data).then => @rootscope.$broadcast("sprint:us:moved", us, oldSprintId, newSprintId) - return @rs.userstories.bulkUpdateBacklogOrder(project, data).then => + @rs.userstories.bulkUpdateBacklogOrder(project, data).then => for us in usList @rootscope.$broadcast("sprint:us:moved", us, oldSprintId, newSprintId) diff --git a/app/coffee/modules/base/repository.coffee b/app/coffee/modules/base/repository.coffee index 0cbf7348..866435d7 100644 --- a/app/coffee/modules/base/repository.coffee +++ b/app/coffee/modules/base/repository.coffee @@ -62,7 +62,7 @@ class RepositoryService extends taiga.Service saveAll: (models, patch=true) -> promises = _.map(models, (x) => @.save(x, true)) - return @q.all.apply(@q, promises) + return @q.all(promises) save: (model, patch=true) -> defered = @q.defer() diff --git a/app/coffee/modules/common/attachments.coffee b/app/coffee/modules/common/attachments.coffee index 2a082259..9fbe6504 100644 --- a/app/coffee/modules/common/attachments.coffee +++ b/app/coffee/modules/common/attachments.coffee @@ -86,7 +86,7 @@ class AttachmentsController extends taiga.Controller # Create attachments in bulk createAttachments: (attachments) -> promises = _.map(attachments, (x) => @._createAttachment(x)) - return @q.all.apply(null, promises).then => + return @q.all(promises).then => @.updateCounters() # Add uploading attachment tracking. From efb5a62f4bf6dd43b20d104e4a216f8983ca2ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Espino?= Date: Tue, 2 Dec 2014 12:20:50 +0100 Subject: [PATCH 47/66] Fix a lot of import/extend lint errors on sass --- app/styles/components/filter.scss | 2 +- app/styles/components/kanban-task.scss | 6 +++--- app/styles/components/taskboard-task.scss | 2 +- app/styles/components/watchers.scss | 2 +- app/styles/layout/invitation.scss | 4 ++-- app/styles/layout/login.scss | 2 +- app/styles/layout/not-found.scss | 2 +- app/styles/layout/typography.scss | 2 +- app/styles/layout/us-detail.scss | 4 ++-- app/styles/modules/admin/admin-functionalities.scss | 2 +- app/styles/modules/admin/admin-roles.scss | 2 +- app/styles/modules/auth/change-password-from-recovery.scss | 2 +- app/styles/modules/auth/login-form.scss | 2 +- app/styles/modules/backlog/backlog-table.scss | 4 ++-- app/styles/modules/backlog/sprints.scss | 6 +++--- app/styles/modules/backlog/taskboard-table.scss | 2 +- app/styles/modules/common/assigned-to.scss | 4 ++-- app/styles/modules/common/attachments.scss | 4 ++-- app/styles/modules/common/category-config.scss | 2 +- app/styles/modules/common/lightbox.scss | 2 +- app/styles/modules/common/related-tasks.scss | 2 +- app/styles/modules/common/wizard.scss | 2 +- app/styles/modules/create-project.scss | 2 +- app/styles/modules/filters/filters.scss | 2 +- app/styles/modules/home-projects-list.scss | 2 +- app/styles/modules/issues/issues-table.scss | 4 ++-- app/styles/modules/kanban/kanban-table.scss | 4 ++-- app/styles/modules/search/search-result-table.scss | 6 +++--- app/styles/modules/team/team-table.scss | 2 +- scsslint.yml | 7 ++++++- 30 files changed, 48 insertions(+), 43 deletions(-) diff --git a/app/styles/components/filter.scss b/app/styles/components/filter.scss index a4d5b48d..dac49854 100644 --- a/app/styles/components/filter.scss +++ b/app/styles/components/filter.scss @@ -1,7 +1,7 @@ .single-filter { @extend %large; - @include clearfix; @extend %title; + @include clearfix; cursor: pointer; display: block; height: 32px; diff --git a/app/styles/components/kanban-task.scss b/app/styles/components/kanban-task.scss index e6a47862..5a09967c 100644 --- a/app/styles/components/kanban-task.scss +++ b/app/styles/components/kanban-task.scss @@ -14,8 +14,8 @@ } } &.ui-sortable-helper { - box-shadow: 1px 1px 15px rgba($black, .4); @include transition(box-shadow .3s linear); + box-shadow: 1px 1px 15px rgba($black, .4); } &.blocked { background: $red; @@ -68,8 +68,8 @@ display: block; } .task-text { - @include table-flex-child($flex-grow: 10, $flex-basis: 50px); @extend %small; + @include table-flex-child($flex-grow: 10, $flex-basis: 50px); padding: 0 .5rem 0 .8rem; word-wrap: break-word; } @@ -83,8 +83,8 @@ } .icon-edit, .icon-drag-h { - @include transition(opacity .2s linear); @extend %large; + @include transition(opacity .2s linear); color: $postit-hover; opacity: 0; position: absolute; diff --git a/app/styles/components/taskboard-task.scss b/app/styles/components/taskboard-task.scss index 6e4d57fb..7b9fe6e0 100644 --- a/app/styles/components/taskboard-task.scss +++ b/app/styles/components/taskboard-task.scss @@ -17,8 +17,8 @@ } } &.ui-sortable-helper { - box-shadow: 1px 1px 15px rgba($black, .4); @include transition(box-shadow .3s linear); + box-shadow: 1px 1px 15px rgba($black, .4); } &.ui-sortable-placeholder { background: $grayer; diff --git a/app/styles/components/watchers.scss b/app/styles/components/watchers.scss index 5c08a5d2..a078792c 100644 --- a/app/styles/components/watchers.scss +++ b/app/styles/components/watchers.scss @@ -35,8 +35,8 @@ } } .watcher-name { - @include table-flex-child(8, 0); @extend %small; + @include table-flex-child(8, 0); color: $grayer; margin-left: 1rem; position: relative; diff --git a/app/styles/layout/invitation.scss b/app/styles/layout/invitation.scss index 8d8f781d..59b7d0c2 100644 --- a/app/styles/layout/invitation.scss +++ b/app/styles/layout/invitation.scss @@ -1,6 +1,6 @@ .invitation-main { - @include table-flex(center, center, flex, row, wrap, center); @extend %background-taiga; + @include table-flex(center, center, flex, row, wrap, center); bottom: 0; left: 0; position: fixed; @@ -62,8 +62,8 @@ } } .forgot-pass { - @include transition(all .3s linear); @extend %small; + @include transition(all .3s linear); color: $gray-light; opacity: 1; position: absolute; diff --git a/app/styles/layout/login.scss b/app/styles/layout/login.scss index 3f53e123..781190aa 100644 --- a/app/styles/layout/login.scss +++ b/app/styles/layout/login.scss @@ -1,10 +1,10 @@ .login-main { + @extend %triangled-bg; //@include table-flex(center, center, flex, row, wrap, center); @include display(flex); @include align-items(center); @include flex-direction(row); @include justify-content(center); - @extend %triangled-bg; bottom: 0; left: 0; position: fixed; diff --git a/app/styles/layout/not-found.scss b/app/styles/layout/not-found.scss index 40ea6346..7c00b74f 100644 --- a/app/styles/layout/not-found.scss +++ b/app/styles/layout/not-found.scss @@ -1,9 +1,9 @@ .error-main { + @extend %background-taiga; @include display(flex); @include align-items(center); @include flex-direction(row); @include justify-content(center); - @extend %background-taiga; bottom: 0; left: 0; position: fixed; diff --git a/app/styles/layout/typography.scss b/app/styles/layout/typography.scss index 8808712b..3127c82c 100755 --- a/app/styles/layout/typography.scss +++ b/app/styles/layout/typography.scss @@ -56,8 +56,8 @@ h1 { color: $green-taiga; } .date { - color: $gray-light; @include ellipsis(500px); + color: $gray-light; } } diff --git a/app/styles/layout/us-detail.scss b/app/styles/layout/us-detail.scss index f93c8199..e2a39843 100644 --- a/app/styles/layout/us-detail.scss +++ b/app/styles/layout/us-detail.scss @@ -9,9 +9,9 @@ padding: 1rem; position: relative; &.blocked { + @include transition(all .2s linear); background: $red; vertical-align: middle; - @include transition(all .2s linear); .us-title-text, input { margin-bottom: .5rem; @@ -50,8 +50,8 @@ @include table-flex(); } input { - background: $white; @include table-flex-child(1, 90%, 0); + background: $white; } .us-title-text { display: flex; diff --git a/app/styles/modules/admin/admin-functionalities.scss b/app/styles/modules/admin/admin-functionalities.scss index 909bd3e0..19be0b10 100644 --- a/app/styles/modules/admin/admin-functionalities.scss +++ b/app/styles/modules/admin/admin-functionalities.scss @@ -25,8 +25,8 @@ opacity: 1; } .icon { - @include table-flex-child(1, 120px, 0, 100%); @extend %xxlarge; + @include table-flex-child(1, 120px, 0, 100%); margin: 0 auto; min-height: 60px; text-align: center; diff --git a/app/styles/modules/admin/admin-roles.scss b/app/styles/modules/admin/admin-roles.scss index 5992dc79..07805b18 100644 --- a/app/styles/modules/admin/admin-roles.scss +++ b/app/styles/modules/admin/admin-roles.scss @@ -5,8 +5,8 @@ color: $grayer; } .edit-value { - @include transition(opacity .3s linear); @extend %medium; + @include transition(opacity .3s linear); color: $gray-light; cursor: pointer; margin-left: .5rem; diff --git a/app/styles/modules/auth/change-password-from-recovery.scss b/app/styles/modules/auth/change-password-from-recovery.scss index 6d5a3292..6558c750 100644 --- a/app/styles/modules/auth/change-password-from-recovery.scss +++ b/app/styles/modules/auth/change-password-from-recovery.scss @@ -14,8 +14,8 @@ } } .get-token { - @include transition(all .3s linear); @extend %small; + @include transition(all .3s linear); color: $gray-light; opacity: 1; position: absolute; diff --git a/app/styles/modules/auth/login-form.scss b/app/styles/modules/auth/login-form.scss index 40d4a36c..80b88cc1 100644 --- a/app/styles/modules/auth/login-form.scss +++ b/app/styles/modules/auth/login-form.scss @@ -9,8 +9,8 @@ } } .forgot-pass { - @include transition(all .3s linear); @extend %small; + @include transition(all .3s linear); color: $gray-light; opacity: 1; position: absolute; diff --git a/app/styles/modules/backlog/backlog-table.scss b/app/styles/modules/backlog/backlog-table.scss index 3c8e7212..81d885aa 100644 --- a/app/styles/modules/backlog/backlog-table.scss +++ b/app/styles/modules/backlog/backlog-table.scss @@ -184,8 +184,8 @@ border-bottom: 1px solid $white; color: $white; &:hover { - background: $red; @include transition (background .2s ease-in); + background: $red; } a { color: $white !important; @@ -217,8 +217,8 @@ } .us-settings a, .icon-drag-v { - @include transition (all .2s ease-in); @extend %large; + @include transition (all .2s ease-in); color: $gray-light; width: 30px; &:hover { diff --git a/app/styles/modules/backlog/sprints.scss b/app/styles/modules/backlog/sprints.scss index 52000ff5..aca0c5f9 100644 --- a/app/styles/modules/backlog/sprints.scss +++ b/app/styles/modules/backlog/sprints.scss @@ -1,7 +1,7 @@ .sprints { .summary { - background: $gray-light; @include clearfix; + background: $gray-light; ul { width: 40%; } @@ -127,8 +127,8 @@ text-align: left; width: 100%; &:hover { - background: lighten($gray-light, 12%); @include transition (background .2s ease-in); + background: lighten($gray-light, 12%); cursor: move; } &:last-child { @@ -146,8 +146,8 @@ } .column-us { - @include table-flex-child(3, 0, 0); @extend %small; + @include table-flex-child(3, 0, 0); padding: 0 4px; } .us-name { diff --git a/app/styles/modules/backlog/taskboard-table.scss b/app/styles/modules/backlog/taskboard-table.scss index 84eafb69..1d028e95 100644 --- a/app/styles/modules/backlog/taskboard-table.scss +++ b/app/styles/modules/backlog/taskboard-table.scss @@ -21,8 +21,8 @@ $column-margin: 0 10px 0 0; position: absolute; } .task-colum-name { - @include table-flex-child($column-flex, $column-width, $column-shrink, $column-width); @extend %large; + @include table-flex-child($column-flex, $column-width, $column-shrink, $column-width); background: $whitish; border-top: 3px solid $gray-light; margin: $column-margin; diff --git a/app/styles/modules/common/assigned-to.scss b/app/styles/modules/common/assigned-to.scss index 9fc78665..4f8171c8 100644 --- a/app/styles/modules/common/assigned-to.scss +++ b/app/styles/modules/common/assigned-to.scss @@ -13,12 +13,12 @@ &.loading { width: 100%; span { + @include animation (loading .5s linear); + @include animation (spin 1s linear infinite); font-size: 30px; padding: 20px 0; text-align: center; width: 100%; - @include animation (loading .5s linear); - @include animation (spin 1s linear infinite); } } .user-avatar { diff --git a/app/styles/modules/common/attachments.scss b/app/styles/modules/common/attachments.scss index 92050f74..a19ef7d4 100644 --- a/app/styles/modules/common/attachments.scss +++ b/app/styles/modules/common/attachments.scss @@ -27,8 +27,8 @@ } .single-attachment { - @include table-flex(); @extend %small; + @include table-flex(); align-items: center; border-bottom: 1px solid $whitish; padding: .5rem 0 .5rem 1rem; @@ -57,9 +57,9 @@ height: 40px; } .attachment-name { + @extend %bold; @include ellipsis(200px); @include table-flex-child(1, 35%, 0); - @extend %bold; padding-right: 1rem; .icon { margin-right: .5rem; diff --git a/app/styles/modules/common/category-config.scss b/app/styles/modules/common/category-config.scss index 0eac6075..9d55a70c 100644 --- a/app/styles/modules/common/category-config.scss +++ b/app/styles/modules/common/category-config.scss @@ -36,8 +36,8 @@ } } .icon { - @include flex(1); @extend %xlarge; + @include flex(1); text-align: right; } .category-items { diff --git a/app/styles/modules/common/lightbox.scss b/app/styles/modules/common/lightbox.scss index 247a34b2..5f71b8c9 100644 --- a/app/styles/modules/common/lightbox.scss +++ b/app/styles/modules/common/lightbox.scss @@ -14,8 +14,8 @@ border-right: 1px solid $gray-light; } &:hover { - color: $grayer; @include transition(color .2s linear); + color: $grayer; } } .active { diff --git a/app/styles/modules/common/related-tasks.scss b/app/styles/modules/common/related-tasks.scss index bf4dfb8b..7ea10e14 100644 --- a/app/styles/modules/common/related-tasks.scss +++ b/app/styles/modules/common/related-tasks.scss @@ -158,8 +158,8 @@ top: .1rem; width: 10%; a { - @include transition (all .2s ease-in); @extend %large; + @include transition (all .2s ease-in); color: $gray-light; &:hover { @include transition (all .2s ease-in); diff --git a/app/styles/modules/common/wizard.scss b/app/styles/modules/common/wizard.scss index 1ea1a730..7708d638 100644 --- a/app/styles/modules/common/wizard.scss +++ b/app/styles/modules/common/wizard.scss @@ -36,9 +36,9 @@ } } .wizard-step { - display: none; @include animation(formSlide .4s ease-in-out); @include animation-direction(alternate-reverse); + display: none; &.active { @include animation(formSlide .4s ease-in-out); &.create-step2, diff --git a/app/styles/modules/create-project.scss b/app/styles/modules/create-project.scss index cf4e8c36..3493b97a 100644 --- a/app/styles/modules/create-project.scss +++ b/app/styles/modules/create-project.scss @@ -1,6 +1,6 @@ .create-project { - @include table-flex(center, center, flex, row, wrap, center); @extend %triangled-bg; + @include table-flex(center, center, flex, row, wrap, center); bottom: 0; left: 0; position: fixed; diff --git a/app/styles/modules/filters/filters.scss b/app/styles/modules/filters/filters.scss index a98e3218..15c5d023 100644 --- a/app/styles/modules/filters/filters.scss +++ b/app/styles/modules/filters/filters.scss @@ -32,8 +32,8 @@ } .filters-inner { - opacity: 0; @include transition (all .1s ease-in); + opacity: 0; .loading { background: $grayer; border: 1px solid #b8b8b8; diff --git a/app/styles/modules/home-projects-list.scss b/app/styles/modules/home-projects-list.scss index ad2ee7c3..66fd5d6f 100644 --- a/app/styles/modules/home-projects-list.scss +++ b/app/styles/modules/home-projects-list.scss @@ -1,8 +1,8 @@ .home-projects-list, .home-project { @extend %background-taiga; - background-color: $black; @include table-flex(center, center, flex, row, wrap, center); + background-color: $black; background-position: center center; background-size: cover; height: 100%; diff --git a/app/styles/modules/issues/issues-table.scss b/app/styles/modules/issues/issues-table.scss index 3c773832..34d642f4 100644 --- a/app/styles/modules/issues/issues-table.scss +++ b/app/styles/modules/issues/issues-table.scss @@ -6,16 +6,16 @@ } .row { &:hover { - background: lighten($green-taiga, 60%); @include transition (background .2s ease-in); + background: lighten($green-taiga, 60%); } .icon { display: inline; } } .row-selected { - background: lighten($green-taiga, 60%); @include transition (background .2s ease-in); + background: lighten($green-taiga, 60%); } .title { @extend %medium; diff --git a/app/styles/modules/kanban/kanban-table.scss b/app/styles/modules/kanban/kanban-table.scss index fe12d441..5c3146c2 100644 --- a/app/styles/modules/kanban/kanban-table.scss +++ b/app/styles/modules/kanban/kanban-table.scss @@ -53,10 +53,10 @@ $column-margin: 0 10px 0 0; position: absolute; } .task-colum-name { + @extend %large; @include table-flex-child($column-flex, $column-width, $column-shrink, $column-width); @include table-flex(); @include justify-content(space-between); - @extend %large; background: $whitish; border-top: 3px solid $gray-light; margin: $column-margin; @@ -84,8 +84,8 @@ $column-margin: 0 10px 0 0; } .kanban-table-body { - @include table-flex(); @extend %medium; + @include table-flex(); overflow: hidden; overflow-x: auto; width: 100%; diff --git a/app/styles/modules/search/search-result-table.scss b/app/styles/modules/search/search-result-table.scss index 3a8b4542..3abe6471 100644 --- a/app/styles/modules/search/search-result-table.scss +++ b/app/styles/modules/search/search-result-table.scss @@ -10,8 +10,8 @@ @include table-flex($align-content: center, $align-items: center); padding: .5rem; &:hover { - background: lighten($green-taiga, 60%); @include transition (background .2s ease-in); + background: lighten($green-taiga, 60%); } .user-stories { @include table-flex-child(5, 0, 1); @@ -27,8 +27,8 @@ } } .row-selected { - background: lighten($green-taiga, 60%); @include transition (background .2s ease-in); + background: lighten($green-taiga, 60%); } // TODO: refactor xaviju @@ -47,8 +47,8 @@ @extend %medium; color: $gray-light; &:hover { - color: $grayer; @include transition (color .3s linear); + color: $grayer; } } } diff --git a/app/styles/modules/team/team-table.scss b/app/styles/modules/team/team-table.scss index 31e59f1b..d05e4435 100644 --- a/app/styles/modules/team/team-table.scss +++ b/app/styles/modules/team/team-table.scss @@ -95,7 +95,7 @@ } } .popover { - @include popover(100%, '', 0, 30px, '', 15px, '', 50%, -5px); @extend %small; + @include popover(100%, '', 0, 30px, '', 15px, '', 50%, -5px); } } diff --git a/scsslint.yml b/scsslint.yml index ea46bae9..77f808be 100644 --- a/scsslint.yml +++ b/scsslint.yml @@ -124,5 +124,10 @@ linters: ZeroUnit: enabled: true + NestingDepth: + enabled: true + max_depth: 4 + Compass::*: - enabled: false \ No newline at end of file + enabled: false + From fb60cf0cddd82da45a17b9962d9011fb377118e2 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Mon, 1 Dec 2014 17:45:44 +0100 Subject: [PATCH 48/66] Adding front for gitlab and bitbucket --- app/coffee/app.coffee | 4 + app/coffee/modules/admin/third-parties.coffee | 181 ++++++++++++++++++ app/coffee/modules/base.coffee | 2 + .../admin-third-parties-bitbucket.jade | 36 ++++ app/partials/admin-third-parties-gitlab.jade | 35 ++++ .../modules/admin-submenu-third-parties.jade | 8 + 6 files changed, 266 insertions(+) create mode 100644 app/partials/admin-third-parties-bitbucket.jade create mode 100644 app/partials/admin-third-parties-gitlab.jade diff --git a/app/coffee/app.coffee b/app/coffee/app.coffee index 1a5794c5..51dd695d 100644 --- a/app/coffee/app.coffee +++ b/app/coffee/app.coffee @@ -100,6 +100,10 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven {templateUrl: "/partials/admin-roles.html"}) $routeProvider.when("/project/:pslug/admin/third-parties/github", {templateUrl: "/partials/admin-third-parties-github.html"}) + $routeProvider.when("/project/:pslug/admin/third-parties/gitlab", + {templateUrl: "/partials/admin-third-parties-gitlab.html"}) + $routeProvider.when("/project/:pslug/admin/third-parties/bitbucket", + {templateUrl: "/partials/admin-third-parties-bitbucket.html"}) # User settings $routeProvider.when("/project/:pslug/user-settings/user-profile", diff --git a/app/coffee/modules/admin/third-parties.coffee b/app/coffee/modules/admin/third-parties.coffee index 842652e8..a341721a 100644 --- a/app/coffee/modules/admin/third-parties.coffee +++ b/app/coffee/modules/admin/third-parties.coffee @@ -78,6 +78,114 @@ class GithubController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi module.controller("GithubController", GithubController) + +############################################################################# +## Gitlab Controller +############################################################################# + +class GitlabController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin) + @.$inject = [ + "$scope", + "$tgRepo", + "$tgResources", + "$routeParams", + "$appTitle" + ] + + constructor: (@scope, @repo, @rs, @params, @appTitle) -> + bindMethods(@) + + @scope.sectionName = "Gitlab" #i18n + @scope.project = {} + @scope.anyComputableRole = true + + promise = @.loadInitialData() + + promise.then () => + @appTitle.set("Gitlab - " + @scope.project.name) + + promise.then null, @.onInitialDataError.bind(@) + + @scope.$on "project:modules:reload", => + @.loadModules() + + loadModules: -> + return @rs.modules.list(@scope.projectId, "gitlab").then (gitlab) => + @scope.gitlab = gitlab + + loadProject: -> + return @rs.projects.get(@scope.projectId).then (project) => + @scope.project = project + @scope.$emit('project:loaded', project) + @scope.anyComputableRole = _.some(_.map(project.roles, (point) -> point.computable)) + + return project + + loadInitialData: -> + promise = @repo.resolve({pslug: @params.pslug}).then (data) => + @scope.projectId = data.project + return data + + return promise.then(=> @.loadProject()) + .then(=> @.loadModules()) + + +module.controller("GitlabController", GitlabController) + + +############################################################################# +## Bitbucket Controller +############################################################################# + +class BitbucketController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.FiltersMixin) + @.$inject = [ + "$scope", + "$tgRepo", + "$tgResources", + "$routeParams", + "$appTitle" + ] + + constructor: (@scope, @repo, @rs, @params, @appTitle) -> + bindMethods(@) + + @scope.sectionName = "Bitbucket" #i18n + @scope.project = {} + @scope.anyComputableRole = true + + promise = @.loadInitialData() + + promise.then () => + @appTitle.set("Bitbucket - " + @scope.project.name) + + promise.then null, @.onInitialDataError.bind(@) + + @scope.$on "project:modules:reload", => + @.loadModules() + + loadModules: -> + return @rs.modules.list(@scope.projectId, "bitbucket").then (bitbucket) => + @scope.bitbucket = bitbucket + + loadProject: -> + return @rs.projects.get(@scope.projectId).then (project) => + @scope.project = project + @scope.$emit('project:loaded', project) + @scope.anyComputableRole = _.some(_.map(project.roles, (point) -> point.computable)) + + return project + + loadInitialData: -> + promise = @repo.resolve({pslug: @params.pslug}).then (data) => + @scope.projectId = data.project + return data + + return promise.then(=> @.loadProject()) + .then(=> @.loadModules()) + +module.controller("BitbucketController", BitbucketController) + + SelectInputText = -> link = ($scope, $el, $attrs) -> $el.on "click", ".select-input-content", () -> @@ -88,6 +196,7 @@ SelectInputText = -> module.directive("tgSelectInputText", SelectInputText) + ############################################################################# ## GithubWebhooks Directive ############################################################################# @@ -121,3 +230,75 @@ GithubWebhooksDirective = ($repo, $confirm, $loading) -> return {link:link} module.directive("tgGithubWebhooks", ["$tgRepo", "$tgConfirm", "$tgLoading", GithubWebhooksDirective]) + + +############################################################################# +## GitlabWebhooks Directive +############################################################################# + +GitlabWebhooksDirective = ($repo, $confirm, $loading) -> + link = ($scope, $el, $attrs) -> + form = $el.find("form").checksley({"onlyOneErrorElement": true}) + submit = debounce 2000, (event) => + event.preventDefault() + + return if not form.validate() + + $loading.start(submitButton) + + promise = $repo.saveAttribute($scope.gitlab, "gitlab") + promise.then -> + $loading.finish(submitButton) + $confirm.notify("success") + $scope.$emit("project:modules:reload") + + promise.then null, (data) -> + $loading.finish(submitButton) + form.setErrors(data) + if data._error_message + $confirm.notify("error", data._error_message) + + submitButton = $el.find(".submit-button") + + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit + + return {link:link} + +module.directive("tgGitlabWebhooks", ["$tgRepo", "$tgConfirm", "$tgLoading", GitlabWebhooksDirective]) + + +############################################################################# +## BitbucketWebhooks Directive +############################################################################# + +BitbucketWebhooksDirective = ($repo, $confirm, $loading) -> + link = ($scope, $el, $attrs) -> + form = $el.find("form").checksley({"onlyOneErrorElement": true}) + submit = debounce 2000, (event) => + event.preventDefault() + + return if not form.validate() + + $loading.start(submitButton) + + promise = $repo.saveAttribute($scope.bitbucket, "bitbucket") + promise.then -> + $loading.finish(submitButton) + $confirm.notify("success") + $scope.$emit("project:modules:reload") + + promise.then null, (data) -> + $loading.finish(submitButton) + form.setErrors(data) + if data._error_message + $confirm.notify("error", data._error_message) + + submitButton = $el.find(".submit-button") + + $el.on "submit", "form", submit + $el.on "click", ".submit-button", submit + + return {link:link} + +module.directive("tgBitbucketWebhooks", ["$tgRepo", "$tgConfirm", "$tgLoading", BitbucketWebhooksDirective]) diff --git a/app/coffee/modules/base.coffee b/app/coffee/modules/base.coffee index 877bc907..a3d8c812 100644 --- a/app/coffee/modules/base.coffee +++ b/app/coffee/modules/base.coffee @@ -93,6 +93,8 @@ urls = { "project-admin-memberships": "/project/:project/admin/memberships" "project-admin-roles": "/project/:project/admin/roles" "project-admin-third-parties-github": "/project/:project/admin/third-parties/github" + "project-admin-third-parties-gitlab": "/project/:project/admin/third-parties/gitlab" + "project-admin-third-parties-bitbucket": "/project/:project/admin/third-parties/bitbucket" # User settings "user-settings-user-profile": "/project/:project/user-settings/user-profile" diff --git a/app/partials/admin-third-parties-bitbucket.jade b/app/partials/admin-third-parties-bitbucket.jade new file mode 100644 index 00000000..4bb006ee --- /dev/null +++ b/app/partials/admin-third-parties-bitbucket.jade @@ -0,0 +1,36 @@ +block head + title Taiga Your agile, free, and open source project management tool + +block content + div.wrapper.roles(tg-bitbucket-webhooks, ng-controller="BitbucketController as ctrl", + ng-init="section='admin'") + sidebar.menu-secondary.sidebar(tg-admin-navigation="third-parties") + include views/modules/admin-menu + sidebar.menu-tertiary.sidebar(tg-admin-navigation="third-parties-bitbucket") + include views/modules/admin-submenu-third-parties + + section.main.admin-common.admin-third-parties + include views/components/mainTitle + + form + fieldset + label(for="secret-key") Secret key + input(type="text", name="secret-key", ng-model="bitbucket.secret", placeholder="Secret key", id="secret-key") + + fieldset + .select-input-text(tg-select-input-text) + div + label(for="payload-url") Payload URL + .field-with-option + input(type="text", ng-model="bitbucket.webhooks_url", name="payload-url", readonly="readonly", placeholder="Payload URL", id="payload-url") + .option-wrapper.select-input-content + .icon.icon-copy + .help-copy Copy to clipboard: Ctrl+C + + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Save") Save + + + a.help-button(href="https://taiga.io/support/bitbucket-integration/", target="_blank") + span.icon.icon-help + span Do you need help? Check out our support page! diff --git a/app/partials/admin-third-parties-gitlab.jade b/app/partials/admin-third-parties-gitlab.jade new file mode 100644 index 00000000..1aa9e78e --- /dev/null +++ b/app/partials/admin-third-parties-gitlab.jade @@ -0,0 +1,35 @@ +block head + title Taiga Your agile, free, and open source project management tool + +block content + div.wrapper.roles(tg-gitlab-webhooks, ng-controller="GitlabController as ctrl", + ng-init="section='admin'") + sidebar.menu-secondary.sidebar(tg-admin-navigation="third-parties") + include views/modules/admin-menu + sidebar.menu-tertiary.sidebar(tg-admin-navigation="third-parties-gitlab") + include views/modules/admin-submenu-third-parties + + section.main.admin-common.admin-third-parties + include views/components/mainTitle + + form + fieldset + label(for="secret-key") Secret key + input(type="text", name="secret-key", ng-model="gitlab.secret", placeholder="Secret key", id="secret-key") + + fieldset + .select-input-text(tg-select-input-text) + div + label(for="payload-url") Payload URL + .field-with-option + input(type="text", ng-model="gitlab.webhooks_url", name="payload-url", readonly="readonly", placeholder="Payload URL", id="payload-url") + .option-wrapper.select-input-content + .icon.icon-copy + .help-copy Copy to clipboard: Ctrl+C + + button(type="submit", class="hidden") + a.button.button-green.submit-button(href="", title="Save") Save + + a.help-button(href="https://taiga.io/support/gitlab-integration/", target="_blank") + span.icon.icon-help + span Do you need help? Check out our support page! diff --git a/app/partials/views/modules/admin-submenu-third-parties.jade b/app/partials/views/modules/admin-submenu-third-parties.jade index 95746408..f491ebb1 100644 --- a/app/partials/views/modules/admin-submenu-third-parties.jade +++ b/app/partials/views/modules/admin-submenu-third-parties.jade @@ -8,3 +8,11 @@ section.admin-submenu a(href="", tg-nav="project-admin-third-parties-github:project=project.slug") span.title Github span.icon.icon-arrow-right + li#adminmenu-third-parties-gitlab + a(href="", tg-nav="project-admin-third-parties-gitlab:project=project.slug") + span.title Gitlab + span.icon.icon-arrow-right + li#adminmenu-third-parties-bitbucket + a(href="", tg-nav="project-admin-third-parties-bitbucket:project=project.slug") + span.title Bitbucket + span.icon.icon-arrow-right From e3b223878dd967c64130ec779adc81b85be0c7e9 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 2 Dec 2014 14:21:15 +0100 Subject: [PATCH 49/66] Adding valid origin ip directive and data --- app/coffee/modules/admin/third-parties.coffee | 21 +++++++++++++++++++ .../admin-third-parties-bitbucket.jade | 4 ++++ app/partials/admin-third-parties-gitlab.jade | 4 ++++ 3 files changed, 29 insertions(+) diff --git a/app/coffee/modules/admin/third-parties.coffee b/app/coffee/modules/admin/third-parties.coffee index a341721a..a515acec 100644 --- a/app/coffee/modules/admin/third-parties.coffee +++ b/app/coffee/modules/admin/third-parties.coffee @@ -302,3 +302,24 @@ BitbucketWebhooksDirective = ($repo, $confirm, $loading) -> return {link:link} module.directive("tgBitbucketWebhooks", ["$tgRepo", "$tgConfirm", "$tgLoading", BitbucketWebhooksDirective]) + + +############################################################################# +## Valid Origin IP's Directive +############################################################################# +ValidOriginIpsDirective = -> + link = ($scope, $el, $attrs, $ngModel) -> + $ngModel.$parsers.push (value) -> + value = $.trim(value) + if value == "" + return [] + + return value.split(",") + + return { + link: link + restrict: "EA" + require: "ngModel" + } + +module.directive("tgValidOriginIps", ValidOriginIpsDirective) diff --git a/app/partials/admin-third-parties-bitbucket.jade b/app/partials/admin-third-parties-bitbucket.jade index 4bb006ee..dfde8acb 100644 --- a/app/partials/admin-third-parties-bitbucket.jade +++ b/app/partials/admin-third-parties-bitbucket.jade @@ -13,6 +13,10 @@ block content include views/components/mainTitle form + fieldset + label(for="valid-origin-ips") Valid origin ips (separated by ,)
Bitbucket requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation. + input(type="text", name="valid-origin-ips", tg-valid-origin-ips, ng-model="bitbucket.valid_origin_ips", placeholder="Valid origin ips", id="valid-origin-ips") + fieldset label(for="secret-key") Secret key input(type="text", name="secret-key", ng-model="bitbucket.secret", placeholder="Secret key", id="secret-key") diff --git a/app/partials/admin-third-parties-gitlab.jade b/app/partials/admin-third-parties-gitlab.jade index 1aa9e78e..1e0af9cf 100644 --- a/app/partials/admin-third-parties-gitlab.jade +++ b/app/partials/admin-third-parties-gitlab.jade @@ -13,6 +13,10 @@ block content include views/components/mainTitle form + fieldset + label(for="valid-origin-ips") Valid origin ips (separated by ,)
Gitlab requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation. + input(type="text", name="valid-origin-ips", tg-valid-origin-ips, ng-model="gitlab.valid_origin_ips", placeholder="Valid origin ips", id="valid-origin-ips") + fieldset label(for="secret-key") Secret key input(type="text", name="secret-key", ng-model="gitlab.secret", placeholder="Secret key", id="secret-key") From 0fb087e8c7719cea750d5d50faa0e04eb329b75e Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 2 Dec 2014 14:22:29 +0100 Subject: [PATCH 50/66] Removing unnecesary anyComputableRole --- app/coffee/modules/admin/third-parties.coffee | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/app/coffee/modules/admin/third-parties.coffee b/app/coffee/modules/admin/third-parties.coffee index a515acec..fc7abc4c 100644 --- a/app/coffee/modules/admin/third-parties.coffee +++ b/app/coffee/modules/admin/third-parties.coffee @@ -46,7 +46,6 @@ class GithubController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi @scope.sectionName = "Github" #i18n @scope.project = {} - @scope.anyComputableRole = true promise = @.loadInitialData() @@ -63,8 +62,6 @@ class GithubController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi return @rs.projects.get(@scope.projectId).then (project) => @scope.project = project @scope.$emit('project:loaded', project) - @scope.anyComputableRole = _.some(_.map(project.roles, (point) -> point.computable)) - return project loadInitialData: -> @@ -97,8 +94,6 @@ class GitlabController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi @scope.sectionName = "Gitlab" #i18n @scope.project = {} - @scope.anyComputableRole = true - promise = @.loadInitialData() promise.then () => @@ -117,8 +112,6 @@ class GitlabController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi return @rs.projects.get(@scope.projectId).then (project) => @scope.project = project @scope.$emit('project:loaded', project) - @scope.anyComputableRole = _.some(_.map(project.roles, (point) -> point.computable)) - return project loadInitialData: -> @@ -151,8 +144,6 @@ class BitbucketController extends mixOf(taiga.Controller, taiga.PageMixin, taiga @scope.sectionName = "Bitbucket" #i18n @scope.project = {} - @scope.anyComputableRole = true - promise = @.loadInitialData() promise.then () => @@ -171,8 +162,6 @@ class BitbucketController extends mixOf(taiga.Controller, taiga.PageMixin, taiga return @rs.projects.get(@scope.projectId).then (project) => @scope.project = project @scope.$emit('project:loaded', project) - @scope.anyComputableRole = _.some(_.map(project.roles, (point) -> point.computable)) - return project loadInitialData: -> From aa71dcc231cdda6291a22ad145b9bb9647af920e Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Tue, 2 Dec 2014 14:57:49 +0100 Subject: [PATCH 51/66] Changing field order --- app/partials/admin-third-parties-bitbucket.jade | 8 ++++---- app/partials/admin-third-parties-gitlab.jade | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/partials/admin-third-parties-bitbucket.jade b/app/partials/admin-third-parties-bitbucket.jade index dfde8acb..7e3ca8f8 100644 --- a/app/partials/admin-third-parties-bitbucket.jade +++ b/app/partials/admin-third-parties-bitbucket.jade @@ -13,10 +13,6 @@ block content include views/components/mainTitle form - fieldset - label(for="valid-origin-ips") Valid origin ips (separated by ,)
Bitbucket requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation. - input(type="text", name="valid-origin-ips", tg-valid-origin-ips, ng-model="bitbucket.valid_origin_ips", placeholder="Valid origin ips", id="valid-origin-ips") - fieldset label(for="secret-key") Secret key input(type="text", name="secret-key", ng-model="bitbucket.secret", placeholder="Secret key", id="secret-key") @@ -30,6 +26,10 @@ block content .option-wrapper.select-input-content .icon.icon-copy .help-copy Copy to clipboard: Ctrl+C + + fieldset + label(for="valid-origin-ips") Valid origin ips (separated by ,) + input(type="text", name="valid-origin-ips", tg-valid-origin-ips, ng-model="bitbucket.valid_origin_ips", placeholder="Bitbucket requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation.", id="valid-origin-ips") button(type="submit", class="hidden") a.button.button-green.submit-button(href="", title="Save") Save diff --git a/app/partials/admin-third-parties-gitlab.jade b/app/partials/admin-third-parties-gitlab.jade index 1e0af9cf..c85b2165 100644 --- a/app/partials/admin-third-parties-gitlab.jade +++ b/app/partials/admin-third-parties-gitlab.jade @@ -13,10 +13,6 @@ block content include views/components/mainTitle form - fieldset - label(for="valid-origin-ips") Valid origin ips (separated by ,)
Gitlab requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation. - input(type="text", name="valid-origin-ips", tg-valid-origin-ips, ng-model="gitlab.valid_origin_ips", placeholder="Valid origin ips", id="valid-origin-ips") - fieldset label(for="secret-key") Secret key input(type="text", name="secret-key", ng-model="gitlab.secret", placeholder="Secret key", id="secret-key") @@ -31,6 +27,10 @@ block content .icon.icon-copy .help-copy Copy to clipboard: Ctrl+C + fieldset + label(for="valid-origin-ips") Valid origin ips (separated by ,) + input(type="text", name="valid-origin-ips", tg-valid-origin-ips, ng-model="gitlab.valid_origin_ips", placeholder="Gitlab requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation.", id="valid-origin-ips") + button(type="submit", class="hidden") a.button.button-green.submit-button(href="", title="Save") Save From ed7a176fe0fe00095f44e655e54fcb42295e13f0 Mon Sep 17 00:00:00 2001 From: Juanfran Date: Tue, 2 Dec 2014 15:20:23 +0100 Subject: [PATCH 52/66] fix #1714 - bulk resort tasks in the taskboard --- app/coffee/modules/resources.coffee | 1 + app/coffee/modules/resources/tasks.coffee | 5 +++++ app/coffee/modules/taskboard/main.coffee | 25 ++++++++++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/app/coffee/modules/resources.coffee b/app/coffee/modules/resources.coffee index 2bce1f4b..46ebe973 100644 --- a/app/coffee/modules/resources.coffee +++ b/app/coffee/modules/resources.coffee @@ -42,6 +42,7 @@ urls = { "userstories-restore": "/userstories/%s/restore" "tasks": "/tasks" "bulk-create-tasks": "/tasks/bulk_create" + "bulk-update-task-taskboard-order": "/tasks/bulk_update_taskboard_order" "tasks-restore": "/tasks/%s/restore" "issues": "/issues" "bulk-create-issues": "/issues/bulk_create" diff --git a/app/coffee/modules/resources/tasks.coffee b/app/coffee/modules/resources/tasks.coffee index 76883117..07cacb18 100644 --- a/app/coffee/modules/resources/tasks.coffee +++ b/app/coffee/modules/resources/tasks.coffee @@ -46,6 +46,11 @@ resourceProvider = ($repo, $http, $urls, $storage) -> return $http.post(url, params).then (result) -> return result.data + service.bulkUpdateTaskTaskboardOrder = (projectId, data) -> + url = $urls.resolve("bulk-update-task-taskboard-order") + params = {project_id: projectId, bulk_tasks: data} + return $http.post(url, params) + service.listValues = (projectId, type) -> params = {"project": projectId} return $repo.queryMany(type, params) diff --git a/app/coffee/modules/taskboard/main.coffee b/app/coffee/modules/taskboard/main.coffee index 7d0cf5d3..e25fe79f 100644 --- a/app/coffee/modules/taskboard/main.coffee +++ b/app/coffee/modules/taskboard/main.coffee @@ -184,21 +184,44 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin) .then(=> @.loadUsersAndRoles()) .then(=> @.loadTaskboard()) + refreshTasksOrder: (tasks) -> + items = @.resortTasks(tasks) + data = @.prepareBulkUpdateData(items) + + return @rs.tasks.bulkUpdateTaskTaskboardOrder(@scope.project.id, data) + + resortTasks: (tasks) -> + items = [] + + for item, index in tasks + item["taskboard_order"] = index + if item.isModified() + items.push(item) + + return items + + prepareBulkUpdateData: (uses) -> + return _.map(uses, (x) -> {"task_id": x.id, "order": x["taskboard_order"]}) + taskMove: (ctx, task, usId, statusId, order) -> # Remove task from old position r = @scope.usTasks[task.user_story][task.status].indexOf(task) @scope.usTasks[task.user_story][task.status].splice(r, 1) # Add task to new position - @scope.usTasks[usId][statusId].splice(order, 0, task) + tasks = @scope.usTasks[usId][statusId] + tasks.splice(order, 0, task) task.user_story = usId task.status = statusId task.taskboard_order = order promise = @repo.save(task) + promise.then => + @.refreshTasksOrder(tasks) @.loadSprintStats() + promise.then null, => console.log "FAIL TASK SAVE" From 90a8959d50f141356529ddd55b4f5a2d269f0621 Mon Sep 17 00:00:00 2001 From: Juanfran Date: Tue, 2 Dec 2014 12:03:06 +0100 Subject: [PATCH 53/66] fix #678 - it's possible to scroll when drag US's --- app/coffee/modules/backlog/sortable.coffee | 5 ++-- app/coffee/modules/backlog/sprints.coffee | 31 ++++++++++++++++++---- app/coffee/modules/nav.coffee | 14 ++++++---- app/styles/layout/base.scss | 3 --- app/styles/modules/backlog/sprints.scss | 13 +++------ 5 files changed, 40 insertions(+), 26 deletions(-) diff --git a/app/coffee/modules/backlog/sortable.coffee b/app/coffee/modules/backlog/sortable.coffee index cbb485c6..b027f501 100644 --- a/app/coffee/modules/backlog/sortable.coffee +++ b/app/coffee/modules/backlog/sortable.coffee @@ -58,9 +58,7 @@ BacklogSortableDirective = ($repo, $rs, $rootscope, $tgConfirm) -> containment: ".wrapper" dropOnEmpty: true placeholder: "row us-item-row us-item-drag sortable-placeholder" - # With scroll activated, it has strange behavior - # with not full screen browser window. - scroll: false + scroll: true # A consequence of length of backlog user story item # the default tolerance ("intersection") not works properly. tolerance: "pointer" @@ -153,6 +151,7 @@ SprintSortableDirective = ($repo, $rs, $rootscope) -> # If the user has not enough permissions we don't enable the sortable if project.my_permissions.indexOf("modify_us") > -1 $el.sortable({ + scroll: true dropOnEmpty: true connectWith: ".sprint-table,.backlog-table-body,.empty-backlog" }) diff --git a/app/coffee/modules/backlog/sprints.coffee b/app/coffee/modules/backlog/sprints.coffee index fcdcd8b6..cba3840f 100644 --- a/app/coffee/modules/backlog/sprints.coffee +++ b/app/coffee/modules/backlog/sprints.coffee @@ -29,23 +29,44 @@ module = angular.module("taigaBacklog") ############################################################################# BacklogSprintDirective = ($repo, $rootscope) -> + sprintTableMinHeight = 50 + slideOptions = { + duration: 500, + easing: 'linear' + } + + refreshSprintTableHeight = (sprintTable) => + if !sprintTable.find(".row").length + sprintTable.css("height", sprintTableMinHeight) + else + sprintTable.css("height", "auto") + + toggleSprint = ($el) => + sprintTable = $el.find(".sprint-table") + sprintArrow = $el.find(".icon-arrow-up") + + sprintArrow.toggleClass('active') + sprintTable.toggleClass('open') + + refreshSprintTableHeight(sprintTable) + link = ($scope, $el, $attrs) -> $scope.$watch $attrs.tgBacklogSprint, (sprint) -> sprint = $scope.$eval($attrs.tgBacklogSprint) if $scope.$first - $el.addClass("sprint-current") - $el.find(".sprint-table").addClass('open') + toggleSprint($el) else if sprint.closed $el.addClass("sprint-closed") else if not $scope.$first and not sprint.closed + toggleSprint($el) $el.addClass("sprint-old-open") # Event Handlers $el.on "click", ".sprint-name > .icon-arrow-up", (event) -> - target = $(event.currentTarget) - target.toggleClass('active') - $el.find(".sprint-table").toggleClass('open') + toggleSprint($el) + + $el.find(".sprint-table").slideToggle(slideOptions) $el.on "click", ".sprint-name > .icon-edit", (event) -> sprint = $scope.$eval($attrs.tgBacklogSprint) diff --git a/app/coffee/modules/nav.coffee b/app/coffee/modules/nav.coffee index e9c8ee66..8283c76b 100644 --- a/app/coffee/modules/nav.coffee +++ b/app/coffee/modules/nav.coffee @@ -121,7 +121,10 @@ ProjectsNavigationDirective = ($rootscope, animationFrame, $timeout, tgLoader, $ timeout timeoutValue, -> overlay.one 'transitionend', () -> - $(document.body).removeClass("loading-project open-projects-nav closed-projects-nav") + $(document.body) + .removeClass("loading-project open-projects-nav closed-projects-nav") + .css("overflow-x", "visible") + overlay.hide() $(document.body).addClass("closed-projects-nav") @@ -153,11 +156,12 @@ ProjectsNavigationDirective = ($rootscope, animationFrame, $timeout, tgLoader, $ $scope.$on "nav:projects-list:open", -> if !$(document.body).hasClass("open-projects-nav") - animationFrame.add () -> - overlay.show() + animationFrame.add () => overlay.show() - animationFrame.add () -> - $(document.body).toggleClass("open-projects-nav") + animationFrame.add( + () => $(document.body).css("overflow-x", "hidden") + () => $(document.body).toggleClass("open-projects-nav") + ) $el.on "click", ".projects-list > li > a", (event) -> # HACK: to solve a problem with the loader when the next url diff --git a/app/styles/layout/base.scss b/app/styles/layout/base.scss index aa4f9a73..8329b3ec 100644 --- a/app/styles/layout/base.scss +++ b/app/styles/layout/base.scss @@ -1,6 +1,5 @@ // Basic layout styles html { - height: 100%; min-height: 100%; width: 100%; } @@ -9,9 +8,7 @@ body { background: #fff; // fallback color: #444; -webkit-font-smoothing: antialiased; // Fix for webkit renderin - height: 100%; min-height: 100%; - overflow-x: hidden; // open-projects-nav -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%; width: 100%; diff --git a/app/styles/modules/backlog/sprints.scss b/app/styles/modules/backlog/sprints.scss index 52000ff5..f80fa5cb 100644 --- a/app/styles/modules/backlog/sprints.scss +++ b/app/styles/modules/backlog/sprints.scss @@ -116,10 +116,6 @@ } } .sprint-table { - @include slide(1000px, overflow-x); - &.open { - min-height: 50px; - } .row { @include table-flex(); border-bottom: 1px solid $gray-light; @@ -211,13 +207,13 @@ } } } - .sprint-table { - @include slide(1000px, overflow-y); - } } // If sprint is closed and date is old .sprint-closed { + .sprint-table { + display: none; + } .sprint-name { .icon-arrow-up { @include transform(rotate(180deg)); @@ -242,9 +238,6 @@ background: darken($gray-light, 10%); } } - .sprint-table { - @include slide(1000px, overflow-y); - } .button-gray { background: $gray-light; } From 97170673fa547668d77b933eb52f8c68183a01f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Thu, 13 Nov 2014 17:29:47 +0100 Subject: [PATCH 54/66] Column fold in taskboard --- app/partials/taskboard.jade | 2 +- .../views/modules/taskboard-table.jade | 9 +- app/styles/components/taskboard-task.scss | 1 - .../modules/backlog/taskboard-table.scss | 85 +++++++++++++++++-- 4 files changed, 86 insertions(+), 11 deletions(-) diff --git a/app/partials/taskboard.jade b/app/partials/taskboard.jade index 9cdf3e1e..a9a191c0 100644 --- a/app/partials/taskboard.jade +++ b/app/partials/taskboard.jade @@ -11,7 +11,7 @@ block content span(tg-bo-bind="project.name", class="project-name-short") span.green(tg-bo-bind="sprint.name") span.date(tg-date-range="sprint.estimated_start,sprint.estimated_finish") - include views/components/sprint-summary + //- include views/components/sprint-summary div.graphics-container div.burndown(tg-sprint-graph) diff --git a/app/partials/views/modules/taskboard-table.jade b/app/partials/views/modules/taskboard-table.jade index d346793f..7cd36876 100644 --- a/app/partials/views/modules/taskboard-table.jade +++ b/app/partials/views/modules/taskboard-table.jade @@ -2,9 +2,12 @@ div.taskboard-table div.taskboard-table-header div.taskboard-table-inner(tg-taskboard-row-width-fixer) h2.task-colum-name "User story" + //- Add class .colum-hfold in .task-column h2.task-colum-name(ng-repeat="s in taskStatusList track by s.id", - ng-style="{'border-top-color':s.color}") + ng-style="{'border-top-color':s.color}", tg-bo-title="s.name") span(tg-bo-bind="s.name") + a.icon.icon-vfold.hfold(href="", title="Fold Column") + a.icon.icon-vunfold.hunfold.hidden(href="", title="Unfold Column") div.taskboard-table-body(tg-taskboard-table-height-fixer) div.taskboard-table-inner(tg-taskboard-row-width-fixer) @@ -19,7 +22,7 @@ div.taskboard-table span(ng-bind="us.total_points") span points include ../components/addnewtask.jade - + //- Add class .colum-hfold in .task-column div.taskboard-tasks-box.task-column(ng-repeat="st in taskStatusList track by st.id", tg-taskboard-sortable) div.taskboard-task(ng-repeat="task in usTasks[us.id][st.id] track by task.id", @@ -31,7 +34,7 @@ div.taskboard-table h3.us-title span Unassigned tasks include ../components/addnewtask.jade - + //- Add class .colum-hfold in .task-column div.taskboard-tasks-box.task-column(ng-repeat="st in taskStatusList track by st.id", tg-taskboard-sortable) div.taskboard-task(ng-repeat="task in usTasks[null][st.id] track by task.id", diff --git a/app/styles/components/taskboard-task.scss b/app/styles/components/taskboard-task.scss index 7b9fe6e0..2a45c564 100644 --- a/app/styles/components/taskboard-task.scss +++ b/app/styles/components/taskboard-task.scss @@ -45,7 +45,6 @@ } .taskboard-task-inner { @include table-flex(); - min-height: 7rem; padding: .5rem; } .taskboard-user-avatar { diff --git a/app/styles/modules/backlog/taskboard-table.scss b/app/styles/modules/backlog/taskboard-table.scss index 1d028e95..4a0f540d 100644 --- a/app/styles/modules/backlog/taskboard-table.scss +++ b/app/styles/modules/backlog/taskboard-table.scss @@ -1,6 +1,7 @@ //Table basic shared vars $column-width: 300px; +$column-folded-width: 45px; $column-flex: 1; $column-shrink: 0; $column-margin: 0 10px 0 0; @@ -21,18 +22,63 @@ $column-margin: 0 10px 0 0; position: absolute; } .task-colum-name { - @extend %large; @include table-flex-child($column-flex, $column-width, $column-shrink, $column-width); + @include table-flex(); + @include justify-content(space-between); + @extend %large; background: $whitish; border-top: 3px solid $gray-light; + cursor: pointer; margin: $column-margin; - padding: .5rem 0; + max-width: $column-width; + padding: .5rem 1rem; position: relative; - text-align: center; text-transform: uppercase; + width: $column-width; &:last-child { margin-right: 0; } + &:hover { + .icon { + &.hfold, + &.hunfold { + @include transition(opacity .2s linear); + opacity: 1; + } + } + } + .icon { + @extend %medium; + @include transition(color .2s linear); + color: $gray-light; + margin-right: .3rem; + &:hover { + color: $green-taiga; + } + &.hfold, + &.hunfold { + @include transition(opacity .2s linear); + @include transform(rotate(90deg)); + display: inline-block; + opacity: 0; + } + } + &.column-hfold { + @include align-items(center); + @include justify-content(center); + max-width: $column-folded-width; + padding: .3rem 0; + width: $column-folded-width; + span { + display: none; + } + .icon { + &.hfold, + &.hunfold { + margin: 0; + } + } + } } } @@ -42,11 +88,40 @@ $column-margin: 0 10px 0 0; overflow-y: scroll; width: 100%; .task-column { - @include table-flex-child($column-flex, $column-width, $column-shrink, $column-width); + @include table-flex-child(); margin: $column-margin; + max-width: $column-width; + width: $column-width; &:last-child { margin-right: 0; } + &.colum-hfold { + max-width: $column-folded-width; + width: $column-folded-width; + .taskboard-task { + background: none; + border: 0; + margin: 0; + min-height: 0; + .taskboard-task-inner { + padding: .2rem; + } + .taskboard-tagline, + .taskboard-text { + display: none; + } + .avatar { + height: 35px; + width: 35px; + } + .icon { + display: none; + } + &.ui-sortable-helper { + box-shadow: none; + } + } + } } .task-row { @include table-flex(); @@ -74,14 +149,12 @@ $column-margin: 0 10px 0 0; } } .taskboard-tasks-box { - //@include filter(saturate(20%)); background: rgba($red, .1); } } } .taskboard-tasks-box { background: $whitish; - //background: $very-light-gray; } .taskboard-userstory-box { From e1362e84d45203dd457322295b4d5ca0b1c3cea8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Thu, 13 Nov 2014 18:05:14 +0100 Subject: [PATCH 55/66] Row Fold --- .../views/modules/taskboard-table.jade | 16 +++--- .../modules/backlog/taskboard-table.scss | 54 +++++++++++++++++-- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/app/partials/views/modules/taskboard-table.jade b/app/partials/views/modules/taskboard-table.jade index 7cd36876..9ca0f95d 100644 --- a/app/partials/views/modules/taskboard-table.jade +++ b/app/partials/views/modules/taskboard-table.jade @@ -2,7 +2,7 @@ div.taskboard-table div.taskboard-table-header div.taskboard-table-inner(tg-taskboard-row-width-fixer) h2.task-colum-name "User story" - //- Add class .colum-hfold in .task-column + //- TODO Add class .colum-fold in .task-column h2.task-colum-name(ng-repeat="s in taskStatusList track by s.id", ng-style="{'border-top-color':s.color}", tg-bo-title="s.name") span(tg-bo-bind="s.name") @@ -11,8 +11,11 @@ div.taskboard-table div.taskboard-table-body(tg-taskboard-table-height-fixer) div.taskboard-table-inner(tg-taskboard-row-width-fixer) - div.task-row(ng-repeat="us in userstories track by us.id", ng-class="{blocked: us.is_blocked}") + //- TODO: Add class .row-fold in .task-column + div.task-row.row-fold(ng-repeat="us in userstories track by us.id", ng-class="{blocked: us.is_blocked}") div.taskboard-userstory-box.task-column(tg-bo-title="us.blocked_note") + a.icon.icon-vfold.vfold(href="", title="Fold Row") + a.icon.icon-vunfold.vunfold.hidden(href="", title="Unfold Row") h3.us-title a(href="", tg-nav="project-userstories-detail:project=project.slug,ref=us.ref", tg-bo-title="'#' + us.ref + ' ' + us.subject") @@ -21,20 +24,21 @@ div.taskboard-table p.points-value span(ng-bind="us.total_points") span points - include ../components/addnewtask.jade - //- Add class .colum-hfold in .task-column + include ../components/addnewtask + //- TODO: Add class .colum-fold in .task-column div.taskboard-tasks-box.task-column(ng-repeat="st in taskStatusList track by st.id", tg-taskboard-sortable) div.taskboard-task(ng-repeat="task in usTasks[us.id][st.id] track by task.id", tg-taskboard-task) include ../components/taskboard-task - div.task-row(ng-init="us = null") + //- TODO: Add class .row-fold in .task-Column + div.task-row.row-fold(ng-init="us = null") div.taskboard-userstory-box.task-column h3.us-title span Unassigned tasks include ../components/addnewtask.jade - //- Add class .colum-hfold in .task-column + //- TODO Add class .colum-fold in .task-column div.taskboard-tasks-box.task-column(ng-repeat="st in taskStatusList track by st.id", tg-taskboard-sortable) div.taskboard-task(ng-repeat="task in usTasks[null][st.id] track by task.id", diff --git a/app/styles/modules/backlog/taskboard-table.scss b/app/styles/modules/backlog/taskboard-table.scss index 4a0f540d..d4e46c89 100644 --- a/app/styles/modules/backlog/taskboard-table.scss +++ b/app/styles/modules/backlog/taskboard-table.scss @@ -63,7 +63,7 @@ $column-margin: 0 10px 0 0; opacity: 0; } } - &.column-hfold { + &.column-fold { @include align-items(center); @include justify-content(center); max-width: $column-folded-width; @@ -95,7 +95,7 @@ $column-margin: 0 10px 0 0; &:last-child { margin-right: 0; } - &.colum-hfold { + &.colum-fold { max-width: $column-folded-width; width: $column-folded-width; .taskboard-task { @@ -152,25 +152,71 @@ $column-margin: 0 10px 0 0; background: rgba($red, .1); } } + &.row-fold { + min-height: 0; + .taskboard-userstory-box { + .us-title { + @include ellipsis(100%); + } + .points-value, + .icon-plus, + .icon-bulk { + display: none; + } + } + .task-column { + @include table-flex(); + @include flex-direction(row); + } + .taskboard-task { + background: none; + border: 0; + margin: 0; + max-width: 40px; + min-height: 0; + width: 40px; + .taskboard-task-inner { + padding: .2rem; + } + .taskboard-tagline, + .taskboard-text { + display: none; + } + .avatar { + height: 35px; + width: 35px; + } + .icon { + display: none; + } + &.ui-sortable-helper { + box-shadow: none; + } + } + } } .taskboard-tasks-box { background: $whitish; } .taskboard-userstory-box { - padding: .5rem; + padding: .5rem .5rem .5rem 1.5rem; .icon { @include transition(color .2s linear); color: $gray-light; position: absolute; right: .5rem; - top: 1rem; + top: .7rem; &:hover { color: $green-taiga; } &.icon-plus { right: 2rem; } + &.icon-vfold { + left: 0; + right: inherit; + } } } } From 1619ef9383d6b52e2e6111030cc01821015f6217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xavier=20Juli=C3=A1n?= Date: Fri, 14 Nov 2014 09:47:22 +0100 Subject: [PATCH 56/66] Fold/unfold comments --- .../views/modules/taskboard-table.jade | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/app/partials/views/modules/taskboard-table.jade b/app/partials/views/modules/taskboard-table.jade index 9ca0f95d..4e3874d1 100644 --- a/app/partials/views/modules/taskboard-table.jade +++ b/app/partials/views/modules/taskboard-table.jade @@ -1,3 +1,19 @@ +// + Column fold integration: + 1. If click on column fold button search all TODOS and add class .colum-fold fold where indicated in comments. + 2. Hide column fold button and show column unfold button (sibling) + 3. Recalculate container table width. + + Row Fold integration: + 1. If click on row fold button search all TODOS and add class .row-fold fold where indicated in comments. + 2. Hide row fold button and show column unfold button (sibling) + 3. Recalculate container table width. + + Row and column integration + 1. I think we will need to do som JS calcs to fix this. Not sure at the moment. + + + div.taskboard-table div.taskboard-table-header div.taskboard-table-inner(tg-taskboard-row-width-fixer) @@ -12,7 +28,7 @@ div.taskboard-table div.taskboard-table-body(tg-taskboard-table-height-fixer) div.taskboard-table-inner(tg-taskboard-row-width-fixer) //- TODO: Add class .row-fold in .task-column - div.task-row.row-fold(ng-repeat="us in userstories track by us.id", ng-class="{blocked: us.is_blocked}") + div.task-row(ng-repeat="us in userstories track by us.id", ng-class="{blocked: us.is_blocked}") div.taskboard-userstory-box.task-column(tg-bo-title="us.blocked_note") a.icon.icon-vfold.vfold(href="", title="Fold Row") a.icon.icon-vunfold.vunfold.hidden(href="", title="Unfold Row") @@ -33,7 +49,7 @@ div.taskboard-table include ../components/taskboard-task //- TODO: Add class .row-fold in .task-Column - div.task-row.row-fold(ng-init="us = null") + div.task-row(ng-init="us = null") div.taskboard-userstory-box.task-column h3.us-title span Unassigned tasks From 533395202be144cb2ee92b9e4963f8c561cc7f76 Mon Sep 17 00:00:00 2001 From: Juanfran Date: Tue, 18 Nov 2014 17:01:12 +0100 Subject: [PATCH 57/66] fold/unfold taskboard tasks columns & us rows --- app/coffee/modules/resources/tasks.coffee | 24 +++ app/coffee/modules/taskboard/main.coffee | 178 +++++++++++++----- .../views/components/taskboard-task.jade | 3 +- .../views/modules/taskboard-table.jade | 50 ++--- app/styles/components/taskboard-task.scss | 1 - .../modules/backlog/taskboard-table.scss | 128 ++++++------- 6 files changed, 223 insertions(+), 161 deletions(-) diff --git a/app/coffee/modules/resources/tasks.coffee b/app/coffee/modules/resources/tasks.coffee index 07cacb18..3e29f612 100644 --- a/app/coffee/modules/resources/tasks.coffee +++ b/app/coffee/modules/resources/tasks.coffee @@ -27,6 +27,8 @@ generateHash = taiga.generateHash resourceProvider = ($repo, $http, $urls, $storage) -> service = {} hashSuffix = "tasks-queryparams" + hashSuffixStatusColumnModes = "tasks-statuscolumnmodels" + hashSuffixUsRowModes = "tasks-usrowmodels" service.get = (projectId, taskId) -> params = service.getQueryParams(projectId) @@ -65,6 +67,28 @@ resourceProvider = ($repo, $http, $urls, $storage) -> hash = generateHash([projectId, ns]) return $storage.get(hash) or {} + service.storeStatusColumnModes = (projectId, params) -> + ns = "#{projectId}:#{hashSuffixStatusColumnModes}" + hash = generateHash([projectId, ns]) + $storage.set(hash, params) + + service.getStatusColumnModes = (projectId) -> + ns = "#{projectId}:#{hashSuffixStatusColumnModes}" + hash = generateHash([projectId, ns]) + return $storage.get(hash) or {} + + service.storeUsRowModes = (projectId, sprintId, params) -> + ns = "#{projectId}:#{hashSuffixUsRowModes}" + hash = generateHash([projectId, sprintId, ns]) + + $storage.set(hash, params) + + service.getUsRowModes = (projectId, sprintId) -> + ns = "#{projectId}:#{hashSuffixUsRowModes}" + hash = generateHash([projectId, sprintId, ns]) + + return $storage.get(hash) or {} + return (instance) -> instance.tasks = service diff --git a/app/coffee/modules/taskboard/main.coffee b/app/coffee/modules/taskboard/main.coffee index e25fe79f..15e5cf7d 100644 --- a/app/coffee/modules/taskboard/main.coffee +++ b/app/coffee/modules/taskboard/main.coffee @@ -103,7 +103,6 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin) loadProject: -> return @rs.projects.get(@scope.projectId).then (project) => @scope.project = project - @scope.$emit('project:loaded', project) # Not used at this momment @scope.pointsList = _.sortBy(project.points, "order") # @scope.roleList = _.sortBy(project.roles, "order") @@ -112,6 +111,9 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.taskStatusList = _.sortBy(project.task_statuses, "order") @scope.usStatusList = _.sortBy(project.us_statuses, "order") @scope.usStatusById = groupBy(project.us_statuses, (e) -> e.id) + + @scope.$emit('project:loaded', project) + return project loadSprintStats: -> @@ -218,6 +220,8 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin) promise = @repo.save(task) + @rootscope.$broadcast("sprint:task:moved", task) + promise.then => @.refreshTasksOrder(tasks) @.loadSprintStats() @@ -291,22 +295,6 @@ TaskboardTaskDirective = ($rootscope) -> module.directive("tgTaskboardTask", ["$rootScope", TaskboardTaskDirective]) - -############################################################################# -## Taskboard Task Row Size Fixer Directive -############################################################################# - -TaskboardRowWidthFixerDirective = -> - link = ($scope, $el, $attrs) -> - bindOnce $scope, "taskStatusList", (statuses) -> - itemSize = 300 + (10 * statuses.length) - size = (1 + statuses.length) * itemSize - $el.css("width", "#{size}px") - - return {link: link} - -module.directive("tgTaskboardRowWidthFixer", TaskboardRowWidthFixerDirective) - ############################################################################# ## Taskboard Table Height Fixer Directive ############################################################################# @@ -331,64 +319,156 @@ TaskboardTableHeightFixerDirective = -> module.directive("tgTaskboardTableHeightFixer", TaskboardTableHeightFixerDirective) +############################################################################# +## Taskboard Squish Column Directive +############################################################################# + +TaskboardSquishColumnDirective = (rs) -> + avatarWidth = 40 + + link = ($scope, $el, $attrs) -> + $scope.$on "sprint:task:moved", () => + recalculateTaskboardWidth() + + bindOnce $scope, "usTasks", (project) -> + $scope.statusesFolded = rs.tasks.getStatusColumnModes($scope.project.id) + $scope.usFolded = rs.tasks.getUsRowModes($scope.project.id, $scope.sprintId) + + recalculateTaskboardWidth() + + $scope.foldStatus = (status) -> + $scope.statusesFolded[status.id] = !!!$scope.statusesFolded[status.id] + rs.tasks.storeStatusColumnModes($scope.projectId, $scope.statusesFolded) + + recalculateTaskboardWidth() + + $scope.foldUs = (us) -> + if !us + $scope.usFolded["unassigned"] = !!!$scope.usFolded["unassigned"] + else + $scope.usFolded[us.id] = !!!$scope.usFolded[us.id] + + rs.tasks.storeUsRowModes($scope.projectId, $scope.sprintId, $scope.usFolded) + + recalculateTaskboardWidth() + + getCeilWidth = (usId, statusId) => + tasks = $scope.usTasks[usId][statusId].length + + if $scope.statusesFolded[statusId] + if tasks and $scope.usFolded[usId] + tasksMatrixSize = Math.round(Math.sqrt(tasks)) + width = avatarWidth * tasksMatrixSize + else + width = avatarWidth + + return width + + return 0 + + setStatusColumnWidth = (statusId, width) => + column = $el.find(".squish-status-#{statusId}") + + if width + column.css('max-width', width) + else + column.removeAttr("style") + + refreshTaskboardTableWidth = () => + columnWidths = [] + + columns = $el.find(".task-colum-name") + + columnWidths = _.map columns, (column) -> + return $(column).outerWidth(true) + + totalWidth = _.reduce columnWidths, (total, width) -> + return total + width + + $el.find('.taskboard-table-inner').css("width", totalWidth) + + recalculateStatusColumnWidth = (statusId) => + statusFoldedWidth = 0 + + _.forEach $scope.userstories, (us) -> + width = getCeilWidth(us.id, statusId) + + statusFoldedWidth = width if width > statusFoldedWidth + + setStatusColumnWidth(statusId, statusFoldedWidth) + + recalculateTaskboardWidth = () => + _.forEach $scope.taskStatusList, (status) -> + recalculateStatusColumnWidth(status.id) + + refreshTaskboardTableWidth() + + return + + return {link: link} + +module.directive("tgTaskboardSquishColumn", ["$tgResources", TaskboardSquishColumnDirective]) ############################################################################# ## Taskboard User Directive ############################################################################# TaskboardUserDirective = ($log) -> - template = _.template(""" -
- class="not-clickable"<% } %>> - <%- name %> + template = """ +
+ +
- """) # TODO: i18n + + + """ # TODO: i18n clickable = false - link = ($scope, $el, $attrs, $model) -> - if not $attrs.tgTaskboardUserAvatar? - return $log.error "TaskboardUserDirective: no attr is defined" + link = ($scope, $el, $attrs) -> + username_label = $el.parent().find("a.task-assigned") + username_label.on "click", (event) -> + if $el.find('a').hasClass('noclick') + return - wtid = $scope.$watch $attrs.tgTaskboardUserAvatar, (v) -> - if not $scope.usersById? - $log.error "TaskboardUserDirective requires userById set in scope." - wtid() - else - user = $scope.usersById[v] - render(user) + $ctrl = $el.controller() + $ctrl.editTaskAssignedTo($scope.task) + + $scope.$watch 'task.assigned_to', (assigned_to) -> + user = $scope.usersById[assigned_to] - render = (user) -> if user is undefined - ctx = {name: "Unassigned", imgurl: "/images/unnamed.png", clickable: clickable} + _.assign($scope, {name: "Unassigned", imgurl: "/images/unnamed.png", clickable: clickable}) else - ctx = {name: user.full_name_display, imgurl: user.photo, clickable: clickable} + _.assign($scope, {name: user.full_name_display, imgurl: user.photo, clickable: clickable}) - html = template(ctx) - $el.html(html) - username_label = $el.parent().find("a.task-assigned") - username_label.html(ctx.name) - username_label.on "click", (event) -> - if $el.find('a').hasClass('noclick') - return + username_label.text($scope.name) - us = $model.$modelValue - $ctrl = $el.controller() - $ctrl.editTaskAssignedTo(us) bindOnce $scope, "project", (project) -> if project.my_permissions.indexOf("modify_task") > -1 clickable = true - $el.on "click", (event) => + $el.find(".avatar-assigned-to").on "click", (event) => if $el.find('a').hasClass('noclick') return - us = $model.$modelValue $ctrl = $el.controller() - $ctrl.editTaskAssignedTo(us) + $ctrl.editTaskAssignedTo($scope.task) - return {link: link, require:"ngModel"} + return { + link: link, + template: template, + scope: { + "usersById": "=users", + "project": "=", + "task": "=", + } + } module.directive("tgTaskboardUserAvatar", ["$log", TaskboardUserDirective]) diff --git a/app/partials/views/components/taskboard-task.jade b/app/partials/views/components/taskboard-task.jade index 9fd01538..29311f7c 100644 --- a/app/partials/views/components/taskboard-task.jade +++ b/app/partials/views/components/taskboard-task.jade @@ -1,7 +1,6 @@ div.taskboard-tagline(tg-colorize-tags="task.tags", tg-colorize-tags-type="taskboard") div.taskboard-task-inner - div.taskboard-user-avatar(tg-taskboard-user-avatar="task.assigned_to", ng-model="task", - ng-class="{iocaine: task.is_iocaine}") + div.taskboard-user-avatar(tg-taskboard-user-avatar, users="usersById", task="task", project="project", ng-class="{iocaine: task.is_iocaine}") span.icon.icon-iocaine(ng-if="task.is_iocaine", title="Feeling a bit overwhelmed by a task? Make sure others know about it by clicking on Iocaine when editing a task. It's possible to become immune to this (fictional) deadly poison by consuming small amounts over time just as it's possible to get better at what you do by occasionally taking on extra challenges!") p.taskboard-text a.task-assigned(href="", title="Assign task") diff --git a/app/partials/views/modules/taskboard-table.jade b/app/partials/views/modules/taskboard-table.jade index 4e3874d1..0454497e 100644 --- a/app/partials/views/modules/taskboard-table.jade +++ b/app/partials/views/modules/taskboard-table.jade @@ -1,37 +1,18 @@ -// - Column fold integration: - 1. If click on column fold button search all TODOS and add class .colum-fold fold where indicated in comments. - 2. Hide column fold button and show column unfold button (sibling) - 3. Recalculate container table width. - - Row Fold integration: - 1. If click on row fold button search all TODOS and add class .row-fold fold where indicated in comments. - 2. Hide row fold button and show column unfold button (sibling) - 3. Recalculate container table width. - - Row and column integration - 1. I think we will need to do som JS calcs to fix this. Not sure at the moment. - - - -div.taskboard-table +div.taskboard-table(tg-taskboard-squish-column) div.taskboard-table-header - div.taskboard-table-inner(tg-taskboard-row-width-fixer) + div.taskboard-table-inner h2.task-colum-name "User story" - //- TODO Add class .colum-fold in .task-column - h2.task-colum-name(ng-repeat="s in taskStatusList track by s.id", - ng-style="{'border-top-color':s.color}", tg-bo-title="s.name") + h2.task-colum-name(ng-repeat="s in taskStatusList track by s.id", ng-style="{'border-top-color':s.color}", ng-class="{'column-fold':statusesFolded[s.id]}", class="squish-status-{{s.id}}", tg-bo-title="s.name") span(tg-bo-bind="s.name") - a.icon.icon-vfold.hfold(href="", title="Fold Column") - a.icon.icon-vunfold.hunfold.hidden(href="", title="Unfold Column") + a.icon.icon-vfold.hfold(href="", ng-click='foldStatus(s)', title="Fold Column", ng-class='{hidden:statusesFolded[s.id]}') + a.icon.icon-vunfold.hunfold(href="", title="Unfold Column", ng-click='foldStatus(s)', ng-class='{hidden:!statusesFolded[s.id]}') div.taskboard-table-body(tg-taskboard-table-height-fixer) - div.taskboard-table-inner(tg-taskboard-row-width-fixer) - //- TODO: Add class .row-fold in .task-column - div.task-row(ng-repeat="us in userstories track by us.id", ng-class="{blocked: us.is_blocked}") + div.taskboard-table-inner + div.task-row(ng-repeat="us in userstories track by us.id", ng-class="{blocked: us.is_blocked, 'row-fold':usFolded[us.id]}") div.taskboard-userstory-box.task-column(tg-bo-title="us.blocked_note") - a.icon.icon-vfold.vfold(href="", title="Fold Row") - a.icon.icon-vunfold.vunfold.hidden(href="", title="Unfold Row") + a.icon.icon-vfold.vfold(href="", title="Fold Row", ng-click='foldUs(us)', ng-class='{hidden:usFolded[us.id]}') + a.icon.icon-vunfold.vunfold(href="", title="Unfold Row", ng-click='foldUs(us)', ng-class='{hidden:!usFolded[us.id]}') h3.us-title a(href="", tg-nav="project-userstories-detail:project=project.slug,ref=us.ref", tg-bo-title="'#' + us.ref + ' ' + us.subject") @@ -41,22 +22,19 @@ div.taskboard-table span(ng-bind="us.total_points") span points include ../components/addnewtask - //- TODO: Add class .colum-fold in .task-column - div.taskboard-tasks-box.task-column(ng-repeat="st in taskStatusList track by st.id", - tg-taskboard-sortable) + div.taskboard-tasks-box.task-column(ng-repeat="st in taskStatusList track by st.id", tg-taskboard-sortable, class="squish-status-{{st.id}}", ng-class="{'column-fold':statusesFolded[st.id]}") div.taskboard-task(ng-repeat="task in usTasks[us.id][st.id] track by task.id", tg-taskboard-task) include ../components/taskboard-task - //- TODO: Add class .row-fold in .task-Column - div.task-row(ng-init="us = null") + div.task-row(ng-init="us = null", ng-class="{'row-fold':usFolded['unassigned']}") div.taskboard-userstory-box.task-column + a.icon.icon-vfold.vfold(href="", title="Fold Row", ng-click='foldUs()', ng-class="{hidden:usFolded['unassigned']}") + a.icon.icon-vunfold.vunfold(href="", title="Unfold Row", ng-click='foldUs()', ng-class="{hidden:!usFolded['unassigned']}") h3.us-title span Unassigned tasks include ../components/addnewtask.jade - //- TODO Add class .colum-fold in .task-column - div.taskboard-tasks-box.task-column(ng-repeat="st in taskStatusList track by st.id", - tg-taskboard-sortable) + div.taskboard-tasks-box.task-column(ng-repeat="st in taskStatusList track by st.id", tg-taskboard-sortable, class="squish-status-{{st.id}}", ng-class="{'column-fold':statusesFolded[st.id]}") div.taskboard-task(ng-repeat="task in usTasks[null][st.id] track by task.id", tg-taskboard-task) include ../components/taskboard-task diff --git a/app/styles/components/taskboard-task.scss b/app/styles/components/taskboard-task.scss index 2a45c564..a306cf3e 100644 --- a/app/styles/components/taskboard-task.scss +++ b/app/styles/components/taskboard-task.scss @@ -1,5 +1,4 @@ .taskboard-task { - @include transition (all .4s linear); background: $postit; border: 1px solid $postit-hover; box-shadow: none; diff --git a/app/styles/modules/backlog/taskboard-table.scss b/app/styles/modules/backlog/taskboard-table.scss index d4e46c89..c2a35a58 100644 --- a/app/styles/modules/backlog/taskboard-table.scss +++ b/app/styles/modules/backlog/taskboard-table.scss @@ -1,11 +1,46 @@ //Table basic shared vars $column-width: 300px; -$column-folded-width: 45px; -$column-flex: 1; +$column-flex: 0; $column-shrink: 0; $column-margin: 0 10px 0 0; +%fold { + .taskboard-task { + background: none; + border: 0; + margin: 0; + min-height: 0; + .taskboard-task-inner { + padding: .2rem; + } + .taskboard-tagline, + .taskboard-text { + display: none; + } + .avatar { + height: 35px; + width: 35px; + } + .icon { + display: none; + } + &.ui-sortable-helper { + box-shadow: none; + } + } + &.task-column, + .task-column { + @include table-flex(flex-start); + @include flex-direction(row); + } + .avatar-task-link { + display: block; + } + .avatar-assigned-to { + display: none; + } +} .taskboard-table { overflow: hidden; @@ -28,7 +63,6 @@ $column-margin: 0 10px 0 0; @extend %large; background: $whitish; border-top: 3px solid $gray-light; - cursor: pointer; margin: $column-margin; max-width: $column-width; padding: .5rem 1rem; @@ -38,15 +72,6 @@ $column-margin: 0 10px 0 0; &:last-child { margin-right: 0; } - &:hover { - .icon { - &.hfold, - &.hunfold { - @include transition(opacity .2s linear); - opacity: 1; - } - } - } .icon { @extend %medium; @include transition(color .2s linear); @@ -57,18 +82,14 @@ $column-margin: 0 10px 0 0; } &.hfold, &.hunfold { - @include transition(opacity .2s linear); @include transform(rotate(90deg)); display: inline-block; - opacity: 0; } } &.column-fold { @include align-items(center); @include justify-content(center); - max-width: $column-folded-width; padding: .3rem 0; - width: $column-folded-width; span { display: none; } @@ -88,39 +109,22 @@ $column-margin: 0 10px 0 0; overflow-y: scroll; width: 100%; .task-column { - @include table-flex-child(); + @include table-flex-child($column-flex, $column-width, $column-shrink, $column-width); margin: $column-margin; max-width: $column-width; width: $column-width; &:last-child { margin-right: 0; } - &.colum-fold { - max-width: $column-folded-width; - width: $column-folded-width; - .taskboard-task { - background: none; - border: 0; - margin: 0; - min-height: 0; - .taskboard-task-inner { - padding: .2rem; - } - .taskboard-tagline, - .taskboard-text { - display: none; - } - .avatar { - height: 35px; - width: 35px; - } - .icon { - display: none; - } - &.ui-sortable-helper { - box-shadow: none; - } - } + } + .row-fold { + @extend %fold; + } + .column-fold { + @extend %fold; + .taskboard-task { + max-width: 40px; + width: 40px; } } .task-row { @@ -164,35 +168,6 @@ $column-margin: 0 10px 0 0; display: none; } } - .task-column { - @include table-flex(); - @include flex-direction(row); - } - .taskboard-task { - background: none; - border: 0; - margin: 0; - max-width: 40px; - min-height: 0; - width: 40px; - .taskboard-task-inner { - padding: .2rem; - } - .taskboard-tagline, - .taskboard-text { - display: none; - } - .avatar { - height: 35px; - width: 35px; - } - .icon { - display: none; - } - &.ui-sortable-helper { - box-shadow: none; - } - } } } .taskboard-tasks-box { @@ -213,12 +188,19 @@ $column-margin: 0 10px 0 0; &.icon-plus { right: 2rem; } - &.icon-vfold { + &.icon-vfold, + &.icon-vunfold { left: 0; right: inherit; } } } + .avatar-task-link { + display: none; + } + .avatar-assigned-to { + display: block; + } } .taskboard-userstory-box { From 7a6f68900473b2adfc984c9ab35a0807d3932e34 Mon Sep 17 00:00:00 2001 From: Juanfran Date: Wed, 3 Dec 2014 14:46:30 +0100 Subject: [PATCH 58/66] add interceptor to handle version errors --- app/coffee/app.coffee | 26 +++++++++++++++++++++--- app/coffee/modules/common/confirm.coffee | 7 +++++-- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/app/coffee/app.coffee b/app/coffee/app.coffee index 51dd695d..223d11d9 100644 --- a/app/coffee/app.coffee +++ b/app/coffee/app.coffee @@ -161,7 +161,7 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven $tgEventsProvider.setSessionId(taiga.sessionId) # Add next param when user try to access to a secction need auth permissions. - authHttpIntercept = ($q, $location, $confirm, $navUrls, $lightboxService) -> + authHttpIntercept = ($q, $location, $navUrls, $lightboxService) -> httpResponseError = (response) -> if response.status == 0 $lightboxService.closeAll() @@ -170,17 +170,37 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven else if response.status == 401 nextPath = $location.path() $location.url($navUrls.resolve("login")).search("next=#{nextPath}") + return $q.reject(response) return { responseError: httpResponseError } - $provide.factory("authHttpIntercept", ["$q", "$location", "$tgConfirm", "$tgNavUrls", - "lightboxService", authHttpIntercept]) + $provide.factory("authHttpIntercept", ["$q", "$location", "$tgNavUrls", "lightboxService", authHttpIntercept]) $httpProvider.interceptors.push('authHttpIntercept'); + # If there is an error in the version throw a notify error + versionCheckHttpIntercept = ($q, $confirm) -> + versionErrorMsg = "Someone inside Taiga has changed this before and our Oompa Loompas cannot apply your changes. Please reload and apply your changes again (they will be lost)." #TODO: i18n + + httpResponseError = (response) -> + if response.status == 400 && response.data.version + $confirm.notify("error", versionErrorMsg, null, 10000) + + return $q.reject(response) + + return $q.reject(response) + + return { + responseError: httpResponseError + } + + $provide.factory("versionCheckHttpIntercept", ["$q", "$tgConfirm", versionCheckHttpIntercept]) + + $httpProvider.interceptors.push('versionCheckHttpIntercept'); + window.checksley.updateValidators({ linewidth: (val, width) -> lines = taiga.nl2br(val).split("
") diff --git a/app/coffee/modules/common/confirm.coffee b/app/coffee/modules/common/confirm.coffee index ce93c707..48d484a4 100644 --- a/app/coffee/modules/common/confirm.coffee +++ b/app/coffee/modules/common/confirm.coffee @@ -170,7 +170,7 @@ class ConfirmService extends taiga.Service return defered.promise - notify: (type, message, title) -> + notify: (type, message, title, time) -> # NOTE: Typesi are: error, success, light-error # See partials/components/notification-message.jade) # Add default texts to NOTIFICATION_MSG for new notification types @@ -178,6 +178,8 @@ class ConfirmService extends taiga.Service selector = ".notification-message-#{type}" el = angular.element(selector) + return if el.hasClass("active") + if title el.find("h4").html(title) else @@ -200,7 +202,8 @@ class ConfirmService extends taiga.Service if @.tsem cancelTimeout(@.tsem) - time = if type == 'error' or type == 'light-error' then 3500 else 1500 + if !time + time = if type == 'error' or type == 'light-error' then 3500 else 1500 @.tsem = timeout time, => body.find(selector) From 1207cc58b08e7ca68a9acdd92550bf72c8c57e1c Mon Sep 17 00:00:00 2001 From: Juanfran Date: Thu, 4 Dec 2014 15:23:50 +0100 Subject: [PATCH 59/66] fix admin height --- app/styles/layout/base.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/styles/layout/base.scss b/app/styles/layout/base.scss index 8329b3ec..3c14a9f8 100644 --- a/app/styles/layout/base.scss +++ b/app/styles/layout/base.scss @@ -87,7 +87,7 @@ body { .wrapper { @include table-flex(); - min-height: 100%; + min-height: 100vh; padding-left: 90px; } From cee89bca77161c11db2c3e23f10413f6abe17574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Fri, 5 Dec 2014 09:34:13 +0100 Subject: [PATCH 60/66] Update CHANGELOG --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 57b2167e..cfdc0219 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,12 @@ # Changelog # -## 1.4.0 Unknown (Unknown) +## 1.4.0 Unknown (Unreleased) ### Features +- Gitlab integration: + + Create Admin Panel with the Gitlab webhooks settings. +- Bitbucket integration: + + Create Admin Panel with the Bitbucket webhooks settings. - Upgrade to AngularJS 1.3. - Use enter to submit lightboxes forms. - Added team members section. @@ -10,12 +14,14 @@ ### Misc - Lots of small and not so small bugfixes. + ## 1.3.0 Dryas hookeriana (2014-11-18) ### Features - GitHub integration (Phase I): + Add button to login/singin with a GitHub account. + Create Admin Panel with the GitHub webhooks settings. +- Show/Hide columns in the Kanban view. - Differentiate blocked user stories on a milestone. ### Misc From ee0860dec1a35320c8ea2f4a16669b7063074a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramiro=20S=C3=A1nchez?= Date: Fri, 5 Dec 2014 10:24:11 +0100 Subject: [PATCH 61/66] Remove black color from task-name classes so default link colors are shown instead --- app/styles/components/kanban-task.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/app/styles/components/kanban-task.scss b/app/styles/components/kanban-task.scss index 5a09967c..da15276e 100644 --- a/app/styles/components/kanban-task.scss +++ b/app/styles/components/kanban-task.scss @@ -79,7 +79,6 @@ } .task-name { @extend %bold; - color: $grayer; } .icon-edit, .icon-drag-h { From 73aa3c34e95cda7617f57545ff4e8bdd732a1384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramiro=20S=C3=A1nchez?= Date: Fri, 5 Dec 2014 13:36:04 +0100 Subject: [PATCH 62/66] Vertically Align related-task us name --- app/styles/modules/common/related-tasks.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/styles/modules/common/related-tasks.scss b/app/styles/modules/common/related-tasks.scss index 7ea10e14..f1cfa16d 100644 --- a/app/styles/modules/common/related-tasks.scss +++ b/app/styles/modules/common/related-tasks.scss @@ -96,6 +96,7 @@ } } .task-name { + display: flex; position: relative; a { display: inline-block; From 0e02785ee2e799c946bda705b7cfea772d920c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramiro=20S=C3=A1nchez?= Date: Fri, 5 Dec 2014 13:54:51 +0100 Subject: [PATCH 63/66] fix related task alignment on safari 7 --- app/styles/modules/common/related-tasks.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/styles/modules/common/related-tasks.scss b/app/styles/modules/common/related-tasks.scss index f1cfa16d..b7c8b087 100644 --- a/app/styles/modules/common/related-tasks.scss +++ b/app/styles/modules/common/related-tasks.scss @@ -96,7 +96,7 @@ } } .task-name { - display: flex; + @include display(flex); position: relative; a { display: inline-block; @@ -198,10 +198,10 @@ } } .avatar { - align-items: center; - display: flex; + @include align-items(center); + @include display(flex); img { - flex-basis: 35px; + @include flex-basis(35px) } figcaption { margin-left: .5rem; From 38b24175aff40a030c6589d1b960e687e81d165a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramiro=20S=C3=A1nchez?= Date: Fri, 5 Dec 2014 14:03:42 +0100 Subject: [PATCH 64/66] Remove black color from task-name in task to be equal to kanban task --- app/styles/components/taskboard-task.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/app/styles/components/taskboard-task.scss b/app/styles/components/taskboard-task.scss index a306cf3e..efe4013d 100644 --- a/app/styles/components/taskboard-task.scss +++ b/app/styles/components/taskboard-task.scss @@ -98,7 +98,6 @@ } .task-name { @extend %bold; - color: $grayer; } .taskboard-text { @extend %small; From 8517bb4626b47d7058e8da1c0e8a7a55769e1c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Sat, 6 Dec 2014 22:57:18 +0100 Subject: [PATCH 65/66] Update changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfdc0219..63e2121a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,11 +7,12 @@ + Create Admin Panel with the Gitlab webhooks settings. - Bitbucket integration: + Create Admin Panel with the Bitbucket webhooks settings. -- Upgrade to AngularJS 1.3. -- Use enter to submit lightboxes forms. - Added team members section. +- Taskboard enhancements: Collapse of columns (task statuses) and rows (user stories). +- Use enter to submit lightboxes forms. ### Misc +- Upgrade to AngularJS 1.3. - Lots of small and not so small bugfixes. From d6b7843875aa8595b95b0e154e9799357f7c505b Mon Sep 17 00:00:00 2001 From: Juanfran Date: Thu, 4 Dec 2014 11:54:47 +0100 Subject: [PATCH 66/66] queue q promises --- app/coffee/modules/common.coffee | 29 +++ app/coffee/modules/common/components.coffee | 113 ++++++---- app/coffee/modules/common/estimation.coffee | 48 ++-- app/coffee/modules/common/history.coffee | 36 +-- app/coffee/modules/common/lightboxes.coffee | 47 ++-- app/coffee/modules/common/tags.coffee | 12 +- app/coffee/modules/issues/detail.coffee | 218 ++++++++++--------- app/coffee/modules/tasks/detail.coffee | 64 +++--- app/coffee/modules/userstories/detail.coffee | 78 ++++--- app/coffee/modules/wiki/main.coffee | 47 ++-- 10 files changed, 409 insertions(+), 283 deletions(-) diff --git a/app/coffee/modules/common.coffee b/app/coffee/modules/common.coffee index b9b31365..06e01a56 100644 --- a/app/coffee/modules/common.coffee +++ b/app/coffee/modules/common.coffee @@ -158,3 +158,32 @@ LimitLineLengthDirective = () -> return {link:link} module.directive("tgLimitLineLength", LimitLineLengthDirective) + +############################################################################# +## Queue Q promises +############################################################################# + +Qqueue = ($q) -> + deferred = $q.defer() + deferred.resolve() + + lastPromise = deferred.promise + + qqueue = { + bindAdd: (fn) => + return (args...) => + lastPromise = lastPromise.then () => fn.apply(@, args) + + return qqueue + add: (fn) => + if !lastPromise + lastPromise = fn() + else + lastPromise = lastPromise.then(fn) + + return qqueue + } + + return qqueue + +module.factory("$tgQqueue", ["$q", Qqueue]) diff --git a/app/coffee/modules/common/components.coffee b/app/coffee/modules/common/components.coffee index f4a4b419..a0591462 100644 --- a/app/coffee/modules/common/components.coffee +++ b/app/coffee/modules/common/components.coffee @@ -161,7 +161,7 @@ module.directive("tgCreatedByDisplay", CreatedByDisplayDirective) ## Watchers directive ############################################################################# -WatchersDirective = ($rootscope, $confirm, $repo) -> +WatchersDirective = ($rootscope, $confirm, $repo, $qqueue) -> # You have to include a div with the tg-lb-watchers directive in the page # where use this directive # @@ -204,17 +204,37 @@ WatchersDirective = ($rootscope, $confirm, $repo) -> isEditable = -> return $scope.project?.my_permissions?.indexOf($attrs.requiredPerm) != -1 - save = (model) -> + save = $qqueue.bindAdd (watchers) => + item = $model.$modelValue.clone() + item.watchers = watchers + $model.$setViewValue(item) + promise = $repo.save($model.$modelValue) promise.then -> $confirm.notify("success") - watchers = _.map(model.watchers, (watcherId) -> $scope.usersById[watcherId]) + watchers = _.map(watchers, (watcherId) -> $scope.usersById[watcherId]) + renderWatchers(watchers) + $rootscope.$broadcast("history:reload") + + promise.then null, -> + $model.$modelValue.revert() + + deleteWatcher = $qqueue.bindAdd (watcherIds) => + item = $model.$modelValue.clone() + item.watchers = watcherIds + $model.$setViewValue(item) + + promise = $repo.save($model.$modelValue) + promise.then -> + $confirm.notify("success") + watchers = _.map(item.watchers, (watcherId) -> $scope.usersById[watcherId]) renderWatchers(watchers) $rootscope.$broadcast("history:reload") promise.then null, -> - model.revert() + item.revert() $confirm.notify("error") + renderWatchers = (watchers) -> ctx = { watchers: watchers @@ -239,13 +259,11 @@ WatchersDirective = ($rootscope, $confirm, $repo) -> $confirm.askOnDelete(title, message).then (finish) => finish() + watcherIds = _.clone($model.$modelValue.watchers, false) watcherIds = _.pull(watcherIds, watcherId) - item = $model.$modelValue.clone() - item.watchers = watcherIds - $model.$setViewValue(item) - save(item) + deleteWatcher(watcherIds) $el.on "click", ".add-watcher", (event) -> event.preventDefault() @@ -258,10 +276,7 @@ WatchersDirective = ($rootscope, $confirm, $repo) -> watchers.push(watcherId) watchers = _.uniq(watchers) - item = $model.$modelValue.clone() - item.watchers = watchers - $model.$setViewValue(item) - save(item) + save(watchers) $scope.$watch $attrs.ngModel, (item) -> return if not item? @@ -273,14 +288,14 @@ WatchersDirective = ($rootscope, $confirm, $repo) -> return {link:link, require:"ngModel"} -module.directive("tgWatchers", ["$rootScope", "$tgConfirm", "$tgRepo", WatchersDirective]) +module.directive("tgWatchers", ["$rootScope", "$tgConfirm", "$tgRepo", "$tgQqueue", WatchersDirective]) ############################################################################# ## Assigned to directive ############################################################################# -AssignedToDirective = ($rootscope, $confirm, $repo, $loading) -> +AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $qqueue) -> # You have to include a div with the tg-lb-assignedto directive in the page # where use this directive # @@ -315,20 +330,24 @@ AssignedToDirective = ($rootscope, $confirm, $repo, $loading) -> isEditable = -> return $scope.project?.my_permissions?.indexOf($attrs.requiredPerm) != -1 - save = (model) -> + save = $qqueue.bindAdd (userId) => + $model.$modelValue.assigned_to = userId + $loading.start($el) promise = $repo.save($model.$modelValue) promise.then -> $loading.finish($el) $confirm.notify("success") - renderAssignedTo(model) + renderAssignedTo($model.$modelValue) $rootscope.$broadcast("history:reload") promise.then null, -> - model.revert() + $model.$modelValue.revert() $confirm.notify("error") $loading.finish($el) + return promise + renderAssignedTo = (issue) -> assignedToId = issue?.assigned_to assignedTo = if assignedToId? then $scope.usersById[assignedToId] else null @@ -354,12 +373,12 @@ AssignedToDirective = ($rootscope, $confirm, $repo, $loading) -> $confirm.ask(title).then (finish) => finish() $model.$modelValue.assigned_to = null - save($model.$modelValue) + save(null) $scope.$on "assigned-to:added", (ctx, userId, item) -> return if item.id != $model.$modelValue.id - $model.$modelValue.assigned_to = userId - save($model.$modelValue) + + save(userId) $scope.$watch $attrs.ngModel, (instance) -> renderAssignedTo(instance) @@ -372,7 +391,7 @@ AssignedToDirective = ($rootscope, $confirm, $repo, $loading) -> require:"ngModel" } -module.directive("tgAssignedTo", ["$rootScope", "$tgConfirm", "$tgRepo", "$tgLoading", AssignedToDirective]) +module.directive("tgAssignedTo", ["$rootScope", "$tgConfirm", "$tgRepo", "$tgLoading", "$tgQqueue", AssignedToDirective]) ############################################################################# @@ -473,7 +492,7 @@ module.directive("tgDeleteButton", ["$log", "$tgRepo", "$tgConfirm", "$tgLocatio ## Editable subject directive ############################################################################# -EditableSubjectDirective = ($rootscope, $repo, $confirm, $loading) -> +EditableSubjectDirective = ($rootscope, $repo, $confirm, $loading, $qqueue) -> template = """
{{ item.subject }} @@ -492,9 +511,11 @@ EditableSubjectDirective = ($rootscope, $repo, $confirm, $loading) -> isEditable = -> return $scope.project.my_permissions.indexOf($attrs.requiredPerm) != -1 - save = -> - $model.$modelValue.subject = $scope.item.subject + save = $qqueue.bindAdd (subject) => + $model.$modelValue.subject = subject + $loading.start($el.find('.save-container')) + promise = $repo.save($model.$modelValue) promise.then -> $confirm.notify("success") @@ -506,6 +527,8 @@ EditableSubjectDirective = ($rootscope, $repo, $confirm, $loading) -> promise.finally -> $loading.finish($el.find('.save-container')) + return promise + $el.click -> return if not isEditable() $el.find('.edit-subject').show() @@ -513,11 +536,13 @@ EditableSubjectDirective = ($rootscope, $repo, $confirm, $loading) -> $el.find('input').focus() $el.on "click", ".save", -> - save() + subject = $scope.item.subject + save(subject) $el.on "keyup", "input", (event) -> if event.keyCode == 13 - save() + subject = $scope.item.subject + save(subject) else if event.keyCode == 27 $model.$modelValue.revert() $el.find('div.edit-subject').hide() @@ -545,7 +570,7 @@ EditableSubjectDirective = ($rootscope, $repo, $confirm, $loading) -> template: template } -module.directive("tgEditableSubject", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", +module.directive("tgEditableSubject", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", EditableSubjectDirective]) @@ -553,7 +578,7 @@ module.directive("tgEditableSubject", ["$rootScope", "$tgRepo", "$tgConfirm", "$ ## Editable subject directive ############################################################################# -EditableDescriptionDirective = ($rootscope, $repo, $confirm, $compile, $loading, $selectedText) -> +EditableDescriptionDirective = ($rootscope, $repo, $confirm, $compile, $loading, $selectedText, $qqueue) -> template = """
return $scope.project.my_permissions.indexOf($attrs.requiredPerm) != -1 + save = $qqueue.bindAdd (description) => + $model.$modelValue.description = description + + $loading.start($el.find('.save-container')) + promise = $repo.save($model.$modelValue) + promise.then -> + $confirm.notify("success") + $rootscope.$broadcast("history:reload") + $el.find('.edit-description').hide() + $el.find('.view-description').show() + promise.then null, -> + $confirm.notify("error") + promise.finally -> + $loading.finish($el.find('.save-container')) + $el.on "mouseup", ".view-description", (event) -> # We want to dettect the a inside the div so we use the target and # not the currentTarget @@ -606,19 +646,8 @@ EditableDescriptionDirective = ($rootscope, $repo, $confirm, $compile, $loading, $el.find('textarea').focus() $el.on "click", ".save", -> - $model.$modelValue.description = $scope.item.description - - $loading.start($el.find('.save-container')) - promise = $repo.save($model.$modelValue) - promise.then -> - $confirm.notify("success") - $rootscope.$broadcast("history:reload") - $el.find('.edit-description').hide() - $el.find('.view-description').show() - promise.then null, -> - $confirm.notify("error") - promise.finally -> - $loading.finish($el.find('.save-container')) + description = $scope.item.description + save(description) $el.on "keyup", "textarea", (event) -> if event.keyCode == 27 @@ -648,7 +677,7 @@ EditableDescriptionDirective = ($rootscope, $repo, $confirm, $compile, $loading, } module.directive("tgEditableDescription", ["$rootScope", "$tgRepo", "$tgConfirm", - "$compile", "$tgLoading", "$selectedText", EditableDescriptionDirective]) + "$compile", "$tgLoading", "$selectedText", "$tgQqueue", EditableDescriptionDirective]) ############################################################################# diff --git a/app/coffee/modules/common/estimation.coffee b/app/coffee/modules/common/estimation.coffee index 6449fe5e..ac81e19a 100644 --- a/app/coffee/modules/common/estimation.coffee +++ b/app/coffee/modules/common/estimation.coffee @@ -165,7 +165,7 @@ module.directive("tgLbUsEstimation", ["$rootScope", "$tgRepo", "$tgConfirm", LbU ## User story estimation directive ############################################################################# -UsEstimationDirective = ($rootScope, $repo, $confirm) -> +UsEstimationDirective = ($rootScope, $repo, $confirm, $qqueue) -> # Display the points of a US and you can edit it. # # Example: @@ -264,6 +264,29 @@ UsEstimationDirective = ($rootScope, $repo, $confirm) -> return _.reduce(notNullValues, (acc, num) -> acc + num) + save = $qqueue.bindAdd (roleId, pointId) => + $el.find(".popover").popover().close() + + # Hell starts here + us = angular.copy($model.$modelValue) + points = _.clone($model.$modelValue.points, true) + points[roleId] = pointId + us.setAttr('points', points) + us.points = points + us.total_points = calculateTotalPoints(us) + $model.$setViewValue(us) + # Hell ends here + + onSuccess = -> + $confirm.notify("success") + $rootScope.$broadcast("history:reload") + onError = -> + $confirm.notify("error") + us.revert() + $model.$setViewValue(us) + + $repo.save($model.$modelValue).then(onSuccess, onError) + $el.on "click", ".total.clickable", (event) -> event.preventDefault() event.stopPropagation() @@ -287,26 +310,7 @@ UsEstimationDirective = ($rootScope, $repo, $confirm) -> roleId = target.data("role-id") pointId = target.data("point-id") - $el.find(".popover").popover().close() - - # Hell starts here - us = angular.copy($model.$modelValue) - points = _.clone($model.$modelValue.points, true) - points[roleId] = pointId - us.setAttr('points', points) - us.points = points - us.total_points = calculateTotalPoints(us) - $model.$setViewValue(us) - # Hell ends here - - onSuccess = -> - $confirm.notify("success") - $rootScope.$broadcast("history:reload") - onError = -> - $confirm.notify("error") - us.revert() - $model.$setViewValue(us) - $repo.save($model.$modelValue).then(onSuccess, onError) + save(roleId, pointId) $scope.$watch $attrs.ngModel, (us) -> render(us) if us @@ -320,4 +324,4 @@ UsEstimationDirective = ($rootScope, $repo, $confirm) -> require: "ngModel" } -module.directive("tgUsEstimation", ["$rootScope", "$tgRepo", "$tgConfirm", UsEstimationDirective]) +module.directive("tgUsEstimation", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgQqueue", UsEstimationDirective]) diff --git a/app/coffee/modules/common/history.coffee b/app/coffee/modules/common/history.coffee index e9987d09..679b9d90 100644 --- a/app/coffee/modules/common/history.coffee +++ b/app/coffee/modules/common/history.coffee @@ -61,7 +61,7 @@ class HistoryController extends taiga.Controller return @rs.history.undeleteComment(type, objectId, activityId).then => @.loadHistory(type, objectId) -HistoryDirective = ($log, $loading) -> +HistoryDirective = ($log, $loading, $qqueue) -> templateChangeDiff = _.template("""
@@ -436,6 +436,24 @@ HistoryDirective = ($log, $loading) -> html = renderHistory(changes, totalChanges) $el.find(".changes-list").html(html) + save = $qqueue.bindAdd (target) => + $scope.$broadcast("markdown-editor:submit") + + $el.find(".comment-list").addClass("activeanimation") + + onSuccess = -> + $ctrl.loadHistory(type, objectId).finally -> + $loading.finish(target) + + onError = -> + $loading.finish(target) + $confirm.notify("error") + + model = $scope.$eval($attrs.ngModel) + $loading.start(target) + + $ctrl.repo.save(model).then(onSuccess, onError) + # Watchers $scope.$watch("comments", renderComments) @@ -447,22 +465,10 @@ HistoryDirective = ($log, $loading) -> $el.on "click", ".add-comment a.button-green", debounce 2000, (event) -> event.preventDefault() - $scope.$broadcast("markdown-editor:submit") target = angular.element(event.currentTarget) - $el.find(".comment-list").addClass("activeanimation") - onSuccess = -> - $ctrl.loadHistory(type, objectId).finally -> - $loading.finish(target) - - onError = -> - $loading.finish(target) - $confirm.notify("error") - - model = $scope.$eval($attrs.ngModel) - $loading.start(target) - $ctrl.repo.save(model).then(onSuccess, onError) + save(target) $el.on "click", ".show-more", (event) -> event.preventDefault() @@ -526,4 +532,4 @@ HistoryDirective = ($log, $loading) -> } -module.directive("tgHistory", ["$log", "$tgLoading", HistoryDirective]) +module.directive("tgHistory", ["$log", "$tgLoading", "$tgQqueue", HistoryDirective]) diff --git a/app/coffee/modules/common/lightboxes.coffee b/app/coffee/modules/common/lightboxes.coffee index fd07cb7a..685a0c91 100644 --- a/app/coffee/modules/common/lightboxes.coffee +++ b/app/coffee/modules/common/lightboxes.coffee @@ -126,19 +126,11 @@ module.directive("lightbox", ["lightboxService", LightboxDirective]) # Issue/Userstory blocking message lightbox directive. -BlockLightboxDirective = ($rootscope, $tgrepo, $confirm, lightboxService, $loading) -> +BlockLightboxDirective = ($rootscope, $tgrepo, $confirm, lightboxService, $loading, $qqueue) -> link = ($scope, $el, $attrs, $model) -> $el.find("h2.title").text($attrs.title) - $scope.$on "block", -> - $el.find(".reason").val($model.$modelValue.blocked_note) - lightboxService.open($el) - - $scope.$on "unblock", (event, model, finishCallback) -> - item = $model.$modelValue.clone() - item.is_blocked = false - item.blocked_note = "" - + unblock = $qqueue.bindAdd (item, finishCallback) => promise = $tgrepo.save(item) promise.then -> $confirm.notify("success") @@ -154,15 +146,9 @@ BlockLightboxDirective = ($rootscope, $tgrepo, $confirm, lightboxService, $loadi promise.finally -> finishCallback() - $scope.$on "$destroy", -> - $el.off() + return promise - $el.on "click", ".button-green", (event) -> - event.preventDefault() - - item = $model.$modelValue.clone() - item.is_blocked = true - item.blocked_note = $el.find(".reason").val() + block = $qqueue.bindAdd (item) => $model.$setViewValue(item) $loading.start($el.find(".button-green")) @@ -181,13 +167,36 @@ BlockLightboxDirective = ($rootscope, $tgrepo, $confirm, lightboxService, $loadi $loading.finish($el.find(".button-green")) lightboxService.close($el) + $scope.$on "block", -> + $el.find(".reason").val($model.$modelValue.blocked_note) + lightboxService.open($el) + + $scope.$on "unblock", (event, model, finishCallback) => + item = $model.$modelValue.clone() + item.is_blocked = false + item.blocked_note = "" + + unblock(item, finishCallback) + + $scope.$on "$destroy", -> + $el.off() + + $el.on "click", ".button-green", (event) -> + event.preventDefault() + + item = $model.$modelValue.clone() + item.is_blocked = true + item.blocked_note = $el.find(".reason").val() + + block(item) + return { templateUrl: "/partials/views/modules/lightbox-block.html" link: link require: "ngModel" } -module.directive("tgLbBlock", ["$rootScope", "$tgRepo", "$tgConfirm", "lightboxService", "$tgLoading", BlockLightboxDirective]) +module.directive("tgLbBlock", ["$rootScope", "$tgRepo", "$tgConfirm", "lightboxService", "$tgLoading", "$tgQqueue", BlockLightboxDirective]) ############################################################################# diff --git a/app/coffee/modules/common/tags.coffee b/app/coffee/modules/common/tags.coffee index 3e910882..3a8e7fbf 100644 --- a/app/coffee/modules/common/tags.coffee +++ b/app/coffee/modules/common/tags.coffee @@ -228,7 +228,7 @@ module.directive("tgLbTagLine", ["$tgResources", LbTagLineDirective]) ## TagLine Directive (for detail pages) ############################################################################# -TagLineDirective = ($rootScope, $repo, $rs, $confirm) -> +TagLineDirective = ($rootScope, $repo, $rs, $confirm, $qqueue) -> ENTER_KEY = 13 ESC_KEY = 27 @@ -288,7 +288,7 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm) -> $el.find("input").autocomplete("close") ## Aux methods - addValue = (value) -> + addValue = $qqueue.bindAdd (value) -> value = trim(value.toLowerCase()) return if value.length == 0 @@ -308,7 +308,7 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm) -> $model.$setViewValue(model) $repo.save(model).then(onSuccess, onError) - deleteValue = (value) -> + deleteValue = $qqueue.bindAdd (value) -> value = trim(value.toLowerCase()) return if value.length == 0 @@ -325,7 +325,8 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm) -> $confirm.notify("error") model.revert() $model.$setViewValue(model) - $repo.save(model).then(onSuccess, onError) + + return $repo.save(model).then(onSuccess, onError) saveInputTag = () -> value = $el.find("input").val() @@ -369,6 +370,7 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm) -> target = angular.element(event.currentTarget) value = target.siblings(".tag-name").text() + deleteValue(value) bindOnce $scope, "project", (project) -> @@ -415,4 +417,4 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm) -> template: template } -module.directive("tgTagLine", ["$rootScope", "$tgRepo", "$tgResources", "$tgConfirm", TagLineDirective]) +module.directive("tgTagLine", ["$rootScope", "$tgRepo", "$tgResources", "$tgConfirm", "$tgQqueue", TagLineDirective]) diff --git a/app/coffee/modules/issues/detail.coffee b/app/coffee/modules/issues/detail.coffee index cb5f7aa4..ff9f2456 100644 --- a/app/coffee/modules/issues/detail.coffee +++ b/app/coffee/modules/issues/detail.coffee @@ -195,7 +195,7 @@ module.directive("tgIssueStatusDisplay", IssueStatusDisplayDirective) ## Issue status button directive ############################################################################# -IssueStatusButtonDirective = ($rootScope, $repo, $confirm, $loading) -> +IssueStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue) -> # Display the status of Issue and you can edit it. # # Example: @@ -236,6 +236,21 @@ IssueStatusButtonDirective = ($rootScope, $repo, $confirm, $loading) -> }) $el.html(html) + save = $qqueue.bindAdd (value, issue) => + onSuccess = -> + $confirm.notify("success") + $rootScope.$broadcast("history:reload") + $loading.finish($el.find(".level-name")) + onError = -> + $confirm.notify("error") + issue.revert() + $model.$setViewValue(issue) + $loading.finish($el.find(".level-name")) + + $loading.start($el.find(".level-name")) + + $repo.save(value).then(onSuccess, onError) + $el.on "click", ".status-data", (event) -> event.preventDefault() event.stopPropagation() @@ -256,20 +271,7 @@ IssueStatusButtonDirective = ($rootScope, $repo, $confirm, $loading) -> issue.status = target.data("status-id") $model.$setViewValue(issue) - $scope.$apply() - - onSuccess = -> - $confirm.notify("success") - $rootScope.$broadcast("history:reload") - $loading.finish($el.find(".level-name")) - onError = -> - $confirm.notify("error") - issue.revert() - $model.$setViewValue(issue) - $loading.finish($el.find(".level-name")) - - $loading.start($el.find(".level-name")) - $repo.save($model.$modelValue).then(onSuccess, onError) + save($model.$modelValue, issue) $scope.$watch $attrs.ngModel, (issue) -> render(issue) if issue @@ -283,13 +285,13 @@ IssueStatusButtonDirective = ($rootScope, $repo, $confirm, $loading) -> require: "ngModel" } -module.directive("tgIssueStatusButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", IssueStatusButtonDirective]) +module.directive("tgIssueStatusButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", IssueStatusButtonDirective]) ############################################################################# ## Issue type button directive ############################################################################# -IssueTypeButtonDirective = ($rootScope, $repo, $confirm, $loading) -> +IssueTypeButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue) -> # Display the type of Issue and you can edit it. # # Example: @@ -330,6 +332,26 @@ IssueTypeButtonDirective = ($rootScope, $repo, $confirm, $loading) -> }) $el.html(html) + save = $qqueue.bindAdd (type) => + $.fn.popover().closeAll() + issue = $model.$modelValue.clone() + issue.type = type + + $model.$setViewValue(issue) + + onSuccess = -> + $confirm.notify("success") + $rootScope.$broadcast("history:reload") + $loading.finish($el.find(".level-name")) + onError = -> + $confirm.notify("error") + issue.revert() + $model.$setViewValue(issue) + $loading.finish($el.find(".level-name")) + $loading.start($el.find(".level-name")) + + $repo.save($model.$modelValue).then(onSuccess, onError) + $el.on "click", ".type-data", (event) -> event.preventDefault() event.stopPropagation() @@ -343,26 +365,8 @@ IssueTypeButtonDirective = ($rootScope, $repo, $confirm, $loading) -> return if not isEditable() target = angular.element(event.currentTarget) - - $.fn.popover().closeAll() - - issue = $model.$modelValue.clone() - issue.type = target.data("type-id") - $model.$setViewValue(issue) - - $scope.$apply() - - onSuccess = -> - $confirm.notify("success") - $rootScope.$broadcast("history:reload") - $loading.finish($el.find(".level-name")) - onError = -> - $confirm.notify("error") - issue.revert() - $model.$setViewValue(issue) - $loading.finish($el.find(".level-name")) - $loading.start($el.find(".level-name")) - $repo.save($model.$modelValue).then(onSuccess, onError) + type = target.data("type-id") + save(type) $scope.$watch $attrs.ngModel, (issue) -> render(issue) if issue @@ -376,14 +380,14 @@ IssueTypeButtonDirective = ($rootScope, $repo, $confirm, $loading) -> require: "ngModel" } -module.directive("tgIssueTypeButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", IssueTypeButtonDirective]) +module.directive("tgIssueTypeButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", IssueTypeButtonDirective]) ############################################################################# ## Issue severity button directive ############################################################################# -IssueSeverityButtonDirective = ($rootScope, $repo, $confirm, $loading) -> +IssueSeverityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue) -> # Display the severity of Issue and you can edit it. # # Example: @@ -424,6 +428,26 @@ IssueSeverityButtonDirective = ($rootScope, $repo, $confirm, $loading) -> }) $el.html(html) + save = $qqueue.bindAdd (severity) => + $.fn.popover().closeAll() + + issue = $model.$modelValue.clone() + issue.severity = severity + $model.$setViewValue(issue) + + onSuccess = -> + $confirm.notify("success") + $rootScope.$broadcast("history:reload") + $loading.finish($el.find(".level-name")) + onError = -> + $confirm.notify("error") + issue.revert() + $model.$setViewValue(issue) + $loading.finish($el.find(".level-name")) + $loading.start($el.find(".level-name")) + + $repo.save($model.$modelValue).then(onSuccess, onError) + $el.on "click", ".severity-data", (event) -> event.preventDefault() event.stopPropagation() @@ -437,26 +461,9 @@ IssueSeverityButtonDirective = ($rootScope, $repo, $confirm, $loading) -> return if not isEditable() target = angular.element(event.currentTarget) + severity = target.data("severity-id") - $.fn.popover().closeAll() - - issue = $model.$modelValue.clone() - issue.severity = target.data("severity-id") - $model.$setViewValue(issue) - - $scope.$apply() - - onSuccess = -> - $confirm.notify("success") - $rootScope.$broadcast("history:reload") - $loading.finish($el.find(".level-name")) - onError = -> - $confirm.notify("error") - issue.revert() - $model.$setViewValue(issue) - $loading.finish($el.find(".level-name")) - $loading.start($el.find(".level-name")) - $repo.save($model.$modelValue).then(onSuccess, onError) + save(severity) $scope.$watch $attrs.ngModel, (issue) -> render(issue) if issue @@ -470,14 +477,14 @@ IssueSeverityButtonDirective = ($rootScope, $repo, $confirm, $loading) -> require: "ngModel" } -module.directive("tgIssueSeverityButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", IssueSeverityButtonDirective]) +module.directive("tgIssueSeverityButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", IssueSeverityButtonDirective]) ############################################################################# ## Issue priority button directive ############################################################################# -IssuePriorityButtonDirective = ($rootScope, $repo, $confirm, $loading) -> +IssuePriorityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue) -> # Display the priority of Issue and you can edit it. # # Example: @@ -518,6 +525,26 @@ IssuePriorityButtonDirective = ($rootScope, $repo, $confirm, $loading) -> }) $el.html(html) + save = $qqueue.bindAdd (priority) => + $.fn.popover().closeAll() + + issue = $model.$modelValue.clone() + issue.priority = priority + $model.$setViewValue(issue) + + onSuccess = -> + $confirm.notify("success") + $rootScope.$broadcast("history:reload") + $loading.finish($el.find(".level-name")) + onError = -> + $confirm.notify("error") + issue.revert() + $model.$setViewValue(issue) + $loading.finish($el.find(".level-name")) + $loading.start($el.find(".level-name")) + + $repo.save($model.$modelValue).then(onSuccess, onError) + $el.on "click", ".priority-data", (event) -> event.preventDefault() event.stopPropagation() @@ -531,26 +558,9 @@ IssuePriorityButtonDirective = ($rootScope, $repo, $confirm, $loading) -> return if not isEditable() target = angular.element(event.currentTarget) + priority = target.data("priority-id") - $.fn.popover().closeAll() - - issue = $model.$modelValue.clone() - issue.priority = target.data("priority-id") - $model.$setViewValue(issue) - - $scope.$apply() - - onSuccess = -> - $confirm.notify("success") - $rootScope.$broadcast("history:reload") - $loading.finish($el.find(".level-name")) - onError = -> - $confirm.notify("error") - issue.revert() - $model.$setViewValue(issue) - $loading.finish($el.find(".level-name")) - $loading.start($el.find(".level-name")) - $repo.save($model.$modelValue).then(onSuccess, onError) + save(priority) $scope.$watch $attrs.ngModel, (issue) -> render(issue) if issue @@ -564,14 +574,14 @@ IssuePriorityButtonDirective = ($rootScope, $repo, $confirm, $loading) -> require: "ngModel" } -module.directive("tgIssuePriorityButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", IssuePriorityButtonDirective]) +module.directive("tgIssuePriorityButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", IssuePriorityButtonDirective]) ############################################################################# ## Promote Issue to US button directive ############################################################################# -PromoteIssueToUsButtonDirective = ($rootScope, $repo, $confirm) -> +PromoteIssueToUsButtonDirective = ($rootScope, $repo, $confirm, $qqueue) -> template = _.template(""" Promote to User Story @@ -579,6 +589,30 @@ PromoteIssueToUsButtonDirective = ($rootScope, $repo, $confirm) -> """) # TODO: i18n link = ($scope, $el, $attrs, $model) -> + + save = $qqueue.bindAdd (issue, finish) => + data = { + generated_from_issue: issue.id + project: issue.project, + subject: issue.subject + description: issue.description + tags: issue.tags + is_blocked: issue.is_blocked + blocked_note: issue.blocked_note + } + + onSuccess = -> + finish() + $confirm.notify("success") + $rootScope.$broadcast("promote-issue-to-us:success") + + onError = -> + finish(false) + $confirm.notify("error") + + $repo.create("userstories", data).then(onSuccess, onError) + + $el.on "click", "a", (event) -> event.preventDefault() issue = $model.$modelValue @@ -588,26 +622,8 @@ PromoteIssueToUsButtonDirective = ($rootScope, $repo, $confirm) -> subtitle = issue.subject $confirm.ask(title, subtitle, message).then (finish) => - data = { - generated_from_issue: issue.id - project: issue.project, - subject: issue.subject - description: issue.description - tags: issue.tags - is_blocked: issue.is_blocked - blocked_note: issue.blocked_note - } + save(issue, finish) - onSuccess = -> - finish() - $confirm.notify("success") - $rootScope.$broadcast("promote-issue-to-us:success") - - onError = -> - finish(false) - $confirm.notify("error") - - $repo.create("userstories", data).then(onSuccess, onError) $scope.$on "$destroy", -> $el.off() @@ -619,5 +635,5 @@ PromoteIssueToUsButtonDirective = ($rootScope, $repo, $confirm) -> link: link } -module.directive("tgPromoteIssueToUsButton", ["$rootScope", "$tgRepo", "$tgConfirm", +module.directive("tgPromoteIssueToUsButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgQqueue", PromoteIssueToUsButtonDirective]) diff --git a/app/coffee/modules/tasks/detail.coffee b/app/coffee/modules/tasks/detail.coffee index 0dfef32a..0bbe2730 100644 --- a/app/coffee/modules/tasks/detail.coffee +++ b/app/coffee/modules/tasks/detail.coffee @@ -199,7 +199,7 @@ module.directive("tgTaskStatusDisplay", TaskStatusDisplayDirective) ## Task status button directive ############################################################################# -TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading) -> +TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue) -> # Display the status of Task and you can edit it. # # Example: @@ -240,6 +240,26 @@ TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading) -> }) $el.html(html) + save = $qqueue.bindAdd (status) => + task = $model.$modelValue.clone() + task.status = status + + $model.$setViewValue(task) + + onSuccess = -> + $confirm.notify("success") + $rootScope.$broadcast("history:reload") + $loading.finish($el.find(".level-name")) + + onError = -> + $confirm.notify("error") + task.revert() + $model.$setViewValue(task) + $loading.finish($el.find(".level-name")) + + $loading.start($el.find(".level-name")) + $repo.save($model.$modelValue).then(onSuccess, onError) + $el.on "click", ".status-data", (event) -> event.preventDefault() event.stopPropagation() @@ -256,25 +276,7 @@ TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading) -> $.fn.popover().closeAll() - task = $model.$modelValue.clone() - task.status = target.data("status-id") - $model.$setViewValue(task) - - $scope.$apply() - - onSuccess = -> - $confirm.notify("success") - $rootScope.$broadcast("history:reload") - $loading.finish($el.find(".level-name")) - - onError = -> - $confirm.notify("error") - task.revert() - $model.$setViewValue(task) - $loading.finish($el.find(".level-name")) - - $loading.start($el.find(".level-name")) - $repo.save($model.$modelValue).then(onSuccess, onError) + save(target.data("status-id")) $scope.$watch $attrs.ngModel, (task) -> render(task) if task @@ -288,11 +290,11 @@ TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading) -> require: "ngModel" } -module.directive("tgTaskStatusButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", +module.directive("tgTaskStatusButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", TaskStatusButtonDirective]) -TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading) -> +TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue) -> template = _.template("""