From fe329b97384982d1cfcc08f72979249d3c972313 Mon Sep 17 00:00:00 2001 From: epriestley Date: Wed, 31 Oct 2012 15:22:32 -0700 Subject: [PATCH] Modernize worker task detail view Summary: Make mobile-friendly and provide UI to cancel/retry tasks. Remove display of task data to arbitrary users, as it may be sensitive. Test Plan: {F22502} {F22503} {F22504} {F22505} {F22506} Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T2015 Differential Revision: https://secure.phabricator.com/D3854 --- src/__celerity_resource_map__.php | 6 +- .../PhabricatorWorkerTaskDetailController.php | 256 ++++++++++-------- .../PhabricatorWorkerTaskUpdateController.php | 94 +++++-- .../storage/PhabricatorWorkerArchiveTask.php | 23 +- .../workers/storage/PhabricatorWorkerTask.php | 4 + src/view/layout/PhabricatorActionView.php | 2 + webroot/rsrc/css/autosprite.css | 32 ++- webroot/rsrc/image/autosprite.png | Bin 155474 -> 156479 bytes 8 files changed, 270 insertions(+), 147 deletions(-) diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 0afbce8d55..b78080b78d 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -51,8 +51,8 @@ celerity_register_resource_map(array( ), '/rsrc/image/autosprite.png' => array( - 'hash' => 'e1735b5cadbaf1f70b70a857eab53601', - 'uri' => '/res/e1735b5c/rsrc/image/autosprite.png', + 'hash' => 'bc9479b2a610a3ecee18dc88744c4ce6', + 'uri' => '/res/bc9479b2/rsrc/image/autosprite.png', 'disk' => '/rsrc/image/autosprite.png', 'type' => 'png', ), @@ -713,7 +713,7 @@ celerity_register_resource_map(array( ), 'autosprite-css' => array( - 'uri' => '/res/10fb7fdc/rsrc/css/autosprite.css', + 'uri' => '/res/6be3e4b3/rsrc/css/autosprite.css', 'type' => 'css', 'requires' => array( diff --git a/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php b/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php index 30cb0c5556..a514e13b52 100644 --- a/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php +++ b/src/applications/daemon/controller/PhabricatorWorkerTaskDetailController.php @@ -31,129 +31,163 @@ final class PhabricatorWorkerTaskDetailController $task = id(new PhabricatorWorkerActiveTask())->load($this->id); if (!$task) { + $task = id(new PhabricatorWorkerArchiveTask())->load($this->id); + } + + if (!$task) { + $title = pht('Task Does Not Exist'); + $error_view = new AphrontErrorView(); $error_view->setTitle('No Such Task'); $error_view->appendChild( - '

This task may have recently completed.

'); - $error_view->setSeverity(AphrontErrorView::SEVERITY_WARNING); - return $this->buildStandardPageResponse( - $error_view, - array( - 'title' => 'Task Does Not Exist', - )); + '

This task may have recently been garbage collected.

