[Bps-public-commit] rt-extension-jsgantt branch, master, updated. 557409f8c348ff842f9e4c33c1b39e3395a95ccc
? sunnavy
sunnavy at bestpractical.com
Thu Jul 1 15:14:56 EDT 2010
The branch, master has been updated
via 557409f8c348ff842f9e4c33c1b39e3395a95ccc (commit)
from e860637c4dc90e599695688e27f94cd4b1cdd9c6 (commit)
Summary of changes:
html/Search/JSGantt.html | 251 +++---------------------------------------
lib/RT/Extension/JSGantt.pm | 252 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 269 insertions(+), 234 deletions(-)
- Log -----------------------------------------------------------------
commit 557409f8c348ff842f9e4c33c1b39e3395a95ccc
Author: sunnavy <sunnavy at bestpractical.com>
Date: Fri Jul 2 03:16:13 2010 +0800
move major logic to .pm
diff --git a/html/Search/JSGantt.html b/html/Search/JSGantt.html
index d38d724..480d158 100644
--- a/html/Search/JSGantt.html
+++ b/html/Search/JSGantt.html
@@ -15,6 +15,7 @@
g.setShowRes(<% RT->Config->Get('JSGanttShowOwner')? 1 : 0 %>);
g.setShowDur(<% RT->Config->Get('JSGanttShowDuration')? 1 : 0 %> );
+% my $show_progress = RT->Config->Get('JSGanttShowProgress' );
% if ( $show_progress ) {
g.setShowComp(1);
% } else {
@@ -32,8 +33,8 @@
// You can also use the XML file parser JSGantt.parseXML('project.xml',g)
% use JSON;
-% for my $id ( @ids ) {
-% my $json = to_json( [ $id, map { $info{$id}{$_} } qw/name start end
+% for my $id ( @$ids ) {
+% my $json = to_json( [ $id, map { $info->{$id}{$_} } qw/name start end
% color link milestone owner progress has_members parent open
% depends/ ] );
% $json =~ s/^\[//; $json =~ s/\]$//;
@@ -55,254 +56,36 @@
<%init>
my $title = loc('JSGantt Results');
-
-my ( $Tickets, @Tickets );
-
-sub related_tickets {
- my $ticket = shift;
- my @types = @_;
- return unless $ticket;
- my @tickets;
- for my $type ( @types ) {
- my $links = $ticket->$type->ItemsArrayRef;
- my $target_or_base =
- $type =~ /DependsOn|MemberOf|RefersTo/ ? 'TargetObj' : 'BaseObj';
- for my $link (@$links) {
- my $obj = $link->$target_or_base;
- if ( $obj && $obj->isa('RT::Ticket') ) {
- push @tickets, $obj;
- }
- }
- }
- return @tickets;
-}
+my @Tickets;
if ( $Ticket ) {
- my %checked;
- my @to_be_checked;
-
- my $ticket = RT::Ticket->new( $session{CurrentUser} );
- $ticket->Load( $Ticket );
- if ( $ticket->id ) {
- # find the highest ancestors to make chart pretty
- my @parents = related_tickets( $ticket, 'MemberOf' );
- @parents = $ticket unless @parents;
- while ( @parents ) {
- my @ancestors;
- for my $parent ( @parents ) {
- unshift @ancestors, related_tickets( $parent, 'MemberOf' );
- }
-
- if ( @ancestors ) {
- @parents = @ancestors;
- }
- else {
- @to_be_checked = @parents;
- undef @parents;
- }
- }
-
- while ( my $ticket = shift @to_be_checked ) {
- push @Tickets, $ticket unless grep { $ticket->id eq $_->id } @Tickets;
- push @to_be_checked, grep { ! $checked{$_->id}++ } related_tickets( $ticket, 'Members' );
- }
-
- @to_be_checked = @Tickets;
- while ( my $ticket = shift @to_be_checked ) {
- push @Tickets, $ticket unless grep { $ticket->id eq $_->id } @Tickets;
- unshift @to_be_checked, grep { ! $checked{$_->id}++ } related_tickets( $ticket, 'Members' );
- unshift @to_be_checked, grep { ! $checked{$_->id}++ } related_tickets( $ticket, 'MemberOf' );
- push @to_be_checked, grep { ! $checked{$_->id}++ } related_tickets(
- $ticket, 'DependsOn', 'DependedOnBy', 'RefersTo', 'ReferredToBy' );
- }
- }
+ @Tickets = RT::Extension::JSGantt->AllRelatedTickets(
+ Ticket => $Ticket,
+ CurrentUser => $session{CurrentUser},
+ );
}
-elsif ( $Query ) {
- $Tickets = RT::Tickets->new( $session{'CurrentUser'} );
- $Tickets->FromSQL( $Query );
+elsif ($Query) {
+ my $Tickets = RT::Tickets->new( $session{'CurrentUser'} );
+ $Tickets->FromSQL($Query);
if ( $OrderBy =~ /\|/ ) {
+
# Multiple Sorts
my @OrderBy = split /\|/, $OrderBy;
my @Order = split /\|/, $Order;
$Tickets->OrderByCols(
map { { FIELD => $OrderBy[$_], ORDER => $Order[$_] } }
- ( 0 .. $#OrderBy )
- );
+ ( 0 .. $#OrderBy ) );
}
else {
$Tickets->OrderBy( FIELD => $OrderBy, ORDER => $Order );
}
@Tickets = @{ $Tickets->ItemsArrayRef };
}
-else {
- $m->abort;
-}
-
-my $progress = 0;
-my $show_progress = RT->Config->Get('JSGanttShowProgress' );
-
-my @colors = grep { defined } RT->Config->Get('JSGanttColorScheme');
- at colors = ( 'ff0000', 'ffff00', 'ff00ff', '00ff00', '00ffff', '0000ff' ) unless @colors;
-my $i;
-my ( @ids, %info );
-my ( $min_start, $min_start_obj );
-
-for my $Ticket (@Tickets) {
- my $subject = $Ticket->Subject;
-
- my $parent = 0;
- if ( $Ticket->MemberOf->Count ) {
- $parent = $Ticket->MemberOf->First->TargetObj->id;
- }
-
- # find start/end, this is, uhh, long long way to go
- my ( $start, $end ) = ( '', '' );
- my ( $start_obj, $end_obj );
- if ( $Ticket->StartsObj->Unix ) {
- my ( $day, $month, $year ) =
- ( $Ticket->StartsObj->Localtime('user') )[ 3, 4, 5 ];
- $start = join '/', $month + 1, $day, $year;
- $start_obj = $Ticket->StartsObj;
- }
- elsif ( $Ticket->StartedObj->Unix ) {
- my ( $day, $month, $year ) =
- ( $Ticket->StartedObj->Localtime('user') )[ 3, 4, 5 ];
- $start = join '/', $month + 1, $day, $year;
- $start_obj = $Ticket->StartedObj;
- }
-
- if ( $Ticket->DueObj->Unix ) {
- my ( $day, $month, $year ) =
- ( $Ticket->DueObj->Localtime('user') )[ 3, 4, 5 ];
- $end = join '/', $month + 1, $day, $year;
- $end_obj = $Ticket->DueObj;
- }
-
- # if $start or $end is empty still
- unless ( $start && $end ) {
- if ( $parent ) {
- # yep, it's sure that $parent lives in %info already
- $start ||= $info{$parent}{start};
- $end ||= $info{$parent}{end};
- }
- else {
- my $hours_per_day = RT->Config->Get('JSGanttWorkingHoursPerDay')
- || 8;
- my $total_time =
- defined $Ticket->TimeLeft
- ? ( $Ticket->TimeWorked + $Ticket->TimeLeft )
- : $Ticket->TimeEstimated;
- $total_time ||= 0;
- my $days = int( $total_time / ( 60 * $hours_per_day ) );
- $days ||= RT->Config->Get('JSGanttDefaultDays') || 7;
- # since we only use date without time, let's make days inclusive
- # ( i.e. 5/12/2010 minus 3 days is 5/10/2010. 10,11,12, 3 days! )
- $days = $days =~ /\./ ? int $days : $days - 1;
- $days = 0 if $days < 0;
-
- if ( $start && !$end ) {
- $end_obj = RT::Date->new( $session{CurrentUser} );
- $end_obj->Set( Value => $start_obj->Unix );
- $end_obj->AddDays($days);
- my ( $day, $month, $year ) =
- ( $end_obj->Localtime('user') )[ 3, 4, 5 ];
- $end = join '/', $month + 1, $day, $year;
- }
-
- if ( $end && !$start ) {
- $start_obj = RT::Date->new( $session{CurrentUser} );
- $start_obj->Set( Value => $end_obj->Unix );
- $start_obj->AddDays( -1 * $days );
- my ( $day, $month, $year ) =
- ( $start_obj->Localtime('user') )[ 3, 4, 5 ];
- $start = join '/', $month + 1, $day, $year;
- }
- }
- }
-
- if ( !$start ) {
- $RT::Logger->warning( "Ticket "
- . $Ticket->id
- . " doesn't have Starts/Started defined, and we can't figure it out either"
- );
- $start = $end;
- }
- if ( !$end ) {
- $RT::Logger->warning( "Ticket "
- . $Ticket->id
- . " doesn't have Due defined, and we can't figure it out either"
- );
- $end = $start;
- }
-
- my $has_members = $Ticket->Members->Count ? 1 : 0;
-
- # parent ticket's start date is not used when drawing
- if ( !$has_members
- && $start_obj
- && ( !$min_start_obj || $min_start_obj->Unix > $start_obj->Unix ) )
- {
- $min_start_obj = $start_obj;
- $min_start = $start;
- }
-
- my $depends = $Ticket->DependsOn;
- my @depends;
- if ( $depends->Count ) {
- while ( my $d = $depends->Next ) {
- push @depends, $d->TargetObj->id;
- }
- }
-
- if ($show_progress) {
- my $total_time =
- defined $Ticket->TimeLeft
- ? ( $Ticket->TimeWorked + $Ticket->TimeLeft )
- : $Ticket->TimeEstimated;
- if ( $Ticket->TimeWorked ) {
- $progress = int( 100 * $Ticket->TimeWorked / $total_time );
- }
- }
-
- push @ids, $Ticket->id;
- $info{$Ticket->id} =
- {
- name => ( $Ticket->id . ': ' . substr $subject, 0, 30 ),
- start => $start,
- end => $end,
- color => $colors[ $i++ % @colors ],
- link => (
- RT->Config->Get('WebPath')
- . '/Ticket/Display.html?id='
- . $Ticket->id
- ),
- milestone => 0,
- owner => ( $Ticket->OwnerObj->Name || $Ticket->OwnerObj->EmailAddress ),
- progress => $progress,
- has_members => $has_members,
- parent => $parent,
- open => 1,
- depends => ( @depends ? join ',', @depends : 0 )
- };
-}
-
-
-#let's tweak our results
-#set to now if all tickets don't have start/end dates
-if ( ! $min_start ) {
- $min_start_obj = RT::Date->new($session{CurrentUser});
- $min_start_obj->SetToNow;
- my ($day,$month,$year) = ($min_start_obj->Localtime('user'))[3,4,5];
- $min_start = join '/', $month+1, $day, $year;
-}
-
-my $no_dates_color = RT->Config->Get('JSGanttNullDatesColor') || '333';
-for my $id ( @ids ) {
- $info{$id}{color} = $no_dates_color unless $info{$id}{start};
- $info{$id}{start} ||= $min_start;
- $info{$id}{end} ||= $min_start;
-}
+my ( $ids, $info ) = RT::Extension::JSGantt->TicketsInfo(
+ Tickets => \@Tickets,
+ CurrentUser => $session{CurrentUser},
+);
</%init>
diff --git a/lib/RT/Extension/JSGantt.pm b/lib/RT/Extension/JSGantt.pm
index e77db1a..2bc567a 100644
--- a/lib/RT/Extension/JSGantt.pm
+++ b/lib/RT/Extension/JSGantt.pm
@@ -5,6 +5,258 @@ our $VERSION = '0.03';
use warnings;
use strict;
+sub AllRelatedTickets {
+ my $class = shift;
+ my %args = ( Ticket => undef, CurrentUser => undef, @_ );
+
+ my @tickets;
+ my %checked;
+ my @to_be_checked;
+ my $ticket = RT::Ticket->new( $args{CurrentUser} );
+ $ticket->Load( $args{Ticket} );
+ if ( $ticket->id ) {
+
+ # find the highest ancestors to make chart pretty
+ my @parents = _RelatedTickets( $ticket, 'MemberOf' );
+ @parents = $ticket unless @parents;
+ while (@parents) {
+ my @ancestors;
+ for my $parent (@parents) {
+ unshift @ancestors, _RelatedTickets( $parent, 'MemberOf' );
+ }
+
+ if (@ancestors) {
+ @parents = @ancestors;
+ }
+ else {
+ @to_be_checked = @parents;
+ undef @parents;
+ }
+ }
+
+ while ( my $ticket = shift @to_be_checked ) {
+ push @tickets, $ticket
+ unless grep { $ticket->id eq $_->id } @tickets;
+ push @to_be_checked,
+ grep { !$checked{ $_->id }++ }
+ _RelatedTickets( $ticket, 'Members' );
+ }
+
+ @to_be_checked = @tickets;
+ while ( my $ticket = shift @to_be_checked ) {
+ push @tickets, $ticket
+ unless grep { $ticket->id eq $_->id } @tickets;
+ unshift @to_be_checked,
+ grep { !$checked{ $_->id }++ }
+ _RelatedTickets( $ticket, 'Members' );
+ unshift @to_be_checked,
+ grep { !$checked{ $_->id }++ }
+ _RelatedTickets( $ticket, 'MemberOf' );
+ push @to_be_checked, grep { !$checked{ $_->id }++ } _RelatedTickets(
+ $ticket, 'DependsOn', 'DependedOnBy', 'RefersTo',
+ 'ReferredToBy'
+ );
+ }
+ }
+ return @tickets;
+}
+
+
+sub TicketsInfo {
+ my $class = shift;
+ my %args = ( Tickets => [], CurrentUser => undef, @_ );
+
+
+ my ( @ids, %info );
+ my $progress = 0;
+ my @colors = grep { defined } RT->Config->Get('JSGanttColorScheme');
+ @colors = ( 'ff0000', 'ffff00', 'ff00ff', '00ff00', '00ffff', '0000ff' )
+ unless @colors;
+ my $i;
+ my $show_progress = RT->Config->Get('JSGanttShowProgress' );
+
+ my ( $min_start, $min_start_obj );
+
+ for my $Ticket (@{$args{Tickets}}) {
+ my $subject = $Ticket->Subject;
+
+ my $parent = 0;
+ if ( $Ticket->MemberOf->Count ) {
+ $parent = $Ticket->MemberOf->First->TargetObj->id;
+ }
+
+ # find start/end, this is, uhh, long long way to go
+ my ( $start, $end ) = ( '', '' );
+ my ( $start_obj, $end_obj );
+ if ( $Ticket->StartsObj->Unix ) {
+ my ( $day, $month, $year ) =
+ ( $Ticket->StartsObj->Localtime('user') )[ 3, 4, 5 ];
+ $start = join '/', $month + 1, $day, $year;
+ $start_obj = $Ticket->StartsObj;
+ }
+ elsif ( $Ticket->StartedObj->Unix ) {
+ my ( $day, $month, $year ) =
+ ( $Ticket->StartedObj->Localtime('user') )[ 3, 4, 5 ];
+ $start = join '/', $month + 1, $day, $year;
+ $start_obj = $Ticket->StartedObj;
+ }
+
+ if ( $Ticket->DueObj->Unix ) {
+ my ( $day, $month, $year ) =
+ ( $Ticket->DueObj->Localtime('user') )[ 3, 4, 5 ];
+ $end = join '/', $month + 1, $day, $year;
+ $end_obj = $Ticket->DueObj;
+ }
+
+ # if $start or $end is empty still
+ unless ( $start && $end ) {
+ if ($parent) {
+
+ # yep, it's sure that $parent lives in %info already
+ $start ||= $info{$parent}{start};
+ $end ||= $info{$parent}{end};
+ }
+ else {
+ my $hours_per_day = RT->Config->Get('JSGanttWorkingHoursPerDay')
+ || 8;
+ my $total_time =
+ defined $Ticket->TimeLeft
+ ? ( $Ticket->TimeWorked + $Ticket->TimeLeft )
+ : $Ticket->TimeEstimated;
+ $total_time ||= 0;
+ my $days = int( $total_time / ( 60 * $hours_per_day ) );
+ $days ||= RT->Config->Get('JSGanttDefaultDays') || 7;
+
+ # since we only use date without time, let's make days inclusive
+ # ( i.e. 5/12/2010 minus 3 days is 5/10/2010. 10,11,12, 3 days! )
+ $days = $days =~ /\./ ? int $days : $days - 1;
+ $days = 0 if $days < 0;
+
+ if ( $start && !$end ) {
+ $end_obj = RT::Date->new( $args{CurrentUser} );
+ $end_obj->Set( Value => $start_obj->Unix );
+ $end_obj->AddDays($days);
+ my ( $day, $month, $year ) =
+ ( $end_obj->Localtime('user') )[ 3, 4, 5 ];
+ $end = join '/', $month + 1, $day, $year;
+ }
+
+ if ( $end && !$start ) {
+ $start_obj = RT::Date->new( $args{CurrentUser} );
+ $start_obj->Set( Value => $end_obj->Unix );
+ $start_obj->AddDays( -1 * $days );
+ my ( $day, $month, $year ) =
+ ( $start_obj->Localtime('user') )[ 3, 4, 5 ];
+ $start = join '/', $month + 1, $day, $year;
+ }
+ }
+ }
+
+ if ( !$start ) {
+ $RT::Logger->warning( "Ticket "
+ . $Ticket->id
+ . " doesn't have Starts/Started defined, and we can't figure it out either"
+ );
+ $start = $end;
+ }
+ if ( !$end ) {
+ $RT::Logger->warning( "Ticket "
+ . $Ticket->id
+ . " doesn't have Due defined, and we can't figure it out either"
+ );
+ $end = $start;
+ }
+
+ my $has_members = $Ticket->Members->Count ? 1 : 0;
+
+ # parent ticket's start date is not used when drawing
+ if ( !$has_members
+ && $start_obj
+ && ( !$min_start_obj || $min_start_obj->Unix > $start_obj->Unix ) )
+ {
+ $min_start_obj = $start_obj;
+ $min_start = $start;
+ }
+
+ my $depends = $Ticket->DependsOn;
+ my @depends;
+ if ( $depends->Count ) {
+ while ( my $d = $depends->Next ) {
+ push @depends, $d->TargetObj->id;
+ }
+ }
+
+ if ($show_progress) {
+ my $total_time =
+ defined $Ticket->TimeLeft
+ ? ( $Ticket->TimeWorked + $Ticket->TimeLeft )
+ : $Ticket->TimeEstimated;
+ if ( $Ticket->TimeWorked ) {
+ $progress = int( 100 * $Ticket->TimeWorked / $total_time );
+ }
+ }
+
+ push @ids, $Ticket->id;
+ $info{ $Ticket->id } = {
+ name => ( $Ticket->id . ': ' . substr $subject, 0, 30 ),
+ start => $start,
+ end => $end,
+ color => $colors[ $i++ % @colors ],
+ link => (
+ RT->Config->Get('WebPath')
+ . '/Ticket/Display.html?id='
+ . $Ticket->id
+ ),
+ milestone => 0,
+ owner =>
+ ( $Ticket->OwnerObj->Name || $Ticket->OwnerObj->EmailAddress ),
+ progress => $progress,
+ has_members => $has_members,
+ parent => $parent,
+ open => 1,
+ depends => ( @depends ? join ',', @depends : 0 )
+ };
+ }
+
+ #let's tweak our results
+ #set to now if all tickets don't have start/end dates
+ if ( !$min_start ) {
+ $min_start_obj = RT::Date->new( $args{CurrentUser} );
+ $min_start_obj->SetToNow;
+ my ( $day, $month, $year ) =
+ ( $min_start_obj->Localtime('user') )[ 3, 4, 5 ];
+ $min_start = join '/', $month + 1, $day, $year;
+ }
+
+ my $no_dates_color = RT->Config->Get('JSGanttNullDatesColor') || '333';
+ for my $id (@ids) {
+ $info{$id}{color} = $no_dates_color unless $info{$id}{start};
+ $info{$id}{start} ||= $min_start;
+ $info{$id}{end} ||= $min_start;
+ }
+ return \@ids, \%info;
+}
+
+sub _RelatedTickets {
+ my $ticket = shift;
+ my @types = @_;
+ return unless $ticket;
+ my @tickets;
+ for my $type ( @types ) {
+ my $links = $ticket->$type->ItemsArrayRef;
+ my $target_or_base =
+ $type =~ /DependsOn|MemberOf|RefersTo/ ? 'TargetObj' : 'BaseObj';
+ for my $link (@$links) {
+ my $obj = $link->$target_or_base;
+ if ( $obj && $obj->isa('RT::Ticket') ) {
+ push @tickets, $obj;
+ }
+ }
+ }
+ return @tickets;
+}
+
+
=head1 NAME
RT::Extension::JSGantt -
-----------------------------------------------------------------------
More information about the Bps-public-commit
mailing list