@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 additional statuses to Ponder

Summary: Ref T9096. This is a first cut at adding additional statuses, happy to add or subtract as needed... maybe even configurable? Also, the dialog doesn't seem to fire, I'll keep debugging.

Test Plan: Close and Reopen many questions. Test applicationSearch params by seeing resolved questions, all questions.

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin

Maniphest Tasks: T9096

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

+147 -94
+2
resources/sql/autopatches/20150806.ponder.status.1.sql
··· 1 + ALTER TABLE {$NAMESPACE}_ponder.ponder_question 2 + MODIFY status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT};
+2
resources/sql/autopatches/20150806.ponder.status.2.sql
··· 1 + UPDATE {$NAMESPACE}_ponder.ponder_question 2 + SET status = 'open' WHERE status = 0;
+2
resources/sql/autopatches/20150806.ponder.status.3.sql
··· 1 + UPDATE {$NAMESPACE}_ponder.ponder_question 2 + SET status = 'resolved' WHERE status = 1;
+1 -1
src/applications/ponder/application/PhabricatorPonderApplication.php
··· 71 71 => 'PonderQuestionHistoryController', 72 72 'preview/' 73 73 => 'PhabricatorMarkupPreviewController', 74 - 'question/(?P<status>open|close)/(?P<id>[1-9]\d*)/' 74 + 'question/status/(?P<id>[1-9]\d*)/' 75 75 => 'PonderQuestionStatusController', 76 76 'vote/' => 'PonderVoteSaveController', 77 77 ),
+47 -8
src/applications/ponder/constants/PonderQuestionStatus.php
··· 2 2 3 3 final class PonderQuestionStatus extends PonderConstants { 4 4 5 - const STATUS_OPEN = 0; 6 - const STATUS_CLOSED = 1; 5 + const STATUS_OPEN = 'open'; 6 + const STATUS_CLOSED_RESOLVED = 'resolved'; 7 + const STATUS_CLOSED_OBSOLETE = 'obsolete'; 8 + const STATUS_CLOSED_DUPLICATE = 'duplicate'; 7 9 8 10 public static function getQuestionStatusMap() { 9 11 return array( 10 - self::STATUS_OPEN => pht('Open'), 11 - self::STATUS_CLOSED => pht('Closed'), 12 + self::STATUS_OPEN => pht('Open'), 13 + self::STATUS_CLOSED_RESOLVED => pht('Closed, Resolved'), 14 + self::STATUS_CLOSED_OBSOLETE => pht('Closed, Obsolete'), 15 + self::STATUS_CLOSED_DUPLICATE => pht('Closed, Duplicate'), 12 16 ); 13 17 } 14 18 15 19 public static function getQuestionStatusFullName($status) { 16 20 $map = array( 17 - self::STATUS_OPEN => pht('Open'), 18 - self::STATUS_CLOSED => pht('Closed by author'), 21 + self::STATUS_OPEN => pht('Open'), 22 + self::STATUS_CLOSED_RESOLVED => pht('Closed, Resolved'), 23 + self::STATUS_CLOSED_OBSOLETE => pht('Closed, Obsolete'), 24 + self::STATUS_CLOSED_DUPLICATE => pht('Closed, Duplicate'), 25 + ); 26 + return idx($map, $status, pht('Unknown')); 27 + } 28 + 29 + public static function getQuestionStatusDescription($status) { 30 + $map = array( 31 + self::STATUS_OPEN => 32 + pht('This question is open for answers.'), 33 + self::STATUS_CLOSED_RESOLVED => 34 + pht('This question has been resolved.'), 35 + self::STATUS_CLOSED_OBSOLETE => 36 + pht('This question is no longer valid or out of date.'), 37 + self::STATUS_CLOSED_DUPLICATE => 38 + pht('This question is a duplicate of another question.'), 19 39 ); 20 40 return idx($map, $status, pht('Unknown')); 21 41 } ··· 23 43 public static function getQuestionStatusTagColor($status) { 24 44 $map = array( 25 45 self::STATUS_OPEN => PHUITagView::COLOR_BLUE, 26 - self::STATUS_CLOSED => PHUITagView::COLOR_BLACK, 46 + self::STATUS_CLOSED_RESOLVED => PHUITagView::COLOR_BLACK, 47 + self::STATUS_CLOSED_OBSOLETE => PHUITagView::COLOR_BLACK, 48 + self::STATUS_CLOSED_DUPLICATE => PHUITagView::COLOR_BLACK, 27 49 ); 28 50 29 51 return idx($map, $status); ··· 32 54 public static function getQuestionStatusIcon($status) { 33 55 $map = array( 34 56 self::STATUS_OPEN => 'fa-question-circle', 35 - self::STATUS_CLOSED => 'fa-check-square-o', 57 + self::STATUS_CLOSED_RESOLVED => 'fa-check', 58 + self::STATUS_CLOSED_OBSOLETE => 'fa-ban', 59 + self::STATUS_CLOSED_DUPLICATE => 'fa-clone', 36 60 ); 37 61 38 62 return idx($map, $status); 39 63 } 64 + 65 + public static function getQuestionStatusOpenMap() { 66 + return array( 67 + self::STATUS_OPEN, 68 + ); 69 + } 70 + 71 + public static function getQuestionStatusClosedMap() { 72 + return array( 73 + self::STATUS_CLOSED_RESOLVED, 74 + self::STATUS_CLOSED_OBSOLETE, 75 + self::STATUS_CLOSED_DUPLICATE, 76 + ); 77 + } 78 + 40 79 41 80 }
+22 -7
src/applications/ponder/controller/PonderQuestionEditController.php
··· 33 33 $v_view = $question->getViewPolicy(); 34 34 $v_edit = $question->getEditPolicy(); 35 35 $v_space = $question->getSpacePHID(); 36 + $v_status = $question->getStatus(); 37 + 36 38 37 39 $errors = array(); 38 40 $e_title = true; ··· 43 45 $v_view = $request->getStr('viewPolicy'); 44 46 $v_edit = $request->getStr('editPolicy'); 45 47 $v_space = $request->getStr('spacePHID'); 48 + $v_status = $request->getStr('status'); 46 49 47 50 $len = phutil_utf8_strlen($v_title); 48 51 if ($len < 1) { ··· 64 67 $xactions[] = id(clone $template) 65 68 ->setTransactionType(PonderQuestionTransaction::TYPE_CONTENT) 66 69 ->setNewValue($v_content); 70 + 71 + $xactions[] = id(clone $template) 72 + ->setTransactionType(PonderQuestionTransaction::TYPE_STATUS) 73 + ->setNewValue($v_status); 67 74 68 75 $xactions[] = id(clone $template) 69 76 ->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY) ··· 130 137 ->setPolicyObject($question) 131 138 ->setPolicies($policies) 132 139 ->setValue($v_edit) 133 - ->setCapability(PhabricatorPolicyCapability::CAN_EDIT)); 140 + ->setCapability(PhabricatorPolicyCapability::CAN_EDIT)) 141 + ->appendChild( 142 + id(new AphrontFormSelectControl()) 143 + ->setLabel(pht('Status')) 144 + ->setName('status') 145 + ->setValue($v_status) 146 + ->setOptions(PonderQuestionStatus::getQuestionStatusMap())); 134 147 135 148 $form->appendControl( 136 149 id(new AphrontFormTokenizerControl()) ··· 149 162 ->setControlID('content') 150 163 ->setPreviewURI($this->getApplicationURI('preview/')); 151 164 152 - $form_box = id(new PHUIObjectBoxView()) 153 - ->setHeaderText(pht('Ask New Question')) 154 - ->setFormErrors($errors) 155 - ->setForm($form); 156 - 157 165 $crumbs = $this->buildApplicationCrumbs(); 158 166 159 167 $id = $question->getID(); 160 168 if ($id) { 161 169 $crumbs->addTextCrumb("Q{$id}", "/Q{$id}"); 162 170 $crumbs->addTextCrumb(pht('Edit')); 171 + $title = pht('Edit Question'); 163 172 } else { 164 173 $crumbs->addTextCrumb(pht('Ask Question')); 174 + $title = pht('Ask New Question'); 165 175 } 166 176 177 + $form_box = id(new PHUIObjectBoxView()) 178 + ->setHeaderText($title) 179 + ->setFormErrors($errors) 180 + ->setForm($form); 181 + 167 182 return $this->buildApplicationPage( 168 183 array( 169 184 $crumbs, ··· 171 186 $preview, 172 187 ), 173 188 array( 174 - 'title' => pht('Ask New Question'), 189 + 'title' => $title, 175 190 )); 176 191 } 177 192
+35 -19
src/applications/ponder/controller/PonderQuestionStatusController.php
··· 6 6 public function handleRequest(AphrontRequest $request) { 7 7 $viewer = $request->getViewer(); 8 8 $id = $request->getURIData('id'); 9 - $status = $request->getURIData('status'); 10 9 11 10 $question = id(new PonderQuestionQuery()) 12 11 ->setViewer($viewer) ··· 21 20 return new Aphront404Response(); 22 21 } 23 22 24 - switch ($status) { 25 - case 'open': 26 - $status = PonderQuestionStatus::STATUS_OPEN; 27 - break; 28 - case 'close': 29 - $status = PonderQuestionStatus::STATUS_CLOSED; 30 - break; 31 - default: 32 - return new Aphront400Response(); 23 + $view_uri = '/Q'.$question->getID(); 24 + $v_status = $question->getStatus(); 25 + 26 + if ($request->isFormPost()) { 27 + $v_status = $request->getStr('status'); 28 + 29 + $xactions = array(); 30 + $xactions[] = id(new PonderQuestionTransaction()) 31 + ->setTransactionType(PonderQuestionTransaction::TYPE_STATUS) 32 + ->setNewValue($v_status); 33 + 34 + $editor = id(new PonderQuestionEditor()) 35 + ->setActor($viewer) 36 + ->setContentSourceFromRequest($request); 37 + 38 + $editor->applyTransactions($question, $xactions); 39 + 40 + return id(new AphrontRedirectResponse())->setURI($view_uri); 33 41 } 34 42 35 - $xactions = array(); 36 - $xactions[] = id(new PonderQuestionTransaction()) 37 - ->setTransactionType(PonderQuestionTransaction::TYPE_STATUS) 38 - ->setNewValue($status); 43 + $radio = id(new AphrontFormRadioButtonControl()) 44 + ->setLabel(pht('Status')) 45 + ->setName('status') 46 + ->setValue($v_status); 47 + 48 + foreach (PonderQuestionStatus::getQuestionStatusMap() as $value => $name) { 49 + $description = PonderQuestionStatus::getQuestionStatusDescription($value); 50 + $radio->addButton($value, $name, $description); 51 + } 39 52 40 - $editor = id(new PonderQuestionEditor()) 41 - ->setActor($viewer) 42 - ->setContentSourceFromRequest($request); 53 + $form = id(new AphrontFormView()) 54 + ->setUser($viewer) 55 + ->appendChild($radio); 43 56 44 - $editor->applyTransactions($question, $xactions); 57 + return $this->newDialog() 58 + ->setTitle(pht('Change Question Status')) 59 + ->appendChild($form->buildLayoutView()) 60 + ->addSubmitButton(pht('Submit')) 61 + ->addCancelButton($view_uri); 45 62 46 - return id(new AphrontRedirectResponse())->setURI('/Q'.$question->getID()); 47 63 } 48 64 49 65 }
+7 -6
src/applications/ponder/controller/PonderQuestionViewController.php
··· 45 45 if ($question->getStatus() == PonderQuestionStatus::STATUS_OPEN) { 46 46 $header->setStatus('fa-square-o', 'bluegrey', pht('Open')); 47 47 } else { 48 - $header->setStatus('fa-check-square-o', 'dark', pht('Closed')); 48 + $text = PonderQuestionStatus::getQuestionStatusFullName( 49 + $question->getStatus()); 50 + $icon = PonderQuestionStatus::getQuestionStatusIcon( 51 + $question->getStatus()); 52 + $header->setStatus($icon, 'dark', $text); 49 53 } 50 54 51 55 $actions = $this->buildActionListView($question); ··· 109 113 if ($question->getStatus() == PonderQuestionStatus::STATUS_OPEN) { 110 114 $name = pht('Close Question'); 111 115 $icon = 'fa-check-square-o'; 112 - $href = 'close'; 113 116 } else { 114 117 $name = pht('Reopen Question'); 115 118 $icon = 'fa-square-o'; 116 - $href = 'open'; 117 119 } 118 120 119 121 $view->addAction( 120 122 id(new PhabricatorActionView()) 121 123 ->setName($name) 122 124 ->setIcon($icon) 123 - ->setRenderAsForm($can_edit) 124 - ->setWorkflow(!$can_edit) 125 + ->setWorkflow(true) 125 126 ->setDisabled(!$can_edit) 126 - ->setHref($this->getApplicationURI("/question/{$href}/{$id}/"))); 127 + ->setHref($this->getApplicationURI("/question/status/{$id}/"))); 127 128 128 129 $view->addAction( 129 130 id(new PhabricatorActionView())
+6 -25
src/applications/ponder/query/PonderQuestionQuery.php
··· 5 5 6 6 private $ids; 7 7 private $phids; 8 + private $status; 8 9 private $authorPHIDs; 9 10 private $answererPHIDs; 10 11 11 12 private $needProjectPHIDs; 12 - 13 - private $status = 'status-any'; 14 - 15 - const STATUS_ANY = 'status-any'; 16 - const STATUS_OPEN = 'status-open'; 17 - const STATUS_CLOSED = 'status-closed'; 18 13 19 14 private $needAnswers; 20 15 private $needViewerVotes; ··· 34 29 return $this; 35 30 } 36 31 37 - public function withStatus($status) { 32 + public function withStatuses($status) { 38 33 $this->status = $status; 39 34 return $this; 40 35 } ··· 84 79 } 85 80 86 81 if ($this->status !== null) { 87 - switch ($this->status) { 88 - case self::STATUS_ANY: 89 - break; 90 - case self::STATUS_OPEN: 91 - $where[] = qsprintf( 92 - $conn, 93 - 'q.status = %d', 94 - PonderQuestionStatus::STATUS_OPEN); 95 - break; 96 - case self::STATUS_CLOSED: 97 - $where[] = qsprintf( 98 - $conn, 99 - 'q.status = %d', 100 - PonderQuestionStatus::STATUS_CLOSED); 101 - break; 102 - default: 103 - throw new Exception(pht("Unknown status query '%s'!", $this->status)); 104 - } 82 + $where[] = qsprintf( 83 + $conn, 84 + 'q.status IN (%Ls)', 85 + $this->status); 105 86 } 106 87 107 88 return $where;
+10 -13
src/applications/ponder/query/PonderQuestionSearchEngine.php
··· 27 27 $query->withAnswererPHIDs($map['answerers']); 28 28 } 29 29 30 - $status = $map['status']; 31 - if ($status != null) { 32 - switch ($status) { 33 - case 0: 34 - $query->withStatus(PonderQuestionQuery::STATUS_OPEN); 35 - break; 36 - case 1: 37 - $query->withStatus(PonderQuestionQuery::STATUS_CLOSED); 38 - break; 39 - } 30 + if ($map['statuses']) { 31 + $query->withStatuses($map['statuses']); 40 32 } 41 33 42 34 return $query; ··· 52 44 ->setKey('answerers') 53 45 ->setAliases(array('answerers')) 54 46 ->setLabel(pht('Answered By')), 55 - id(new PhabricatorSearchSelectField()) 47 + id(new PhabricatorSearchCheckboxesField()) 56 48 ->setLabel(pht('Status')) 57 - ->setKey('status') 49 + ->setKey('statuses') 58 50 ->setOptions(PonderQuestionStatus::getQuestionStatusMap()), 59 51 ); 60 52 } ··· 66 58 protected function getBuiltinQueryNames() { 67 59 $names = array( 68 60 'open' => pht('Open Questions'), 61 + 'resolved' => pht('Resolved Questions'), 69 62 'all' => pht('All Questions'), 70 63 ); 71 64 ··· 85 78 case 'all': 86 79 return $query; 87 80 case 'open': 88 - return $query->setParameter('status', PonderQuestionQuery::STATUS_OPEN); 81 + return $query->setParameter( 82 + 'statuses', array(PonderQuestionStatus::STATUS_OPEN)); 83 + case 'resolved': 84 + return $query->setParameter( 85 + 'statuses', array(PonderQuestionStatus::STATUS_CLOSED_RESOLVED)); 89 86 case 'authored': 90 87 return $query->setParameter( 91 88 'authorPHIDs',
+1 -1
src/applications/ponder/storage/PonderQuestion.php
··· 65 65 self::CONFIG_COLUMN_SCHEMA => array( 66 66 'title' => 'text255', 67 67 'voteCount' => 'sint32', 68 - 'status' => 'uint32', 68 + 'status' => 'text32', 69 69 'content' => 'text', 70 70 'heat' => 'double', 71 71 'answerCount' => 'uint32',
+12 -14
src/applications/ponder/storage/PonderQuestionTransaction.php
··· 87 87 return pht( 88 88 '%s reopened this question.', 89 89 $this->renderHandleLink($author_phid)); 90 - case PonderQuestionStatus::STATUS_CLOSED: 90 + case PonderQuestionStatus::STATUS_CLOSED_RESOLVED: 91 91 return pht( 92 - '%s closed this question.', 92 + '%s closed this question as resolved.', 93 + $this->renderHandleLink($author_phid)); 94 + case PonderQuestionStatus::STATUS_CLOSED_OBSOLETE: 95 + return pht( 96 + '%s closed this question as obsolete.', 97 + $this->renderHandleLink($author_phid)); 98 + case PonderQuestionStatus::STATUS_CLOSED_DUPLICATE: 99 + return pht( 100 + '%s closed this question as a duplicate.', 93 101 $this->renderHandleLink($author_phid)); 94 102 } 95 103 } ··· 106 114 case self::TYPE_CONTENT: 107 115 return 'fa-pencil'; 108 116 case self::TYPE_STATUS: 109 - switch ($new) { 110 - case PonderQuestionStatus::STATUS_OPEN: 111 - return 'fa-check-circle'; 112 - case PonderQuestionStatus::STATUS_CLOSED: 113 - return 'fa-minus-circle'; 114 - } 117 + return PonderQuestionStatus::getQuestionStatusIcon($new); 115 118 case self::TYPE_ANSWERS: 116 119 return 'fa-plus'; 117 120 } ··· 130 133 case self::TYPE_ANSWERS: 131 134 return PhabricatorTransactions::COLOR_GREEN; 132 135 case self::TYPE_STATUS: 133 - switch ($new) { 134 - case PonderQuestionStatus::STATUS_OPEN: 135 - return PhabricatorTransactions::COLOR_GREEN; 136 - case PonderQuestionStatus::STATUS_CLOSED: 137 - return PhabricatorTransactions::COLOR_INDIGO; 138 - } 136 + return PonderQuestionStatus::getQuestionStatusTagColor($new); 139 137 } 140 138 } 141 139