Emmanuel BENOîT
1423434dfd
The amount of unsatisfied transitive dependencies is displayed in the tasks list (and used to sort it) and on task pages.
368 lines
9.9 KiB
PHP
368 lines
9.9 KiB
PHP
<?php
|
|
|
|
abstract class View_TasksBase
|
|
extends BaseURLAwareView
|
|
{
|
|
protected $tasks;
|
|
protected $dao;
|
|
|
|
|
|
protected function __construct( )
|
|
{
|
|
$this->dao = Loader::DAO( 'tasks' );
|
|
}
|
|
|
|
|
|
public final function render( )
|
|
{
|
|
if ( empty( $this->tasks ) ) {
|
|
return HTML::make( 'div' )
|
|
->setAttribute( 'class' , 'no-table' )
|
|
->appendText( 'No tasks to display.' );
|
|
}
|
|
return HTML::make( 'dl' )
|
|
->append( $this->generateList( ) )
|
|
->setAttribute( 'class' , 'tasks' );
|
|
}
|
|
|
|
|
|
private function generateList( )
|
|
{
|
|
$result = array( );
|
|
$prevPriority = 6;
|
|
foreach ( $this->tasks as $task ) {
|
|
$priority = ( $task->completed_by === null ) ? $task->priority : -1;
|
|
if ( $priority !== $prevPriority ) {
|
|
if ( $priority == -1 ) {
|
|
$text = 'Completed tasks';
|
|
$extraClass = ' completed';
|
|
} else {
|
|
$text = $this->dao->translatePriority( $priority ) . ' priority';
|
|
$extraClass = '';
|
|
}
|
|
$prevPriority = $priority;
|
|
|
|
array_push( $result , HTML::make( 'dt' )
|
|
->setAttribute( 'class' , 'sub-title' . $extraClass )
|
|
->appendText( $text ) );
|
|
}
|
|
$result = array_merge( $result , $this->generateItem( $task ) );
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
protected abstract function generateItem( $task );
|
|
}
|
|
|
|
|
|
class View_AllTasks
|
|
extends View_TasksBase
|
|
{
|
|
|
|
public function __construct( $tasks )
|
|
{
|
|
parent::__construct( );
|
|
$this->tasks = $tasks;
|
|
}
|
|
|
|
protected function generateItem( $task )
|
|
{
|
|
$cell = array( );
|
|
array_push( $cell , HTML::make( 'dt' )
|
|
->appendElement( HTML::make( 'a' )
|
|
->setAttribute( 'href' , $this->base . '/tasks/view?id=' . $task->id )
|
|
->appendText( $task->title ) ) );
|
|
|
|
array_push( $cell , HTML::make( 'dd' )->append( $this->formatPlaceLineage( $task->item ) ) );
|
|
|
|
$addedAt = strtotime( $task->added_at );
|
|
$addedAtDate = date( 'd/m/o' , $addedAt );
|
|
$addedAtTime = date( 'H:i:s' , $addedAt );
|
|
array_push( $cell ,
|
|
HTML::make( 'dd' )->appendText( "Added $addedAtDate at $addedAtTime by {$task->added_by}" ) );
|
|
if ( $task->missing_dependencies !== null ) {
|
|
if ( $task->missing_dependencies > 1 ) {
|
|
$end = 'ies';
|
|
} else {
|
|
$end = 'y';
|
|
}
|
|
array_push( $cell ,
|
|
$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' );
|
|
}
|
|
} elseif ( $task->completed_by !== null ) {
|
|
$completedAt = strtotime( $task->completed_at );
|
|
$completedAtDate = date( 'd/m/o' , $completedAt );
|
|
$completedAtTime = date( 'H:i:s' , $completedAt );
|
|
array_push( $cell , HTML::make( 'dd' )->appendText(
|
|
"Completed $completedAtDate at $completedAtTime by {$task->completed_by}" ) );
|
|
|
|
foreach ( $cell as $entry ) {
|
|
$entry->setAttribute( 'class' , 'completed' );
|
|
}
|
|
}
|
|
|
|
return $cell;
|
|
}
|
|
|
|
private function formatPlaceLineage( $item )
|
|
{
|
|
$item = Loader::DAO( 'items' )->get( $item );
|
|
$lineage = $item->lineage;
|
|
array_push( $lineage , $item->id );
|
|
|
|
$contents = array( );
|
|
foreach ( Loader::DAO( 'items' )->getAll( $lineage ) as $ancestor ) {
|
|
if ( ! empty( $contents ) ) {
|
|
array_push( $contents , ' » ' );
|
|
}
|
|
array_push( $contents , HTML::make( 'a' )
|
|
->setAttribute( 'href' , $this->base . '/items/view?id=' . $ancestor->id )
|
|
->appendText( $ancestor->name ) );
|
|
}
|
|
array_unshift( $contents, 'On ' );
|
|
|
|
return $contents;
|
|
}
|
|
}
|
|
|
|
|
|
class View_Tasks
|
|
extends View_TasksBase
|
|
{
|
|
public function __construct( $tasks )
|
|
{
|
|
parent::__construct( );
|
|
$this->tasks = $tasks;
|
|
}
|
|
|
|
|
|
protected function generateItem( $task )
|
|
{
|
|
$cell = array( );
|
|
array_push( $cell , HTML::make( 'dt' )
|
|
->appendElement( HTML::make( 'a' )
|
|
->setAttribute( 'href' , $this->base . '/tasks/view?id=' . $task->id )
|
|
->appendText( $task->title ) ) );
|
|
|
|
$addedAt = strtotime( $task->added_at );
|
|
$addedAtDate = date( 'd/m/o' , $addedAt );
|
|
$addedAtTime = date( 'H:i:s' , $addedAt );
|
|
array_push( $cell ,
|
|
HTML::make( 'dd' )->appendText( "Added $addedAtDate at $addedAtTime by {$task->added_by}" ) );
|
|
|
|
if ( $task->missing_dependencies !== null ) {
|
|
if ( $task->missing_dependencies > 1 ) {
|
|
$end = 'ies';
|
|
} else {
|
|
$end = 'y';
|
|
}
|
|
array_push( $cell ,
|
|
$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' );
|
|
}
|
|
} elseif ( $task->completed_by !== null ) {
|
|
$completedAt = strtotime( $task->completed_at );
|
|
$completedAtDate = date( 'd/m/o' , $completedAt );
|
|
$completedAtTime = date( 'H:i:s' , $completedAt );
|
|
array_push( $cell , HTML::make( 'dd' )->appendText(
|
|
"Completed $completedAtDate at $completedAtTime by {$task->completed_by}" ) );
|
|
foreach ( $cell as $entry ) {
|
|
$entry->setAttribute( 'class' , 'completed' );
|
|
}
|
|
}
|
|
|
|
return $cell;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
class View_TaskDetails
|
|
extends BaseURLAwareView
|
|
{
|
|
private $task;
|
|
|
|
public function __construct( $task )
|
|
{
|
|
$this->task = $task;
|
|
}
|
|
|
|
public function render( )
|
|
{
|
|
$list = HTML::make( 'dl' )
|
|
->setAttribute( 'class' , 'tasks' )
|
|
->appendElement( HTML::make( 'dt' )
|
|
->appendText( 'On item:' ) )
|
|
->appendElement( HTML::make( 'dd' )
|
|
->append( $this->formatPlaceLineage( $this->task->item ) ) );
|
|
|
|
if ( $this->task->description != '' ) {
|
|
$list->appendElement( HTML::make( 'dt' )
|
|
->appendText( 'Description:' ) )
|
|
->appendElement( HTML::make( 'dd' )
|
|
->appendRaw( $this->formatDescription( ) ) );
|
|
}
|
|
|
|
$list->appendElement( HTML::make( 'dt' )
|
|
->appendText( 'Added:' ) )
|
|
->appendElement( HTML::make( 'dd' )
|
|
->appendText( $this->formatAction( $this->task->added_at , $this->task->added_by ) ) );
|
|
|
|
if ( $this->task->completed_by === null ) {
|
|
$list->appendElement( HTML::make( 'dt' )
|
|
->appendText( 'Priority:' ) )
|
|
->appendElement( HTML::make( 'dd' )
|
|
->appendText( Loader::DAO( 'tasks' )
|
|
->translatePriority( $this->task->priority ) ) );
|
|
} else {
|
|
$list->appendElement( HTML::make( 'dt' )
|
|
->appendText( 'Completed:' ) )
|
|
->appendElement( HTML::make( 'dd' )
|
|
->appendText( $this->formatAction(
|
|
$this->task->completed_at , $this->task->completed_by ) ) );
|
|
}
|
|
|
|
return $list;
|
|
}
|
|
|
|
private function formatPlaceLineage( $item )
|
|
{
|
|
$lineage = $item->lineage;
|
|
array_push( $lineage , $item->id );
|
|
|
|
$contents = array( );
|
|
foreach ( Loader::DAO( 'items' )->getAll( $lineage ) as $ancestor ) {
|
|
if ( ! empty( $contents ) ) {
|
|
array_push( $contents , ' » ' );
|
|
}
|
|
array_push( $contents , HTML::make( 'a' )
|
|
->setAttribute( 'href' , $this->base . '/items/view?id=' . $ancestor->id )
|
|
->appendText( $ancestor->name ) );
|
|
}
|
|
|
|
return $contents;
|
|
}
|
|
|
|
|
|
private function formatDescription( )
|
|
{
|
|
$description = HTML::from( $this->task->description );
|
|
return preg_replace( '/\n/s' , '<br/>' , $description );
|
|
}
|
|
|
|
|
|
private function formatAction( $timestamp , $user )
|
|
{
|
|
$ts = strtotime( $timestamp );
|
|
$tsDate = date( 'd/m/o' , $ts );
|
|
$tsTime = date( 'H:i:s' , $ts );
|
|
return "$tsDate at $tsTime by $user";
|
|
}
|
|
}
|
|
|
|
|
|
class View_TaskNote
|
|
implements View
|
|
{
|
|
private $note;
|
|
|
|
public function __construct( $note )
|
|
{
|
|
$this->note = $note;
|
|
}
|
|
|
|
public function render( )
|
|
{
|
|
$text = HTML::make( 'p' )
|
|
->appendRaw( preg_replace( '/\n/s' , '<br/>' , HTML::from( $this->note->text ) ) );
|
|
|
|
$ts = strtotime( $this->note->added_at );
|
|
$tsDate = date( 'd/m/o' , $ts );
|
|
$tsTime = date( 'H:i:s' , $ts );
|
|
$details = HTML::make( 'div')
|
|
->setAttribute( 'style' , 'font-size: 9pt' )
|
|
->appendElement( HTML::make( 'em' )
|
|
->appendText( "Note added $tsDate at $tsTime by {$this->note->author}" ) );
|
|
|
|
return array( $text , $details );
|
|
}
|
|
}
|
|
|
|
|
|
class View_TaskDependencies
|
|
extends BaseURLAwareView
|
|
{
|
|
private $task;
|
|
private $reverse;
|
|
|
|
public function __construct( $task , $reverse )
|
|
{
|
|
$this->task = $task;
|
|
$this->reverse = $reverse;
|
|
}
|
|
|
|
public function render( )
|
|
{
|
|
$source = $this->reverse ? 'reverseDependencies' : 'dependencies';
|
|
if ( empty( $this->task->$source ) ) {
|
|
return HTML::make( 'div' )
|
|
->setAttribute( 'class' , 'no-table' )
|
|
->appendText( 'This task has no dependencies.' );
|
|
}
|
|
|
|
$list = HTML::make( 'ul' )->setAttribute( 'class' , 'dep-list' );
|
|
$prevItem = null;
|
|
$itemList = null;
|
|
foreach ( $this->task->$source as $dependency ) {
|
|
if ( $prevItem !== $dependency->item ) {
|
|
$itemList = HTML::make( 'ul' );
|
|
$list->appendElement( HTML::make( 'li' )
|
|
->appendText( 'In ' )
|
|
->appendElement( HTML::make( 'a' )
|
|
->setAttribute( 'href' , $this->base . '/items/view?id=' . $dependency->item )
|
|
->appendText( $dependency->item_name ) )
|
|
->appendElement( $itemList ) );
|
|
$prevItem = $dependency->item;
|
|
}
|
|
|
|
$entry = HTML::make( 'li' )->appendElement(
|
|
$link = HTML::make( 'a' )
|
|
->setAttribute( 'href' , $this->base . '/tasks/view?id=' . $dependency->id )
|
|
->appendText( $dependency->title ) );
|
|
if ( ! $this->reverse ) {
|
|
$link->setAttribute( 'class' , ( $dependency->completed == 't' )
|
|
? 'satisfied' : 'missing' );
|
|
|
|
if ( $this->task->completed_at === null ) {
|
|
$entry->appendText( ' (' )
|
|
->appendElement( HTML::make( 'a' )
|
|
->setAttribute( 'href' , $this->base . '/tasks/deps/delete?from='
|
|
. $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)" );
|
|
}
|
|
}
|
|
}
|
|
|
|
$itemList->appendElement( $entry );
|
|
}
|
|
return $list;
|
|
}
|
|
}
|