'); + $error_view->setSeverity(AphrontErrorView::SEVERITY_NODATA); + + $content = $error_view; + } else { + $title = 'Task '.$task->getID(); + + $header = id(new PhabricatorHeaderView()) + ->setHeader('Task '.$task->getID().' ('.$task->getTaskClass().')'); + + $actions = $this->buildActionListView($task); + $properties = $this->buildPropertyListView($task); + + $content = array( + $header, + $actions, + $properties, + ); } - $data = id(new PhabricatorWorkerTaskData())->loadOneWhere( - 'id = %d', - $task->getDataID()); - - $extra = null; - switch ($task->getTaskClass()) { - case 'PhabricatorRepositorySvnCommitChangeParserWorker': - case 'PhabricatorRepositoryGitCommitChangeParserWorker': - $commit_id = idx($data->getData(), 'commitID'); - if ($commit_id) { - $commit = id(new PhabricatorRepositoryCommit())->load($commit_id); - if ($commit) { - $repository = id(new PhabricatorRepository())->load( - $commit->getRepositoryID()); - if ($repository) { - $extra = - "NOTE: ". - "You can manually retry this task by running this script:". - "
".
-                  "phabricator/\$ ./scripts/repository/reparse.php ".
-                  "r".
-                  phutil_escape_html($repository->getCallsign()).
-                  phutil_escape_html($commit->getCommitIdentifier()).
-                  " ".
-                  "--change".
-                "
"; - } - } - } - break; - default: - break; - } - - if ($data) { - $data = json_encode($data->getData()); - } - - $form = id(new AphrontFormView()) - ->setUser($user) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('ID') - ->setValue($task->getID())) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('Type') - ->setValue($task->getTaskClass())) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('Lease Owner') - ->setValue($task->getLeaseOwner())) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('Lease Expires') - ->setValue($task->getLeaseExpires() - time())) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('Failure Count') - ->setValue($task->getFailureCount())) - ->appendChild( - id(new AphrontFormTextAreaControl()) - ->setLabel('Data') - ->setValue($data)); - - if ($extra) { - $form->appendChild( - id(new AphrontFormMarkupControl()) - ->setLabel('More') - ->setValue($extra)); - } - - $form - ->appendChild( - id(new AphrontFormSubmitControl()) - ->addCancelButton('/daemon/', 'Back')); - - $panel = new AphrontPanelView(); - $panel->setHeader('Task Detail'); - $panel->setWidth(AphrontPanelView::WIDTH_WIDE); - $panel->appendChild($form); - - $panel->addButton( - javelin_render_tag( - 'a', - array( - 'href' => '/daemon/task/'.$task->getID().'/delete/', - 'class' => 'button grey', - 'sigil' => 'workflow', - ), - 'Delete Task')); - - $panel->addButton( - javelin_render_tag( - 'a', - array( - 'href' => '/daemon/task/'.$task->getID().'/release/', - 'class' => 'button grey', - 'sigil' => 'workflow', - ), - 'Free Lease')); - $nav = $this->buildSideNavView(); $nav->selectFilter(''); - $nav->appendChild($panel); + $nav->appendChild($content); return $this->buildApplicationPage( $nav, array( - 'title' => 'Task', + 'title' => $title, )); } + private function buildActionListView(PhabricatorWorkerTask $task) { + $user = $this->getRequest()->getUser(); + + $view = new PhabricatorActionListView(); + $view->setUser($user); + + $id = $task->getID(); + + if ($task->isArchived()) { + $result_success = PhabricatorWorkerArchiveTask::RESULT_SUCCESS; + $can_retry = ($task->getResult() != $result_success); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Retry Task')) + ->setHref($this->getApplicationURI('/task/'.$id.'/retry/')) + ->setIcon('undo') + ->setWorkflow(true) + ->setDisabled(!$can_retry)); + } else { + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Cancel Task')) + ->setHref($this->getApplicationURI('/task/'.$id.'/cancel/')) + ->setIcon('delete') + ->setWorkflow(true)); + } + + $can_release = (!$task->isArchived()) && + ($task->getLeaseOwner()); + + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Free Lease')) + ->setHref($this->getApplicationURI('/task/'.$id.'/release/')) + ->setIcon('unlock') + ->setWorkflow(true) + ->setDisabled(!$can_release)); + + return $view; + } + + private function buildPropertyListView(PhabricatorWorkerTask $task) { + $view = new PhabricatorPropertyListView(); + + if ($task->isArchived()) { + switch ($task->getResult()) { + case PhabricatorWorkerArchiveTask::RESULT_SUCCESS: + $status = pht('Complete'); + break; + case PhabricatorWorkerArchiveTask::RESULT_FAILURE: + $status = pht('Failed'); + break; + case PhabricatorWorkerArchiveTask::RESULT_CANCELLED: + $status = pht('Cancelled'); + break; + default: + throw new Exception("Unknown task status!"); + } + } else { + $status = pht('Queued'); + } + + $view->addProperty( + pht('Task Status'), + $status); + + $view->addProperty( + pht('Task Class'), + phutil_escape_html($task->getTaskClass())); + + if ($task->getLeaseExpires()) { + if ($task->getLeaseExpires() > time()) { + $lease_status = pht('Leased'); + } else { + $lease_status = pht('Lease Expired'); + } + } else { + $lease_status = ''.pht('Not Leased').''; + } + + $view->addProperty( + pht('Lease Status'), + $lease_status); + + $view->addProperty( + pht('Lease Owner'), + $task->getLeaseOwner() + ? phutil_escape_html($task->getLeaseOwner()) + : ''.pht('None').''); + + if ($task->getLeaseExpires() && $task->getLeaseOwner()) { + $expires = ($task->getLeaseExpires() - time()); + $expires = phabricator_format_relative_time_detailed($expires); + } else { + $expires = ''.pht('None').''; + } + + $view->addProperty( + pht('Lease Expires'), + $expires); + + $view->addProperty( + pht('Failure Count'), + phutil_escape_html($task->getFailureCount())); + + if ($task->isArchived()) { + $duration = phutil_escape_html(number_format($task->getDuration()).' us'); + } else { + $duration = ''.pht('Not Completed').''; + } + + $view->addProperty( + pht('Duration'), + $duration); + + return $view; + } + } diff --git a/src/applications/daemon/controller/PhabricatorWorkerTaskUpdateController.php b/src/applications/daemon/controller/PhabricatorWorkerTaskUpdateController.php index f5d5d445ca..0356473760 100644 --- a/src/applications/daemon/controller/PhabricatorWorkerTaskUpdateController.php +++ b/src/applications/daemon/controller/PhabricatorWorkerTaskUpdateController.php @@ -32,48 +32,104 @@ final class PhabricatorWorkerTaskUpdateController $user = $request->getUser(); $task = id(new PhabricatorWorkerActiveTask())->load($this->id); + if (!$task) { + $task = id(new PhabricatorWorkerArchiveTask())->load($this->id); + } + if (!$task) { return new Aphront404Response(); } + $result_success = PhabricatorWorkerArchiveTask::RESULT_SUCCESS; + $can_retry = ($task->isArchived()) && + ($task->getResult() != $result_success); + + $can_cancel = !$task->isArchived(); + $can_release = (!$task->isArchived()) && + ($task->getLeaseOwner()); + + $next_uri = $this->getApplicationURI('/task/'.$task->getID().'/'); + if ($request->isFormPost()) { switch ($this->action) { - case 'delete': - $task->delete(); + case 'retry': + if ($can_retry) { + $task->unarchiveTask(); + } + break; + case 'cancel': + if ($can_cancel) { + // Forcibly break the lease if one exists, so we can archive the + // task. + $task->setLeaseOwner(null); + $task->setLeaseExpires(time()); + + $task->archiveTask( + PhabricatorWorkerArchiveTask::RESULT_CANCELLED, + 0); + } break; case 'release': - $task->setLeaseOwner(null); - $task->setLeaseExpires(time()); - $task->save(); + if ($can_release) { + $task->setLeaseOwner(null); + $task->setLeaseExpires(time()); + $task->save(); + } break; } - return id(new AphrontRedirectResponse())->setURI('/daemon/'); + return id(new AphrontRedirectResponse()) + ->setURI($next_uri); } $dialog = new AphrontDialogView(); $dialog->setUser($user); switch ($this->action) { - case 'delete': - $dialog->setTitle('Really delete task?'); - $dialog->appendChild( - '

