"Add dependencies" implemented

A few bugs in the SQL scripts have been fixed. It is now possible to add
new dependencies to a task from the details page.
This commit is contained in:
Emmanuel BENOîT 2012-02-05 20:55:09 +01:00
parent 60d4fe1199
commit ba3fcc2470
8 changed files with 161 additions and 4 deletions

View file

@ -22,6 +22,7 @@ GRANT SELECT,UPDATE ON notes_note_id_seq TO :webapp_user;
CREATE SEQUENCE task_dependencies_taskdep_id_seq INCREMENT 1 CREATE SEQUENCE task_dependencies_taskdep_id_seq INCREMENT 1
MINVALUE 1 MAXVALUE 9223372036854775807 MINVALUE 1 MAXVALUE 9223372036854775807
START 1 CACHE 1; START 1 CACHE 1;
GRANT SELECT,UPDATE ON task_dependencies_taskdep_id_seq TO :webapp_user;
-- Tables -- Tables

View file

@ -287,7 +287,7 @@ CREATE OR REPLACE FUNCTION tasks_add_dependency( t_id INT , t_dependency INT )
SECURITY INVOKER SECURITY INVOKER
AS $tasks_add_dependency$ AS $tasks_add_dependency$
BEGIN BEGIN
INSERT INTO task_dependencies( task_id , task_id_depends_on ) INSERT INTO task_dependencies( task_id , task_id_depends )
VALUES ( t_id , t_dependency ); VALUES ( t_id , t_dependency );
RETURN 0; RETURN 0;
EXCEPTION EXCEPTION

View file

@ -57,7 +57,7 @@ class DAO_Items
public function getLineage( Data_Item $item ) public function getLineage( Data_Item $item )
{ {
if ( is_array( $item->lineage ) ) { if ( is_array( $item->lineage ) ) {
return; return $item->lineage;
} }
$query = $this->query( $query = $this->query(
@ -80,6 +80,7 @@ class DAO_Items
array_push( $stack , $entry->item_id ); array_push( $stack , $entry->item_id );
} }
$item->lineage = $stack; $item->lineage = $stack;
return $item->lineage;
} }

View file

@ -107,7 +107,7 @@ class DAO_Tasks
. 'INNER JOIN items i USING ( item_id ) ' . 'INNER JOIN items i USING ( item_id ) '
. 'LEFT OUTER JOIN completed_tasks ct ON ct.task_id = t.task_id ' . 'LEFT OUTER JOIN completed_tasks ct ON ct.task_id = t.task_id '
. 'WHERE td.task_id = $1 ' . 'WHERE td.task_id = $1 '
. 'ORDER BY i.item_name , t.task_priority , t.task_title' )->execute( $id ); . 'ORDER BY i.item_name , t.task_priority DESC , t.task_title' )->execute( $id );
$task->reverseDependencies = $this->query( $task->reverseDependencies = $this->query(
'SELECT t.task_id AS id , t.task_title AS title , t.item_id AS item , ' 'SELECT t.task_id AS id , t.task_title AS title , t.item_id AS item , '
. 'i.item_name AS item_name , ' . 'i.item_name AS item_name , '
@ -117,6 +117,12 @@ class DAO_Tasks
. 'INNER JOIN items i USING ( item_id ) ' . 'INNER JOIN items i USING ( item_id ) '
. 'LEFT OUTER JOIN completed_tasks ct USING ( task_id ) ' . 'LEFT OUTER JOIN completed_tasks ct USING ( task_id ) '
. 'WHERE td.task_id_depends = $1 ' . 'WHERE td.task_id_depends = $1 '
. 'ORDER BY i.item_name , t.task_priority DESC , t.task_title' )->execute( $id );
$task->possibleDependencies = $this->query(
'SELECT t.task_id AS id , t.task_title AS title , t.item_id AS item , '
. 'i.item_name AS item_name '
. 'FROM tasks_possible_dependencies( $1 ) t '
. 'INNER JOIN items i USING ( item_id ) '
. 'ORDER BY i.item_name , t.task_priority , t.task_title' )->execute( $id ); . 'ORDER BY i.item_name , t.task_priority , t.task_title' )->execute( $id );
return $task; return $task;
@ -218,4 +224,11 @@ class DAO_Tasks
->execute( $id , $text ); ->execute( $id , $text );
} }
public function addDependency( $id , $dependency )
{
$result = $this->query( 'SELECT tasks_add_dependency( $1 , $2 ) AS error' )
->execute( $id , $dependency );
return $result[0]->error;
}
} }

View file

