From 9871755140b743775c58939bf8b8ac712bf22282 Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Tue, 19 May 2009 00:06:08 +0200 Subject: [PATCH 01/59] #300: Added migration for dependencies support --- db/migrate/20090516000646_add_todo_dependencies.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 db/migrate/20090516000646_add_todo_dependencies.rb diff --git a/db/migrate/20090516000646_add_todo_dependencies.rb b/db/migrate/20090516000646_add_todo_dependencies.rb new file mode 100644 index 00000000..769343f2 --- /dev/null +++ b/db/migrate/20090516000646_add_todo_dependencies.rb @@ -0,0 +1,13 @@ +class AddTodoDependencies < ActiveRecord::Migration + def self.up + create_table :dependencies do |t| + t.integer :todo_id, :null => false + t.integer :predecessor_id, :null => false + t.string :relationship_type + end + end + + def self.down + drop_table :dependencies + end +end From 947172f435ff30bcfb4b35c4281cc907055eb8d4 Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Tue, 19 May 2009 00:29:36 +0200 Subject: [PATCH 02/59] #300: Added model for dependency relation --- app/models/dependency.rb | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 app/models/dependency.rb diff --git a/app/models/dependency.rb b/app/models/dependency.rb new file mode 100644 index 00000000..53c73f65 --- /dev/null +++ b/app/models/dependency.rb @@ -0,0 +1,9 @@ +class Dependency < ActiveRecord::Base + + belongs_to :todo, + :class_name => "Todo", :foreign_key => "todo_id" + belongs_to :predecessor, + :class_name => "Todo", :foreign_key => "predecessor_id" + +end + From 5b1acce71e919a17fbd86af9aeff56cebb87f187 Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Tue, 19 May 2009 16:08:01 +0200 Subject: [PATCH 03/59] #300: Added pending items to deferred block in project view --- app/views/projects/show.html.erb | 2 +- app/views/todos/_deferred.rhtml | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/views/projects/show.html.erb b/app/views/projects/show.html.erb index 0ed68cbd..efa84ab9 100644 --- a/app/views/projects/show.html.erb +++ b/app/views/projects/show.html.erb @@ -4,7 +4,7 @@ <%= render :partial => "projects/project", :locals => { :project => @project, :collapsible => false } %> - <%= render :partial => "todos/deferred", :locals => { :deferred => @deferred, :collapsible => false, :append_descriptor => "in this project", :parent_container_type => 'project' } %> + <%= render :partial => "todos/deferred", :locals => { :deferred => @deferred, :collapsible => false, :append_descriptor => "in this project", :parent_container_type => 'project', :pending => @pending } %> <% unless @max_completed==0 -%> <%= render :partial => "todos/completed", :locals => { :done => @done, :collapsible => false, :suppress_project => true, :append_descriptor => "in this project" } %> <% end -%> diff --git a/app/views/todos/_deferred.rhtml b/app/views/todos/_deferred.rhtml index 58c16756..c38e1561 100644 --- a/app/views/todos/_deferred.rhtml +++ b/app/views/todos/_deferred.rhtml @@ -3,15 +3,16 @@ <% if collapsible %> <%= image_tag("collapse.png") %> <% end %> - Deferred actions <%= append_descriptor ? append_descriptor : '' %> + Deferred/pending actions <%= append_descriptor ? append_descriptor : '' %>
-
-

Currently there are no deferred actions

+
+

Currently there are no deferred or pending actions

