1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-09 16:32:39 +01:00

Update Ponder Answer layout

Summary: Ref T9099, A step forward for the main Ponder UI. Mostly moving stuff into View classes and reducing clutter. Took a pass at keeping comments and helpfuls, but unclear what the 'final' UI will be (I'm just designing as I use the product).

Test Plan:
Review a number of questions and answers.

{F702495}

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: Korvin

Maniphest Tasks: T9099

Differential Revision: https://secure.phabricator.com/D13872
This commit is contained in:
Chad Little 2015-08-11 10:42:40 -07:00
parent 53ffaaa889
commit 306af6fb28
7 changed files with 332 additions and 175 deletions

View file

@ -93,7 +93,7 @@ return array(
'rsrc/css/application/policy/policy-edit.css' => '815c66f7',
'rsrc/css/application/policy/policy-transaction-detail.css' => '82100a43',
'rsrc/css/application/policy/policy.css' => '957ea14c',
'rsrc/css/application/ponder/ponder-view.css' => '4e557c89',
'rsrc/css/application/ponder/ponder-view.css' => '6a399881',
'rsrc/css/application/projects/project-icon.css' => '4e3eaa5a',
'rsrc/css/application/releeph/releeph-core.css' => '9b3c5733',
'rsrc/css/application/releeph/releeph-preview-branch.css' => 'b7a6f4a5',
@ -811,7 +811,7 @@ return array(
'policy-css' => '957ea14c',
'policy-edit-css' => '815c66f7',
'policy-transaction-detail-css' => '82100a43',
'ponder-view-css' => '4e557c89',
'ponder-view-css' => '6a399881',
'project-icon-css' => '4e3eaa5a',
'raphael-core' => '51ee6b43',
'raphael-g' => '40dde778',

View file

@ -3398,11 +3398,13 @@ phutil_register_library_map(array(
'PonderAnswerTransaction' => 'applications/ponder/storage/PonderAnswerTransaction.php',
'PonderAnswerTransactionComment' => 'applications/ponder/storage/PonderAnswerTransactionComment.php',
'PonderAnswerTransactionQuery' => 'applications/ponder/query/PonderAnswerTransactionQuery.php',
'PonderAnswerView' => 'applications/ponder/view/PonderAnswerView.php',
'PonderConstants' => 'applications/ponder/constants/PonderConstants.php',
'PonderController' => 'applications/ponder/controller/PonderController.php',
'PonderDAO' => 'applications/ponder/storage/PonderDAO.php',
'PonderDefaultViewCapability' => 'applications/ponder/capability/PonderDefaultViewCapability.php',
'PonderEditor' => 'applications/ponder/editor/PonderEditor.php',
'PonderFooterView' => 'applications/ponder/view/PonderFooterView.php',
'PonderHelpfulSaveController' => 'applications/ponder/controller/PonderHelpfulSaveController.php',
'PonderModerateCapability' => 'applications/ponder/capability/PonderModerateCapability.php',
'PonderQuestion' => 'applications/ponder/storage/PonderQuestion.php',
@ -7569,7 +7571,6 @@ phutil_register_library_map(array(
'PhabricatorPolicyInterface',
'PhabricatorFlaggableInterface',
'PhabricatorSubscribableInterface',
'PhabricatorTokenReceiverInterface',
'PhabricatorDestructibleInterface',
),
'PonderAnswerCommentController' => 'PonderController',
@ -7583,11 +7584,13 @@ phutil_register_library_map(array(
'PonderAnswerTransaction' => 'PhabricatorApplicationTransaction',
'PonderAnswerTransactionComment' => 'PhabricatorApplicationTransactionComment',
'PonderAnswerTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
'PonderAnswerView' => 'AphrontTagView',
'PonderConstants' => 'Phobject',
'PonderController' => 'PhabricatorController',
'PonderDAO' => 'PhabricatorLiskDAO',
'PonderDefaultViewCapability' => 'PhabricatorPolicyCapability',
'PonderEditor' => 'PhabricatorApplicationTransactionEditor',
'PonderFooterView' => 'AphrontTagView',
'PonderHelpfulSaveController' => 'PonderController',
'PonderModerateCapability' => 'PhabricatorPolicyCapability',
'PonderQuestion' => array(

View file

@ -16,7 +16,6 @@ final class PonderQuestionViewController extends PonderController {
return new Aphront404Response();
}
$question_xactions = $this->buildQuestionTransactions($question);
$answers = $this->buildAnswers($question->getAnswers());
$authors = mpull($question->getAnswers(), null, 'getAuthorPHID');
@ -54,9 +53,40 @@ final class PonderQuestionViewController extends PonderController {
$properties = $this->buildPropertyListView($question, $actions);
$sidebar = $this->buildSidebar($question);
$content_id = celerity_generate_unique_node_id();
$timeline = $this->buildTransactionTimeline(
$question,
id(new PonderQuestionTransactionQuery())
->withTransactionTypes(array(PhabricatorTransactions::TYPE_COMMENT)));
$xactions = $timeline->getTransactions();
$add_comment = id(new PhabricatorApplicationTransactionCommentView())
->setUser($viewer)
->setObjectPHID($question->getPHID())
->setShowPreview(false)
->setHeaderText(pht('Question Comment'))
->setAction($this->getApplicationURI("/question/comment/{$id}/"))
->setSubmitButtonName(pht('Comment'));
$comment_view = phutil_tag(
'div',
array(
'id' => $content_id,
'style' => 'display: none;',
),
array(
$timeline,
$add_comment,
));
$footer = id(new PonderFooterView())
->setContentID($content_id)
->setCount(count($xactions));
$object_box = id(new PHUIObjectBoxView())
->setHeader($header)
->addPropertyList($properties);
->addPropertyList($properties)
->appendChild($footer);
$crumbs = $this->buildApplicationCrumbs($this->buildSideNavView());
$crumbs->addTextCrumb('Q'.$id, '/Q'.$id);
@ -64,7 +94,7 @@ final class PonderQuestionViewController extends PonderController {
$ponder_view = id(new PHUITwoColumnView())
->setMainColumn(array(
$object_box,
$question_xactions,
$comment_view,
$answers,
$answer_add_panel,
))
@ -170,32 +200,6 @@ final class PonderQuestionViewController extends PonderController {
return $view;
}
private function buildQuestionTransactions(PonderQuestion $question) {
$viewer = $this->getViewer();
$id = $question->getID();
$timeline = $this->buildTransactionTimeline(
$question,
id(new PonderQuestionTransactionQuery())
->withTransactionTypes(array(PhabricatorTransactions::TYPE_COMMENT)));
$xactions = $timeline->getTransactions();
$add_comment = id(new PhabricatorApplicationTransactionCommentView())
->setUser($viewer)
->setObjectPHID($question->getPHID())
->setShowPreview(false)
->setHeaderText(pht('Question Comment'))
->setAction($this->getApplicationURI("/question/comment/{$id}/"))
->setSubmitButtonName(pht('Comment'));
return $this->wrapComments(
count($xactions),
array(
$timeline,
$add_comment,
));
}
/**
* This is fairly non-standard; building N timelines at once (N = number of
* answers) is tricky business.
@ -206,8 +210,6 @@ final class PonderQuestionViewController extends PonderController {
private function buildAnswers(array $answers) {
$viewer = $this->getViewer();
$out = array();
$xactions = id(new PonderAnswerTransactionQuery())
->setViewer($viewer)
->withTransactionTypes(array(PhabricatorTransactions::TYPE_COMMENT))
@ -227,143 +229,19 @@ final class PonderQuestionViewController extends PonderController {
$xaction_groups = mgroup($xactions, 'getObjectPHID');
$view = array();
foreach ($answers as $answer) {
$author_phid = $answer->getAuthorPHID();
$xactions = idx($xaction_groups, $answer->getPHID(), array());
$id = $answer->getID();
$out[] = phutil_tag('br');
$out[] = phutil_tag('br');
$out[] = id(new PhabricatorAnchorView())
->setAnchorName("A$id");
$header = id(new PHUIHeaderView())
->setHeader($viewer->renderHandle($author_phid));
$actions = $this->buildAnswerActions($answer);
$properties = $this->buildAnswerProperties($answer, $actions);
$object_box = id(new PHUIObjectBoxView())
->setHeader($header)
->addPropertyList($properties);
$out[] = $object_box;
$details = array();
$details[] = id(new PhabricatorApplicationTransactionView())
$view[] = id(new PonderAnswerView())
->setUser($viewer)
->setObjectPHID($answer->getPHID())
->setAnswer($answer)
->setTransactions($xactions)
->setMarkupEngine($engine);
$form = id(new PhabricatorApplicationTransactionCommentView())
->setUser($viewer)
->setObjectPHID($answer->getPHID())
->setShowPreview(false)
->setHeaderText(pht('Answer Comment'))
->setAction($this->getApplicationURI("/answer/comment/{$id}/"))
->setSubmitButtonName(pht('Comment'));
$details[] = $form;
$out[] = $this->wrapComments(
count($xactions),
$details);
}
$out[] = phutil_tag('br');
$out[] = phutil_tag('br');
return $out;
}
private function buildAnswerActions(PonderAnswer $answer) {
$viewer = $this->getViewer();
$request = $this->getRequest();
$id = $answer->getID();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$answer,
PhabricatorPolicyCapability::CAN_EDIT);
$view = id(new PhabricatorActionListView())
->setUser($viewer)
->setObject($answer)
->setObjectURI($request->getRequestURI());
$user_marked = $answer->getUserVote();
$can_vote = $viewer->isLoggedIn();
if ($user_marked) {
$helpful_uri = "/answer/helpful/remove/{$id}/";
$helpful_icon = 'fa-times';
$helpful_text = pht('Remove Helpful');
} else {
$helpful_uri = "/answer/helpful/add/{$id}/";
$helpful_icon = 'fa-thumbs-up';
$helpful_text = pht('Mark as Helpful');
}
$view->addAction(
id(new PhabricatorActionView())
->setIcon($helpful_icon)
->setName($helpful_text)
->setHref($this->getApplicationURI($helpful_uri))
->setRenderAsForm(true)
->setDisabled(!$can_vote)
->setWorkflow($can_vote));
$view->addAction(
id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Answer'))
->setHref($this->getApplicationURI("/answer/edit/{$id}/"))
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
$view->addAction(
id(new PhabricatorActionView())
->setIcon('fa-list')
->setName(pht('View History'))
->setHref($this->getApplicationURI("/answer/history/{$id}/")));
return $view;
}
private function buildAnswerProperties(
PonderAnswer $answer,
PhabricatorActionListView $actions) {
$viewer = $this->getViewer();
$view = id(new PHUIPropertyListView())
->setUser($viewer)
->setObject($answer)
->setActionList($actions);
$view->addProperty(
pht('Created'),
phabricator_datetime($answer->getDateCreated(), $viewer));
$view->addProperty(
pht('Helpfuls'),
$answer->getVoteCount());
$view->invokeWillRenderEvent();
$view->addSectionHeader(pht('Answer'));
$view->addTextContent(
array(
phutil_tag(
'div',
array(
'class' => 'phabricator-remarkup',
),
PhabricatorMarkupEngine::renderOneObject(
$answer,
$answer->getMarkupField(),
$viewer)),
));
return $view;
}

View file

@ -8,7 +8,6 @@ final class PonderAnswer extends PonderDAO
PhabricatorPolicyInterface,
PhabricatorFlaggableInterface,
PhabricatorSubscribableInterface,
PhabricatorTokenReceiverInterface,
PhabricatorDestructibleInterface {
const MARKUP_FIELD_CONTENT = 'markup:content';
@ -234,16 +233,6 @@ final class PonderAnswer extends PonderDAO
}
/* -( PhabricatorTokenReceiverInterface )---------------------------------- */
public function getUsersToNotifyOfTokenGiven() {
return array(
$this->getAuthorPHID(),
);
}
/* -( PhabricatorSubscribableInterface )----------------------------------- */

View file

@ -0,0 +1,172 @@
<?php
final class PonderAnswerView extends AphrontTagView {
private $answer;
private $transactions;
private $engine;
public function setAnswer($answer) {
$this->answer = $answer;
return $this;
}
public function setTransactions($transactions) {
$this->transactions = $transactions;
return $this;
}
public function setMarkupEngine(PhabricatorMarkupEngine $engine) {
$this->engine = $engine;
return $this;
}
protected function getTagAttributes() {
return array(
'class' => 'ponder-answer-view',
);
}
protected function getTagContent() {
require_celerity_resource('ponder-view-css');
$answer = $this->answer;
$viewer = $this->getUser();
$author_phid = $answer->getAuthorPHID();
$actions = $this->buildAnswerActions();
$action_button = id(new PHUIButtonView())
->setTag('a')
->setText(pht('Actions'))
->setHref('#')
->setIconFont('fa-bars')
->setDropdownMenu($actions);
$header = id(new PHUIHeaderView())
->setUser($viewer)
->setEpoch($answer->getDateCreated())
->setHeader($viewer->renderHandle($author_phid))
->addActionLink($action_button);
$content = phutil_tag(
'div',
array(
'class' => 'phabricator-remarkup mlt mlb msr msl',
),
PhabricatorMarkupEngine::renderOneObject(
$answer,
$answer->getMarkupField(),
$viewer));
$id = $answer->getID();
$anchor = id(new PhabricatorAnchorView())
->setAnchorName("A$id");
$content_id = celerity_generate_unique_node_id();
$footer = id(new PonderFooterView())
->setContentID($content_id)
->setCount(count($this->transactions));
$votes = $answer->getVoteCount();
if ($votes) {
$icon = id(new PHUIIconView())
->setIconFont('fa-thumbs-up');
$helpful = phutil_tag(
'span',
array(
'class' => 'ponder-footer-action',
),
array($votes, $icon));
$footer->addAction($helpful);
}
$answer_view = id(new PHUIObjectBoxView())
->setHeader($header)
->appendChild($anchor)
->appendChild($content)
->appendChild($footer);
$transaction_view = id(new PhabricatorApplicationTransactionView())
->setUser($viewer)
->setObjectPHID($answer->getPHID())
->setTransactions($this->transactions)
->setMarkupEngine($this->engine);
$comment_view = id(new PhabricatorApplicationTransactionCommentView())
->setUser($viewer)
->setObjectPHID($answer->getPHID())
->setShowPreview(false)
->setHeaderText(pht('Answer Comment'))
->setAction("/ponder/answer/comment/{$id}/")
->setSubmitButtonName(pht('Comment'));
$hidden_view = phutil_tag(
'div',
array(
'id' => $content_id,
'style' => 'display: none;',
),
array(
$transaction_view,
$comment_view,
));
return array(
$answer_view,
$hidden_view,
);
}
private function buildAnswerActions() {
$viewer = $this->getUser();
$answer = $this->answer;
$id = $answer->getID();
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$answer,
PhabricatorPolicyCapability::CAN_EDIT);
$view = id(new PhabricatorActionListView())
->setUser($viewer)
->setObject($answer)
->setObjectURI('Q'.$answer->getQuestionID());
$user_marked = $answer->getUserVote();
$can_vote = $viewer->isLoggedIn();
if ($user_marked) {
$helpful_uri = "/ponder/answer/helpful/remove/{$id}/";
$helpful_icon = 'fa-times';
$helpful_text = pht('Remove Helpful');
} else {
$helpful_uri = "/ponder/answer/helpful/add/{$id}/";
$helpful_icon = 'fa-thumbs-up';
$helpful_text = pht('Mark as Helpful');
}
$view->addAction(
id(new PhabricatorActionView())
->setIcon($helpful_icon)
->setName($helpful_text)
->setHref($helpful_uri)
->setRenderAsForm(true)
->setDisabled(!$can_vote)
->setWorkflow($can_vote));
$view->addAction(
id(new PhabricatorActionView())
->setIcon('fa-pencil')
->setName(pht('Edit Answer'))
->setHref("/ponder/answer/edit/{$id}/")
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
$view->addAction(
id(new PhabricatorActionView())
->setIcon('fa-list')
->setName(pht('View History'))
->setHref("/ponder/answer/history/{$id}/"));
return $view;
}
}

View file

@ -0,0 +1,79 @@
<?php
final class PonderFooterView extends AphrontTagView {
private $contentID;
private $count;
private $actions = array();
public function setContentID($content_id) {
$this->contentID = $content_id;
return $this;
}
public function setCount($count) {
$this->count = $count;
return $this;
}
public function addAction($action) {
$this->actions[] = $action;
return $this;
}
protected function getTagAttributes() {
return array(
'class' => 'ponder-footer-view',
);
}
protected function getTagContent() {
Javelin::initBehavior('phabricator-reveal-content');
$hide_action_id = celerity_generate_unique_node_id();
$show_action_id = celerity_generate_unique_node_id();
$content_id = $this->contentID;
if ($this->count == 0) {
$text = pht('Add a Comment');
} else {
$text = pht('Show %s Comments', new PhutilNumber($this->count));
}
$actions = array();
$hide_action = javelin_tag(
'a',
array(
'sigil' => 'reveal-content',
'class' => 'ponder-footer-action',
'id' => $hide_action_id,
'href' => '#',
'meta' => array(
'showIDs' => array($content_id, $show_action_id),
'hideIDs' => array($hide_action_id),
),
),
$text);
$show_action = javelin_tag(
'a',
array(
'sigil' => 'reveal-content',
'style' => 'display: none;',
'class' => 'ponder-footer-action',
'id' => $show_action_id,
'href' => '#',
'meta' => array(
'showIDs' => array($hide_action_id),
'hideIDs' => array($content_id, $show_action_id),
),
),
pht('Hide Comments'));
$actions[] = $hide_action;
$actions[] = $show_action;
return array($actions, $this->actions);
}
}

View file

@ -14,7 +14,43 @@
border-right: 1px solid {$lightblueborder};
}
.device-desktop .ponder-comments-view {
width: 90%;
margin: 0 auto;
.ponder-question-view .phui-property-list-properties-wrap {
width: 66%;
}
.ponder-question-view .phui-property-list-actions {
width: 30%;
}
.ponder-answer-view {
margin-top: 16px;
}
.ponder-answer-view .phui-header-subheader {
display: inline;
margin-left: 12px;
}
.ponder-footer-view {
margin: 0 4px -4px;
}
.ponder-footer-view .ponder-footer-action {
padding: 4px 8px;
margin-right: 8px;
color: {$bluetext};
display: inline-block;
background-color: rgba(71, 87, 120, 0.06);
font-size: {$smallerfontsize};
}
.ponder-footer-view .ponder-footer-action .phui-icon-view {
color: {$bluetext};
margin-left: 4px;
}
.ponder-footer-view a:hover {
text-decoration: none;
color: {$darkbluetext};
background-color: rgba(71, 87, 120, 0.10);
}