@ -107,10 +107,15 @@ class Ctrl_TaskDependencies
public function handle( Page $page ) public function handle( Page $page )
{ {
$views = array( $views = array(
Loader::View( 'box' , 'Dependencies' , $depBox = Loader::View( 'box' , 'Dependencies' ,
Loader::View( 'task_dependencies' , $this->task , false ) ) Loader::View( 'task_dependencies' , $this->task , false ) )
); );
if ( ! empty( $this->task->possibleDependencies ) ) {
$depBox->addButton( BoxButton::create( 'Add dependency' , 'tasks/deps/add?to=' . $this->task->id )
->setClass( 'list-add' ) );
}
if ( ! empty( $this->task->reverseDependencies ) ) { if ( ! empty( $this->task->reverseDependencies ) ) {
array_push( $views , Loader::View( 'box' , 'Reverse dependencies' , array_push( $views , Loader::View( 'box' , 'Reverse dependencies' ,
Loader::View( 'task_dependencies' , $this->task , true ) ) ); Loader::View( 'task_dependencies' , $this->task , true ) ) );
@ -340,3 +345,43 @@ class Ctrl_EditNote
return true; return true;
} }
} }
class Ctrl_DependencyAdd
extends Controller
implements FormAware
{
private $form;
public function setForm( Form $form )
{
$this->form = $form;
}
public function handle( Page $page )
{
$id = (int) $this->form->field( 'to' )->value( );
$dependency = $this->form->field( 'dependency' )->value( );
$error = Loader::DAO( 'tasks' )->addDependency( $id , $dependency );
switch ( $error ) {
case 0:
return true;
case 1:
$name->putError( 'The task you selected has been deleted.' );
break;
case 2:
$item->putError( 'This dependency is no longer possible.' );
break;
default:
$name->putError( "An unknown error occurred ($error)" );
break;
}
return null;
}
}

View file

@ -18,6 +18,8 @@ $package[ 'ctrls' ][] = 'delete_note_form';
$package[ 'ctrls' ][] = 'delete_note'; $package[ 'ctrls' ][] = 'delete_note';
$package[ 'ctrls' ][] = 'delete_task_form'; $package[ 'ctrls' ][] = 'delete_task_form';
$package[ 'ctrls' ][] = 'delete_task'; $package[ 'ctrls' ][] = 'delete_task';
$package[ 'ctrls' ][] = 'dependency_add';
$package[ 'ctrls' ][] = 'dependency_add_form';
$package[ 'ctrls' ][] = 'edit_note_form'; $package[ 'ctrls' ][] = 'edit_note_form';
$package[ 'ctrls' ][] = 'edit_note'; $package[ 'ctrls' ][] = 'edit_note';
$package[ 'ctrls' ][] = 'edit_task_form'; $package[ 'ctrls' ][] = 'edit_task_form';

View file

@ -353,3 +353,97 @@ class Ctrl_EditNoteForm
} }
} }
class Ctrl_DependencyAddForm
extends Controller
{
public function handle( Page $page )
{
// Check selected note
try {
$id = (int) $this->getParameter( 'to' );
} catch ( ParameterException $e ) {
return 'tasks';
}
$tasks = Loader::DAO( 'tasks' );
$task = $tasks->get( $id );
if ( $task === null ) {
return 'tasks';
}
if ( $task->completed_at !== null || empty( $task->possibleDependencies ) ) {
return 'tasks/view?id=' . $id;
}
$page->setTitle( $task->title . ' (task)' );
// Generate form
$form = Loader::Create( 'Form' , 'Add dependency' , 'add-dep' )
->addField( Loader::Create( 'Field' , 'to' , 'hidden' )
->setDefaultValue( $id ) );
$this->addDependencySelector( $form , $task->possibleDependencies );
return $form->setURL( 'tasks/view?id=' . $id )
->addController( Loader::Ctrl( 'dependency_add' ) )
->controller( );
}
private function addDependencySelector( $form , $possibleDependencies )
{
$form->addField( $select = Loader::Create( 'Field' , 'dependency' , 'select' )
->setDescription( 'Dependency to add:' )
->addOption( '' , '(please select a task)' ) );
$depsByItem = $this->getDependenciesByItem( $possibleDependencies );
$items = $this->getItemsToDisplay( $depsByItem );
foreach ( $items as $item ) {
$prefix = '-' . str_repeat( '--' , $item->depth );
$name = $prefix . ' ' . $item->name;
$select->addOption( 'I' . $item->id , $name , true );
if ( ! array_key_exists( $item->id , $depsByItem ) ) {
continue;
}
foreach ( $depsByItem[ $item->id ] as $task ) {
$select->addOption( $task->id , $prefix . '-> ' . $task->title );
}
}
return true;
}
private function getDependenciesByItem( $possibleDependencies )
{
$dbi = array( );
foreach ( $possibleDependencies as $pDep ) {
$dbi[ $pDep->item ][] = $pDep;
}
return $dbi;
}
private function getItemsToDisplay( $depsByItem )
{
$dao = Loader::DAO( 'items' );
$allItems = $dao->getTreeList( );
$found = array( );
foreach ( array_keys( $depsByItem ) as $id ) {
if ( array_key_exists( $id , $found ) ) {
continue;
}
$item = $dao->get( $id );
foreach ( $dao->getLineage( $item ) as $parent ) {
$found[ $parent ] = 1;
}
$found[ $id ] = 1;
}
$result = array( );
foreach ( $allItems as $item ) {
if ( array_key_exists( $item->id , $found ) ) {
array_push( $result , $item );
}
}
return $result;
}
}

View file

@ -16,6 +16,7 @@ class Page_TasksTasks
'view' => 'view_task' , 'view' => 'view_task' ,
'notes/edit' => 'edit_note_form' , 'notes/edit' => 'edit_note_form' ,
'notes/delete' => 'delete_note_form' , 'notes/delete' => 'delete_note_form' ,
'deps/add' => 'dependency_add_form' ,
)); ));
} }