@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 basic "View" and "Edit" features to Nuance

Summary:
Ref T8783.

The "View" UI is where a user would check their request for feedback or a resolution, if it's something that makes sense for them to interact with from the web UI.

The "Edit" UI is the manage/admin UI where you'd respond to a request. It's similar to the view UI but will have actions and eventually some queue UI, etc.

(I don't think items need a normal "Edit" UI -- it doesn't make sense to "Edit" a tweet or inbound email -- but maybe this will shuffle around a little eventually.)

Test Plan:
View

{F747218}

Edit

{F747219}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T8783

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

+214 -30
+73 -12
src/applications/nuance/controller/NuanceItemEditController.php
··· 3 3 final class NuanceItemEditController extends NuanceController { 4 4 5 5 public function handleRequest(AphrontRequest $request) { 6 - $viewer = $request->getViewer(); 6 + $viewer = $this->getViewer(); 7 7 $id = $request->getURIData('id'); 8 8 9 - if (!$id) { 10 - $item = new NuanceItem(); 11 - } else { 12 - $item = id(new NuanceItemQuery()) 13 - ->setViewer($viewer) 14 - ->withIDs(array($id)) 15 - ->executeOne(); 16 - } 17 - 9 + $item = id(new NuanceItemQuery()) 10 + ->setViewer($viewer) 11 + ->withIDs(array($id)) 12 + ->requireCapabilities( 13 + array( 14 + PhabricatorPolicyCapability::CAN_VIEW, 15 + PhabricatorPolicyCapability::CAN_EDIT, 16 + )) 17 + ->executeOne(); 18 18 if (!$item) { 19 19 return new Aphront404Response(); 20 20 } 21 + 22 + $title = pht('Item %d', $item->getID()); 21 23 22 24 $crumbs = $this->buildApplicationCrumbs(); 23 - $title = 'TODO'; 25 + $crumbs->addTextCrumb($title); 26 + $crumbs->addTextCrumb(pht('Edit')); 27 + 28 + $properties = $this->buildPropertyView($item); 29 + $actions = $this->buildActionView($item); 30 + $properties->setActionList($actions); 31 + 32 + $box = id(new PHUIObjectBoxView()) 33 + ->setHeaderText($title) 34 + ->addPropertyList($properties); 24 35 25 36 return $this->buildApplicationPage( 26 - $crumbs, 37 + array( 38 + $crumbs, 39 + $box, 40 + ), 27 41 array( 28 42 'title' => $title, 29 43 )); 30 44 } 45 + 46 + private function buildPropertyView(NuanceItem $item) { 47 + $viewer = $this->getViewer(); 48 + 49 + $properties = id(new PHUIPropertyListView()) 50 + ->setUser($viewer) 51 + ->setObject($item); 52 + 53 + $properties->addProperty( 54 + pht('Date Created'), 55 + phabricator_datetime($item->getDateCreated(), $viewer)); 56 + 57 + $properties->addProperty( 58 + pht('Requestor'), 59 + $viewer->renderHandle($item->getRequestorPHID())); 60 + 61 + $properties->addProperty( 62 + pht('Source'), 63 + $viewer->renderHandle($item->getSourcePHID())); 64 + 65 + $source = $item->getSource(); 66 + $definition = $source->requireDefinition(); 67 + 68 + $definition->renderItemEditProperties( 69 + $viewer, 70 + $item, 71 + $properties); 72 + 73 + return $properties; 74 + } 75 + 76 + private function buildActionView(NuanceItem $item) { 77 + $viewer = $this->getViewer(); 78 + $id = $item->getID(); 79 + 80 + $actions = id(new PhabricatorActionListView()) 81 + ->setUser($viewer); 82 + 83 + $actions->addAction( 84 + id(new PhabricatorActionView()) 85 + ->setName(pht('View Item')) 86 + ->setIcon('fa-eye') 87 + ->setHref($this->getApplicationURI("item/view/{$id}/"))); 88 + 89 + return $actions; 90 + } 91 + 31 92 32 93 }
+63 -4
src/applications/nuance/controller/NuanceItemViewController.php
··· 3 3 final class NuanceItemViewController extends NuanceController { 4 4 5 5 public function handleRequest(AphrontRequest $request) { 6 - $viewer = $request->getViewer(); 6 + $viewer = $this->getViewer(); 7 7 $id = $request->getURIData('id'); 8 8 9 9 $item = id(new NuanceItemQuery()) 10 10 ->setViewer($viewer) 11 11 ->withIDs(array($id)) 12 12 ->executeOne(); 13 - 14 13 if (!$item) { 15 14 return new Aphront404Response(); 16 15 } 16 + 17 + $title = pht('Item %d', $item->getID()); 17 18 18 19 $crumbs = $this->buildApplicationCrumbs(); 19 - $title = 'TODO'; 20 + $crumbs->addTextCrumb($title); 21 + 22 + $properties = $this->buildPropertyView($item); 23 + $actions = $this->buildActionView($item); 24 + $properties->setActionList($actions); 25 + 26 + $box = id(new PHUIObjectBoxView()) 27 + ->setHeaderText($title) 28 + ->addPropertyList($properties); 20 29 21 30 return $this->buildApplicationPage( 22 - $crumbs, 31 + array( 32 + $crumbs, 33 + $box, 34 + ), 23 35 array( 24 36 'title' => $title, 25 37 )); 26 38 } 39 + 40 + private function buildPropertyView(NuanceItem $item) { 41 + $viewer = $this->getViewer(); 42 + 43 + $properties = id(new PHUIPropertyListView()) 44 + ->setUser($viewer) 45 + ->setObject($item); 46 + 47 + $properties->addProperty( 48 + pht('Date Created'), 49 + phabricator_datetime($item->getDateCreated(), $viewer)); 50 + 51 + $source = $item->getSource(); 52 + $definition = $source->requireDefinition(); 53 + 54 + $definition->renderItemViewProperties( 55 + $viewer, 56 + $item, 57 + $properties); 58 + 59 + return $properties; 60 + } 61 + 62 + private function buildActionView(NuanceItem $item) { 63 + $viewer = $this->getViewer(); 64 + $id = $item->getID(); 65 + 66 + $actions = id(new PhabricatorActionListView()) 67 + ->setUser($viewer); 68 + 69 + $can_edit = PhabricatorPolicyFilter::hasCapability( 70 + $viewer, 71 + $item, 72 + PhabricatorPolicyCapability::CAN_EDIT); 73 + 74 + $actions->addAction( 75 + id(new PhabricatorActionView()) 76 + ->setName(pht('Edit Item')) 77 + ->setIcon('fa-pencil') 78 + ->setHref($this->getApplicationURI("item/edit/{$id}/")) 79 + ->setDisabled(!$can_edit) 80 + ->setWorkflow(!$can_edit)); 81 + 82 + return $actions; 83 + } 84 + 85 + 27 86 }
+3 -1
src/applications/nuance/phid/NuanceRequestorPHIDType.php
··· 29 29 foreach ($handles as $phid => $handle) { 30 30 $requestor = $objects[$phid]; 31 31 32 - $handle->setName($requestor->getBestName()); 32 + // TODO: This is currently useless and should be far more informative. 33 + $handle->setName(pht('Requestor %d', $requestor->getID())); 34 + 33 35 $handle->setURI($requestor->getURI()); 34 36 } 35 37 }
+29 -12
src/applications/nuance/query/NuanceItemQuery.php
··· 17 17 return $this; 18 18 } 19 19 20 - public function withSourcePHIDs($source_phids) { 20 + public function withSourcePHIDs(array $source_phids) { 21 21 $this->sourcePHIDs = $source_phids; 22 22 return $this; 23 + } 24 + 25 + public function newResultObject() { 26 + return new NuanceItem(); 23 27 } 24 28 25 29 protected function loadPage() { 26 - $table = new NuanceItem(); 27 - $conn = $table->establishConnection('r'); 30 + return $this->loadStandardPage($this->newResultObject()); 31 + } 32 + 33 + protected function willFilterPage(array $items) { 34 + $source_phids = mpull($items, 'getSourcePHID'); 35 + 36 + // NOTE: We always load sources, even if the viewer can't formally see 37 + // them. If they can see the item, they're allowed to be aware of the 38 + // source in some sense. 39 + $sources = id(new NuanceSourceQuery()) 40 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 41 + ->withPHIDs($source_phids) 42 + ->execute(); 43 + $sources = mpull($sources, null, 'getPHID'); 28 44 29 - $data = queryfx_all( 30 - $conn, 31 - '%Q FROM %T %Q %Q %Q', 32 - $this->buildSelectClause($conn), 33 - $table->getTableName(), 34 - $this->buildWhereClause($conn), 35 - $this->buildOrderClause($conn), 36 - $this->buildLimitClause($conn)); 45 + foreach ($items as $key => $item) { 46 + $source = idx($sources, $item->getSourcePHID()); 47 + if (!$source) { 48 + $this->didRejectResult($items[$key]); 49 + unset($items[$key]); 50 + continue; 51 + } 52 + $item->attachSource($source); 53 + } 37 54 38 - return $table->loadAllFromArray($data); 55 + return $items; 39 56 } 40 57 41 58 protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
+30 -1
src/applications/nuance/source/NuancePhabricatorFormSourceDefinition.php
··· 61 61 62 62 if ($request->isFormPost()) { 63 63 $properties = array( 64 - 'complaint' => (string)$request->getStr('text'), 64 + 'complaint' => (string)$request->getStr('complaint'), 65 65 ); 66 66 67 67 $content_source = PhabricatorContentSource::newFromRequest($request); ··· 98 98 ->appendChild($form); 99 99 100 100 return $box; 101 + } 102 + 103 + public function renderItemViewProperties( 104 + PhabricatorUser $viewer, 105 + NuanceItem $item, 106 + PHUIPropertyListView $view) { 107 + $this->renderItemCommonProperties($viewer, $item, $view); 108 + } 109 + 110 + public function renderItemEditProperties( 111 + PhabricatorUser $viewer, 112 + NuanceItem $item, 113 + PHUIPropertyListView $view) { 114 + $this->renderItemCommonProperties($viewer, $item, $view); 115 + } 116 + 117 + private function renderItemCommonProperties( 118 + PhabricatorUser $viewer, 119 + NuanceItem $item, 120 + PHUIPropertyListView $view) { 121 + 122 + $complaint = $item->getNuanceProperty('complaint'); 123 + $complaint = PhabricatorMarkupEngine::renderOneObject( 124 + id(new PhabricatorMarkupOneOff())->setContent($complaint), 125 + 'default', 126 + $viewer); 127 + 128 + $view->addSectionHeader(pht('Complaint')); 129 + $view->addTextContent($complaint); 101 130 } 102 131 103 132 }
+14
src/applications/nuance/source/NuanceSourceDefinition.php
··· 268 268 return $item; 269 269 } 270 270 271 + public function renderItemViewProperties( 272 + PhabricatorUser $viewer, 273 + NuanceItem $item, 274 + PHUIPropertyListView $view) { 275 + return; 276 + } 277 + 278 + public function renderItemEditProperties( 279 + PhabricatorUser $viewer, 280 + NuanceItem $item, 281 + PHUIPropertyListView $view) { 282 + return; 283 + } 284 + 271 285 272 286 /* -( Handling Action Requests )------------------------------------------- */ 273 287
+2
src/applications/nuance/storage/NuanceItem.php
··· 19 19 protected $mailKey; 20 20 protected $dateNuanced; 21 21 22 + private $source = self::ATTACHABLE; 23 + 22 24 public static function initializeNewItem() { 23 25 return id(new NuanceItem()) 24 26 ->setDateNuanced(time())