The work this task represents will never be performed if you '. - 'delete it. Are you sure you want to delete it?

'); - $dialog->addSubmitButton('Delete Task'); + case 'retry': + if ($can_retry) { + $dialog->setTitle('Really retry task?'); + $dialog->appendChild( + '

The task will be put back in the queue and executed '. + 'again.

'); + $dialog->addSubmitButton('Retry Task'); + } else { + $dialog->setTitle('Can Not Retry'); + $dialog->appendChild( + '

Only archived, unsuccessful tasks can be retried.

'); + } + break; + case 'cancel': + if ($can_cancel) { + $dialog->setTitle('Really cancel task?'); + $dialog->appendChild( + '

The work this task represents will never be performed if you '. + 'cancel it. Are you sure you want to cancel it?

'); + $dialog->addSubmitButton('Cancel Task'); + } else { + $dialog->setTitle('Can Not Cancel'); + $dialog->appendChild( + '

Only active tasks can be cancelled.

'); + } break; case 'release': - $dialog->setTitle('Really free task lease?'); - $dialog->appendChild( - '

If the process which owns the task lease is still doing work '. - 'on it, the work may be performed twice. Are you sure you '. - 'want to free the lease?

'); - $dialog->addSubmitButton('Free Lease'); + if ($can_release) { + $dialog->setTitle('Really free task lease?'); + $dialog->appendChild( + '

