@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add very basic routing to Nuance

Summary:
Ref T8783. Sort out some relationships and fields:

- Make Items 1:1 with Queues: each item is always in exactly one queue. Minor discussion on T8783. I think this is easier to understand and reason about (and implement!) and can't come up with any real cases where it isn't powerful enough.
- Remove "QueueItem", which allowed items to be in multiple queues at once.
- Remove "dateNuanced", which is equivalent to "dateCreated" in all cases.

Then add really basic routing:

- Add "Default Queue" for Sources. New items from the source route into that queue.
- (Some day there will be routing rules, but for now the rule is "always route into the default queue".)
- Show queue on items.
- Show more / more useful edit history and transactions in several UIs.

Test Plan:
{F749445}

{F749446}

{F749447}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T8783

Differential Revision: https://secure.phabricator.com/D13988

+288 -72
+1
resources/sql/autopatches/20150823.nuance.queue.1.sql
··· 1 + DROP TABLE {$NAMESPACE}_nuance.nuance_queueitem;
+2
resources/sql/autopatches/20150823.nuance.queue.2.sql
··· 1 + ALTER TABLE {$NAMESPACE}_nuance.nuance_item 2 + ADD queuePHID VARBINARY(64) NOT NULL;
+2
resources/sql/autopatches/20150823.nuance.queue.3.sql
··· 1 + ALTER TABLE {$NAMESPACE}_nuance.nuance_source 2 + ADD defaultQueuePHID VARBINARY(64) NOT NULL;
+2
resources/sql/autopatches/20150823.nuance.queue.4.sql
··· 1 + ALTER TABLE {$NAMESPACE}_nuance.nuance_item 2 + DROP dateNuanced;
+2 -2
src/__phutil_library_map__.php
··· 1288 1288 'NuancePhabricatorFormSourceDefinition' => 'applications/nuance/source/NuancePhabricatorFormSourceDefinition.php', 1289 1289 'NuanceQuery' => 'applications/nuance/query/NuanceQuery.php', 1290 1290 'NuanceQueue' => 'applications/nuance/storage/NuanceQueue.php', 1291 + 'NuanceQueueDatasource' => 'applications/nuance/typeahead/NuanceQueueDatasource.php', 1291 1292 'NuanceQueueEditController' => 'applications/nuance/controller/NuanceQueueEditController.php', 1292 1293 'NuanceQueueEditor' => 'applications/nuance/editor/NuanceQueueEditor.php', 1293 - 'NuanceQueueItem' => 'applications/nuance/storage/NuanceQueueItem.php', 1294 1294 'NuanceQueueListController' => 'applications/nuance/controller/NuanceQueueListController.php', 1295 1295 'NuanceQueuePHIDType' => 'applications/nuance/phid/NuanceQueuePHIDType.php', 1296 1296 'NuanceQueueQuery' => 'applications/nuance/query/NuanceQueueQuery.php', ··· 5080 5080 'PhabricatorPolicyInterface', 5081 5081 'PhabricatorApplicationTransactionInterface', 5082 5082 ), 5083 + 'NuanceQueueDatasource' => 'PhabricatorTypeaheadDatasource', 5083 5084 'NuanceQueueEditController' => 'NuanceController', 5084 5085 'NuanceQueueEditor' => 'PhabricatorApplicationTransactionEditor', 5085 - 'NuanceQueueItem' => 'NuanceDAO', 5086 5086 'NuanceQueueListController' => 'NuanceController', 5087 5087 'NuanceQueuePHIDType' => 'PhabricatorPHIDType', 5088 5088 'NuanceQueueQuery' => 'NuanceQuery',
+11
src/applications/nuance/controller/NuanceItemEditController.php
··· 33 33 ->setHeaderText($title) 34 34 ->addPropertyList($properties); 35 35 36 + $timeline = $this->buildTransactionTimeline( 37 + $item, 38 + new NuanceItemTransactionQuery()); 39 + 40 + $timeline->setShouldTerminate(true); 41 + 36 42 return $this->buildApplicationPage( 37 43 array( 38 44 $crumbs, 39 45 $box, 46 + $timeline, 40 47 ), 41 48 array( 42 49 'title' => $title, ··· 61 68 $properties->addProperty( 62 69 pht('Source'), 63 70 $viewer->renderHandle($item->getSourcePHID())); 71 + 72 + $properties->addProperty( 73 + pht('Queue'), 74 + $viewer->renderHandle($item->getQueuePHID())); 64 75 65 76 $source = $item->getSource(); 66 77 $definition = $source->requireDefinition();
+20 -1
src/applications/nuance/controller/NuanceSourceViewController.php
··· 13 13 return new Aphront404Response(); 14 14 } 15 15 16 - $source_phid = $source->getPHID(); 16 + $source_id = $source->getID(); 17 17 18 18 $timeline = $this->buildTransactionTimeline( 19 19 $source, ··· 34 34 35 35 $crumbs->addTextCrumb($title); 36 36 37 + 38 + $can_edit = PhabricatorPolicyFilter::hasCapability( 39 + $viewer, 40 + $source, 41 + PhabricatorPolicyCapability::CAN_EDIT); 42 + 43 + $routing_list = id(new PHUIPropertyListView()) 44 + ->addProperty( 45 + pht('Default Queue'), 46 + $viewer->renderHandle($source->getDefaultQueuePHID())); 47 + 48 + $routing_header = id(new PHUIHeaderView()) 49 + ->setHeader(pht('Routing Rules')); 50 + 51 + $routing = id(new PHUIObjectBoxView()) 52 + ->setHeader($routing_header) 53 + ->addPropertyList($routing_list); 54 + 37 55 return $this->buildApplicationPage( 38 56 array( 39 57 $crumbs, 40 58 $box, 59 + $routing, 41 60 $timeline, 42 61 ), 43 62 array(
+8
src/applications/nuance/editor/NuanceItemEditor.php
··· 18 18 $types[] = NuanceItemTransaction::TYPE_SOURCE; 19 19 $types[] = NuanceItemTransaction::TYPE_REQUESTOR; 20 20 $types[] = NuanceItemTransaction::TYPE_PROPERTY; 21 + $types[] = NuanceItemTransaction::TYPE_QUEUE; 21 22 22 23 $types[] = PhabricatorTransactions::TYPE_EDGE; 23 24 $types[] = PhabricatorTransactions::TYPE_COMMENT; ··· 38 39 return $object->getSourcePHID(); 39 40 case NuanceItemTransaction::TYPE_OWNER: 40 41 return $object->getOwnerPHID(); 42 + case NuanceItemTransaction::TYPE_QUEUE: 43 + return $object->getQueuePHID(); 41 44 case NuanceItemTransaction::TYPE_PROPERTY: 42 45 $key = $xaction->getMetadataValue( 43 46 NuanceItemTransaction::PROPERTY_KEY); ··· 56 59 case NuanceItemTransaction::TYPE_SOURCE: 57 60 case NuanceItemTransaction::TYPE_OWNER: 58 61 case NuanceItemTransaction::TYPE_PROPERTY: 62 + case NuanceItemTransaction::TYPE_QUEUE: 59 63 return $xaction->getNewValue(); 60 64 } 61 65 ··· 76 80 case NuanceItemTransaction::TYPE_OWNER: 77 81 $object->setOwnerPHID($xaction->getNewValue()); 78 82 break; 83 + case NuanceItemTransaction::TYPE_QUEUE: 84 + $object->setQueuePHID($xaction->getNewValue()); 85 + break; 79 86 case NuanceItemTransaction::TYPE_PROPERTY: 80 87 $key = $xaction->getMetadataValue( 81 88 NuanceItemTransaction::PROPERTY_KEY); ··· 93 100 case NuanceItemTransaction::TYPE_SOURCE: 94 101 case NuanceItemTransaction::TYPE_OWNER: 95 102 case NuanceItemTransaction::TYPE_PROPERTY: 103 + case NuanceItemTransaction::TYPE_QUEUE: 96 104 return; 97 105 } 98 106
+21
src/applications/nuance/editor/NuanceSourceEditor.php
··· 15 15 $types = parent::getTransactionTypes(); 16 16 17 17 $types[] = NuanceSourceTransaction::TYPE_NAME; 18 + $types[] = NuanceSourceTransaction::TYPE_DEFAULT_QUEUE; 18 19 19 20 $types[] = PhabricatorTransactions::TYPE_EDGE; 20 21 $types[] = PhabricatorTransactions::TYPE_COMMENT; ··· 31 32 switch ($xaction->getTransactionType()) { 32 33 case NuanceSourceTransaction::TYPE_NAME: 33 34 return $object->getName(); 35 + case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE: 36 + return $object->getDefaultQueuePHID(); 34 37 } 35 38 36 39 return parent::getCustomTransactionOldValue($object, $xaction); ··· 42 45 43 46 switch ($xaction->getTransactionType()) { 44 47 case NuanceSourceTransaction::TYPE_NAME: 48 + case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE: 45 49 return $xaction->getNewValue(); 46 50 } 47 51 ··· 56 60 case NuanceSourceTransaction::TYPE_NAME: 57 61 $object->setName($xaction->getNewValue()); 58 62 break; 63 + case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE: 64 + $object->setDefaultQueuePHID($xaction->getNewValue()); 65 + break; 59 66 } 60 67 } 61 68 ··· 65 72 66 73 switch ($xaction->getTransactionType()) { 67 74 case NuanceSourceTransaction::TYPE_NAME: 75 + case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE: 68 76 return; 69 77 } 70 78 ··· 93 101 94 102 $error->setIsMissingFieldError(true); 95 103 $errors[] = $error; 104 + } 105 + break; 106 + case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE: 107 + foreach ($xactions as $xaction) { 108 + if (!$xaction->getNewValue()) { 109 + $error = new PhabricatorApplicationTransactionValidationError( 110 + $type, 111 + pht('Required'), 112 + pht('Sources must have a default queue.'), 113 + $xaction); 114 + $error->setIsMissingFieldError(true); 115 + $errors[] = $error; 116 + } 96 117 } 97 118 break; 98 119 }
+39 -13
src/applications/nuance/source/NuanceSourceDefinition.php
··· 169 169 170 170 $form = $this->augmentEditForm($form, $ex); 171 171 172 + $default_phid = $source->getDefaultQueuePHID(); 173 + if ($default_phid) { 174 + $default_queues = array($default_phid); 175 + } else { 176 + $default_queues = array(); 177 + } 178 + 172 179 $form 180 + ->appendControl( 181 + id(new AphrontFormTokenizerControl()) 182 + ->setLabel(pht('Default Queue')) 183 + ->setName('defaultQueuePHIDs') 184 + ->setLimit(1) 185 + ->setDatasource(new NuanceQueueDatasource()) 186 + ->setValue($default_queues)) 173 187 ->appendChild( 174 188 id(new AphrontFormPolicyControl()) 175 - ->setUser($user) 176 - ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) 177 - ->setPolicyObject($source) 178 - ->setPolicies($policies) 179 - ->setName('viewPolicy')) 189 + ->setUser($user) 190 + ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) 191 + ->setPolicyObject($source) 192 + ->setPolicies($policies) 193 + ->setName('viewPolicy')) 180 194 ->appendChild( 181 195 id(new AphrontFormPolicyControl()) 182 - ->setUser($user) 183 - ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) 184 - ->setPolicyObject($source) 185 - ->setPolicies($policies) 186 - ->setName('editPolicy')) 196 + ->setUser($user) 197 + ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) 198 + ->setPolicyObject($source) 199 + ->setPolicies($policies) 200 + ->setName('editPolicy')) 187 201 ->appendChild( 188 202 id(new AphrontFormSubmitControl()) 189 - ->addCancelButton($source->getURI()) 190 - ->setValue(pht('Save'))); 203 + ->addCancelButton($source->getURI()) 204 + ->setValue(pht('Save'))); 191 205 192 206 return $form; 193 207 } ··· 213 227 $transactions[] = id(new NuanceSourceTransaction()) 214 228 ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) 215 229 ->setNewValue($request->getStr('editPolicy')); 230 + 216 231 $transactions[] = id(new NuanceSourceTransaction()) 217 232 ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) 218 233 ->setNewValue($request->getStr('viewPolicy')); 219 - $transactions[] = id(new NuanceSourceTransaction()) 234 + 235 + $transactions[] = id(new NuanceSourceTransaction()) 220 236 ->setTransactionType(NuanceSourceTransaction::TYPE_NAME) 221 237 ->setNewvalue($request->getStr('name')); 238 + 239 + $transactions[] = id(new NuanceSourceTransaction()) 240 + ->setTransactionType(NuanceSourceTransaction::TYPE_DEFAULT_QUEUE) 241 + ->setNewvalue(head($request->getArr('defaultQueuePHIDs'))); 222 242 223 243 return $transactions; 224 244 } ··· 250 270 $xactions[] = id(new NuanceItemTransaction()) 251 271 ->setTransactionType(NuanceItemTransaction::TYPE_REQUESTOR) 252 272 ->setNewValue($requestor->getPHID()); 273 + 274 + // TODO: Eventually, apply real routing rules. For now, just put everything 275 + // in the default queue for the source. 276 + $xactions[] = id(new NuanceItemTransaction()) 277 + ->setTransactionType(NuanceItemTransaction::TYPE_QUEUE) 278 + ->setNewValue($source->getDefaultQueuePHID()); 253 279 254 280 foreach ($properties as $key => $property) { 255 281 $xactions[] = id(new NuanceItemTransaction())
+8 -8
src/applications/nuance/storage/NuanceItem.php
··· 17 17 protected $sourceLabel; 18 18 protected $data = array(); 19 19 protected $mailKey; 20 - protected $dateNuanced; 20 + protected $queuePHID; 21 21 22 22 private $source = self::ATTACHABLE; 23 23 24 24 public static function initializeNewItem() { 25 25 return id(new NuanceItem()) 26 - ->setDateNuanced(time()) 27 26 ->setStatus(self::STATUS_OPEN); 28 27 } 29 28 ··· 38 37 'sourceLabel' => 'text255?', 39 38 'status' => 'uint32', 40 39 'mailKey' => 'bytes20', 41 - 'dateNuanced' => 'epoch', 42 40 ), 43 41 self::CONFIG_KEY_SCHEMA => array( 44 42 'key_source' => array( 45 - 'columns' => array('sourcePHID', 'status', 'dateNuanced', 'id'), 43 + 'columns' => array('sourcePHID', 'status'), 46 44 ), 47 45 'key_owner' => array( 48 - 'columns' => array('ownerPHID', 'status', 'dateNuanced', 'id'), 46 + 'columns' => array('ownerPHID', 'status'), 47 + ), 48 + 'key_requestor' => array( 49 + 'columns' => array('requestorPHID', 'status'), 49 50 ), 50 - 'key_contacter' => array( 51 - 'columns' => array('requestorPHID', 'status', 'dateNuanced', 'id'), 51 + 'key_queue' => array( 52 + 'columns' => array('queuePHID', 'status'), 52 53 ), 53 54 ), 54 55 ) + parent::getConfiguration(); ··· 144 145 'sourceLabel' => $this->getSourceLabel(), 145 146 'dateCreated' => $this->getDateCreated(), 146 147 'dateModified' => $this->getDateModified(), 147 - 'dateNuanced' => $this->getDateNuanced(), 148 148 ); 149 149 } 150 150
+52
src/applications/nuance/storage/NuanceItemTransaction.php
··· 9 9 const TYPE_REQUESTOR = 'nuance.item.requestor'; 10 10 const TYPE_SOURCE = 'nuance.item.source'; 11 11 const TYPE_PROPERTY = 'nuance.item.property'; 12 + const TYPE_QUEUE = 'nuance.item.queue'; 12 13 13 14 public function getApplicationTransactionType() { 14 15 return NuanceItemPHIDType::TYPECONST; ··· 16 17 17 18 public function getApplicationTransactionCommentObject() { 18 19 return new NuanceItemTransactionComment(); 20 + } 21 + 22 + public function shouldHide() { 23 + $old = $this->getOldValue(); 24 + $type = $this->getTransactionType(); 25 + 26 + switch ($type) { 27 + case self::TYPE_REQUESTOR: 28 + case self::TYPE_SOURCE: 29 + return ($old === null); 30 + } 31 + 32 + return parent::shouldHide(); 33 + } 34 + 35 + public function getRequiredHandlePHIDs() { 36 + $old = $this->getOldValue(); 37 + $new = $this->getNewValue(); 38 + $type = $this->getTransactionType(); 39 + 40 + $phids = parent::getRequiredHandlePHIDs(); 41 + switch ($type) { 42 + case self::TYPE_QUEUE: 43 + if ($old) { 44 + $phids[] = $old; 45 + } 46 + if ($new) { 47 + $phids[] = $new; 48 + } 49 + break; 50 + } 51 + 52 + return $phids; 53 + } 54 + 55 + public function getTitle() { 56 + $old = $this->getOldValue(); 57 + $new = $this->getNewValue(); 58 + $type = $this->getTransactionType(); 59 + 60 + $author_phid = $this->getAuthorPHID(); 61 + 62 + switch ($type) { 63 + case self::TYPE_QUEUE: 64 + return pht( 65 + '%s routed this item to the %s queue.', 66 + $this->renderHandleLink($author_phid), 67 + $this->renderHandleLink($new)); 68 + } 69 + 70 + return parent::getTitle(); 19 71 } 20 72 21 73 }
-34
src/applications/nuance/storage/NuanceQueueItem.php
··· 1 - <?php 2 - 3 - final class NuanceQueueItem 4 - extends NuanceDAO { 5 - 6 - protected $queuePHID; 7 - protected $itemPHID; 8 - protected $itemStatus; 9 - protected $itemDateNuanced; 10 - 11 - protected function getConfiguration() { 12 - return array( 13 - self::CONFIG_COLUMN_SCHEMA => array( 14 - 'itemStatus' => 'uint32', 15 - 'itemDateNuanced' => 'epoch', 16 - ), 17 - self::CONFIG_KEY_SCHEMA => array( 18 - 'key_one_per_queue' => array( 19 - 'columns' => array('itemPHID', 'queuePHID'), 20 - 'unique' => true, 21 - ), 22 - 'key_queue' => array( 23 - 'columns' => array( 24 - 'queuePHID', 25 - 'itemStatus', 26 - 'itemDateNuanced', 27 - 'id', 28 - ), 29 - ), 30 - ), 31 - ) + parent::getConfiguration(); 32 - } 33 - 34 - }
+30
src/applications/nuance/storage/NuanceQueueTransaction.php
··· 12 12 return new NuanceQueueTransactionComment(); 13 13 } 14 14 15 + public function shouldHide() { 16 + $old = $this->getOldValue(); 17 + $type = $this->getTransactionType(); 18 + 19 + switch ($type) { 20 + case self::TYPE_NAME: 21 + return ($old === null); 22 + } 23 + 24 + return parent::shouldHide(); 25 + } 26 + 27 + public function getTitle() { 28 + $old = $this->getOldValue(); 29 + $new = $this->getNewValue(); 30 + $type = $this->getTransactionType(); 31 + 32 + $author_phid = $this->getAuthorPHID(); 33 + 34 + switch ($type) { 35 + case self::TYPE_NAME: 36 + return pht( 37 + '%s renamed this queue from "%s" to "%s".', 38 + $this->renderHandleLink($author_phid), 39 + $old, 40 + $new); 41 + } 42 + 43 + return parent::getTitle(); 44 + } 15 45 }
+1
src/applications/nuance/storage/NuanceSource.php
··· 11 11 protected $mailKey; 12 12 protected $viewPolicy; 13 13 protected $editPolicy; 14 + protected $defaultQueuePHID; 14 15 15 16 private $definition; 16 17
+51 -14
src/applications/nuance/storage/NuanceSourceTransaction.php
··· 3 3 final class NuanceSourceTransaction 4 4 extends NuanceTransaction { 5 5 6 - const TYPE_NAME = 'name-source'; 6 + const TYPE_NAME = 'source.name'; 7 + const TYPE_DEFAULT_QUEUE = 'source.queue.default'; 7 8 8 9 public function getApplicationTransactionType() { 9 10 return NuanceSourcePHIDType::TYPECONST; ··· 13 14 return new NuanceSourceTransactionComment(); 14 15 } 15 16 17 + public function shouldHide() { 18 + $old = $this->getOldValue(); 19 + $new = $this->getNewValue(); 20 + $type = $this->getTransactionType(); 21 + 22 + switch ($type) { 23 + case self::TYPE_DEFAULT_QUEUE: 24 + return !$old; 25 + case self::TYPE_NAME: 26 + return ($old === null); 27 + } 28 + 29 + return parent::shouldHide(); 30 + } 31 + 32 + public function getRequiredHandlePHIDs() { 33 + $old = $this->getOldValue(); 34 + $new = $this->getNewValue(); 35 + $type = $this->getTransactionType(); 36 + 37 + $phids = parent::getRequiredHandlePHIDs(); 38 + switch ($type) { 39 + case self::TYPE_DEFAULT_QUEUE: 40 + if ($old) { 41 + $phids[] = $old; 42 + } 43 + if ($new) { 44 + $phids[] = $new; 45 + } 46 + break; 47 + } 48 + 49 + return $phids; 50 + } 51 + 16 52 public function getTitle() { 17 53 $old = $this->getOldValue(); 18 54 $new = $this->getNewValue(); 55 + $type = $this->getTransactionType(); 19 56 $author_phid = $this->getAuthorPHID(); 20 57 21 - switch ($this->getTransactionType()) { 58 + switch ($type) { 59 + case self::TYPE_DEFAULT_QUEUE: 60 + return pht( 61 + '%s changed the default queue from %s to %s.', 62 + $this->renderHandleLink($author_phid), 63 + $this->renderHandleLink($old), 64 + $this->renderHandleLink($new)); 22 65 case self::TYPE_NAME: 23 - if ($old === null) { 24 - return pht( 25 - '%s created this source.', 26 - $this->renderHandleLink($author_phid)); 27 - } else { 28 - return pht( 29 - '%s renamed this source from "%s" to "%s".', 30 - $this->renderHandleLink($author_phid), 31 - $old, 32 - $new); 33 - } 34 - break; 66 + return pht( 67 + '%s renamed this source from "%s" to "%s".', 68 + $this->renderHandleLink($author_phid), 69 + $old, 70 + $new); 35 71 } 36 72 73 + return parent::getTitle(); 37 74 } 38 75 39 76 }
+38
src/applications/nuance/typeahead/NuanceQueueDatasource.php
··· 1 + <?php 2 + 3 + final class NuanceQueueDatasource 4 + extends PhabricatorTypeaheadDatasource { 5 + 6 + public function getBrowseTitle() { 7 + return pht('Browse Queues'); 8 + } 9 + 10 + public function getPlaceholderText() { 11 + return pht('Type a queue name...'); 12 + } 13 + 14 + public function getDatasourceApplicationClass() { 15 + return 'PhabricatorNuanceApplication'; 16 + } 17 + 18 + public function loadResults() { 19 + $viewer = $this->getViewer(); 20 + $raw_query = $this->getRawQuery(); 21 + 22 + $results = array(); 23 + 24 + // TODO: Make this use real typeahead logic. 25 + $query = new NuanceQueueQuery(); 26 + $queues = $this->executeQuery($query); 27 + 28 + foreach ($queues as $queue) { 29 + $results[] = id(new PhabricatorTypeaheadResult()) 30 + ->setName($queue->getName()) 31 + ->setURI('/nuance/queue/'.$queue->getID().'/') 32 + ->setPHID($queue->getPHID()); 33 + } 34 + 35 + return $this->filterResultsAgainstTokens($results); 36 + } 37 + 38 + }