From 1423434dfd054329a16dec92a489ac84e4ed3a59 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= <tseeker@nocternity.net>
Date: Mon, 6 Feb 2012 10:45:39 +0100
Subject: [PATCH] Transitive dependencies

The amount of unsatisfied transitive dependencies is displayed in the
tasks list (and used to sort it) and on task pages.
---
 database/tasks-functions.sql      | 14 ++++++++++++--
 includes/t-data/dao_tasks.inc.php |  8 +++++---
 includes/t-tasks/views.inc.php    | 17 +++++++++++++++--
 3 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/database/tasks-functions.sql b/database/tasks-functions.sql
index 6eb66e8..d31994a 100644
--- a/database/tasks-functions.sql
+++ b/database/tasks-functions.sql
@@ -93,7 +93,8 @@ CREATE VIEW tasks_list
 			ct.completed_task_time AS completed_at,
 			u2.user_view_name AS completed_by ,
 			t.task_priority AS priority ,
-			bd.bad_deps AS missing_dependencies
+			bd.bad_deps AS missing_dependencies ,
+			mtd.trans_missing AS total_missing_dependencies
 		FROM tasks t
 			INNER JOIN users_view u1 ON u1.user_id = t.user_id
 			LEFT OUTER JOIN completed_tasks ct ON ct.task_id = t.task_id
@@ -105,7 +106,16 @@ CREATE VIEW tasks_list
 							ON dct.task_id = td.task_id_depends
 					WHERE dct.task_id IS NULL
 					GROUP BY td.task_id
-				) AS bd ON bd.task_id = t.task_id;
+				) AS bd ON bd.task_id = t.task_id
+			LEFT OUTER JOIN (
+				SELECT tdn.task_id , COUNT( DISTINCT task_id_copyof ) AS trans_missing
+					FROM taskdep_nodes tdn
+						LEFT OUTER JOIN completed_tasks ct
+							ON ct.task_id = task_id_copyof
+					WHERE NOT tnode_reverse AND ct.task_id IS NULL
+						AND tdn.task_id <> tdn.task_id_copyof
+					GROUP BY tdn.task_id
+				) AS mtd ON mtd.task_id = t.task_id;
 
 GRANT SELECT ON tasks_list TO :webapp_user;
 
diff --git a/includes/t-data/dao_tasks.inc.php b/includes/t-data/dao_tasks.inc.php
index 482336d..ebda39c 100644
--- a/includes/t-data/dao_tasks.inc.php
+++ b/includes/t-data/dao_tasks.inc.php
@@ -27,7 +27,7 @@ class DAO_Tasks
 			.				'priority '
 			.			'ELSE '
 			.				'-1 '
-			.		'END ) DESC , missing_dependencies ASC NULLS FIRST , added_at DESC' )->execute( );
+			.		'END ) DESC , total_missing_dependencies ASC NULLS FIRST , added_at DESC' )->execute( );
 	}
 
 	public function getAllActiveTasks( )
@@ -43,7 +43,7 @@ class DAO_Tasks
 		return $this->query(
 			'SELECT * FROM tasks_list '
 			.	'WHERE completed_at IS NULL AND missing_dependencies IS NOT NULL '
-			.	'ORDER BY priority DESC , missing_dependencies ASC , added_at DESC' )->execute( );
+			.	'ORDER BY priority DESC , total_missing_dependencies ASC , added_at DESC' )->execute( );
 	}
 
 
@@ -98,10 +98,12 @@ class DAO_Tasks
 		$task->dependencies = $this->query(
 			'SELECT t.task_id AS id , t.task_title AS title , t.item_id AS item , '
 			.		'i.item_name AS item_name , '
-			.		'( ct.completed_task_time IS NOT NULL ) AS completed '
+			.		'( ct.completed_task_time IS NOT NULL ) AS completed , '
+			.		'tl.total_missing_dependencies AS missing_dependencies '
 			.	'FROM task_dependencies td '
 			.		'INNER JOIN tasks t ON t.task_id = td.task_id_depends '
 			.		'INNER JOIN items i USING ( item_id ) '
+			.		'INNER JOIN tasks_list tl ON tl.id = t.task_id '
 			.		'LEFT OUTER JOIN completed_tasks ct ON ct.task_id = t.task_id '
 			.	'WHERE td.task_id = $1 '
 			.	'ORDER BY i.item_name , t.task_priority DESC , t.task_title' )->execute( $id );
diff --git a/includes/t-tasks/views.inc.php b/includes/t-tasks/views.inc.php
index 64f8009..f141473 100644
--- a/includes/t-tasks/views.inc.php
+++ b/includes/t-tasks/views.inc.php
@@ -87,7 +87,10 @@ class View_AllTasks
 				$end = 'y';
 			}
 			array_push( $cell ,
-				HTML::make( 'dd' )->appendText( "{$task->missing_dependencies} missing dependenc$end" ) );
+				$md = HTML::make( 'dd' )->appendText( "{$task->missing_dependencies} missing dependenc$end" ) );
+			if ( $task->total_missing_dependencies != $task->missing_dependencies ) {
+				$md->appendText( " ({$task->total_missing_dependencies} when counting transitive dependencies)" );
+			}
 
 			foreach ( $cell as $entry ) {
 				$entry->setAttribute( 'class' , 'missing-deps' );
@@ -160,7 +163,10 @@ class View_Tasks
 				$end = 'y';
 			}
 			array_push( $cell ,
-				HTML::make( 'dd' )->appendText( "{$task->missing_dependencies} missing dependenc$end" ) );
+				$md = HTML::make( 'dd' )->appendText( "{$task->missing_dependencies} missing dependenc$end" ) );
+			if ( $task->total_missing_dependencies != $task->missing_dependencies ) {
+				$md->appendText( " ({$task->total_missing_dependencies} when counting transitive dependencies)" );
+			}
 
 			foreach ( $cell as $entry ) {
 				$entry->setAttribute( 'class' , 'missing-deps' );
@@ -345,6 +351,13 @@ class View_TaskDependencies
 								. $this->task->id . '&to=' . $dependency->id )
 							->appendText( 'remove') )
 						->appendText( ')' );
+					if ( $dependency->missing_dependencies != 0 ) {
+						$end = $dependency->missing_dependencies > 1 ? 'ies' : 'y';
+						$entry->appendElement( HTML::make( 'ul' )
+							->appendElement( $mdeps = HTML::make( 'li' ) ) );
+						$mdeps->appendText( $dependency->missing_dependencies
+								. " missing dependenc$end (transitively)" );
+					}
 				}
 			}