If the process which owns the task lease is still doing work '. + 'on it, the work may be performed twice. Are you sure you '. + 'want to free the lease?

'); + $dialog->addSubmitButton('Free Lease'); + } else { + $dialog->setTitle('Can Not Free Lease'); + $dialog->appendChild( + '

Only active, leased tasks may have their leases freed.

'); + } break; default: return new Aphront404Response(); } - $dialog->addCancelButton('/daemon/'); + $dialog->addCancelButton($next_uri); return id(new AphrontDialogResponse())->setDialog($dialog); } diff --git a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php index e22370e314..2ff3c98228 100644 --- a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php +++ b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php @@ -18,8 +18,9 @@ final class PhabricatorWorkerArchiveTask extends PhabricatorWorkerTask { - const RESULT_SUCCESS = 0; - const RESULT_FAILURE = 1; + const RESULT_SUCCESS = 0; + const RESULT_FAILURE = 1; + const RESULT_CANCELLED = 2; protected $duration; protected $result; @@ -63,4 +64,22 @@ final class PhabricatorWorkerArchiveTask extends PhabricatorWorkerTask { return $result; } + public function unarchiveTask() { + $this->openTransaction(); + $active = id(new PhabricatorWorkerActiveTask()) + ->setID($this->getID()) + ->setTaskClass($this->getTaskClass()) + ->setLeaseOwner(null) + ->setLeaseExpires(0) + ->setFailureCount(0) + ->setDataID($this->getDataID()) + ->insert(); + + $this->setDataID(null); + $this->delete(); + $this->saveTransaction(); + + return $active; + } + } diff --git a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php index 06c5e78fbf..324ec32b49 100644 --- a/src/infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php +++ b/src/infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php @@ -37,4 +37,8 @@ abstract class PhabricatorWorkerTask extends PhabricatorWorkerDAO { return $this->data; } + public function isArchived() { + return ($this instanceof PhabricatorWorkerArchiveTask); + } + } diff --git a/src/view/layout/PhabricatorActionView.php b/src/view/layout/PhabricatorActionView.php index bf745f5b7c..73dea19d81 100644 --- a/src/view/layout/PhabricatorActionView.php +++ b/src/view/layout/PhabricatorActionView.php @@ -151,6 +151,8 @@ final class PhabricatorActionView extends AphrontView { 'subscribe-add', 'subscribe-auto', 'subscribe-delete', + 'undo', + 'unlock', 'unpublish', 'world', ); diff --git a/webroot/rsrc/css/autosprite.css b/webroot/rsrc/css/autosprite.css index 474b24f252..d673f91c40 100644 --- a/webroot/rsrc/css/autosprite.css +++ b/webroot/rsrc/css/autosprite.css @@ -808,50 +808,58 @@ background-position: 0px -7823px; } -.action-unpublish { +.action-undo { background-position: 0px -7840px; } -.action-world { +.action-unlock { background-position: 0px -7857px; } -.remarkup-assist-b { +.action-unpublish { background-position: 0px -7874px; } +.action-world { + background-position: 0px -7891px; +} + +.remarkup-assist-b { + background-position: 0px -7908px; +} + .remarkup-assist-code { - background-position: 0px -7889px; + background-position: 0px -7923px; } .remarkup-assist-i { - background-position: 0px -7904px; + background-position: 0px -7938px; } .remarkup-assist-image { - background-position: 0px -7919px; + background-position: 0px -7953px; } .remarkup-assist-ol { - background-position: 0px -7934px; + background-position: 0px -7968px; } .remarkup-assist-tag { - background-position: 0px -7949px; + background-position: 0px -7983px; } .remarkup-assist-tt { - background-position: 0px -7964px; + background-position: 0px -7998px; } .remarkup-assist-ul { - background-position: 0px -7979px; + background-position: 0px -8013px; } .remarkup-assist-help { - background-position: 0px -7994px; + background-position: 0px -8028px; } .remarkup-assist-table { - background-position: 0px -8009px; + background-position: 0px -8043px; } diff --git a/webroot/rsrc/image/autosprite.png b/webroot/rsrc/image/autosprite.png index feed650f3adda1b01eaf745c7ef62274b0960b45..69c8352f6d1a8fb910ae345a9c279566af0b4c3e 100644 GIT binary patch delta 15923 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�gO!$)FSiq{(oudi;r^i<|q}Guoq&zp-smn4&TF1fdXs=IP?{Wn!(7F3@d|I?~!aWfr8mevcsmFG@A@OSy9AK^!gBUaKp7C60`)!u}8>H-pfv z1MC2)`;q=@pC5W_ID0qfv)HlnontoF54d%rcoBT`CX;-)o$> zy0l%63AH4^DAFAOUnwd$?saT%?C9_?%KmaAdzcyxF&%EL3OyLJ&HTX8)y9?(*5E+*lA|gZjTZb6?)fNdgHSGCHeU~H_BRe}g z<5)%k0m9d;>nFz9uM|U>j}EKiKd?02Oh&`-k5^l@;#?2sD$r zR6elt{&(4^)nnFDz0Ew8egBRUo206d*z@hS^s7=4OZ~ofTvRfV?!!c-zL0S$(JM1t zY0%D85mRQj+(01e%ikA8NDUzq_N)fDF4b9|{rQ7SN3EJ+JuA(b0K=T9h((hwWHVtq zbQk@0EmbqA@2{qs1`d2}_;Q~j^O|)cHx(6Ho5^Vi{?myioB&WzwVnK7J{-8#?qhnj zKiPJBQ|jISKT2%eR-#Tx@j!x!#&!S5xVShFQ6SG}R1KonXR3b>YI7EEhZ(^PPJ!UyxmpW_CIq1v<27qi1|@_z3R z9&X2S+J3~z)BP!2QktCW&D6Sr+-(d^W9{LJY$#<3B2nnnSs7m(6n(phmt3X)h1>q+ zZfK9$OMan1AtkfaE6Pmc9s#%#t;Wyuq#e&G$kc zcud3>hhy|Pm#(z1R3R%7kUakBBC5=CJe%bXAYZ~0WIIzF&qn&zwlF7$GaO*j6NdRS zd#YF^uQVW%?61J}F4edQL+p_wMvzT(ylamYW&zS~)E`Yuuh;o}Z*z4xulxv+PcN^0 ztzv{a5@c%0`+|?+#@#s<(jRZ-bycvIv$fssqG%No?#ik|hIihS#`nYE_hN@lEH}PfgLa?%d_H@9O3=_D zOMdMV$=W~Xdw700-L7a{s%Pw1X|!G z=M%jU?t{HyH0es%F=-u^Hfc?g8tYmqjFnnmDvDUpvTDf5-dT z2qJA;ny&OQJWo`2TyorWgR5x%A)@1zV1KU6rkj@%?5jL>f{=3#NKD`3%hsg+*h zDBF2SDVN3yO*A=~o{11|{o9eUt^m(L{s#=kaw7AZ{VOyKmOPu@DHLD+>-Lg#~N`KZsT7 zoh-bO-jj_%$fBTsVRUo6OkeEYe$X_q?f8_gqT!~;W%O@%vH^#Pe|24DH18k@o8P06 zwLYEh-)}1c1jMKOSyc%xWSYbqOh#@6!;oGXw=@%4o7`WkU(#Dq+>YPLnaoR^6#O#K kfoHjy;u_2sy?WtX9>?5_)bpx+Z4C#=ODjoLzB3B^e}d`IQvd(} delta 14910 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