[Rt-commit] rt branch, 4.2/date-time-improvements-in-charts, updated. rt-3.8.10-115-g2658116

Ruslan Zakirov ruz at bestpractical.com
Fri Jul 1 10:37:52 EDT 2011


The branch, 4.2/date-time-improvements-in-charts has been updated
       via  26581169ab91409b6d2e3dc54c87ed4ef2538546 (commit)
       via  24023cd8baa24d85fc00eb91f5b03b4929747b9c (commit)
       via  f77af1c0b9e48dfd1b7f5ebdc9092682fc0aa8c0 (commit)
       via  b479a984db4cfaaac278bb1eefb1aadc0f48beac (commit)
       via  db65b465d3a0656ce80faec4a33213f436038388 (commit)
       via  6d7537c3521d98049d8194e28b0b0d0a9dbadf2b (commit)
      from  1aa4ec78bf058ed0ab582c388972f9f66ef2dc8b (commit)

Summary of changes:
 lib/RT/Report/Tickets.pm |  190 ++++++++++++++++++++++++++++++++--------------
 share/html/Search/Chart  |   48 +++++++-----
 2 files changed, 162 insertions(+), 76 deletions(-)

- Log -----------------------------------------------------------------
commit 6d7537c3521d98049d8194e28b0b0d0a9dbadf2b
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Jun 29 00:19:28 2011 +0400

    support picturing complex functions with subvalues

diff --git a/share/html/Search/Chart b/share/html/Search/Chart
index 71dd41f..64a6281 100644
--- a/share/html/Search/Chart
+++ b/share/html/Search/Chart
@@ -56,23 +56,10 @@ $ChartStyle => 'bars'
 use GD;
 use GD::Text;
 
- at ChartFunction = grep defined && length, @ChartFunction;
-$ChartStyle = 'bars' if @ChartFunction > 1;
-
-my $chart_class;
-if ($ChartStyle eq 'pie') {
-    require GD::Graph::pie;
-    $chart_class = "GD::Graph::pie";
-} else {
-    require GD::Graph::bars;
-    $chart_class = "GD::Graph::bars";
-}
-
 use RT::Report::Tickets;
 my $report = RT::Report::Tickets->new( $session{'CurrentUser'} );
 
 my %columns;
