diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1663,6 +1663,7 @@ 'NuanceQueueTransactionQuery' => 'applications/nuance/query/NuanceQueueTransactionQuery.php', 'NuanceQueueTransactionType' => 'applications/nuance/xaction/NuanceQueueTransactionType.php', 'NuanceQueueViewController' => 'applications/nuance/controller/NuanceQueueViewController.php', + 'NuanceQueueWorkController' => 'applications/nuance/controller/NuanceQueueWorkController.php', 'NuanceSchemaSpec' => 'applications/nuance/storage/NuanceSchemaSpec.php', 'NuanceSource' => 'applications/nuance/storage/NuanceSource.php', 'NuanceSourceActionController' => 'applications/nuance/controller/NuanceSourceActionController.php', @@ -6788,6 +6789,7 @@ 'NuanceQueueTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'NuanceQueueTransactionType' => 'PhabricatorModularTransactionType', 'NuanceQueueViewController' => 'NuanceQueueController', + 'NuanceQueueWorkController' => 'NuanceQueueController', 'NuanceSchemaSpec' => 'PhabricatorConfigSchemaSpec', 'NuanceSource' => array( 'NuanceDAO', diff --git a/src/applications/nuance/application/PhabricatorNuanceApplication.php b/src/applications/nuance/application/PhabricatorNuanceApplication.php --- a/src/applications/nuance/application/PhabricatorNuanceApplication.php +++ b/src/applications/nuance/application/PhabricatorNuanceApplication.php @@ -51,6 +51,7 @@ $this->getQueryRoutePattern() => 'NuanceQueueListController', $this->getEditRoutePattern('edit/') => 'NuanceQueueEditController', 'view/(?P[1-9]\d*)/' => 'NuanceQueueViewController', + 'work/(?P[1-9]\d*)/' => 'NuanceQueueWorkController', ), ), '/action/' => array( diff --git a/src/applications/nuance/controller/NuanceQueueViewController.php b/src/applications/nuance/controller/NuanceQueueViewController.php --- a/src/applications/nuance/controller/NuanceQueueViewController.php +++ b/src/applications/nuance/controller/NuanceQueueViewController.php @@ -70,6 +70,14 @@ ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); + $curtain->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Begin Work')) + ->setIcon('fa-play-circle-o') + ->setHref($this->getApplicationURI("queue/work/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)); + return $curtain; } diff --git a/src/applications/nuance/controller/NuanceQueueWorkController.php b/src/applications/nuance/controller/NuanceQueueWorkController.php new file mode 100644 --- /dev/null +++ b/src/applications/nuance/controller/NuanceQueueWorkController.php @@ -0,0 +1,98 @@ +getViewer(); + + $queue = id(new NuanceQueueQuery()) + ->setViewer($viewer) + ->withIDs(array($request->getURIData('id'))) + ->executeOne(); + if (!$queue) { + return new Aphront404Response(); + } + + $title = $queue->getName(); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb(pht('Queues'), $this->getApplicationURI('queue/')); + $crumbs->addTextCrumb($queue->getName(), $queue->getURI()); + $crumbs->addTextCrumb(pht('Work')); + $crumbs->setBorder(true); + + // For now, just pick the first open item. + + $items = id(new NuanceItemQuery()) + ->setViewer($viewer) + ->withQueuePHIDs( + array( + $queue->getPHID(), + )) + ->withStatuses( + array( + NuanceItem::STATUS_OPEN, + )) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + )) + ->setLimit(5) + ->execute(); + + if (!$items) { + return $this->newDialog() + ->setTitle(pht('Queue Empty')) + ->appendParagraph( + pht( + 'This queue has no open items which you have permission to '. + 'work on.')) + ->addCancelButton($queue->getURI()); + } + + $item = head($items); + + $curtain = $this->buildCurtain($queue); + + $timeline = $this->buildTransactionTimeline( + $item, + new NuanceItemTransactionQuery()); + $timeline->setShouldTerminate(true); + + $view = id(new PHUITwoColumnView()) + ->setCurtain($curtain) + ->setMainColumn($timeline); + + return $this->newPage() + ->setTitle($title) + ->setCrumbs($crumbs) + ->appendChild($view); + } + + private function buildCurtain(NuanceQueue $queue) { + $viewer = $this->getViewer(); + $id = $queue->getID(); + + $curtain = $this->newCurtainView(); + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_DIVIDER)); + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setType(PhabricatorActionView::TYPE_LABEL) + ->setName(pht('Queue Actions'))); + + $curtain->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Manage Queue')) + ->setIcon('fa-cog') + ->setHref($this->getApplicationURI("queue/view/{$id}/"))); + + return $curtain; + } + +} diff --git a/src/applications/nuance/query/NuanceItemQuery.php b/src/applications/nuance/query/NuanceItemQuery.php --- a/src/applications/nuance/query/NuanceItemQuery.php +++ b/src/applications/nuance/query/NuanceItemQuery.php @@ -6,9 +6,11 @@ private $ids; private $phids; private $sourcePHIDs; + private $queuePHIDs; private $itemTypes; private $itemKeys; private $containerKeys; + private $statuses; public function withIDs(array $ids) { $this->ids = $ids; @@ -25,6 +27,11 @@ return $this; } + public function withQueuePHIDs(array $queue_phids) { + $this->queuePHIDs = $queue_phids; + return $this; + } + public function withItemTypes(array $item_types) { $this->itemTypes = $item_types; return $this; @@ -35,6 +42,11 @@ return $this; } + public function withStatuses(array $statuses) { + $this->statuses = $statuses; + return $this; + } + public function withItemContainerKeys(array $container_keys) { $this->containerKeys = $container_keys; return $this; @@ -49,13 +61,11 @@ } protected function willFilterPage(array $items) { + $viewer = $this->getViewer(); $source_phids = mpull($items, 'getSourcePHID'); - // NOTE: We always load sources, even if the viewer can't formally see - // them. If they can see the item, they're allowed to be aware of the - // source in some sense. $sources = id(new NuanceSourceQuery()) - ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->setViewer($viewer) ->withPHIDs($source_phids) ->execute(); $sources = mpull($sources, null, 'getPHID'); @@ -81,6 +91,43 @@ $item->attachImplementation($type); } + $queue_phids = array(); + foreach ($items as $item) { + $queue_phid = $item->getQueuePHID(); + if ($queue_phid) { + $queue_phids[$queue_phid] = $queue_phid; + } + } + + if ($queue_phids) { + $queues = id(new NuanceQueueQuery()) + ->setViewer($viewer) + ->withPHIDs($queue_phids) + ->execute(); + $queues = mpull($queues, null, 'getPHID'); + } else { + $queues = array(); + } + + foreach ($items as $key => $item) { + $queue_phid = $item->getQueuePHID(); + + if (!$queue_phid) { + $item->attachQueue(null); + continue; + } + + $queue = idx($queues, $queue_phid); + + if (!$queue) { + unset($items[$key]); + $this->didRejectResult($item); + continue; + } + + $item->attachQueue($queue); + } + return $items; } @@ -94,6 +141,13 @@ $this->sourcePHIDs); } + if ($this->queuePHIDs !== null) { + $where[] = qsprintf( + $conn, + 'queuePHID IN (%Ls)', + $this->queuePHIDs); + } + if ($this->ids !== null) { $where[] = qsprintf( $conn, @@ -108,6 +162,13 @@ $this->phids); } + if ($this->statuses !== null) { + $where[] = qsprintf( + $conn, + 'status IN (%Ls)', + $this->statuses); + } + if ($this->itemTypes !== null) { $where[] = qsprintf( $conn, diff --git a/src/applications/nuance/query/NuanceItemSearchEngine.php b/src/applications/nuance/query/NuanceItemSearchEngine.php --- a/src/applications/nuance/query/NuanceItemSearchEngine.php +++ b/src/applications/nuance/query/NuanceItemSearchEngine.php @@ -72,6 +72,19 @@ $impl->getItemTypeDisplayIcon(), $impl->getItemTypeDisplayName()); + $queue = $item->getQueue(); + if ($queue) { + $view->addAttribute( + phutil_tag( + 'a', + array( + 'href' => $queue->getURI(), + ), + $queue->getName())); + } else { + $view->addAttribute(phutil_tag('em', array(), pht('Not in Queue'))); + } + $list->addItem($view); } diff --git a/src/applications/nuance/storage/NuanceItem.php b/src/applications/nuance/storage/NuanceItem.php --- a/src/applications/nuance/storage/NuanceItem.php +++ b/src/applications/nuance/storage/NuanceItem.php @@ -23,6 +23,7 @@ protected $data = array(); protected $mailKey; + private $queue = self::ATTACHABLE; private $source = self::ATTACHABLE; private $implementation = self::ATTACHABLE; @@ -176,6 +177,15 @@ return $this; } + public function getQueue() { + return $this->assertAttached($this->queue); + } + + public function attachQueue(NuanceQueue $queue = null) { + $this->queue = $queue; + return $this; + } + /* -( PhabricatorApplicationTransactionInterface )------------------------- */