From f529ade9f7bf16f528598d6e36d90f4948c2126f Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 5 Jun 2015 10:49:35 -0700 Subject: [PATCH] Add Nuance Queue list/edit/detail views Summary: Ref T8434. Throw these together. Test Plan: Created a new Queue. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T8434 Differential Revision: https://secure.phabricator.com/D13163 --- src/__phutil_library_map__.php | 4 + .../PhabricatorNuanceApplication.php | 1 + .../controller/NuanceQueueEditController.php | 100 +++++++++++++++++- .../controller/NuanceQueueListController.php | 48 +++++++++ .../controller/NuanceQueueViewController.php | 97 +++++++++++++---- .../nuance/editor/NuanceQueueEditor.php | 80 +++++++++++++- .../nuance/query/NuanceQueueSearchEngine.php | 75 +++++++++++++ .../nuance/storage/NuanceQueueTransaction.php | 2 + 8 files changed, 378 insertions(+), 29 deletions(-) create mode 100644 src/applications/nuance/controller/NuanceQueueListController.php create mode 100644 src/applications/nuance/query/NuanceQueueSearchEngine.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 4295b0d587..59fd905fb4 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1120,8 +1120,10 @@ phutil_register_library_map(array( 'NuanceQueueEditController' => 'applications/nuance/controller/NuanceQueueEditController.php', 'NuanceQueueEditor' => 'applications/nuance/editor/NuanceQueueEditor.php', 'NuanceQueueItem' => 'applications/nuance/storage/NuanceQueueItem.php', + 'NuanceQueueListController' => 'applications/nuance/controller/NuanceQueueListController.php', 'NuanceQueuePHIDType' => 'applications/nuance/phid/NuanceQueuePHIDType.php', 'NuanceQueueQuery' => 'applications/nuance/query/NuanceQueueQuery.php', + 'NuanceQueueSearchEngine' => 'applications/nuance/query/NuanceQueueSearchEngine.php', 'NuanceQueueTransaction' => 'applications/nuance/storage/NuanceQueueTransaction.php', 'NuanceQueueTransactionComment' => 'applications/nuance/storage/NuanceQueueTransactionComment.php', 'NuanceQueueTransactionQuery' => 'applications/nuance/query/NuanceQueueTransactionQuery.php', @@ -4463,8 +4465,10 @@ phutil_register_library_map(array( 'NuanceQueueEditController' => 'NuanceController', 'NuanceQueueEditor' => 'PhabricatorApplicationTransactionEditor', 'NuanceQueueItem' => 'NuanceDAO', + 'NuanceQueueListController' => 'NuanceController', 'NuanceQueuePHIDType' => 'PhabricatorPHIDType', 'NuanceQueueQuery' => 'NuanceQuery', + 'NuanceQueueSearchEngine' => 'PhabricatorApplicationSearchEngine', 'NuanceQueueTransaction' => 'NuanceTransaction', 'NuanceQueueTransactionComment' => 'PhabricatorApplicationTransactionComment', 'NuanceQueueTransactionQuery' => 'PhabricatorApplicationTransactionQuery', diff --git a/src/applications/nuance/application/PhabricatorNuanceApplication.php b/src/applications/nuance/application/PhabricatorNuanceApplication.php index 949f48d7f2..835e625997 100644 --- a/src/applications/nuance/application/PhabricatorNuanceApplication.php +++ b/src/applications/nuance/application/PhabricatorNuanceApplication.php @@ -51,6 +51,7 @@ final class PhabricatorNuanceApplication extends PhabricatorApplication { 'create/' => 'NuanceSourceCreateController', ), 'queue/' => array( + '(?:query/(?P[^/]+)/)?' => 'NuanceQueueListController', 'view/(?P[1-9]\d*)/' => 'NuanceQueueViewController', 'edit/(?P[1-9]\d*)/' => 'NuanceQueueEditController', 'new/' => 'NuanceQueueEditController', diff --git a/src/applications/nuance/controller/NuanceQueueEditController.php b/src/applications/nuance/controller/NuanceQueueEditController.php index 8c02672890..cfb657615d 100644 --- a/src/applications/nuance/controller/NuanceQueueEditController.php +++ b/src/applications/nuance/controller/NuanceQueueEditController.php @@ -4,11 +4,13 @@ final class NuanceQueueEditController extends NuanceController { public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); + $queues_uri = $this->getApplicationURI('queue/'); $queue_id = $request->getURIData('id'); $is_new = !$queue_id; if ($is_new) { $queue = NuanceQueue::initializeNewQueue(); + $cancel_uri = $queues_uri; } else { $queue = id(new NuanceQueueQuery()) ->setViewer($viewer) @@ -17,12 +19,60 @@ final class NuanceQueueEditController extends NuanceController { if (!$queue) { return new Aphront404Response(); } + $cancel_uri = $queue->getURI(); + } + + $v_name = $queue->getName(); + $e_name = true; + $v_edit = $queue->getEditPolicy(); + $v_view = $queue->getViewPolicy(); + + $validation_exception = null; + if ($request->isFormPost()) { + $e_name = null; + + $v_name = $request->getStr('name'); + $v_edit = $request->getStr('editPolicy'); + $v_view = $request->getStr('viewPolicy'); + + $type_name = NuanceQueueTransaction::TYPE_NAME; + $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; + $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; + + $xactions = array(); + + $xactions[] = id(new NuanceQueueTransaction()) + ->setTransactionType($type_name) + ->setNewValue($v_name); + + $xactions[] = id(new NuanceQueueTransaction()) + ->setTransactionType($type_view) + ->setNewValue($v_view); + + $xactions[] = id(new NuanceQueueTransaction()) + ->setTransactionType($type_edit) + ->setNewValue($v_edit); + + $editor = id(new NuanceQueueEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request) + ->setContinueOnNoEffect(true); + + try { + + $editor->applyTransactions($queue, $xactions); + + $uri = $queue->getURI(); + return id(new AphrontRedirectResponse())->setURI($uri); + } catch (PhabricatorApplicationTransactionValidationException $ex) { + $validation_exception = $ex; + + $e_name = $ex->getShortMessage($type_name); + } } $crumbs = $this->buildApplicationCrumbs(); - $crumbs->addTextCrumb( - pht('Queues'), - $this->getApplicationURI('queue/')); + $crumbs->addTextCrumb(pht('Queues'), $queues_uri); if ($is_new) { $title = pht('Create Queue'); @@ -33,8 +83,50 @@ final class NuanceQueueEditController extends NuanceController { $crumbs->addTextCrumb(pht('Edit')); } + $policies = id(new PhabricatorPolicyQuery()) + ->setViewer($viewer) + ->setObject($queue) + ->execute(); + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel(pht('Name')) + ->setName('name') + ->setError($e_name) + ->setValue($v_name)) + ->appendChild( + id(new AphrontFormPolicyControl()) + ->setUser($viewer) + ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) + ->setPolicyObject($queue) + ->setPolicies($policies) + ->setValue($v_view) + ->setName('viewPolicy')) + ->appendChild( + id(new AphrontFormPolicyControl()) + ->setUser($viewer) + ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) + ->setPolicyObject($queue) + ->setPolicies($policies) + ->setValue($v_edit) + ->setName('editPolicy')) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton($cancel_uri) + ->setValue(pht('Save'))); + + $box = id(new PHUIObjectBoxView()) + ->setHeaderText($title) + ->setValidationException($validation_exception) + ->appendChild($form); + return $this->buildApplicationPage( - $crumbs, + array( + $crumbs, + $box, + ), array( 'title' => $title, )); diff --git a/src/applications/nuance/controller/NuanceQueueListController.php b/src/applications/nuance/controller/NuanceQueueListController.php new file mode 100644 index 0000000000..e139386bdf --- /dev/null +++ b/src/applications/nuance/controller/NuanceQueueListController.php @@ -0,0 +1,48 @@ +getRequest(); + $controller = id(new PhabricatorApplicationSearchController($request)) + ->setQueryKey($request->getURIData('queryKey')) + ->setSearchEngine(new NuanceQueueSearchEngine()) + ->setNavigation($this->buildSideNavView()); + + return $this->delegateToController($controller); + } + + public function buildSideNavView($for_app = false) { + $user = $this->getRequest()->getUser(); + + $nav = new AphrontSideNavFilterView(); + $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); + + id(new NuanceQueueSearchEngine()) + ->setViewer($user) + ->addNavigationItems($nav->getMenu()); + + $nav->selectFilter(null); + + return $nav; + } + + protected function buildApplicationCrumbs() { + $crumbs = parent::buildApplicationCrumbs(); + + // TODO: Maybe use SourceManage capability? + $can_create = true; + + $crumbs->addAction( + id(new PHUIListItemView()) + ->setName(pht('Create Queue')) + ->setHref($this->getApplicationURI('queue/new/')) + ->setIcon('fa-plus-square') + ->setDisabled(!$can_create) + ->setWorkflow(!$can_create)); + + return $crumbs; + } + +} diff --git a/src/applications/nuance/controller/NuanceQueueViewController.php b/src/applications/nuance/controller/NuanceQueueViewController.php index 261b528193..d619cfb946 100644 --- a/src/applications/nuance/controller/NuanceQueueViewController.php +++ b/src/applications/nuance/controller/NuanceQueueViewController.php @@ -2,41 +2,92 @@ final class NuanceQueueViewController extends NuanceController { - private $queueID; + public function handleRequest(AphrontRequest $request) { + $viewer = $this->getViewer(); - public function setQueueID($queue_id) { - $this->queueID = $queue_id; - return $this; - } - public function getQueueID() { - return $this->queueID; - } - - public function willProcessRequest(array $data) { - $this->setQueueID($data['id']); - } - - public function processRequest() { - $request = $this->getRequest(); - $user = $request->getUser(); - - $queue_id = $this->getQueueID(); $queue = id(new NuanceQueueQuery()) - ->setViewer($user) - ->withIDs(array($queue_id)) + ->setViewer($viewer) + ->withIDs(array($request->getURIData('id'))) ->executeOne(); - if (!$queue) { return new Aphront404Response(); } + $title = $queue->getName(); + $crumbs = $this->buildApplicationCrumbs(); - $title = pht('TODO'); + $crumbs->addTextCrumb(pht('Queues'), $this->getApplicationURI('queue/')); + $crumbs->addTextCrumb($queue->getName()); + + $header = $this->buildHeaderView($queue); + $actions = $this->buildActionView($queue); + $properties = $this->buildPropertyView($queue, $actions); + + $box = id(new PHUIObjectBoxView()) + ->setHeader($header) + ->addPropertyList($properties); + + $timeline = $this->buildTransactionTimeline( + $queue, + new NuanceQueueTransactionQuery()); + $timeline->setShouldTerminate(true); return $this->buildApplicationPage( - $crumbs, + array( + $crumbs, + $box, + $timeline, + ), array( 'title' => $title, )); } + + private function buildHeaderView(NuanceQueue $queue) { + $viewer = $this->getViewer(); + + $header = id(new PHUIHeaderView()) + ->setUser($viewer) + ->setHeader($queue->getName()) + ->setPolicyObject($queue); + + return $header; + } + + private function buildActionView(NuanceQueue $queue) { + $viewer = $this->getViewer(); + $id = $queue->getID(); + + $actions = id(new PhabricatorActionListView()) + ->setObjectURI($queue->getURI()) + ->setUser($viewer); + + $can_edit = PhabricatorPolicyFilter::hasCapability( + $viewer, + $queue, + PhabricatorPolicyCapability::CAN_EDIT); + + $actions->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Edit Queue')) + ->setIcon('fa-pencil') + ->setHref($this->getApplicationURI("queue/edit/{$id}/")) + ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)); + + return $actions; + } + + private function buildPropertyView( + NuanceQueue $queue, + PhabricatorActionListView $actions) { + $viewer = $this->getViewer(); + + $properties = id(new PHUIPropertyListView()) + ->setUser($viewer) + ->setObject($queue) + ->setActionList($actions); + + return $properties; + } } diff --git a/src/applications/nuance/editor/NuanceQueueEditor.php b/src/applications/nuance/editor/NuanceQueueEditor.php index 69d18f6e4a..589ab5da5c 100644 --- a/src/applications/nuance/editor/NuanceQueueEditor.php +++ b/src/applications/nuance/editor/NuanceQueueEditor.php @@ -14,12 +14,88 @@ final class NuanceQueueEditor public function getTransactionTypes() { $types = parent::getTransactionTypes(); - $types[] = PhabricatorTransactions::TYPE_EDGE; - $types[] = PhabricatorTransactions::TYPE_COMMENT; + $types[] = NuanceQueueTransaction::TYPE_NAME; + $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; return $types; } + protected function getCustomTransactionOldValue( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + switch ($xaction->getTransactionType()) { + case NuanceQueueTransaction::TYPE_NAME: + return $object->getName(); + } + + return parent::getCustomTransactionOldValue($object, $xaction); + } + + protected function getCustomTransactionNewValue( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + switch ($xaction->getTransactionType()) { + case NuanceQueueTransaction::TYPE_NAME: + return $xaction->getNewValue(); + } + + return parent::getCustomTransactionNewValue($object, $xaction); + } + + protected function applyCustomInternalTransaction( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + switch ($xaction->getTransactionType()) { + case NuanceQueueTransaction::TYPE_NAME: + $object->setName($xaction->getNewValue()); + break; + } + } + + protected function applyCustomExternalTransaction( + PhabricatorLiskDAO $object, + PhabricatorApplicationTransaction $xaction) { + + switch ($xaction->getTransactionType()) { + case NuanceQueueTransaction::TYPE_NAME: + return; + } + + return parent::applyCustomExternalTransaction($object, $xaction); + } + protected function validateTransaction( + PhabricatorLiskDAO $object, + $type, + array $xactions) { + + $errors = parent::validateTransaction($object, $type, $xactions); + + switch ($type) { + case NuanceQueueTransaction::TYPE_NAME: + $missing = $this->validateIsEmptyTextField( + $object->getName(), + $xactions); + + if ($missing) { + $error = new PhabricatorApplicationTransactionValidationError( + $type, + pht('Required'), + pht('A queue must have a name.'), + nonempty(last($xactions), null)); + + $error->setIsMissingFieldError(true); + $errors[] = $error; + } + break; + } + + return $errors; + } + + } diff --git a/src/applications/nuance/query/NuanceQueueSearchEngine.php b/src/applications/nuance/query/NuanceQueueSearchEngine.php new file mode 100644 index 0000000000..139068ed50 --- /dev/null +++ b/src/applications/nuance/query/NuanceQueueSearchEngine.php @@ -0,0 +1,75 @@ + pht('All Queues'), + ); + + return $names; + } + + public function buildSavedQueryFromBuiltin($query_key) { + $query = $this->newSavedQuery(); + $query->setQueryKey($query_key); + + switch ($query_key) { + case 'all': + return $query; + } + + return parent::buildSavedQueryFromBuiltin($query_key); + } + + protected function renderResultList( + array $queues, + PhabricatorSavedQuery $query, + array $handles) { + assert_instances_of($queues, 'NuanceQueue'); + + $viewer = $this->requireViewer(); + + $list = new PHUIObjectItemListView(); + $list->setUser($viewer); + foreach ($queues as $queue) { + $item = id(new PHUIObjectItemView()) + ->setObjectName(pht('Queue %d', $queue->getID())) + ->setHeader($queue->getName()) + ->setHref($queue->getURI()); + $list->addItem($item); + } + + return $list; + } + +} diff --git a/src/applications/nuance/storage/NuanceQueueTransaction.php b/src/applications/nuance/storage/NuanceQueueTransaction.php index 0e8ffcfdee..46ace23cd1 100644 --- a/src/applications/nuance/storage/NuanceQueueTransaction.php +++ b/src/applications/nuance/storage/NuanceQueueTransaction.php @@ -2,6 +2,8 @@ final class NuanceQueueTransaction extends NuanceTransaction { + const TYPE_NAME = 'nuance.queue.name'; + public function getApplicationTransactionType() { return NuanceQueuePHIDType::TYPECONST; }