mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 14:52:41 +01:00
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
This commit is contained in:
parent
dc687dbd92
commit
d2ef273ecd
12 changed files with 147 additions and 94 deletions
2
resources/sql/autopatches/20150806.ponder.status.1.sql
Normal file
2
resources/sql/autopatches/20150806.ponder.status.1.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_ponder.ponder_question
|
||||
MODIFY status VARCHAR(32) NOT NULL COLLATE {$COLLATE_TEXT};
|
2
resources/sql/autopatches/20150806.ponder.status.2.sql
Normal file
2
resources/sql/autopatches/20150806.ponder.status.2.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
UPDATE {$NAMESPACE}_ponder.ponder_question
|
||||
SET status = 'open' WHERE status = 0;
|
2
resources/sql/autopatches/20150806.ponder.status.3.sql
Normal file
2
resources/sql/autopatches/20150806.ponder.status.3.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
UPDATE {$NAMESPACE}_ponder.ponder_question
|
||||
SET status = 'resolved' WHERE status = 1;
|
|
@ -71,7 +71,7 @@ final class PhabricatorPonderApplication extends PhabricatorApplication {
|
|||
=> 'PonderQuestionHistoryController',
|
||||
'preview/'
|
||||
=> 'PhabricatorMarkupPreviewController',
|
||||
'question/(?P<status>open|close)/(?P<id>[1-9]\d*)/'
|
||||
'question/status/(?P<id>[1-9]\d*)/'
|
||||
=> 'PonderQuestionStatusController',
|
||||
'vote/' => 'PonderVoteSaveController',
|
||||
),
|
||||
|
|
|
@ -2,20 +2,40 @@
|
|||
|
||||
final class PonderQuestionStatus extends PonderConstants {
|
||||
|
||||
const STATUS_OPEN = 0;
|
||||
const STATUS_CLOSED = 1;
|
||||
const STATUS_OPEN = 'open';
|
||||
const STATUS_CLOSED_RESOLVED = 'resolved';
|
||||
const STATUS_CLOSED_OBSOLETE = 'obsolete';
|
||||
const STATUS_CLOSED_DUPLICATE = 'duplicate';
|
||||
|
||||
public static function getQuestionStatusMap() {
|
||||
return array(
|
||||
self::STATUS_OPEN => pht('Open'),
|
||||
self::STATUS_CLOSED => pht('Closed'),
|
||||
self::STATUS_OPEN => pht('Open'),
|
||||
self::STATUS_CLOSED_RESOLVED => pht('Closed, Resolved'),
|
||||
self::STATUS_CLOSED_OBSOLETE => pht('Closed, Obsolete'),
|
||||
self::STATUS_CLOSED_DUPLICATE => pht('Closed, Duplicate'),
|
||||
);
|
||||
}
|
||||
|
||||
public static function getQuestionStatusFullName($status) {
|
||||
$map = array(
|
||||
self::STATUS_OPEN => pht('Open'),
|
||||
self::STATUS_CLOSED => pht('Closed by author'),
|
||||
self::STATUS_OPEN => pht('Open'),
|
||||
self::STATUS_CLOSED_RESOLVED => pht('Closed, Resolved'),
|
||||
self::STATUS_CLOSED_OBSOLETE => pht('Closed, Obsolete'),
|
||||
self::STATUS_CLOSED_DUPLICATE => pht('Closed, Duplicate'),
|
||||
);
|
||||
return idx($map, $status, pht('Unknown'));
|
||||
}
|
||||
|
||||
public static function getQuestionStatusDescription($status) {
|
||||
$map = array(
|
||||
self::STATUS_OPEN =>
|
||||
pht('This question is open for answers.'),
|
||||
self::STATUS_CLOSED_RESOLVED =>
|
||||
pht('This question has been resolved.'),
|
||||
self::STATUS_CLOSED_OBSOLETE =>
|
||||
pht('This question is no longer valid or out of date.'),
|
||||
self::STATUS_CLOSED_DUPLICATE =>
|
||||
pht('This question is a duplicate of another question.'),
|
||||
);
|
||||
return idx($map, $status, pht('Unknown'));
|
||||
}
|
||||
|
@ -23,7 +43,9 @@ final class PonderQuestionStatus extends PonderConstants {
|
|||
public static function getQuestionStatusTagColor($status) {
|
||||
$map = array(
|
||||
self::STATUS_OPEN => PHUITagView::COLOR_BLUE,
|
||||
self::STATUS_CLOSED => PHUITagView::COLOR_BLACK,
|
||||
self::STATUS_CLOSED_RESOLVED => PHUITagView::COLOR_BLACK,
|
||||
self::STATUS_CLOSED_OBSOLETE => PHUITagView::COLOR_BLACK,
|
||||
self::STATUS_CLOSED_DUPLICATE => PHUITagView::COLOR_BLACK,
|
||||
);
|
||||
|
||||
return idx($map, $status);
|
||||
|
@ -32,10 +54,27 @@ final class PonderQuestionStatus extends PonderConstants {
|
|||
public static function getQuestionStatusIcon($status) {
|
||||
$map = array(
|
||||
self::STATUS_OPEN => 'fa-question-circle',
|
||||
self::STATUS_CLOSED => 'fa-check-square-o',
|
||||
self::STATUS_CLOSED_RESOLVED => 'fa-check',
|
||||
self::STATUS_CLOSED_OBSOLETE => 'fa-ban',
|
||||
self::STATUS_CLOSED_DUPLICATE => 'fa-clone',
|
||||
);
|
||||
|
||||
return idx($map, $status);
|
||||
}
|
||||
|
||||
public static function getQuestionStatusOpenMap() {
|
||||
return array(
|
||||
self::STATUS_OPEN,
|
||||
);
|
||||
}
|
||||
|
||||
public static function getQuestionStatusClosedMap() {
|
||||
return array(
|
||||
self::STATUS_CLOSED_RESOLVED,
|
||||
self::STATUS_CLOSED_OBSOLETE,
|
||||
self::STATUS_CLOSED_DUPLICATE,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -33,6 +33,8 @@ final class PonderQuestionEditController extends PonderController {
|
|||
$v_view = $question->getViewPolicy();
|
||||
$v_edit = $question->getEditPolicy();
|
||||
$v_space = $question->getSpacePHID();
|
||||
$v_status = $question->getStatus();
|
||||
|
||||
|
||||
$errors = array();
|
||||
$e_title = true;
|
||||
|
@ -43,6 +45,7 @@ final class PonderQuestionEditController extends PonderController {
|
|||
$v_view = $request->getStr('viewPolicy');
|
||||
$v_edit = $request->getStr('editPolicy');
|
||||
$v_space = $request->getStr('spacePHID');
|
||||
$v_status = $request->getStr('status');
|
||||
|
||||
$len = phutil_utf8_strlen($v_title);
|
||||
if ($len < 1) {
|
||||
|
@ -65,6 +68,10 @@ final class PonderQuestionEditController extends PonderController {
|
|||
->setTransactionType(PonderQuestionTransaction::TYPE_CONTENT)
|
||||
->setNewValue($v_content);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType(PonderQuestionTransaction::TYPE_STATUS)
|
||||
->setNewValue($v_status);
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
|
||||
->setNewValue($v_view);
|
||||
|
@ -130,7 +137,13 @@ final class PonderQuestionEditController extends PonderController {
|
|||
->setPolicyObject($question)
|
||||
->setPolicies($policies)
|
||||
->setValue($v_edit)
|
||||
->setCapability(PhabricatorPolicyCapability::CAN_EDIT));
|
||||
->setCapability(PhabricatorPolicyCapability::CAN_EDIT))
|
||||
->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setLabel(pht('Status'))
|
||||
->setName('status')
|
||||
->setValue($v_status)
|
||||
->setOptions(PonderQuestionStatus::getQuestionStatusMap()));
|
||||
|
||||
$form->appendControl(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
|
@ -149,21 +162,23 @@ final class PonderQuestionEditController extends PonderController {
|
|||
->setControlID('content')
|
||||
->setPreviewURI($this->getApplicationURI('preview/'));
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('Ask New Question'))
|
||||
->setFormErrors($errors)
|
||||
->setForm($form);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
|
||||
$id = $question->getID();
|
||||
if ($id) {
|
||||
$crumbs->addTextCrumb("Q{$id}", "/Q{$id}");
|
||||
$crumbs->addTextCrumb(pht('Edit'));
|
||||
$title = pht('Edit Question');
|
||||
} else {
|
||||
$crumbs->addTextCrumb(pht('Ask Question'));
|
||||
$title = pht('Ask New Question');
|
||||
}
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText($title)
|
||||
->setFormErrors($errors)
|
||||
->setForm($form);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
|
@ -171,7 +186,7 @@ final class PonderQuestionEditController extends PonderController {
|
|||
$preview,
|
||||
),
|
||||
array(
|
||||
'title' => pht('Ask New Question'),
|
||||
'title' => $title,
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ final class PonderQuestionStatusController
|
|||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
$id = $request->getURIData('id');
|
||||
$status = $request->getURIData('status');
|
||||
|
||||
$question = id(new PonderQuestionQuery())
|
||||
->setViewer($viewer)
|
||||
|
@ -21,29 +20,46 @@ final class PonderQuestionStatusController
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
switch ($status) {
|
||||
case 'open':
|
||||
$status = PonderQuestionStatus::STATUS_OPEN;
|
||||
break;
|
||||
case 'close':
|
||||
$status = PonderQuestionStatus::STATUS_CLOSED;
|
||||
break;
|
||||
default:
|
||||
return new Aphront400Response();
|
||||
$view_uri = '/Q'.$question->getID();
|
||||
$v_status = $question->getStatus();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$v_status = $request->getStr('status');
|
||||
|
||||
$xactions = array();
|
||||
$xactions[] = id(new PonderQuestionTransaction())
|
||||
->setTransactionType(PonderQuestionTransaction::TYPE_STATUS)
|
||||
->setNewValue($v_status);
|
||||
|
||||
$editor = id(new PonderQuestionEditor())
|
||||
->setActor($viewer)
|
||||
->setContentSourceFromRequest($request);
|
||||
|
||||
$editor->applyTransactions($question, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($view_uri);
|
||||
}
|
||||
|
||||
$xactions = array();
|
||||
$xactions[] = id(new PonderQuestionTransaction())
|
||||
->setTransactionType(PonderQuestionTransaction::TYPE_STATUS)
|
||||
->setNewValue($status);
|
||||
$radio = id(new AphrontFormRadioButtonControl())
|
||||
->setLabel(pht('Status'))
|
||||
->setName('status')
|
||||
->setValue($v_status);
|
||||
|
||||
$editor = id(new PonderQuestionEditor())
|
||||
->setActor($viewer)
|
||||
->setContentSourceFromRequest($request);
|
||||
foreach (PonderQuestionStatus::getQuestionStatusMap() as $value => $name) {
|
||||
$description = PonderQuestionStatus::getQuestionStatusDescription($value);
|
||||
$radio->addButton($value, $name, $description);
|
||||
}
|
||||
|
||||
$editor->applyTransactions($question, $xactions);
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendChild($radio);
|
||||
|
||||
return $this->newDialog()
|
||||
->setTitle(pht('Change Question Status'))
|
||||
->appendChild($form->buildLayoutView())
|
||||
->addSubmitButton(pht('Submit'))
|
||||
->addCancelButton($view_uri);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI('/Q'.$question->getID());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -45,7 +45,11 @@ final class PonderQuestionViewController extends PonderController {
|
|||
if ($question->getStatus() == PonderQuestionStatus::STATUS_OPEN) {
|
||||
$header->setStatus('fa-square-o', 'bluegrey', pht('Open'));
|
||||
} else {
|
||||
$header->setStatus('fa-check-square-o', 'dark', pht('Closed'));
|
||||
$text = PonderQuestionStatus::getQuestionStatusFullName(
|
||||
$question->getStatus());
|
||||
$icon = PonderQuestionStatus::getQuestionStatusIcon(
|
||||
$question->getStatus());
|
||||
$header->setStatus($icon, 'dark', $text);
|
||||
}
|
||||
|
||||
$actions = $this->buildActionListView($question);
|
||||
|
@ -109,21 +113,18 @@ final class PonderQuestionViewController extends PonderController {
|
|||
if ($question->getStatus() == PonderQuestionStatus::STATUS_OPEN) {
|
||||
$name = pht('Close Question');
|
||||
$icon = 'fa-check-square-o';
|
||||
$href = 'close';
|
||||
} else {
|
||||
$name = pht('Reopen Question');
|
||||
$icon = 'fa-square-o';
|
||||
$href = 'open';
|
||||
}
|
||||
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName($name)
|
||||
->setIcon($icon)
|
||||
->setRenderAsForm($can_edit)
|
||||
->setWorkflow(!$can_edit)
|
||||
->setWorkflow(true)
|
||||
->setDisabled(!$can_edit)
|
||||
->setHref($this->getApplicationURI("/question/{$href}/{$id}/")));
|
||||
->setHref($this->getApplicationURI("/question/status/{$id}/")));
|
||||
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
|
|
|
@ -5,17 +5,12 @@ final class PonderQuestionQuery
|
|||
|
||||
private $ids;
|
||||
private $phids;
|
||||
private $status;
|
||||
private $authorPHIDs;
|
||||
private $answererPHIDs;
|
||||
|
||||
private $needProjectPHIDs;
|
||||
|
||||
private $status = 'status-any';
|
||||
|
||||
const STATUS_ANY = 'status-any';
|
||||
const STATUS_OPEN = 'status-open';
|
||||
const STATUS_CLOSED = 'status-closed';
|
||||
|
||||
private $needAnswers;
|
||||
private $needViewerVotes;
|
||||
|
||||
|
@ -34,7 +29,7 @@ final class PonderQuestionQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withStatus($status) {
|
||||
public function withStatuses($status) {
|
||||
$this->status = $status;
|
||||
return $this;
|
||||
}
|
||||
|
@ -84,24 +79,10 @@ final class PonderQuestionQuery
|
|||
}
|
||||
|
||||
if ($this->status !== null) {
|
||||
switch ($this->status) {
|
||||
case self::STATUS_ANY:
|
||||
break;
|
||||
case self::STATUS_OPEN:
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'q.status = %d',
|
||||
PonderQuestionStatus::STATUS_OPEN);
|
||||
break;
|
||||
case self::STATUS_CLOSED:
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'q.status = %d',
|
||||
PonderQuestionStatus::STATUS_CLOSED);
|
||||
break;
|
||||
default:
|
||||
throw new Exception(pht("Unknown status query '%s'!", $this->status));
|
||||
}
|
||||
$where[] = qsprintf(
|
||||
$conn,
|
||||
'q.status IN (%Ls)',
|
||||
$this->status);
|
||||
}
|
||||
|
||||
return $where;
|
||||
|
|
|
@ -27,16 +27,8 @@ final class PonderQuestionSearchEngine
|
|||
$query->withAnswererPHIDs($map['answerers']);
|
||||
}
|
||||
|
||||
$status = $map['status'];
|
||||
if ($status != null) {
|
||||
switch ($status) {
|
||||
case 0:
|
||||
$query->withStatus(PonderQuestionQuery::STATUS_OPEN);
|
||||
break;
|
||||
case 1:
|
||||
$query->withStatus(PonderQuestionQuery::STATUS_CLOSED);
|
||||
break;
|
||||
}
|
||||
if ($map['statuses']) {
|
||||
$query->withStatuses($map['statuses']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
|
@ -52,9 +44,9 @@ final class PonderQuestionSearchEngine
|
|||
->setKey('answerers')
|
||||
->setAliases(array('answerers'))
|
||||
->setLabel(pht('Answered By')),
|
||||
id(new PhabricatorSearchSelectField())
|
||||
id(new PhabricatorSearchCheckboxesField())
|
||||
->setLabel(pht('Status'))
|
||||
->setKey('status')
|
||||
->setKey('statuses')
|
||||
->setOptions(PonderQuestionStatus::getQuestionStatusMap()),
|
||||
);
|
||||
}
|
||||
|
@ -66,6 +58,7 @@ final class PonderQuestionSearchEngine
|
|||
protected function getBuiltinQueryNames() {
|
||||
$names = array(
|
||||
'open' => pht('Open Questions'),
|
||||
'resolved' => pht('Resolved Questions'),
|
||||
'all' => pht('All Questions'),
|
||||
);
|
||||
|
||||
|
@ -85,7 +78,11 @@ final class PonderQuestionSearchEngine
|
|||
case 'all':
|
||||
return $query;
|
||||
case 'open':
|
||||
return $query->setParameter('status', PonderQuestionQuery::STATUS_OPEN);
|
||||
return $query->setParameter(
|
||||
'statuses', array(PonderQuestionStatus::STATUS_OPEN));
|
||||
case 'resolved':
|
||||
return $query->setParameter(
|
||||
'statuses', array(PonderQuestionStatus::STATUS_CLOSED_RESOLVED));
|
||||
case 'authored':
|
||||
return $query->setParameter(
|
||||
'authorPHIDs',
|
||||
|
|
|
@ -65,7 +65,7 @@ final class PonderQuestion extends PonderDAO
|
|||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'title' => 'text255',
|
||||
'voteCount' => 'sint32',
|
||||
'status' => 'uint32',
|
||||
'status' => 'text32',
|
||||
'content' => 'text',
|
||||
'heat' => 'double',
|
||||
'answerCount' => 'uint32',
|
||||
|
|
|
@ -87,9 +87,17 @@ final class PonderQuestionTransaction
|
|||
return pht(
|
||||
'%s reopened this question.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
case PonderQuestionStatus::STATUS_CLOSED:
|
||||
case PonderQuestionStatus::STATUS_CLOSED_RESOLVED:
|
||||
return pht(
|
||||
'%s closed this question.',
|
||||
'%s closed this question as resolved.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
case PonderQuestionStatus::STATUS_CLOSED_OBSOLETE:
|
||||
return pht(
|
||||
'%s closed this question as obsolete.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
case PonderQuestionStatus::STATUS_CLOSED_DUPLICATE:
|
||||
return pht(
|
||||
'%s closed this question as a duplicate.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
}
|
||||
}
|
||||
|
@ -106,12 +114,7 @@ final class PonderQuestionTransaction
|
|||
case self::TYPE_CONTENT:
|
||||
return 'fa-pencil';
|
||||
case self::TYPE_STATUS:
|
||||
switch ($new) {
|
||||
case PonderQuestionStatus::STATUS_OPEN:
|
||||
return 'fa-check-circle';
|
||||
case PonderQuestionStatus::STATUS_CLOSED:
|
||||
return 'fa-minus-circle';
|
||||
}
|
||||
return PonderQuestionStatus::getQuestionStatusIcon($new);
|
||||
case self::TYPE_ANSWERS:
|
||||
return 'fa-plus';
|
||||
}
|
||||
|
@ -130,12 +133,7 @@ final class PonderQuestionTransaction
|
|||
case self::TYPE_ANSWERS:
|
||||
return PhabricatorTransactions::COLOR_GREEN;
|
||||
case self::TYPE_STATUS:
|
||||
switch ($new) {
|
||||
case PonderQuestionStatus::STATUS_OPEN:
|
||||
return PhabricatorTransactions::COLOR_GREEN;
|
||||
case PonderQuestionStatus::STATUS_CLOSED:
|
||||
return PhabricatorTransactions::COLOR_INDIGO;
|
||||
}
|
||||
return PonderQuestionStatus::getQuestionStatusTagColor($new);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue