From 3f5f1eb6ac5422799a0a7bb7f27f1d7060b9c625 Mon Sep 17 00:00:00 2001
From: BeezyT <timo@ezdesign.de>
Date: Tue, 10 Apr 2012 09:26:12 +0000
Subject: [PATCH] refs #2714, refs #3073

 * flat settings are passed to graph views and exports
 * csv renderer does not do flattening anymore. the new api parameters can be used instead - js and tests updated accordingly
 * aggregate rows are italic (imo, the plus logo would be misleading because it would suggest clickability)
 * disable row evolution on flat tables for performance reasons
 * minor language adjustments

git-svn-id: http://dev.piwik.org/svn/trunk@6181 59fd770c-687e-43c8-a1e3-f5a4ff64c105
---
 core/API/DataTableManipulator/Flattener.php   |  21 ++++--
 core/API/DocumentationGenerator.php           |   5 +-
 core/API/ResponseBuilder.php                  |   5 --
 core/DataTable/Renderer/Csv.php               |  68 +-----------------
 lang/en.php                                   |   3 +-
 plugins/CoreHome/templates/datatable.css      |   4 ++
 plugins/CoreHome/templates/datatable.js       |  25 +++++--
 plugins/CoreHome/templates/datatable_cell.tpl |   5 +-
 tests/integration/CsvExport.test.php          |   6 +-
 ...CustomVariables.getCustomVariables_day.csv | Bin 2344 -> 2408 bytes
 ...CustomVariables.getCustomVariables_day.csv | Bin 3118 -> 3374 bytes
 ...inner1_trans-de__VisitsSummary.get_day.csv | Bin 514 -> 566 bytes
 12 files changed, 49 insertions(+), 93 deletions(-)