<%= render :partial => "todos/todo", :collection => deferred, :locals => { :parent_container_type => parent_container_type } %> + <%= render :partial => "todos/todo", :collection => pending, :locals => { :parent_container_type => parent_container_type } %>
-
\ No newline at end of file + From cc033e2165b9a004375a856228f7e7d5dedbea25 Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Wed, 4 Nov 2009 22:31:17 -0500 Subject: [PATCH 04/59] Conflicts: db/tracks-17-blank.db --- app/models/dependency.rb | 6 ++---- .../20090516000646_add_todo_dependencies.rb | 2 +- db/tracks-17-blank.db | Bin 46080 -> 55296 bytes 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/models/dependency.rb b/app/models/dependency.rb index 53c73f65..dd347c1f 100644 --- a/app/models/dependency.rb +++ b/app/models/dependency.rb @@ -1,9 +1,7 @@ class Dependency < ActiveRecord::Base - belongs_to :todo, - :class_name => "Todo", :foreign_key => "todo_id" - belongs_to :predecessor, - :class_name => "Todo", :foreign_key => "predecessor_id" + belongs_to :predecessor, :foreign_key => 'predecessor_id', :class_name => 'Todo' + belongs_to :successor, :foreign_key => 'successor_id', :class_name => 'Todo' end diff --git a/db/migrate/20090516000646_add_todo_dependencies.rb b/db/migrate/20090516000646_add_todo_dependencies.rb index 769343f2..2ca58dae 100644 --- a/db/migrate/20090516000646_add_todo_dependencies.rb +++ b/db/migrate/20090516000646_add_todo_dependencies.rb @@ -1,7 +1,7 @@ class AddTodoDependencies < ActiveRecord::Migration def self.up create_table :dependencies do |t| - t.integer :todo_id, :null => false + t.integer :successor_id, :null => false t.integer :predecessor_id, :null => false t.string :relationship_type end diff --git a/db/tracks-17-blank.db b/db/tracks-17-blank.db index 941c0958742f7b1e7be50c6fc27ea6b54f61d1d4..fdbc4ca62cbcf091127d39d5e7c25dfbb10f471c 100644 GIT binary patch literal 55296 zcmeHwYiwgzejo2W)M$pDv1a^|$M&pgjc0AGJ)ZmECB)LeMn%0~+xa@>BBXb*O8&(w6g?a?~zR>^Fs#d6d7xn{l7GTUwQoqDtQPN(A8Yp>U9M!mLoC-S!cj^V!( z_20=~%5am)C8+EHa)*sf& zQrR%f8cG68M-P|Z=$L40*D@b~hH6yNDzmDVtr6UkqB!tAZ`zEtxoPe-%~t6FH6EBv zt==+sRlQxV*LDrFr8moscD;##I|a(#SOrc{J`Skua@E}J)oTF7o>}8v?UTUiItP{Q zqP^|9QQrlfpo|B!wq0&p=I+G#JYK7l;>PN(*0nNK?vU! zl)GZUFNybs@O>dTA&BY!{P#WNmvM1FE&`up1di|US3R>||N4x_bIbE}S*w?trlHER z77XtxN>Ecmx)u~P!4$=i6cUV}wr4CTa!3<&Z6TxzAvG8dnVPYusbOtFR)dnJ1cQ63 z7*sV$mI9irhW4OlsG8a`Wo;p-=#mi%nu@p=l#B%t1t_6CEhL!Ao*vc=%?wL{K1~Mi z3Zh?1;U~%${{@{gcsU& zGb#OhxqBY&9{&pe`y~E39{xwswc~wmdUke}`%uOx!xE{3+p-J4xV;=nE&EfE==!ps z1^M5cquO0OnOcr5Z~Ncdj&DS^^ZvEvyi-kt@z-=}fzCKv+jS_3&SlXLH8tZHeW)}>FmVGB zSyRUW@AT~R&)Z-@0K*6_wl0m8PeU$Na80eAWgI=yF=q1Llk<3T{OY415W9>It5b|n zej&`jr#Q9PWqJ${7IZO0ta`Cr8`+Bs@I*Mg6?(JVptHH5wpxevCg{$dR@7zTNZ77d zOh++e2H*hMa%-0{-3J<$d*vo{tp^X4rCunR+G&?|+ug=l1OJB2w8w1IdIO$`va#D~ zp5-_gbgOArP3CO500iS{cg>?l86JhR`N{l;$|c4tKKkl_*!rFp+d1GH8+AMMVgo+` zU&nYh>a8;MUrcazz|`*3=g7t$GC`4gxCR~%mU|K#1qHXAgW+_3QLo8?IW`iHgzK_) z?WrBBJ;_HfY`@I}Y`@vrL*porvY!!Q(5XLvjr?=i|3wce;^KZ>1Y86@4FpoKJR%%- z?WQbyJl7(I;Wte1Z8(+nvf1*t>;6{apArcxG#tM{=aW~$hSX@Zo6f=2)GD54g~&!!d><} z&&_bMyjriC+#Ww9_A}|9dIg#N@A-zu^9}A-_-o`h9!FbG*73o!(@b~#u*-BudzH<; zKQ*R1+M%Dm?ubP{D1Q^ymL8;6J`z1}{{73-v-j?C$2S-#Exm-b!QE=P*i@;y+d36+ zZ49QlQ}J^^3`>60gdf)dht|>jhhMtFjJA(nW_7aVE_Qi(ylfUm%R9@z5lN>u<4I)N zSWaR=d9zN@gyXzN-LPCJg~Cse=)<9U?T@MD-aF=h_Wy z^>eRTua1>R9-x8CCN{VDOj zg{}L$E%W^j^JAJ z{x$h+@-6aPm*CI$QoHD?~?mOAp&`e z+##=$o8(z?jZ71c|0(}t{*O?B`*9I?90*(&_<1V&1Vs!Af)ES@uiqPl$bu*;flxs4 zzQf-L1ig20RlING8t}e_tL*&>u99~iSJC?>u7dXs{)Qa(ewn`^DdY}6Ba_$pnFVs2 zpHavhKO=fy<8O$9*N^z1_f@0~dB22^u=f_OA@3`=%HEd|D|%l-Y`}XH-vi`DekSCd zMWpC`0l|v*d0Zv$bBGLkpGCOjeFh<-_Xa{F?{!=SGQ-bE-lq{6^j|{7leG5EtszW7_6Up9Y4=;FJF^AGUs^}7cRoK!iW!6ouvE10zZ@-^Sjd*08X?<%sen zo?4n1=Ut9_ZPZyiQ%CEb$|H`N8D^$p=)M%3(56vj>eADAaxCm{}~0Y}_(cNdb5By9hj)2vGXx zJiq6m|36osk6wRjn)*t9@vkvw$+)kjb>ipsF=xr#iP(?j={nbg^tjw$=lP^2EMOyf zv%P!Dvjz3Mg&p_fUPHL35YBehkGa7H4|LS`cI!IaTg)>xT$@LxQ7G28J2h-jvY$P% zANUZE3Jocmh;w@T5Ipp};b{e{jh#V*yoef&8TRLw>y8Z|)KfT2K-&YC88r~A{EP*f*>A@ zhZ#Im*phli-}{lzT?nUs+K+`0-5(6$Uu_Hlajwca`*{K#c=S$4>0!qC)=t^_pKJe5;&^VDi@@g}0V@A_@+ThhLtNaCi-3#3=MaIX_$e$G zK2Nw5PB3^1&k5rP$9~YG0D1CHJ>>UsaX&5sE&@*g0^!pEeHbd%*=Q5L667HTQI`Pyat+`~RMRj=N2C z5pWUsga}L#j^lZHS;E*78{^w=SM;`qDE*Iwh zKJVjuWQueiZ%0x$F3pP1bMHGmukhW{MQ8SOJ^lXTB!8zf5%Y4=0Jt~VBjfX5d*;%t zGRt)xrBc5qE0&!mz<#|nso?Q+tY{X5vis){%vYYBo_%+gJHF;9ojrp>8$EiCg$2Dl zsfr1SSv@Qq^^D4xo7bM3o(-ciZc=5mVQ_P^e6O5a(;($oHFns1?Rj(v?r&#@25n%7 z4HDWxw*_m2Z`dY+Fjzc4+!g$nOEIyIqyU98KnSzyO~>4G&6GqV2LxgAZw z3PFFO)Mih2-G0u@(G@%B)kzJoBOU2ky>_^x-udIpFP`qYozPLhum^UW|AI9SGoICi zVb}ZmKhFR9bK;)=^>~?{Tbql(V@2Q!cKxzL&v^Qc9dX0-e|P=wu?~Y%;zW*QHyu@=p@@Js`?|8^}@WuVO z2)GD5(FpjxT!iD#K46eX?`Amuy}?<5gZ00kVEzAz?zY=_7XcT6heCj90R#H~G0y*Z zsLXC+7XcT6ClrAhpBLMId3H{yk9_EvBAO3p{58n05{>*{@?ZP^p3u&@&2|xZtO$UB zu5+Wa(YO=8`D)chf%Pd)hR-rZG*v<>?3Ei?gKZv7A%RoXB>WzPUSO z7e%-5L9I9FD^BoIBZ7x{o*q<+WX@8(W2IiE&;Lw&{*nj({}*@2{RyAuzef%c_=rBo z+|B9P4QyR`%dyLY9X)h%p94Fqg2lWxX_v#Iu`A^Q&oCZvm2rSe6Y2lo5%%v>Yp7eW zi-3#3BS&CF{~V)#j?q8I=$~Ws&rPKNQ~LiuBkbQJZ=hSCi-3#3BSK(Y|K|q!KR3|- zxq<%A4fKCT`IGg3+8)Xm+>eWZi@+BS0eAoZ7jDSi4!Z~p5$Hev>z@BN1jPN~BJjCG z;OZ1R@QL2MAw(`s#nMR)j!sm(yfk;bGch}dbY;IW3h3fvSFT|q-k3H!_Z6R#)LD( z=Z~jvPtSf8FZu1Cfq}Qx;a#q~r(WHAD&X#*ujyobE4}O=oIib5_WpA8sX{0!_6vdM zt8-|`iPJxDmKgdMu>lZUOe=NQ>JzGJ2s9<>5 z_K5=Q6TR7bKaFE2eA9!w?SyY#pc!YEGO=}b^11%;;iEdy=57Dw*<>f;5R{M|pvoUZcQusDEr_5#z``IF_F@5}!`rSJdy)6W{=yX|oi za1nS^2(V4ReGPzp?aTi@{k!LXJ}Q*ma$E#H>j==j0G#9ePl5k+dj9VZ$@j@0lmCw0 z|KB0sCjW|ji~J_}4e}58-{gOt{2lVQ$uE&#B;O!^g&dGNDd9iuvOq-g z6>^)rLS7&<L;7 z$#>`vDf}F}EnH!@&^2}o`q@qSGP?zCvYX7an{H3e-~ffkBfkdz>|x> z^b~!+hvyRZ1oXd5Pm}(ascH5e5YOf5Y4#2f&lFwx7g9nvAr%^0)#|CSOeN8+6wSkW zF}@h-|HYCAT5Y?eW)(}XWLkx+P<(GED)`ix)myJ+4%Zg-PF@OkjMxea$#hY`+A#BC zRL~@&ro}Spd@fNds@7Ela5;XT(nn6E0(#s9nH(z4YYCtg$w9=4TaZzYHp(yKV3`6S&I=1S2V#A z3R$tYUS;6X0+-Ndy9NYG?M5LjmbB^$K#6yB^m9uJAE=Vm@5ZQQWg}~~e1&B@lTy;M z>ADkfhQ&^WwybMp(_?+!+j90fmTBoy+BrPuG(8j0V=Eohd^R8t!h@lG79i*0k(Z7v zA7;#wCWV_S`a51oLR7Oy6&tWrb){X{DPagllgdYD)!NS3R17f>}U)>%?#ABj`LJkT`cwyu!C5po$hNqj)((p`I?=?cc_)55k(zlMQ3l0=0#kzCtz-PIMzpw1U!frI5+& z?4;56T=W364QeaalBq3aV?W(ZX5#^TKgw6ry<~Mm_9e54>Sn6aD`dCi|`@v4F@)>$(D-m@#5-+4^5Nf z%Pa5abHz@&nmIDEnVzv&68bEvP|{X2)>)|gKryY4i@Hzm)oVF9d0^xc`-MzcQnMNP zy&UB%3$;^dJCLS8`#vtx6lmWAkY>|27AqX+RiRVJZa0jTFq;QCsc_&!U^&t{j1H#d zLB5u>^jg7MTQqt`HqlmdTQvYyHL}XS5wi}oa>+8-_*aTP^RUsNEI7V1K-lKpQbIJq z9JR7?sL7aBF-t1!=#6zqmW;GQe}kKJiw%%v(d<&muzir0qmUX9E#*iU{HqR*(g9nR zwQ{kRuVn;G%g%Z&dZ0@dL{6??K^lY@3yy_TI!dG>XF!gET??%QGY!&3FK%TUC38{P z@fC6_VgbyYGICl=K1&%pNQ7a1_ELdBv1$1_LQ_jjE{-Q zLx>bK4~$>lKG0W;5;zHP(CceC0en0P`30T^?&8yH8^P^rxU20bJxI$2m_x&?Qie!5 zN~O5gjnop=6%oHJ$mvENK$#gj)@{qD?F(!gg4n?wx2;SjkpS0h>p+z<0IL6U{Es~N z?|xhaz7Pm}aD}_%+4%6T{GhjEMI)uqVyeEQ){=YqYNnpgK}&{o)#cXeX7T6%;<*8u z@0o{saIu;!<)xCfu~g52+)F-vHQE9hmI}3POSi%$st{zB>T7xpDs(QXMHb^5Mh;xp z3O5R|%4)nQb~K5qTvpd-?!;F$DNtUl7NCpSUdb0s{$dR{Ci+ z_Zu-Sw$k&d%cYVol|qq7KDbzkicl>p=3(TkKI%ugD=2rx1-~TS7sdO6I2dqxm_QJJ z0{-sdPsX2uzjyE#=yS=n)uA%e@R`y|OOKUGX(`-=aPEPr9XfgM-p)zoq+ZMCGLXla zjt^pBAKXsKf%BTQz8c9|)%YUQE31$_i8jPzRIjFsW;QIwSCh~e z(?#&zlCc<7G#THe6{tuMY~3jIu!KMb8V1|)fum!<8Wu!CFCI%MEMh0xF|uMAgILt0 zJPKOrsq)6X_zIIxD9mbUP)s4XqAdt3Ymmt@VR%tlTCi)0g}VT*yI$5ITBD&wSZlh} z?$Ocl8H*#iYUCo!z`~Sj>LOJY6V$jGGXX{_ab#dCt&U3TkM&B|a0;wcYi*MLg_>>k zpwum7^N?!ok}g}&D@(vafy%TIG*%O00h6VWgOawA+}Eqtp|QFV^w|+e*q;osj8I55 zoC*mv_JKgpwV{mDE+r52+E&N+Ael-YAU#Uj4+L$uRc&ZPsPQJ{Y-gtDJ^Vd6BcM_KiSKa3;Pwtw*lUf z?B$h>*s_>RCHM2$t;6Jgk&)J>*jkO3N>$7vnD3biXqp-k6-^AYFkig5z7c_?L6t2{ zN>J?u`e3o9%bBv4wU`Ox)RQm?D8V=4tF1Mkn#~v27ME?qsiMh72YoEVbb)FU=s<(% zQJu-4gubIRbaA9Z`JiCZQb1C)IYVWO`7M}DaE`|6qbe(u#}nEqWpbw`e(~hQhcV%> zJZ$z-J}iP`_Dm>Y>S_XpR9J+$CO{NWs|1SmN-HfTyI?UX0;%KV=@hv@@C(_(rlPut5BfFbYo49=HPAV`!N=+Fls%7`3gq@s4AD} z`5;7?p#WLYRkJHCHP@hS2s(6)pRE}aUlqX6`V4%;zgwW93hdnhXCFoM8G9Ty4osXj z9iH_pSWPS)v}aws7+;UTm*p_iGlzxP3V?{$6O=E-GCgWtC%V)$hxG0O`4ha$cOLVy zc^AY9o%3vnHp@mCg<(<&H6P%2j_m;)1k~C((5Pq!v!@K;3t)hWxoiI}ML?&jn3tLhoUFt**!j(hoFdtkM zqHRolxH{qH$;k$+($XH7%6?9Q`T;ARnuOc?57zo%2A@{@9;EdxQl44PcR=cJ9PNk> zmsPx&hlNL(Ob!+tysSa^z+la_$`Lbpz9kE$Vig`4lW`cIR8YcD-_s>c;7rB69r%nE^{TDpP15mv=PP+>Ve`V0=z|p=D*QLzcx1CfO^9$> zTy%Dn$5r>uQsRB6Q{_SynqbwUzMvkP9ZOJ)fdt&=$xyUcU&~7?`)VwGxLGow5v?5R zu_GlXtyHQ14tKb(O6kpF144rk1j|Dz#i`K%oj-=sBGk$#thOQ}{XguNob0z4E)6^{V5*TC)d753SM2L4VEjf`93_Yh zoxpIS9F@Rj4Uarc#(+}V4-8Y2I%7@y|(SFB}4(52nA060i|@uIm<=p-*=J$T#)`{ z(7y!oSI%+m`)uF-1zh{59L_$c$N6C$&al--9_NR3IQyI)=ZAGTQ!X|1I6thz8MgY! z<20-W`S2k0SR!h3HnTnQ@sdNuAv$C<24>0Q)Gy}R>vjxnEZVnsgNS^xs zDbbc{^nf;7=fL`KE9$i4GP!6a5A{sP3IvmbxeX>r)*ZG1^?*Ilo;zXAVJV9)vTQfN z9|Q0|fSJ<8k{xQ-Io9@I*V?vT-&22t^}Y0PL4jtbtB8X&E-Tb;dZt=ns+a=NWz?}8 fSyNZ3{%@Nzl~4jA9_xD|{415V23OH~wbc0kCdZAl delta 477 zcmYjNJ4ho@6n*dBo0v7O_=BLBF{D_P_?c0Ih$%#2*;t7Py3IOK6pLt(6p0p+fg!pe z==dzePDO&niuzb&8y75gLDTcX zl85j`EhT0$X7Ww=i2E#M8MC&-Y#MgD+BF-UnkH}B6khO43IRD!89QYsmhsa~>27zC zClKJv&GM$F7ClWqe|##I7>z^|k-50vHx`RUCn7WQsn1ceLmMthQ@J90RYCf=C?2bm zX?+3n!dtu=zBtNxlJO+Z!3sR$G|n>JGWtbg@w?E?6{(v`aI`^%uKbl{PBzJ)61FkG zM_HClTE?JU*xl#yF74qWkh#du5Okn?#&tAs9^)9r3H*k`IDld7#SjLu1?$m=)mVXU zBzS;($if|5!zG-oW*xh&%uQ From e9de70ed95a7c7347e9b39f77ed64987307d04ff Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Wed, 20 May 2009 02:05:49 +0200 Subject: [PATCH 05/59] #300: Added pending state and predecessor/successor relations to Todo model --- app/models/todo.rb | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/models/todo.rb b/app/models/todo.rb index d608e56f..3aaefbb8 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -4,6 +4,11 @@ class Todo < ActiveRecord::Base belongs_to :project belongs_to :user belongs_to :recurring_todo + + has_many :predecessor_dependencies, :foreign_key => 'predecessor_id', :class_name => 'Dependency' + has_many :successor_dependencies, :foreign_key => 'successor_id', :class_name => 'Dependency' + has_many :predecessors, :through => :successor_dependencies + has_many :successors, :through => :predecessor_dependencies named_scope :active, :conditions => { :state => 'active' } named_scope :not_completed, :conditions => ['NOT (state = ? )', 'completed'] @@ -19,6 +24,7 @@ class Todo < ActiveRecord::Base state :project_hidden state :completed, :enter => Proc.new { |t| t.completed_at = Time.zone.now }, :exit => Proc.new { |t| t.completed_at = nil } state :deferred + state :pending event :defer do transitions :to => :deferred, :from => [:active] @@ -30,6 +36,9 @@ class Todo < ActiveRecord::Base event :activate do transitions :to => :active, :from => [:project_hidden, :completed, :deferred] + transitions :to => :active, :from => [:pending], + :guard => Proc.new{|t| t.show_from.blank? or t.show_from > user.date} + transitions :to => :deferred, :from => [:pending] end event :hide do @@ -40,6 +49,10 @@ class Todo < ActiveRecord::Base transitions :to => :deferred, :from => [:project_hidden], :guard => Proc.new{|t| !t.show_from.blank? } transitions :to => :active, :from => [:project_hidden] end + + event :block do + transitions :to => :pending, :from => [:active] + end attr_protected :user @@ -92,7 +105,7 @@ class Todo < ActiveRecord::Base def project original_project.nil? ? Project.null_object : original_project end - + alias_method :original_set_initial_state, :set_initial_state def set_initial_state From b136816ff1e90ff806b8d930d222c6edda8e0de3 Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Wed, 20 May 2009 02:06:42 +0200 Subject: [PATCH 06/59] #300: Updated Project and User models to use the new Todo model --- app/models/project.rb | 5 +++++ app/models/user.rb | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/app/models/project.rb b/app/models/project.rb index b5dbd3c1..88053a1c 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -20,6 +20,11 @@ class Project < ActiveRecord::Base :class_name => 'Todo', :conditions => ["todos.state = ? ", "deferred"], :order => "show_from" + has_many :pending_todos, + :include => [:context,:tags,:project], + :class_name => 'Todo', + :conditions => ["todos.state = ? ", "pending"], + :order => "show_from" has_many :notes, :dependent => :delete_all, :order => "created_at DESC" diff --git a/app/models/user.rb b/app/models/user.rb index 6ce58aa8..30c5a6fb 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -98,6 +98,10 @@ class User < ActiveRecord::Base find(:all, :conditions => ['show_from <= ?', Time.zone.now ]).collect { |t| t.activate! } end end + has_many :pending_todos, + :class_name => 'Todo', + :conditions => [ 'state = ?', 'pending' ], + :order => 'show_from ASC, todos.created_at DESC' has_many :completed_todos, :class_name => 'Todo', :conditions => ['todos.state = ? AND NOT(todos.completed_at IS NULL)', 'completed'], From ced0e8f5316e5ae8586d4cbc2020e4c02f9aa4be Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Wed, 20 May 2009 13:00:14 +0200 Subject: [PATCH 07/59] #300: Added uncompleted_predecessors to Todo model. --- app/models/todo.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/todo.rb b/app/models/todo.rb index 3aaefbb8..9c5488eb 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -9,6 +9,8 @@ class Todo < ActiveRecord::Base has_many :successor_dependencies, :foreign_key => 'successor_id', :class_name => 'Dependency' has_many :predecessors, :through => :successor_dependencies has_many :successors, :through => :predecessor_dependencies + has_many :uncompleted_predecessors, :through => :successor_dependencies, + :source => :predecessor, :conditions => ['NOT (state = ?)', 'completed'] named_scope :active, :conditions => { :state => 'active' } named_scope :not_completed, :conditions => ['NOT (state = ? )', 'completed'] From cb4ed7ff7f81374a06b39ceb69b5ccb556bae3f4 Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Wed, 20 May 2009 13:02:28 +0200 Subject: [PATCH 08/59] #300: Updated projects and todos controllers to use Todo dependencies. --- app/controllers/projects_controller.rb | 3 ++- app/controllers/todos_controller.rb | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index d62f6aa0..56da269e 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -47,10 +47,11 @@ class ProjectsController < ApplicationController @not_done = @project.not_done_todos_including_hidden @deferred = @project.deferred_todos + @pending = @project.pending_todos @done = @project.todos.find_in_state(:all, :completed, :order => "todos.completed_at DESC", :limit => current_user.prefs.show_number_completed, :include => [:context]) @count = @not_done.size - @down_count = @count + @deferred.size + @down_count = @count + @deferred.size + @pending.size @next_project = current_user.projects.next_from(@project) @previous_project = current_user.projects.previous_from(@project) @default_tags = @project.default_tags diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 949d94bf..de6e283e 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -142,6 +142,24 @@ class TodosController < ApplicationController # check if this todo has a related recurring_todo. If so, create next todo @new_recurring_todo = check_for_next_todo(@todo) if @saved + if @todo.completed? + logger.debug "completed #{@todo.description}" + # A todo was completed - check for pending todos + @todo.successors.each do |t| + if t.uncompleted_predecessors.empty? # Activate pending todos + logger.debug "activated #{t.description}" + t.activate! + end + end + else + # Block todos for undone actions - (it does no harm if they are already pending) + logger.debug "undid #{@todo.description}" + @todo.successors.each do |t| + logger.debug "blocked #{t.description}" + t.block! + end + end + respond_to do |format| format.js do if @saved From 101df3fb6b9551f85b10803717ce856b5bd56894 Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Wed, 4 Nov 2009 22:32:44 -0500 Subject: [PATCH 09/59] Simple dependency handling working on project page. The database contains actions with dependencies. Please rename to tracks-17-blank.db or update database path accordingly. Conflicts: app/views/todos/toggle_check.js.rjs --- app/controllers/todos_controller.rb | 14 ++++++++++---- app/helpers/todos_helper.rb | 2 +- app/views/todos/toggle_check.js.rjs | 16 +++++++++++++++- db/tracks-17-test.db | Bin 0 -> 55296 bytes 4 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 db/tracks-17-test.db diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index de6e283e..71d22346 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -144,19 +144,25 @@ class TodosController < ApplicationController if @todo.completed? logger.debug "completed #{@todo.description}" - # A todo was completed - check for pending todos + # A todo was completed - check for pending todos to activate + @pending_to_activate = [] @todo.successors.each do |t| if t.uncompleted_predecessors.empty? # Activate pending todos logger.debug "activated #{t.description}" t.activate! + @pending_to_activate << t end end else - # Block todos for undone actions - (it does no harm if they are already pending) + # Block active successors for undone action + @active_to_block = [] logger.debug "undid #{@todo.description}" @todo.successors.each do |t| - logger.debug "blocked #{t.description}" - t.block! + if t.state == 'active' + logger.debug "blocked #{t.description}" + t.block! + @active_to_block << t + end end end diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index b39d5674..cfd1dbf8 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -203,7 +203,7 @@ module TodosHelper def item_container_id (todo) if source_view_is :project return "p#{todo.project_id}items" if todo.active? - return "tickler" if todo.deferred? + return "tickler" if todo.deferred? or todo.pending? end return "c#{todo.context_id}items" end diff --git a/app/views/todos/toggle_check.js.rjs b/app/views/todos/toggle_check.js.rjs index 5f9e2734..92289b16 100644 --- a/app/views/todos/toggle_check.js.rjs +++ b/app/views/todos/toggle_check.js.rjs @@ -8,9 +8,15 @@ if @saved page.insert_html :top, "completed_containeritems", :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => "completed" } page.visual_effect :highlight, dom_id(@todo, 'line'), {'startcolor' => "'#99ff99'"} page[empty_container_msg_div_id].show if @down_count == 0 && !empty_container_msg_div_id.nil? - page.show 'tickler-empty-nd' if source_view_is(:project) && @deferred_count == 0 + page.show 'tickler-empty-nd' if source_view_is(:project) && @deferred_count == 0 && @pending_count == 0 page.hide 'empty-d' # If we've checked something as done, completed items can't be empty end + # Activate pending todos that are successors of the completed + @pending_to_activate.each do |t| + logger.debug "#300: Removing #{t.description} from pending block and adding it to active" + page[t].remove + page.insert_html :bottom, item_container_id(t), :partial => 'todos/todo', :locals => { :todo => t, :parent_container_type => parent_container_type } + end # remove container if empty if @remaining_in_context == 0 && source_view_is(:todo) @@ -44,6 +50,14 @@ if @saved page.show "empty-d" if @completed_count == 0 page.show "c"+@todo.context.id.to_s page[empty_container_msg_div_id].hide unless empty_container_msg_div_id.nil? # If we've checked something as undone, incomplete items can't be empty + # If active todos are successors of the reactivated todo they will be blocked + @active_to_block.each do |t| + logger.debug "#300: Block #{t.description} that are a successor of #{@todo.description}" + page[t].remove # Remove it from active + # Insert it in deferred/pending block + logger.debug "Insert #{t.description} in deferred/pending block" + page.insert_html :bottom, item_container_id(t), :partial => 'todos/todo', :locals => { :todo => t, :parent_container_type => parent_container_type } + end end page.hide "status" diff --git a/db/tracks-17-test.db b/db/tracks-17-test.db new file mode 100644 index 0000000000000000000000000000000000000000..3f79ee534f3c54d4cefffc7d92941aef82694641 GIT binary patch literal 55296 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 Date: Thu, 21 May 2009 01:55:53 +0200 Subject: [PATCH 10/59] #300: Home view working when completing/undoing todos Updated toggle_check.js.rjs to handle DOM manipulation for the Home page. --- app/views/todos/toggle_check.js.rjs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/views/todos/toggle_check.js.rjs b/app/views/todos/toggle_check.js.rjs index 92289b16..68a6a89a 100644 --- a/app/views/todos/toggle_check.js.rjs +++ b/app/views/todos/toggle_check.js.rjs @@ -14,7 +14,7 @@ if @saved # Activate pending todos that are successors of the completed @pending_to_activate.each do |t| logger.debug "#300: Removing #{t.description} from pending block and adding it to active" - page[t].remove + page[t].remove if source_view_is(:project) # Remove todo from pending block (if it exists) page.insert_html :bottom, item_container_id(t), :partial => 'todos/todo', :locals => { :todo => t, :parent_container_type => parent_container_type } end @@ -54,9 +54,10 @@ if @saved @active_to_block.each do |t| logger.debug "#300: Block #{t.description} that are a successor of #{@todo.description}" page[t].remove # Remove it from active - # Insert it in deferred/pending block - logger.debug "Insert #{t.description} in deferred/pending block" - page.insert_html :bottom, item_container_id(t), :partial => 'todos/todo', :locals => { :todo => t, :parent_container_type => parent_container_type } + if source_view_is(:project) # Insert it in deferred/pending block if existing + logger.debug "Insert #{t.description} in deferred/pending block" + page.insert_html :bottom, item_container_id(t), :partial => 'todos/todo', :locals => { :todo => t, :parent_container_type => parent_container_type } + end end end From 381db782a061470e4b355d00eedc30f3274fdf09 Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Fri, 22 May 2009 14:33:56 +0200 Subject: [PATCH 11/59] #300: Added pending items to tag view --- app/controllers/todos_controller.rb | 3 +++ app/views/todos/tag.html.erb | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 71d22346..83207f76 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -433,6 +433,9 @@ class TodosController < ApplicationController @deferred = tag_collection.find(:all, :conditions => ['todos.user_id = ? and state = ?', current_user.id, 'deferred'], :order => 'show_from ASC, todos.created_at DESC') + @pending = tag_collection.find(:all, + :conditions => ['todos.user_id = ? and state = ?', current_user.id, 'pending'], + :order => 'show_from ASC, todos.created_at DESC') # If you've set no_completed to zero, the completed items box isn't shown on # the tag page diff --git a/app/views/todos/tag.html.erb b/app/views/todos/tag.html.erb index c6418da5..7804c9b9 100644 --- a/app/views/todos/tag.html.erb +++ b/app/views/todos/tag.html.erb @@ -8,7 +8,13 @@ :locals => { :collapsible => true } %> <% unless @deferred.nil? -%> - <%= render :partial => "todos/deferred", :locals => { :deferred => @deferred, :collapsible => true, :append_descriptor => "tagged with ‘#{@tag_name}’", :parent_container_type => 'tag' } %> + <%= render :partial => "todos/deferred", :locals => { + :deferred => @deferred, + :pending => @pending, + :collapsible => true, + :append_descriptor => "tagged with ‘#{@tag_name}’", + :parent_container_type => 'tag' + } %> <% end -%> <% unless @hidden_todos.nil? -%> From 74fcaf407ca89435551754d0d1668c4ae54a7d0e Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Wed, 4 Nov 2009 22:37:33 -0500 Subject: [PATCH 12/59] Bug #300: check_toggle.js working for Tag view Conflicts: app/helpers/todos_helper.rb --- app/helpers/todos_helper.rb | 7 ++++--- app/views/todos/toggle_check.js.rjs | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index cfd1dbf8..fd7039d4 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -201,9 +201,10 @@ module TodosHelper end def item_container_id (todo) - if source_view_is :project - return "p#{todo.project_id}items" if todo.active? - return "tickler" if todo.deferred? or todo.pending? + if todo.deferred? or todo.pending? + return "tickler" + elsif source_view_is :project + return "p#{todo.project_id}items" end return "c#{todo.context_id}items" end diff --git a/app/views/todos/toggle_check.js.rjs b/app/views/todos/toggle_check.js.rjs index 68a6a89a..041e80c6 100644 --- a/app/views/todos/toggle_check.js.rjs +++ b/app/views/todos/toggle_check.js.rjs @@ -14,7 +14,7 @@ if @saved # Activate pending todos that are successors of the completed @pending_to_activate.each do |t| logger.debug "#300: Removing #{t.description} from pending block and adding it to active" - page[t].remove if source_view_is(:project) # Remove todo from pending block (if it exists) + page[t].remove if source_view_is(:project) or source_view_is(:tag) page.insert_html :bottom, item_container_id(t), :partial => 'todos/todo', :locals => { :todo => t, :parent_container_type => parent_container_type } end @@ -54,8 +54,8 @@ if @saved @active_to_block.each do |t| logger.debug "#300: Block #{t.description} that are a successor of #{@todo.description}" page[t].remove # Remove it from active - if source_view_is(:project) # Insert it in deferred/pending block if existing - logger.debug "Insert #{t.description} in deferred/pending block" + if source_view_is(:project) or source_view_is(:tag) # Insert it in deferred/pending block if existing + logger.debug "Insert #{t.description} in #{item_container_id(t)} block" page.insert_html :bottom, item_container_id(t), :partial => 'todos/todo', :locals => { :todo => t, :parent_container_type => parent_container_type } end end From 45dd524519cdce230bf69857176482cc15d5fd35 Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Wed, 4 Nov 2009 22:38:27 -0500 Subject: [PATCH 13/59] Bug #300: Disabled completion check box for pending items. --- app/helpers/todos_helper.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index fd7039d4..ec7a2d3c 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -82,7 +82,8 @@ module TodosHelper def remote_toggle_checkbox - check_box_tag('item_id', toggle_check_todo_path(@todo), @todo.completed?, :class => 'item-checkbox') + check_box_tag('item_id', toggle_check_todo_path(@todo), @todo.completed?, :class => 'item-checkbox', + :disabled => @todo.pending?) end def date_span From 42cbe52224f639d04bd3be5d882080c9e42c7afd Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Wed, 4 Nov 2009 22:39:19 -0500 Subject: [PATCH 14/59] Bug #300: First shot at dependency entry in edit form Limitations: * No javascript update of dependency changes. * No resolution for duplicate descriptions. Conflicts: app/views/todos/_edit_form.rhtml --- app/controllers/todos_controller.rb | 44 +++++++++++++++++++++++++++-- app/helpers/todos_helper.rb | 14 +++++++++ app/models/todo.rb | 33 ++++++++++++++++++++++ app/views/todos/_edit_form.rhtml | 10 ++++++- 4 files changed, 98 insertions(+), 3 deletions(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 83207f76..69c6c621 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -8,7 +8,7 @@ class TodosController < ApplicationController :completed_archive, :check_deferred, :toggle_check, :toggle_star, :edit, :update, :create, :calendar, :auto_complete_for_tag] append_before_filter :get_todo_from_params, :only => [ :edit, :toggle_check, :toggle_star, :show, :update, :destroy ] - protect_from_forgery :except => [:auto_complete_for_tag] + protect_from_forgery :except => [:auto_complete_for_tag, :auto_complete_for_predecessor] session :off, :only => :index, :if => Proc.new { |req| is_feed_request(req) } @@ -214,7 +214,25 @@ class TodosController < ApplicationController @original_item_project_id = @todo.project_id @original_item_was_deferred = @todo.deferred? @original_item_due = @todo.due - @original_item_due_id = get_due_id_for_calendar(@todo.due) + @original_item_due_id = get_due_id_for_calendar(@todo.due) + @original_item_predecessor_list = @todo.predecessors.collect{|t| t.description}.join(', ') + if params[:predecessor_list] + logger.debug "---old #{@original_item_predecessor_list}" + logger.debug "---new #{params[:predecessor_list]}" + @todo.add_predecessor_list(params[:predecessor_list]) + if @original_item_predecessor_list != params[:predecessor_list] + # Recalculate dependencies for this todo + if @todo.uncompleted_predecessors.empty? + if @todo.state == 'pending' + @todo.activate! # Activate pending if no uncompleted predecessors + end + else + if @todo.state == 'active' + @todo.block! # Block active if we got uncompleted predecessors + end + end + end + end if params['todo']['project_id'].blank? && !params['project_name'].nil? if params['project_name'] == 'None' @@ -540,6 +558,28 @@ class TodosController < ApplicationController render :inline => "<%= auto_complete_result(@items, :name) %>" end + def auto_complete_for_predecessor + get_todo_from_params + # Begin matching todos in current project + @items = current_user.todos.find(:all, + :conditions => [ 'NOT (id = ?) AND description LIKE ? AND project_id = ?', + @todo.id, + '%' + params[:predecessor_list] + '%', + @todo.project_id ], + :order => 'description ASC', + :limit => 10 + ) + if @items.empty? # Match todos in other projects + @items = current_user.todos.find(:all, + :conditions => [ 'NOT (id = ?) AND description LIKE ?', + params[:id], '%' + params[:predecessor_list] + '%' ], + :order => 'description ASC', + :limit => 10 + ) + end + render :inline => "<%= auto_complete_result(@items, :description) %>" + end + private def get_todo_from_params diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index ec7a2d3c..70c54385 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -116,6 +116,20 @@ module TodosHelper if tag_list.empty? then "" else "#{tag_list}" end end + # TODO: Use DELIMITER + def predecessor_list_text + @todo.predecessors.collect{|t| t.description}.join(', ') + end + + def predecessor_list + predecessor_list = @todo.predecessors.collect{|t| + '' + + link_to(t.name, :controller => "todos", :action => "tag", :id => t.name) + + "" + }.join('') + '#{predecessor_list}' + end + def deferred_due_date if @todo.deferred? && @todo.due "(action due on #{format_date(@todo.due)})" diff --git a/app/models/todo.rb b/app/models/todo.rb index 9c5488eb..06ab02d5 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -154,6 +154,39 @@ class Todo < ActiveRecord::Base return self.recurring_todo_id != nil end + def add_predecessor(predecessor) + logger.debug "add_predecessor #{predecessor.description}" + end + + # TODO: DELIMITER + # TODO: Todo::Error + # TODO: Handle todos with the same description + def add_predecessor_list(predecessor_list) + logger.debug "add_predecessor_list #{predecessor_list}" + raise "Can't handle other types than string for now" unless predecessor_list.kind_of? String + list = predecessor_list.split(',').map do |description| + description.strip.squeeze(" ") + end + current = self.predecessors.map(&:description) + remove_list = current - list + # This is probably a bit naive code... + remove_list.each do |description| + t = Todo.find_by_description(description) + logger.debug "Removing #{t.description} from #{self.description} as predecessor" + self.predecessors.delete(t) + end + add_list = list - current + # ... as is this? + add_list.each do |description| + t = Todo.find_by_description(description) + #raise Todo::Error, "predecessor could not be found: #{description}" if t.nil? + # Create dependency record + self.predecessors << t unless self.predecessors.include?(t) + end +# debugger + + end + # Rich Todo API def self.from_rich_message(user, default_context_id, description, notes) diff --git a/app/views/todos/_edit_form.rhtml b/app/views/todos/_edit_form.rhtml index e471984e..2f8e4bc5 100644 --- a/app/views/todos/_edit_form.rhtml +++ b/app/views/todos/_edit_form.rhtml @@ -46,13 +46,21 @@ + +<%= text_field_tag 'predecessor_list', predecessor_list_text, :id => dom_id(@todo, 'predecessor_list'), :size => 30, :tabindex => 15 %> +<%= content_tag("div", "", :id => dom_id(@todo, 'predecessor_list')+"_auto_complete", :class => "auto_complete") %> +<%= auto_complete_field dom_id(@todo, 'predecessor_list'), { + :url => {:controller => 'todos', :action => 'auto_complete_for_predecessor', :id => @todo.id}, + :tokens => [','] +} %> + <% if controller.controller_name == "project" || @todo.deferred? -%> <% end -%>
- From 2bf48a15cbe642bbe56d219df1d9f49638696358 Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Wed, 4 Nov 2009 22:43:21 -0500 Subject: [PATCH 15/59] Bug #300: Added infrastructure for collapsible dependency block, similar to todo notes. Conflicts: app/views/layouts/standard.html.erb public/javascripts/application.js --- app/views/todos/_todo.html.erb | 1 + app/views/todos/_toggle_dependencies.rhtml | 5 +++++ public/javascripts/application.js | 4 ++++ public/stylesheets/standard.css | 3 +++ 4 files changed, 13 insertions(+) create mode 100644 app/views/todos/_toggle_dependencies.rhtml diff --git a/app/views/todos/_todo.html.erb b/app/views/todos/_todo.html.erb index 4d2ad947..587aa8ff 100644 --- a/app/views/todos/_todo.html.erb +++ b/app/views/todos/_todo.html.erb @@ -29,6 +29,7 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag' <%= deferred_due_date %> <%= project_and_context_links( parent_container_type, :suppress_context => suppress_context, :suppress_project => suppress_project ) %> <%= render(:partial => "todos/toggle_notes", :locals => { :item => todo }) if todo.notes? %> + <%= render(:partial => "todos/toggle_dependencies", :locals => { :item => todo }) if todo.uncompleted_predecessors.empty? or !todo.successors.empty? %>
+ + <%= text_field_tag "predecessor_list", nil, :size => 30, :tabindex => 8 %> + <%= content_tag("div", "", :id => "predecessor_list_auto_complete", :class => "auto_complete") %> + <%= auto_complete_field 'predecessor_list', { + :url => {:controller => 'todos', :action => 'auto_complete_for_predecessor', :id => nil}, + :tokens => [','] + } %> + <%= source_view_tag( @source_view ) %> <%= hidden_field_tag :_tag_name, @tag_name.underscore.gsub(/\s+/,'_') if source_view_is :tag %> From 407689780d59f7c55cf5052791c65f141660e2ae Mon Sep 17 00:00:00 2001 From: Eric Allen Date: Tue, 10 Nov 2009 22:05:24 -0500 Subject: [PATCH 18/59] Ticket #300: Fixed broken create.js functionality Conflicts: app/views/todos/create.js.rjs --- app/helpers/todos_helper.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 99367a0c..9f186721 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -228,7 +228,7 @@ module TodosHelper def item_container_id (todo) if todo.deferred? or todo.pending? - return "tickler" + return "tickleritems" elsif source_view_is :project return "p#{todo.project_id}items" end @@ -248,6 +248,7 @@ module TodosHelper return true if source_view_is(:project) && @todo.project.hidden? && @todo.project_hidden? return true if source_view_is(:project) && @todo.deferred? return true if !source_view_is(:deferred) && @todo.active? + return true if source_view_is(:project) && @todo.pending? return false end From fc9ffeaa4bf6c19e4788f970ce3d200d0c9f7279 Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Mon, 8 Jun 2009 23:42:46 +0200 Subject: [PATCH 19/59] #300: Removing link tag from successor icon --- app/helpers/todos_helper.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 9f186721..23cda92f 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -99,11 +99,10 @@ module TodosHelper end def successors_span - unless @todo.successors.empty? - successors_count = @todo.successors.length - title = "Has #{pluralize(successors_count, 'pending action')}: #{@todo.successors.map(&:description).join(', ')}" - link_to(image_tag( 'blank.png', :width=>'10', :height=>'16', :border=>'0' ), - '#', {:class => 'show_successors', :title => title}) + unless @todo.pending_successors.empty? + pending_count = @todo.pending_successors.length + title = "Has #{pluralize(pending_count, 'pending action')}: #{@todo.pending_successors.map(&:description).join(', ')}" + image_tag( 'successor_off.png', :width=>'10', :height=>'16', :border=>'0', :title => title ) end end From 4016c89cdf4e44c32f6622949f18a75ac8d18b42 Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Mon, 8 Jun 2009 23:43:40 +0200 Subject: [PATCH 20/59] #300: Added pending_successors collection and enforces referential integrity for dependencies --- app/models/todo.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/models/todo.rb b/app/models/todo.rb index 61558d67..c2704cc0 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -5,12 +5,15 @@ class Todo < ActiveRecord::Base belongs_to :user belongs_to :recurring_todo - has_many :predecessor_dependencies, :foreign_key => 'predecessor_id', :class_name => 'Dependency' - has_many :successor_dependencies, :foreign_key => 'successor_id', :class_name => 'Dependency' - has_many :predecessors, :through => :successor_dependencies - has_many :successors, :through => :predecessor_dependencies + has_many :predecessor_dependencies, :foreign_key => 'predecessor_id', :class_name => 'Dependency', :dependent => :destroy + has_many :successor_dependencies, :foreign_key => 'successor_id', :class_name => 'Dependency', :dependent => :destroy + has_many :predecessors, :through => :successor_dependencies, :dependent => :destroy + has_many :successors, :through => :predecessor_dependencies, :dependent => :destroy has_many :uncompleted_predecessors, :through => :successor_dependencies, - :source => :predecessor, :conditions => ['NOT (state = ?)', 'completed'] + :source => :predecessor, :conditions => ['NOT (state = ?)', 'completed'], :dependent => :destroy + has_many :pending_successors, :through => :predecessor_dependencies, + :source => :successor, :conditions => ['state = ?', 'pending'], :dependent => :destroy + named_scope :active, :conditions => { :state => 'active' } named_scope :not_completed, :conditions => ['NOT (state = ? )', 'completed'] From 3d3b703dfd471299c0b047d4863b9fd644a30c44 Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Tue, 9 Jun 2009 00:06:30 +0200 Subject: [PATCH 21/59] #300: Changed user.date to Time.zone.now --- app/models/todo.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/todo.rb b/app/models/todo.rb index c2704cc0..a143e9cf 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -42,7 +42,7 @@ class Todo < ActiveRecord::Base event :activate do transitions :to => :active, :from => [:project_hidden, :completed, :deferred] transitions :to => :active, :from => [:pending], - :guard => Proc.new{|t| t.show_from.blank? or t.show_from > user.date} + :guard => Proc.new{|t| t.show_from.blank? or t.show_from > Time.zone.now} transitions :to => :deferred, :from => [:pending] end From 06e4bd4412908e718adcd1ecf9b85f1da058ef18 Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Tue, 9 Jun 2009 00:13:56 +0200 Subject: [PATCH 22/59] #300: Displays show_from correctly --- app/models/todo.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/todo.rb b/app/models/todo.rb index a143e9cf..f39f30a2 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -42,7 +42,7 @@ class Todo < ActiveRecord::Base event :activate do transitions :to => :active, :from => [:project_hidden, :completed, :deferred] transitions :to => :active, :from => [:pending], - :guard => Proc.new{|t| t.show_from.blank? or t.show_from > Time.zone.now} + :guard => Proc.new{|t| t.show_from.blank? or Time.zone.now > t.show_from} transitions :to => :deferred, :from => [:pending] end From c8b442cc412eb39532f899a14759de9c7b64e2d5 Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Tue, 9 Jun 2009 13:45:39 +0200 Subject: [PATCH 23/59] #300: Referential integrity maintained when deleting todos which are part in a dependency relationship --- app/controllers/todos_controller.rb | 21 ++++++++++++++++++--- app/models/todo.rb | 8 ++++---- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 7c6d1ee2..56c9213c 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -77,7 +77,8 @@ class TodosController < ApplicationController @todo.tag_with(tag_list) @todo.tags.reload end - + + # TODO: Check if we can reload cache here instead of saving twice unless predecessor_list.blank? @todo.add_predecessor_list(predecessor_list) unless @todo.uncompleted_predecessors.empty? || @todo.state == 'project_hidden' @@ -348,16 +349,30 @@ class TodosController < ApplicationController @context_id = @todo.context_id @project_id = @todo.project_id + # activate successors if they only depend on this todo + activated_successor_count = 0 + @todo.pending_successors.each do |successor| + successor.uncompleted_predecessors.delete(@todo) + if successor.uncompleted_predecessors.empty? + successor.activate! + activated_successor_count += 1 + end + end + @saved = @todo.destroy # check if this todo has a related recurring_todo. If so, create next todo @new_recurring_todo = check_for_next_todo(@todo) if @saved - + respond_to do |format| format.html do if @saved - notify :notice, "Successfully deleted next action", 2.0 + message = "Successfully deleted next action" + if activated_successor_count > 0 + message += " activated #{pluralize(activated_successor_count, 'pending action')}" + end + notify :notice, message, 2.0 redirect_to :action => 'index' else notify :error, "Failed to delete the action", 2.0 diff --git a/app/models/todo.rb b/app/models/todo.rb index f39f30a2..cd195cc8 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -7,12 +7,12 @@ class Todo < ActiveRecord::Base has_many :predecessor_dependencies, :foreign_key => 'predecessor_id', :class_name => 'Dependency', :dependent => :destroy has_many :successor_dependencies, :foreign_key => 'successor_id', :class_name => 'Dependency', :dependent => :destroy - has_many :predecessors, :through => :successor_dependencies, :dependent => :destroy - has_many :successors, :through => :predecessor_dependencies, :dependent => :destroy + has_many :predecessors, :through => :successor_dependencies + has_many :successors, :through => :predecessor_dependencies has_many :uncompleted_predecessors, :through => :successor_dependencies, - :source => :predecessor, :conditions => ['NOT (state = ?)', 'completed'], :dependent => :destroy + :source => :predecessor, :conditions => ['NOT (state = ?)', 'completed'] has_many :pending_successors, :through => :predecessor_dependencies, - :source => :successor, :conditions => ['state = ?', 'pending'], :dependent => :destroy + :source => :successor, :conditions => ['state = ?', 'pending'] named_scope :active, :conditions => { :state => 'active' } From fe066e3bcb1020465ebe5535c53cd9afae05cca0 Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Wed, 10 Jun 2009 00:07:23 +0200 Subject: [PATCH 24/59] #300: Added infrastructure for drag and drop dependency creation --- app/controllers/todos_controller.rb | 9 +++++++++ app/helpers/todos_helper.rb | 8 ++++++++ app/views/todos/_todo.html.erb | 11 +++++++++++ public/stylesheets/standard.css | 10 +++++----- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 56c9213c..20afba9b 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -140,6 +140,15 @@ class TodosController < ApplicationController format.xml { render :xml => @todo.to_xml( :root => 'todo', :except => :user_id ) } end end + + def add_predecessor + logger.debug "add_predecessor" + @predecessor = Todo.find(params['predecessor']) + @successor = Todo.find(params['successor']) + respond_to do |format| + format.js + end + end # Toggles the 'done' status of the action # diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 23cda92f..111d0adf 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -106,6 +106,14 @@ module TodosHelper end end + def grip_span + unless @todo.completed? + image_tag('grip.png', :width => '7', :height => '16', :border => '0', + :title => 'Drag onto another action to make it depend on this action', + :class => 'grip') + end + end + def tag_list_text @todo.tags.collect{|t| t.name}.join(', ') end diff --git a/app/views/todos/_todo.html.erb b/app/views/todos/_todo.html.erb index d253f760..59134ad9 100644 --- a/app/views/todos/_todo.html.erb +++ b/app/views/todos/_todo.html.erb @@ -22,6 +22,7 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag' <% end %>
+ <%= grip_span %> <%= date_span -%> <%= h sanitize(todo.description) %> <%= successors_span %> @@ -39,3 +40,13 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag' <% end -%>
+<%= +draggable_element(dom_id(todo), :revert => "'failure'", :handle => "'grip'", :onDrop => "''") +%> +<%= +drop_receiving_element(dom_id(todo), + :url => {:controller => "todos", :action => "add_predecessor"}, + :with => "'successor=' + encodeURIComponent(element.id.split('_').last()) + '&predecessor=' + encodeURIComponent(#{todo.id})" +) +%> + diff --git a/public/stylesheets/standard.css b/public/stylesheets/standard.css index 2c7330bd..8fb551f8 100644 --- a/public/stylesheets/standard.css +++ b/public/stylesheets/standard.css @@ -381,11 +381,7 @@ input.item-checkbox { .description, .stale_l1, .stale_l2, .stale_l3 { margin-left: 60px; - position:relative; -} - -.stale_l1, .stale_l2, .stale_l3 { - padding-left: 3px; + position:relative; } .stale_l1 { @@ -939,6 +935,10 @@ div.message { color: #666; } +.grip { + cursor: move; +} + /* Error message styles */ .fieldWithErrors { padding: 2px; From 00e063a0a2b011c5ab14b6a656bee15eab5eb638 Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Fri, 12 Jun 2009 22:09:46 +0200 Subject: [PATCH 25/59] #300: Implemented basic drag and drop dependency support. Dragging an action onto another action creates a dependency to that action. --- app/controllers/todos_controller.rb | 8 ++++++-- app/helpers/todos_helper.rb | 4 ++-- app/views/todos/_todo.html.erb | 2 +- app/views/todos/add_predecessor.js.rjs | 14 ++++++++++++++ public/images/grip.png | Bin 0 -> 192 bytes 5 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 app/views/todos/add_predecessor.js.rjs create mode 100644 public/images/grip.png diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 20afba9b..4ab166fc 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -142,9 +142,13 @@ class TodosController < ApplicationController end def add_predecessor - logger.debug "add_predecessor" @predecessor = Todo.find(params['predecessor']) - @successor = Todo.find(params['successor']) + @todo = Todo.find(params['successor']) + @original_state = @todo.state + # Add predecessor + @todo.predecessors << @predecessor + @todo.state = 'pending' + @saved = @todo.save respond_to do |format| format.js end diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index 111d0adf..6a2762d7 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -90,7 +90,7 @@ module TodosHelper if @todo.completed? "#{format_date( @todo.completed_at )}" elsif @todo.pending? - "Pending " + "Pending " elsif @todo.deferred? show_date( @todo.show_from ) else @@ -109,7 +109,7 @@ module TodosHelper def grip_span unless @todo.completed? image_tag('grip.png', :width => '7', :height => '16', :border => '0', - :title => 'Drag onto another action to make it depend on this action', + :title => 'Drag onto another action to make it depend on that action', :class => 'grip') end end diff --git a/app/views/todos/_todo.html.erb b/app/views/todos/_todo.html.erb index 59134ad9..ee2eab24 100644 --- a/app/views/todos/_todo.html.erb +++ b/app/views/todos/_todo.html.erb @@ -41,7 +41,7 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag' <%= -draggable_element(dom_id(todo), :revert => "'failure'", :handle => "'grip'", :onDrop => "''") +draggable_element(dom_id(todo), :revert => "'true'", :handle => "'grip'", :onDrop => "''") %> <%= drop_receiving_element(dom_id(todo), diff --git a/app/views/todos/add_predecessor.js.rjs b/app/views/todos/add_predecessor.js.rjs new file mode 100644 index 00000000..4b4d46ee --- /dev/null +++ b/app/views/todos/add_predecessor.js.rjs @@ -0,0 +1,14 @@ +if @saved + # show update message + status_message = "Added #{@predecessor.description} as dependency." + unless @original_state == 'pending' + status_message += " #{@todo.description} set to pending" + page[@todo].remove + page['tickler-empty-nd'].hide + page.insert_html :bottom, item_container_id(@todo), :partial => 'todos/todo', :locals => { :todo => @todo, :parent_container_type => parent_container_type } + end + page.notify :notice, status_message, 5.0 +else + page.replace_html "status", content_tag("div", content_tag("h2", "Unable to add dependency"), "id" => "errorExplanation", "class" => "errorExplanation") +end + diff --git a/public/images/grip.png b/public/images/grip.png new file mode 100644 index 0000000000000000000000000000000000000000..40e3d9e438f38b07abf8b53a29de14145821da46 GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^>_9BQ!3HF6HKu+5QjEnx?oJHr&dIz4aySb-B8wRq zxP?KOkzv*x37{Z*iKnkC`%N}ZAr1bUZ)bV{g(OQ{BTAg}b8}PkN*J7rQWHy3QxwWG zOEMJPJ$(bh8~Mb6igZ0)977~7C)fP{Wy$RK;osNdw)+47_y79-|G##LnXr$b@Ol>u htJ#HDZZsN-F?_7-Id%9YV=7Q1gQu&X%Q~loCIC7fJHr3~ literal 0 HcmV?d00001 From 08d24a1b8f56aa339b7431ede4678c805255986c Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Sun, 14 Jun 2009 23:15:45 +0200 Subject: [PATCH 26/59] #300: Added some visual feedback when hovering over drop target --- app/views/todos/_todo.html.erb | 3 ++- public/stylesheets/standard.css | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/views/todos/_todo.html.erb b/app/views/todos/_todo.html.erb index ee2eab24..0d023284 100644 --- a/app/views/todos/_todo.html.erb +++ b/app/views/todos/_todo.html.erb @@ -46,7 +46,8 @@ draggable_element(dom_id(todo), :revert => "'true'", :handle => "'grip'", :onDr <%= drop_receiving_element(dom_id(todo), :url => {:controller => "todos", :action => "add_predecessor"}, - :with => "'successor=' + encodeURIComponent(element.id.split('_').last()) + '&predecessor=' + encodeURIComponent(#{todo.id})" + :with => "'successor=' + encodeURIComponent(element.id.split('_').last()) + '&predecessor=' + encodeURIComponent(#{todo.id})", + :hoverclass => 'hover' ) %> diff --git a/public/stylesheets/standard.css b/public/stylesheets/standard.css index 8fb551f8..45617228 100644 --- a/public/stylesheets/standard.css +++ b/public/stylesheets/standard.css @@ -939,6 +939,11 @@ div.message { cursor: move; } +.hover { + background: #EAEAEA; + font-weight: bold; +} + /* Error message styles */ .fieldWithErrors { padding: 2px; From 90d77f37cbaace797f2610c58e727696f172d3ba Mon Sep 17 00:00:00 2001 From: Henrik Bohre Date: Mon, 15 Jun 2009 23:56:34 +0200 Subject: [PATCH 27/59] #300: Displays successors recursively --- app/views/todos/_successor.html.erb | 20 ++++++++++++++++++++ app/views/todos/_todo.html.erb | 3 ++- app/views/todos/_toggle_successors.html.erb | 9 +++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 app/views/todos/_successor.html.erb create mode 100644 app/views/todos/_toggle_successors.html.erb diff --git a/app/views/todos/_successor.html.erb b/app/views/todos/_successor.html.erb new file mode 100644 index 00000000..9570d0b3 --- /dev/null +++ b/app/views/todos/_successor.html.erb @@ -0,0 +1,20 @@ +<% +suppress_context ||= false +suppress_project ||= false +suppress_dependencies ||= false +parameters = "_source_view=#{@source_view}" +parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag' +@z_index_counter = @z_index_counter - 1 # for IE z-index bug +%> +
+
+
+ <%= link_to(image_tag( 'blank.png', :width=>'16', :height=>'16', :border=>'0', :class => 'delete_item' ), "#", + { :class => 'remove_successor', :title => 'Remove successor', :style => "background: transparent;"}) %> + <%= h sanitize(successor.description) %> + <% #= successors_span %> + <%= render(:partial => "todos/toggle_successors", :locals => { :item => successor }) unless successor.pending_successors.empty? %> +
+
+
+ diff --git a/app/views/todos/_todo.html.erb b/app/views/todos/_todo.html.erb index 0d023284..2ca193d0 100644 --- a/app/views/todos/_todo.html.erb +++ b/app/views/todos/_todo.html.erb @@ -25,12 +25,13 @@ parameters += "&_tag_name=#{@tag_name}" if @source_view == 'tag' <%= grip_span %> <%= date_span -%> <%= h sanitize(todo.description) %> - <%= successors_span %> + <% #= successors_span %> <%= image_tag_for_recurring_todo(todo) if @todo.from_recurring_todo? %> <%= tag_list %> <%= deferred_due_date %> <%= project_and_context_links( parent_container_type, :suppress_context => suppress_context, :suppress_project => suppress_project ) %> <%= render(:partial => "todos/toggle_notes", :locals => { :item => todo }) if todo.notes? %> + <%= render(:partial => "todos/toggle_successors", :locals => { :item => todo }) unless todo.pending_successors.empty? %>