-
 if ( $Cache and my $data = delete $session{'charts_cache'}{ $Cache } ) {
     %columns = %{ $data->{'columns'} };
     $report->Deserialize( $data->{'report'} );
@@ -100,14 +87,22 @@ my $min_value;
 my $max_key_length = 0;
 while ( my $entry = $report->Next ) {
     my $key = join ' - ', map $entry->LabelValue( $_ ), @{ $columns{'Groups'} };
+    push @{ $data[0] }, $key;
 
-    my @values = map $entry->RawValue($_), @{ $columns{'Functions'} };
-    if ($chart_class eq 'GD::Graph::pie') {
-        $key .= ' - '. $entry->LabelValue( $columns{'Functions'}[0] );
+    my @values;
+    foreach my $column ( @{ $columns{'Functions'} } ) {
+        my $v = $entry->RawValue( $column );
+        unless ( ref $v ) {
+            push @values, $v;
+            next;
+        }
+
+        my @subs = $report->FindImplementationCode(
+            $report->ColumnInfo( $column )->{'META'}{'SubValues'}
+        )->( $report );
+        push @values, map $v->{$_}, @subs;
     }
 
-    push @{ $data[0] }, $key;
-
     my $i = 0;
     push @{ $data[++$i] }, $_ foreach @values;
 
@@ -118,6 +113,23 @@ while ( my $entry = $report->Next ) {
     $max_key_length = length $key if $max_key_length < length $key;
 }
 
+$ChartStyle = 'bars' if @data > 2;
+if ( $ChartStyle eq 'pie' ) {
+    my $i = 0;
+    while ( my $entry = $report->Next ) {
+        $data[0][$i++] .= ' - '. $entry->LabelValue( $columns{'Functions'}[0] );
+    }
+}
+
+my $chart_class;
+if ($ChartStyle eq 'pie') {
+    require GD::Graph::pie;
+    $chart_class = "GD::Graph::pie";
+} else {
+    require GD::Graph::bars;
+    $chart_class = "GD::Graph::bars";
+}
+
 my %font_config = RT->Config->Get('ChartFont');
 my $font = $font_config{ $session{CurrentUser}->UserObj->Lang || '' }
     || $font_config{'others'};

commit db65b465d3a0656ce80faec4a33213f436038388
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Jun 29 00:20:19 2011 +0400

    NoTotals and NoHideEmpty

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index 1099191..52840f8 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -830,12 +830,15 @@ sub FormatTable {
         }
 
         my %total;
-        while ( my $entry = $self->Next ) {
-            my $raw = $entry->RawValue( $column ) || {};
-            $raw = { '' => $raw } unless ref $raw;
-            $total{ $_ } += $raw->{ $_ } foreach grep $raw->{$_}, @subs;
+        unless ( $info->{'META'}{'NoTotals'} ) {
+            while ( my $entry = $self->Next ) {
+                my $raw = $entry->RawValue( $column ) || {};
+                $raw = { '' => $raw } unless ref $raw;
+                $total{ $_ } += $raw->{ $_ } foreach grep $raw->{$_}, @subs;
+            }
+            @subs = grep $total{$_}, @subs
+                unless $info->{'META'}{'NoHideEmpty'};
         }
-        @subs = grep $total{$_}, @subs;
 
         my $label = $self->Label( $column );
 
@@ -886,12 +889,19 @@ sub FormatTable {
             $i++;
         }
 
-        my $total_code = $self->LabelValueCode( $column );
-        foreach my $e ( @subs ) {
-            my $total = $total{ $e };
-            $total = $total_code->( $self, %$info, VALUE => $total )
-                if $total_code;
-            push @{ $footer[0]{'cells'} }, { type => 'value', value => $total };
+        unless ( $info->{'META'}{'NoTotals'} ) {
+            my $total_code = $self->LabelValueCode( $column );
+            foreach my $e ( @subs ) {
+                my $total = $total{ $e };
+                $total = $total_code->( $self, %$info, VALUE => $total )
+                    if $total_code;
+                push @{ $footer[0]{'cells'} }, { type => 'value', value => $total };
+            }
+        }
+        else {
+            foreach my $e ( @subs ) {
+                push @{ $footer[0]{'cells'} }, { type => 'value', value => undef };
+            }
         }
     }
 

commit b479a984db4cfaaac278bb1eefb1aadc0f48beac
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Jul 1 16:57:37 2011 +0400

    fill in @STATISTICS with foreach loops

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index 52840f8..57b661f 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -196,40 +196,35 @@ our %GROUPINGS_META = (
 
 our @STATISTICS = (
     COUNT             => ['Tickets', 'Count', 'id'],
-
-    'SUM(TimeWorked)' => ['Total time worked',   'Time', 'SUM', 'TimeWorked' ],
-    'AVG(TimeWorked)' => ['Average time worked', 'Time', 'AVG', 'TimeWorked' ],
-    'MIN(TimeWorked)' => ['Minimum time worked', 'Time', 'MIN', 'TimeWorked' ],
-    'MAX(TimeWorked)' => ['Maximum time worked', 'Time', 'MAX', 'TimeWorked' ],
-
-    'SUM(TimeEstimated)' => ['Total time estimated',   'Time', 'SUM', 'TimeEstimated' ],
-    'AVG(TimeEstimated)' => ['Average time estimated', 'Time', 'AVG', 'TimeEstimated' ],
-    'MIN(TimeEstimated)' => ['Minimum time estimated', 'Time', 'MIN', 'TimeEstimated' ],
-    'MAX(TimeEstimated)' => ['Maximum time estimated', 'Time', 'MAX', 'TimeEstimated' ],
-
-    'SUM(TimeLeft)' => ['Total time left',   'Time', 'SUM', 'TimeLeft' ],
-    'AVG(TimeLeft)' => ['Average time left', 'Time', 'AVG', 'TimeLeft' ],
-    'MIN(TimeLeft)' => ['Minimum time left', 'Time', 'MIN', 'TimeLeft' ],
-    'MAX(TimeLeft)' => ['Maximum time left', 'Time', 'MAX', 'TimeLeft' ],
-
-    'SUM(Created-Resolved)'
-        => ['Summary of Created-Resolved', 'DateTimeInterval', 'SUM', 'Created', 'Resolved' ],
-    'AVG(Created-Resolved)'
-        => ['Average Created-Resolved', 'DateTimeInterval', 'AVG', 'Created', 'Resolved' ],
-    'MIN(Created-Resolved)'
-        => ['Minimum Created-Resolved', 'DateTimeInterval', 'MIN', 'Created', 'Resolved' ],
-    'MAX(Created-Resolved)'
-        => ['Maximum Created-Resolved', 'DateTimeInterval', 'MAX', 'Created', 'Resolved' ],
-
-    'SUM(Created-LastUpdated)'
-        => ['Summary of Created-LastUpdated', 'DateTimeInterval', 'SUM', 'Created', 'LastUpdated' ],
-    'AVG(Created-LastUpdated)'
-        => ['Average Created-LastUpdated', 'DateTimeInterval', 'AVG', 'Created', 'LastUpdated' ],
-    'MIN(Created-LastUpdated)'
-        => ['Minimum Created-LastUpdated', 'DateTimeInterval', 'MIN', 'Created', 'LastUpdated' ],
-    'MAX(Created-LastUpdated)'
-        => ['Maximum Created-LastUpdated', 'DateTimeInterval', 'MAX', 'Created', 'LastUpdated' ],
 );
+
+foreach my $field (qw(TimeWorked TimeEstimated TimeLeft)) {
+    my $friendly = lc join ' ', split /(?<=[a-z])(?=A-Z)/, $field;
+    push @STATISTICS, (
+        "SUM($field)" => ["Total $friendly",   'Time', 'SUM', $field ],
+        "AVG($field)" => ["Average $friendly", 'Time', 'AVG', $field ],
+        "MIN($field)" => ["Minimum $friendly", 'Time', 'MIN', $field ],
+        "MAX($field)" => ["Maximum $friendly", 'Time', 'MAX', $field ],
+    );
+}
+
+
+foreach my $pair (qw(
+    Created-Resolved
+    Created-LastUpdated
+    Starts-Started
+    Due-Resolved
+    Started-Resolved
+)) {
+    my ($from, $to) = split /-/, $pair;
+    push @STATISTICS, (
+        "SUM($pair)" => ["Summary of $pair", 'DateTimeInterval', 'SUM', $from, $to ],
+        "AVG($pair)" => ["Average $pair", 'DateTimeInterval', 'AVG', $from, $to ],
+        "MIN($pair)" => ["Minimum $pair", 'DateTimeInterval', 'MIN', $from, $to ],
+        "MAX($pair)" => ["Maximum $pair", 'DateTimeInterval', 'MAX', $from, $to ],
+    );
+}
+
 our %STATISTICS;
 
 our %STATISTICS_META = (

commit f77af1c0b9e48dfd1b7f5ebdc9092682fc0aa8c0
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Jul 1 17:06:46 2011 +0400

    abstract seconds -> string conversion

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index 57b661f..0c2e71c 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -227,6 +227,22 @@ foreach my $pair (qw(
 
 our %STATISTICS;
 
+my $duration_to_string_cb = sub {
+    my $self = shift;
+    my %args = @_;
+    my $v = $args{'VALUE'};
+    unless ( ref $v ) {
+        return $self->loc("(no value)") unless defined $v && length $v;
+        return RT::Date->new( $self->CurrentUser )->DurationAsString( $v );
+    }
+
+    my $date = RT::Date->new( $self->CurrentUser );
+    foreach my $e ( values %$v ) {
+        $e = $date->DurationAsString( $e ) if defined $e && length $e;
+        $e = $self->loc("(no value)") unless defined $e && length $e;
+    }
+};
+
 our %STATISTICS_META = (
     Count => {
         Function => sub {
@@ -254,15 +270,9 @@ our %STATISTICS_META = (
         Function => sub {
             my $self = shift;
             my ($function, $field) = @_;
-            return (FUNCTION => $function, FIELD => $field);
-        },
-        Display => sub {
-            my $self = shift;
-            my %args = @_;
-            my $v = $args{'VALUE'};
-            return $self->loc("(no value)") unless defined $v && length $v;
-            return RT::Date->new( $self->CurrentUser )->DurationAsString( $v*60 );
+            return (FUNCTION => "$function(?)*60", FIELD => $field);
         },
+        Display => $duration_to_string_cb,
     },
     DateTimeInterval => {
         Function => sub {
@@ -276,13 +286,7 @@ our %STATISTICS_META = (
 
             return (FUNCTION => "$function($interval)");
         },
-        Display => sub {
-            my $self = shift;
-            my %args = @_;
-            my $v = $args{'VALUE'};
-            return $self->loc("(no value)") unless defined $v && length $v;
-            return RT::Date->new( $self->CurrentUser )->DurationAsString( $v );
-        },
+        Display => $duration_to_string_cb,
     },
 );
 

commit 24023cd8baa24d85fc00eb91f5b03b4929747b9c
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Jul 1 17:12:00 2011 +0400

    SubValues for stats with SQL only
    
    This allows to group several stats like calculatables

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index 0c2e71c..cd5a429 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -450,6 +450,15 @@ sub SetupGroupings {
                 $e->{'FUNCTION'} = 'NULL';
                 $e->{'NAME'} = $self->Column( FUNCTION => 'NULL' );
             }
+            elsif ( $e->{'META'}{'SubValues'} ) {
+                my %tmp = $code->( $self, @{ $e->{INFO} }[2 .. scalar @{ $e->{INFO} } -1 ] );
+                $e->{'NAME'} = 'postfunction'. $self->{'postfunctions'}++;
+                while ( my ($k, $v) = each %tmp ) {
+                    $e->{'MAP'}{ $k }{'NAME'} = $self->Column( %$v );
+                    @{ $e->{'MAP'}{ $k } }{'FUNCTION', 'ALIAS', 'FIELD'} =
+                        @{ $v }{'FUNCTION', 'ALIAS', 'FIELD'};
+                }
+            }
             else {
                 my %tmp = $code->( $self, @{ $e->{INFO} }[2 .. scalar @{ $e->{INFO} } -1 ] );
                 $e->{'NAME'} = $self->Column( %tmp );
@@ -601,9 +610,12 @@ sub CalculatePostFunctions {
     my $info = $self->{'column_info'};
     foreach my $column ( values %$info ) {
         next unless $column->{'TYPE'} eq 'statistic';
-        next unless $column->{'META'}{'Calculate'};
-
-        $self->CalculatePostFunction( $column );
+        if ( $column->{'META'}{'Calculate'} ) {
+            $self->CalculatePostFunction( $column );
+        }
+        elsif ( $column->{'META'}{'SubValues'} ) {
+            $self->MapSubValues( $column );
+        }
     }
 }
 
@@ -629,6 +641,23 @@ sub CalculatePostFunction {
     }
 }
 
+sub MapSubValues {
+    my $self = shift;
+    my $info = shift;
+
+    my $to = $info->{'NAME'};
+    my $map = $info->{'MAP'};
+
+    foreach my $item ( @{ $self->{'items'} } ) {
+        my $dst = $item->{'values'}{ $to } = { };
+        while (my ($k, $v) = each %{ $map } ) {
+            $dst->{ $k } = delete $item->{'values'}{ $v->{'NAME'} };
+            delete $item->{'fetched'}{ $v->{'NAME'} };
+        }
+        $item->{'fetched'}{ $to } = 1;
+    }
+}
+
 sub GenerateDateFunction {
     my $self = shift;
     my %args = @_;

commit 26581169ab91409b6d2e3dc54c87ed4ef2538546
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Jul 1 17:23:57 2011 +0400

    TimeAll and DateTimeIntervalAll statistics

diff --git a/lib/RT/Report/Tickets.pm b/lib/RT/Report/Tickets.pm
index cd5a429..c7868ca 100644
--- a/lib/RT/Report/Tickets.pm
+++ b/lib/RT/Report/Tickets.pm
@@ -201,6 +201,7 @@ our @STATISTICS = (
 foreach my $field (qw(TimeWorked TimeEstimated TimeLeft)) {
     my $friendly = lc join ' ', split /(?<=[a-z])(?=A-Z)/, $field;
     push @STATISTICS, (
+        "ALL($field)" => [ucfirst $friendly,   'TimeAll',     $field ],
         "SUM($field)" => ["Total $friendly",   'Time', 'SUM', $field ],
         "AVG($field)" => ["Average $friendly", 'Time', 'AVG', $field ],
         "MIN($field)" => ["Minimum $friendly", 'Time', 'MIN', $field ],
@@ -218,6 +219,7 @@ foreach my $pair (qw(
 )) {
     my ($from, $to) = split /-/, $pair;
     push @STATISTICS, (
+        "ALL($pair)" => [$pair, 'DateTimeIntervalAll', $from, $to ],
         "SUM($pair)" => ["Summary of $pair", 'DateTimeInterval', 'SUM', $from, $to ],
         "AVG($pair)" => ["Average $pair", 'DateTimeInterval', 'AVG', $from, $to ],
         "MIN($pair)" => ["Minimum $pair", 'DateTimeInterval', 'MIN', $from, $to ],
@@ -274,6 +276,20 @@ our %STATISTICS_META = (
         },
         Display => $duration_to_string_cb,
     },
+    TimeAll => {
+        SubValues => sub { return ('Minimum', 'Average', 'Maximum', 'Summary') },
+        Function => sub {
+            my $self = shift;
+            my $field = shift;
+            return (
+                Minimum => { FUNCTION => "MIN(?)*60", FIELD => $field },
+                Average => { FUNCTION => "AVG(?)*60", FIELD => $field },
+                Maximum => { FUNCTION => "MAX(?)*60", FIELD => $field },
+                Summary => { FUNCTION => "SUM(?)*60", FIELD => $field },
+            );
+        },
+        Display => $duration_to_string_cb,
+    },
     DateTimeInterval => {
         Function => sub {
             my $self = shift;
@@ -288,6 +304,26 @@ our %STATISTICS_META = (
         },
         Display => $duration_to_string_cb,
     },
+    DateTimeIntervalAll => {
+        SubValues => sub { return ('Minimum', 'Average', 'Maximum', 'Summary') },
+        Function => sub {
+            my $self = shift;
+            my ($from, $to) = @_;
+
+            my $interval = $self->DateTimeIntervalFunction(
+                From => { FUNCTION => $self->NotSetDateToNullFunction( FIELD => $from ) },
+                To   => { FUNCTION => $self->NotSetDateToNullFunction( FIELD => $to ) },
+            );
+
+            return (
+                Minimum => { FUNCTION => "MIN($interval)" },
+                Average => { FUNCTION => "AVG($interval)" },
+                Maximum => { FUNCTION => "MAX($interval)" },
+                Summary => { FUNCTION => "SUM($interval)" },
+            );
+        },
+        Display => $duration_to_string_cb,
+    },
 );
 
 sub Groupings {

-----------------------------------------------------------------------


More information about the Rt-commit mailing list