diff --git a/core/API/DataTableManipulator/Flattener.php b/core/API/DataTableManipulator/Flattener.php
index d9e5f1014e..f620d9a1ad 100644
--- a/core/API/DataTableManipulator/Flattener.php
+++ b/core/API/DataTableManipulator/Flattener.php
@@ -67,13 +67,17 @@ class Piwik_API_DataTableManipulator_Flattener extends Piwik_API_DataTableManipu
 	private function flattenRow(Piwik_DataTable_Row $row, Piwik_DataTable $dataTable, $date,
 			$labelPrefix = '', $parentLogo = false) {
 		
-		$label = trim($row->getColumn('label'));
-		if (substr($label, 0, 1) == '/' && $this->recursiveLabelSeparator == '/')
+		$label = $row->getColumn('label');
+		if ($label !== false)
 		{
-			$label = substr($label, 1);
+			$label = trim($label);
+			if (substr($label, 0, 1) == '/' && $this->recursiveLabelSeparator == '/')
+			{
+				$label = substr($label, 1);
+			}
+			$label = $labelPrefix . $label;
+			$row->setColumn('label', $label);
 		}
-		$label = $labelPrefix . $label;
-		$row->setColumn('label', $label);
 		
 		$logo = $row->getMetadata('logo');
 		if ($logo === false && $parentLogo !== false)
@@ -87,14 +91,17 @@ class Piwik_API_DataTableManipulator_Flattener extends Piwik_API_DataTableManipu
 		
 		if ($subTable === null)
 		{
+			if ($this->includeAggregateRows)
+			{
+				$row->setMetadata('is_aggregate', 0);
+			}
 			$dataTable->addRow($row);
 		}
 		else
 		{
 			if ($this->includeAggregateRows)
 			{
-				$aggregate = Piwik_Translate('CoreHome_Aggregate');
-				$row->setColumn('label', $row->getColumn('label').' ['.$aggregate.']');
+				$row->setMetadata('is_aggregate', 1);
 				$dataTable->addRow($row);
 			}
 			$prefix = $label . $this->recursiveLabelSeparator;
diff --git a/core/API/DocumentationGenerator.php b/core/API/DocumentationGenerator.php
index 92431f5fcf..eca8c41edd 100644
--- a/core/API/DocumentationGenerator.php
+++ b/core/API/DocumentationGenerator.php
@@ -174,16 +174,17 @@ class Piwik_API_DocumentationGenerator
 		// the parameter 'hideIdSubDatable' is used for integration tests only
 		// the parameter 'serialize' sets php outputs human readable, used in integration tests and debug
 		// the parameter 'language' sets the language for the response (eg. country names)
-		// the parameter 'includeInnerNodes' is used for nested csv/tsv export
+		// the parameter 'flat' reduces a hierarchical table to a single level by concatenating labels
+		// the parameter 'include_aggregate_rows' can be set to include inner nodes in flat reports
 		// the parameter 'translateColumnNames' can be set to translate metric names in csv/tsv exports
 		$aParameters['format'] = false;
 		$aParameters['hideIdSubDatable'] = false;
 		$aParameters['serialize'] = false;
 		$aParameters['language'] = false;
-		$aParameters['includeInnerNodes'] = false;
 		$aParameters['translateColumnNames'] = false;
         $aParameters['label'] = false;
 		$aParameters['flat'] = false;
+		$aParameters['include_aggregate_rows'] = false;
         $aParameters['filter_truncate'] = false;
 		
 		$moduleName = Piwik_API_Proxy::getInstance()->getModuleNameFromClassName($class);
diff --git a/core/API/ResponseBuilder.php b/core/API/ResponseBuilder.php
index eb0af44bef..a007ddc3d2 100644
--- a/core/API/ResponseBuilder.php
+++ b/core/API/ResponseBuilder.php
@@ -205,12 +205,7 @@ class Piwik_API_ResponseBuilder
 		}
 		else if($format == 'csv' || $format == 'tsv')
 		{
-			$renderer->setIncludeInnerNodes(Piwik_Common::getRequestVar('includeInnerNodes', true, 'int', $this->request));
 			$renderer->setConvertToUnicode(Piwik_Common::getRequestVar('convertToUnicode', true, 'int', $this->request));
-			if (substr($method, 0, 8) == 'Actions.')
-			{
-				$renderer->setRecursiveLabelSeparator('/');
-			}
 		}
 		
 		// prepare translation of column names
diff --git a/core/DataTable/Renderer/Csv.php b/core/DataTable/Renderer/Csv.php
index 2d906d9994..41d13c9962 100644
--- a/core/DataTable/Renderer/Csv.php
+++ b/core/DataTable/Renderer/Csv.php
@@ -52,21 +52,6 @@ class Piwik_DataTable_Renderer_Csv extends Piwik_DataTable_Renderer
 	 */
 	public $convertToUnicode = true;
 	
-	/**
-	 * Whether to include inner nodes in the export or not
-	 * (only works if expanded=1)
-	 * 
-	 * @var bool
-	 */
-	public $includeInnerNodes = false;
-	
-	/**
-	 * Separator for building recursive labels (or paths)
-	 * 
-	 * @var string
-	 */
-	public $recursiveLabelSeparator = ' - ';
-	
 	/**
 	 * idSubtable will be exported in a column called 'idsubdatatable'
 	 *
@@ -103,21 +88,11 @@ class Piwik_DataTable_Renderer_Csv extends Piwik_DataTable_Renderer
 		$this->convertToUnicode = $bool;
 	}
 	
-	public function setIncludeInnerNodes($bool)
-	{
-		$this->includeInnerNodes = $bool;
-	}
-	
 	public function setSeparator($separator)
 	{
 		$this->separator = $separator;
 	}
 	
-	public function setRecursiveLabelSeparator($separator)
-	{
-		$this->recursiveLabelSeparator = $separator;
-	}
-	
 	protected function renderTable($table)
 	{
 		if($table instanceof Piwik_DataTable_Array)
@@ -162,7 +137,7 @@ class Piwik_DataTable_Renderer_Csv extends Piwik_DataTable_Renderer
 		return $str;
 	}
 	
-	protected function renderDataTable( $table, $returnRowArray = false, $labelPrefix = false )
+	protected function renderDataTable( $table )
 	{	
 		if($table instanceof Piwik_DataTable_Simple)
 		{
@@ -216,18 +191,7 @@ class Piwik_DataTable_Renderer_Csv extends Piwik_DataTable_Renderer
 				else
 				{
 					$allColumns[$name] = true;
-					if ($name == 'label' && $labelPrefix)
-					{
-						if (substr($value, 0, 1) == '/' && $this->recursiveLabelSeparator == '/')
-						{
-							$value = substr($value, 1);
-						}
-						$csvRow[$name] = $labelPrefix.$value;
-					}
-					else
-					{
-						$csvRow[$name] = $value;
-					}
+					$csvRow[$name] = $value;
 				}
 			}
 
@@ -264,26 +228,7 @@ class Piwik_DataTable_Renderer_Csv extends Piwik_DataTable_Renderer
 				}
 			}
 			
-			if($this->isRenderSubtables()
-				&& $row->getIdSubDataTable() !== null)
-			{
-				if($this->includeInnerNodes)
-				{
-					$csv[] = $csvRow;
-				}
-				try{
-					$idSubTable = $row->getIdSubDataTable();
-					$subTable = Piwik_DataTable_Manager::getInstance()->getTable($idSubTable);
-					$prefix = isset($csvRow['label']) ? $csvRow['label'].$this->recursiveLabelSeparator : '';
-					$csv = array_merge($csv, $this->renderDataTable($subTable, true, $prefix));
-				} catch (Exception $e) {
-					// the subtables are not loaded we don't do anything 
-				}
-			}
-			else
-			{
-				$csv[] = $csvRow;
-			}
+			$csv[] = $csvRow;
 		}
 		
 		// now we make sure that all the rows in the CSV array have all the columns
@@ -298,13 +243,6 @@ class Piwik_DataTable_Renderer_Csv extends Piwik_DataTable_Renderer
 			}
 		}
 		
-		// return the array of rows instead of the formatted string
-		// this is used for recursive calls
-		if($returnRowArray)
-		{
-			return $csv;
-		}
-		
 		$str = '';		
 		
 		// specific case, we have only one column and this column wasn't named properly (indexed by a number)
diff --git a/lang/en.php b/lang/en.php
index f9a33bd365..d3e794731e 100644
--- a/lang/en.php
+++ b/lang/en.php
@@ -439,8 +439,7 @@ $translations = array(
 	'CoreHome_IncludeAllPopulation_js' => 'Include all population',
 	'CoreHome_ExcludeLowPopulation_js' => 'Exclude low population',
 	'CoreHome_DataTableIncludeAggregateRows_js' => 'Include aggregate rows',
-	'CoreHome_DataTableExcludeAggregateRows_js' => 'Exclude aggregate rows',
-	'CoreHome_Aggregate' => 'aggregate',
+	'CoreHome_DataTableExcludeAggregateRows_js' => 'Hide aggregate rows',
 	'CoreHome_PageOf_js' => '%1$s of %2$s',
 	'CoreHome_FlattenDataTable_js' => 'Flatten the table',
 	'CoreHome_UnFlattenDataTable_js' => 'Un-flatten the table',
diff --git a/plugins/CoreHome/templates/datatable.css b/plugins/CoreHome/templates/datatable.css
index 2e3475d10b..cc2eef87db 100644
--- a/plugins/CoreHome/templates/datatable.css
+++ b/plugins/CoreHome/templates/datatable.css
@@ -165,6 +165,10 @@ table.dataTable th.label {
 	border-left: 0;
 }
 
+table.dataTable span.label.highlighted {
+	font-style: italic;
+}
+
 /* the cell containing the subdatatable */
 table.dataTable .cellSubDataTable {
 	margin: 0;
diff --git a/plugins/CoreHome/templates/datatable.js b/plugins/CoreHome/templates/datatable.js
index ffaa67b7f4..e60fc509b8 100644
--- a/plugins/CoreHome/templates/datatable.js
+++ b/plugins/CoreHome/templates/datatable.js
@@ -521,7 +521,11 @@ dataTable.prototype =
 			.click(function(){
 				var viewDataTable = $(this).attr('format');
 				self.setActiveIcon(this, domElem);
-				self.resetAllFilters();
+				
+				var filters = self.resetAllFilters();
+				self.param.flat = filters.flat;
+				self.param.include_aggregate_rows = filters.include_aggregate_rows;
+				
 				self.param.viewDataTable = viewDataTable;
 				self.reloadAjaxDataTable();
 				self.notifyWidgetParametersChange($(this), {viewDataTable: self.param.viewDataTable});
@@ -632,10 +636,15 @@ dataTable.prototype =
 						+'&period='+period
 						+'&date='+param_date
 						+ ( typeof self.param.filter_pattern != "undefined" ? '&filter_pattern=' + self.param.filter_pattern : '')
-						+ ( typeof self.param.filter_pattern_recursive != "undefined" ? '&filter_pattern_recursive=' + self.param.filter_pattern_recursive : '')
-						+'&expanded=1';
-				if (format == 'CSV' || format == 'TSV') {
-					str += '&includeInnerNodes=1';
+						+ ( typeof self.param.filter_pattern_recursive != "undefined" ? '&filter_pattern_recursive=' + self.param.filter_pattern_recursive : '');
+				
+				if (typeof self.param.flat != "undefined" && self.param.flat) {
+					str += '&flat=1';
+					if (typeof self.param.include_aggregate_rows != "undefined" && self.param.include_aggregate_rows) {
+						str += '&includeAggregateRows=1';
+					}
+				} else {
+					str += '&expanded=1';
 				}
 				if (format == 'CSV' || format == 'TSV' || format == 'RSS') {
 					str += '&translateColumnNames=1&language='+piwik.language;
@@ -697,9 +706,11 @@ dataTable.prototype =
 		
 		var ul = $('div.tableConfiguration ul', domElem);
 		
-		if (ul.find('li').size() == 0)
+		if (ul.find('li').size() == 0 ||
+			!(self.param.viewDataTable == 'table' || self.param.viewDataTable == 'tableAllColumns'
+				|| self.param.viewDataTable == 'tableGoals'))
 		{
-			// hide the icon when there are no actions available
+			// hide the icon when there are no actions available or we're not in a table view
 			$('div.tableConfiguration', domElem).remove();
 			return;
 		}
diff --git a/plugins/CoreHome/templates/datatable_cell.tpl b/plugins/CoreHome/templates/datatable_cell.tpl
index 453f03d1eb..0ba698ab44 100644
--- a/plugins/CoreHome/templates/datatable_cell.tpl
+++ b/plugins/CoreHome/templates/datatable_cell.tpl
@@ -1,6 +1,7 @@
 {if $column=='label'}
 	<div class="dataTableRowActions">
-		{if !isset($properties.disable_row_evolution) || $properties.disable_row_evolution === false}
+		{if (!isset($properties.disable_row_evolution) || $properties.disable_row_evolution === false)
+				&& !(isset($javascriptVariablesToSet.flat) && $javascriptVariablesToSet.flat == 1)}
 			<a href="#" class="actionRowEvolution"><img src="themes/default/images/row_evolution.png" alt="" /></a>
 		{/if}
 	</div>
@@ -14,7 +15,7 @@
 {/if}
 {if $column=='label'}
 	{logoHtml metadata=$row.metadata alt=$row.columns.label}
-	<span class='label'>{* make sure there are no whitespaces inside the span
+	<span class='label{if !empty($row.metadata.is_aggregate) && $row.metadata.is_aggregate } highlighted{/if}'>{* make sure there are no whitespaces inside the span
 *}{/if}{*
 *}{if isset($row.columns[$column])}{$row.columns[$column]}{else}{$defaultWhenColumnValueNotDefined}{/if}{*
 *}{if $column=='label'}</span>{/if}
diff --git a/tests/integration/CsvExport.test.php b/tests/integration/CsvExport.test.php
index cae94a4822..4d55b9f7fa 100755
--- a/tests/integration/CsvExport.test.php
+++ b/tests/integration/CsvExport.test.php
@@ -15,13 +15,13 @@ class Test_Piwik_Integration_CsvExport extends Test_Piwik_Integration_TwoVisitsW
 	{
 		$apiToCall = array('VisitsSummary.get', 'CustomVariables.getCustomVariables');
 
-		$enExtraParam = array('expanded' => 1, 'includeInnerNodes' => 0, 'translateColumnNames' => 1);
+		$enExtraParam = array('expanded' => 0, 'flat' => 1, 'include_aggregate_rows' => 0, 'translateColumnNames' => 1);
 
-		$deExtraParam = array('expanded' => 1, 'includeInnerNodes' => 1, 'translateColumnNames' => 1);
+		$deExtraParam = array('expanded' => 0, 'flat' => 1, 'include_aggregate_rows' => 1, 'translateColumnNames' => 1);
 
 		return array(
 			array($apiToCall, array('idSite' => $this->idSite, 'date' => $this->dateTime, 'format' => 'csv',
-									'otherRequestParameters' => array('expanded' => 0),
+									'otherRequestParameters' => array('expanded' => 0, 'flat' => 0),
 									'testSuffix' => '_xp0')),
 			
 			array($apiToCall, array('idSite' => $this->idSite, 'date' => $this->dateTime, 'format' => 'csv',
diff --git a/tests/integration/expected/test_csvExport_xp1_inner0_trans-en__CustomVariables.getCustomVariables_day.csv b/tests/integration/expected/test_csvExport_xp1_inner0_trans-en__CustomVariables.getCustomVariables_day.csv
index c4fdcda7d9eacf198c697eb9d1c3e83cb02a5943..74ffd5973fba0dcdd8a314dc6da682c5b5190088 100644
GIT binary patch
delta 88
zcmZ1>^g?KZ5v!szLn%WsLkUAZLoR~?Ll{FMLlHwJkW6C8VMqmvlucgFp}jed)q|NR
GrHufNHxwNJ

delta 24
ccmaDMv_fcu5i4WZ<mVjPo9kFTn8D0O0Bo@cdjJ3c

diff --git a/tests/integration/expected/test_csvExport_xp1_inner1_trans-de__CustomVariables.getCustomVariables_day.csv b/tests/integration/expected/test_csvExport_xp1_inner1_trans-de__CustomVariables.getCustomVariables_day.csv
index 052c9e3dfd1e8211dfad38e63de217ed5d942c61..3db9bbd8f8c101aa2c87b6c18320f8028de6650d 100644
GIT binary patch
delta 422
zcmZ1{u}*5k1}1$S2499$h7yKEh7=$!0kZQLtQZs+G8u{);(;RRKv)D6O^3)%UeA=s
ztixb9nV-3mQD-tQv+m?g%vO_MFkb<QZr;tZoDnD-&z1~Ubdb$3JshaH2xzbZ&;k%k
zfguTONhwgQ3M>K=PXk(*2gDGyAV(-LgaNHA0*WO9b>skL6u>Hy88YCeA?cdDn$vRf
z3HE@=)7Z_xPC3mk$u#)^rxn;Cl3e*fw#?)OTo#k}u^CKe;WmOgP#4G+saIgo1sYE$
irvjZ13@aq8GkGnyFwi{)llOBQg5C9=+nxo;X8-^-om|%d

delta 183
zcmZ1{wN7Hg2Bygmm=Y!*VAh(P$Lt5BQzrjm>6@Iu=Ct__%QD8vkGQoaUtlwvyo^mt
zU4cQDL4hHRA(0`6p_CyN$j)QPXD9*EDL`HtLne@)%8)YoJe&FCd+bd>?6Y|T#~H@S
s4P0hGEHU{KR~VRf;kE!8>@fKNw;YgmQzUHUL>}eIJ9rExzu~b10JM)d{{R30

diff --git a/tests/integration/expected/test_csvExport_xp1_inner1_trans-de__VisitsSummary.get_day.csv b/tests/integration/expected/test_csvExport_xp1_inner1_trans-de__VisitsSummary.get_day.csv
index 83685ea0f42830f29eeead5bbd8235f4bcf1ad7e..9962efd45a82faccdf392d9c60bb4085fb0507d4 100644
GIT binary patch
delta 64
zcmZo-*~YTr6r;WlgD*oWLkUA7LkbX=0NHsARtyRZnGD4Y@j#JuAS?okrbA>WpJcRT
J(P1!P007@C4cq_#

delta 11
ScmdnS(!{di6yxMyj1~YJyaa*(

-- 
GitLab