Commit 91c08ca6 authored by epriestley's avatar epriestley
Browse files

Add breadcrumbs and ApplicationSearch to Phriction

Summary: Fixes T3631. Also adds ApplicationSearch.

Test Plan: Viewed "New", "Edit"; saw breadcrumbs. Viewed "index", saw application search.

Reviewers: btrahan, chad

Reviewed By: chad

CC: aran

Maniphest Tasks: T3631

Differential Revision: https://secure.phabricator.com/D6593
parent 091beee7
......@@ -1863,6 +1863,7 @@ phutil_register_library_map(array(
'PhrictionNewController' => 'applications/phriction/controller/PhrictionNewController.php',
'PhrictionPHIDTypeDocument' => 'applications/phriction/phid/PhrictionPHIDTypeDocument.php',
'PhrictionRemarkupRule' => 'applications/phriction/remarkup/PhrictionRemarkupRule.php',
'PhrictionSearchEngine' => 'applications/phriction/query/PhrictionSearchEngine.php',
'PhrictionSearchIndexer' => 'applications/phriction/search/PhrictionSearchIndexer.php',
'PonderAddAnswerView' => 'applications/ponder/view/PonderAddAnswerView.php',
'PonderAddCommentView' => 'applications/ponder/view/PonderAddCommentView.php',
......@@ -3957,11 +3958,16 @@ phutil_register_library_map(array(
'PhrictionDocumentTestCase' => 'PhabricatorTestCase',
'PhrictionEditController' => 'PhrictionController',
'PhrictionHistoryController' => 'PhrictionController',
'PhrictionListController' => 'PhrictionController',
'PhrictionListController' =>
array(
0 => 'PhrictionController',
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
),
'PhrictionMoveController' => 'PhrictionController',
'PhrictionNewController' => 'PhrictionController',
'PhrictionPHIDTypeDocument' => 'PhabricatorPHIDType',
'PhrictionRemarkupRule' => 'PhutilRemarkupRule',
'PhrictionSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhrictionSearchIndexer' => 'PhabricatorSearchDocumentIndexer',
'PonderAddAnswerView' => 'AphrontView',
'PonderAddCommentView' => 'AphrontView',
......
......@@ -42,8 +42,7 @@ final class PhabricatorApplicationPhriction extends PhabricatorApplication {
'/w/(?P<slug>.+/)' => 'PhrictionDocumentController',
'/phriction/' => array(
'' => 'PhrictionListController',
'list/(?P<view>[^/]+)/' => 'PhrictionListController',
'(?:query/(?P<queryKey>[^/]+)/)?' => 'PhrictionListController',
'history(?P<slug>/)' => 'PhrictionHistoryController',
'history/(?P<slug>.+/)' => 'PhrictionHistoryController',
......
......@@ -5,45 +5,28 @@
*/
abstract class PhrictionController extends PhabricatorController {
public function buildStandardPageResponse($view, array $data) {
$page = $this->buildStandardPageView();
$page->setApplicationName(pht('Phriction'));
$page->setBaseURI('/w/');
$page->setTitle(idx($data, 'title'));
$page->setGlyph("\xE2\x9A\xA1");
$page->appendChild($view);
$page->setSearchDefaultScope(PhabricatorSearchScope::SCOPE_WIKI);
$response = new AphrontWebpageResponse();
return $response->setContent($page->render());
}
public function buildSideNavView($filter = null, $for_app = false) {
public function buildSideNavView($for_app = false) {
$user = $this->getRequest()->getUser();
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI('/phriction/list/'));
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
if ($for_app) {
$nav->addFilter('', pht('Root Document'), '/w/');
$nav->addFilter('', pht('New Document'), '/phriction/new');
$nav->addFilter('create', pht('New Document'));
$nav->addFilter('/phriction/', pht('Index'));
}
$nav->addLabel(pht('Filters'));
$nav->addFilter('active', pht('Active Documents'));
$nav->addFilter('all', pht('All Documents'));
$nav->addFilter('updates', pht('Recently Updated'));
id(new PhrictionSearchEngine())
->setViewer($user)
->addNavigationItems($nav->getMenu());
$nav->selectFilter($filter, 'active');
$nav->selectFilter(null);
return $nav;
}
public function buildApplicationMenu() {
return $this->buildSideNavView(null, true)->getMenu();
return $this->buildSideNavView(true)->getMenu();
}
public function buildApplicationCrumbs() {
......
......@@ -248,11 +248,26 @@ final class PhrictionEditController
'uri' => '/phriction/preview/?draftkey='.$draft_key,
));
$crumbs = $this->buildApplicationCrumbs();
if ($document->getID()) {
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName($content->getTitle())
->setHref(PhrictionDocument::getSlugURI($document->getSlug())));
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName(pht('Edit')));
} else {
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName(pht('Create')));
}
return $this->buildApplicationPage(
array(
$crumbs,
$draft_note,
$error_view,
$header,
$form,
$preview_panel,
),
......
<?php
/**
* @group phriction
*/
final class PhrictionListController
extends PhrictionController {
extends PhrictionController
implements PhabricatorApplicationSearchResultsControllerInterface {
private $view;
private $queryKey;
private $documents;
private $handles;
public function shouldAllowPublic() {
return true;
}
public function willProcessRequest(array $data) {
$this->view = idx($data, 'view');
$this->queryKey = idx($data, 'queryKey');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$controller = id(new PhabricatorApplicationSearchController($request))
->setQueryKey($this->queryKey)
->setSearchEngine(new PhrictionSearchEngine())
->setNavigation($this->buildSideNavView());
$views = array(
'active' => pht('Active Documents'),
'all' => pht('All Documents'),
'updates' => pht('Recently Updated'),
);
return $this->delegateToController($controller);
}
if (empty($views[$this->view])) {
$this->view = 'active';
}
public function renderResultsList(
array $documents,
PhabricatorSavedQuery $query) {
assert_instances_of($documents, 'PhrictionDocument');
$nav = $this->buildSideNavView($this->view);
$crumbs = $this->buildApplicationCrumbs();
$crumbs->addCrumb(id(new PhabricatorCrumbView())
->setName($views[$this->view])
->setHref($this->getApplicationURI('list/' . $this->view)));
$nav->appendChild(
array(
$crumbs,
));
$pager = id(new AphrontCursorPagerView())
->readFromRequest($request);
$query = id(new PhrictionDocumentQuery())
->setViewer($user);
switch ($this->view) {
case 'active':
$query->withStatus(PhrictionDocumentQuery::STATUS_OPEN);
break;
case 'all':
$query->withStatus(PhrictionDocumentQuery::STATUS_NONSTUB);
break;
case 'updates':
$query->withStatus(PhrictionDocumentQuery::STATUS_NONSTUB);
$query->setOrder(PhrictionDocumentQuery::ORDER_UPDATED);
break;
default:
throw new Exception("Unknown view '{$this->view}'!");
}
$this->documents = $query->executeWithCursorPager($pager);
$changeref_docs = array();
if ($this->view == 'updates') {
// Loading some documents here since they may not appear in the query
// results.
$changeref_ids = array_filter(mpull(
mpull($this->documents, 'getContent'), 'getChangeRef'));
if ($changeref_ids) {
$changeref_docs = id(new PhrictionDocumentQuery())
->setViewer($user)
->withIDs($changeref_ids)
->execute();
}
}
$viewer = $this->getRequest()->getUser();
$phids = array();
foreach ($this->documents as $document) {
$phids[] = $document->getContent()->getAuthorPHID();
foreach ($documents as $document) {
$content = $document->getContent();
if ($document->hasProject()) {
$phids[] = $document->getProject()->getPHID();
}
$phids[] = $content->getAuthorPHID();
}
$this->handles = $this->loadViewerHandles($phids);
$this->loadHandles($phids);
$list = new PhabricatorObjectItemListView();
$list->setUser($viewer);
foreach ($documents as $document) {
$content = $document->getContent();
$slug = $document->getSlug();
$author_phid = $content->getAuthorPHID();
$slug_uri = PhrictionDocument::getSlugURI($slug);
$byline = pht(
'Edited by %s',
$this->getHandle($author_phid)->renderLink());
$updated = phabricator_datetime(
$content->getDateCreated(),
$viewer);
$item = id(new PhabricatorObjectItemView())
->setHeader($content->getTitle())
->setHref($slug_uri)
->addByline($byline)
->addIcon('none', $updated);
foreach ($this->documents as $document) {
if ($this->view == 'updates') {
$list->addItem(
$this->buildItemForUpdates($document, $changeref_docs));
} else {
$list->addItem(
$this->buildItemTheCasualWay($document));
if ($document->hasProject()) {
$item->addAttribute(
$this->getHandle($document->getProject()->getPHID())->renderLink());
}
}
$nav->appendChild($list);
$nav->appendChild($pager);
return $this->buildApplicationPage(
$nav,
array(
'title' => pht('Document Index'),
'dust' => true,
));
}
private function buildItemTheCasualWay(PhrictionDocument $document) {
$user = $this->getRequest()->getUser();
$project_link = null;
if ($document->hasProject()) {
$project_phid = $document->getProject()->getPHID();
$project_link = $this->handles[$project_phid]->renderLink();
}
$content = $document->getContent();
$author = $this->handles[$content->getAuthorPHID()]->renderLink();
$title = $content->getTitle();
$slug = $document->getSlug();
$slug_uri = PhrictionDocument::getSlugURI($slug);
$edit_uri = '/phriction/edit/' . $document->getID() . '/';
$history_uri = PhrictionDocument::getSlugURI($slug, 'history');
$item = id(new PhabricatorObjectItemView())
->setHeader($title)
->setHref($slug_uri)
->addAttribute(pht('By %s', $author))
->addAttribute(pht('Updated: %s',
phabricator_datetime($content->getDateCreated(), $user)))
->addAttribute($slug_uri);
if ($project_link) {
$item->addAttribute(pht('Project %s', $project_link));
}
return $item;
}
private function buildItemForUpdates(PhrictionDocument $document,
array $docs_from_refs) {
$user = $this->getRequest()->getUser();
$content = $document->getContent();
$version = $content->getVersion();
$author = $this->handles[$content->getAuthorPHID()]->renderLink();
$title = $content->getTitle();
$slug = $document->getSlug();
$slug_uri = PhrictionDocument::getSlugURI($slug);
$document_link = hsprintf('<a href="%s">%s</a>', $slug_uri, $title);
$change_type = $content->getChangeType();
switch ($content->getChangeType()) {
case PhrictionChangeType::CHANGE_DELETE:
$change_type = pht('%s deleted %s', $author, $document_link);
break;
case PhrictionChangeType::CHANGE_EDIT:
$change_type = pht('%s edited %s', $author, $document_link);
break;
case PhrictionChangeType::CHANGE_MOVE_HERE:
case PhrictionChangeType::CHANGE_MOVE_AWAY:
$change_ref = $content->getChangeRef();
$ref_doc = idx($docs_from_refs, $change_ref);
if (!$ref_doc) {
if ($change_type == PhrictionChangeType::CHANGE_MOVE_HERE) {
$change_type = pht(
'%s moved %s from elsewhere',
$author,
$document_link);
} else {
$change_type = pht(
'%s moved %s to elsewhere',
$author,
$document_link);
}
} else {
$ref_doc_slug = PhrictionDocument::getSlugURI($ref_doc->getSlug());
$ref_doc_link = hsprintf('<a href="%s">%1$s</a>', $ref_doc_slug);
if ($change_type == PhrictionChangeType::CHANGE_MOVE_HERE) {
$change_type = pht(
'%s moved %s from %s',
$author,
$document_link,
$ref_doc_link);
} else {
$change_type = pht(
'%s moved %s to %s',
$author,
$document_link,
$ref_doc_link);
}
}
break;
default:
throw new Exception("Unknown change type!");
break;
}
$item = id(new PhabricatorObjectItemView())
->setHeader($change_type)
->addAttribute(phabricator_datetime($content->getDateCreated(), $user))
->addAttribute($slug_uri);
if ($content->getDescription()) {
$item->addAttribute($content->getDescription());
}
$item->addAttribute($slug_uri);
switch ($document->getStatus()) {
case PhrictionDocumentStatus::STATUS_DELETED:
$item->setDisabled(true);
$item->addIcon('delete', pht('Deleted'));
break;
case PhrictionDocumentStatus::STATUS_MOVED:
$item->setDisabled(true);
$item->addIcon('arrow-right', pht('Moved Away'));
break;
}
if ($version > 1) {
$diff_uri = new PhutilURI('/phriction/diff/'.$document->getID().'/');
$uri = $diff_uri->alter('l', $version - 1)->alter('r', $version);
$item->addIcon('history', pht('View Change'),
array(
'href' => $uri,
));
} else {
$item->addIcon('history-grey', pht('No diff available'));
$list->addItem($item);
}
return $item;
return $list;
}
}
<?php
final class PhrictionSearchEngine
extends PhabricatorApplicationSearchEngine {
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter('status', $request->getArr('status'));
$saved->setParameter('order', $request->getArr('order'));
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new PhrictionDocumentQuery())
->withStatus(PhrictionDocumentQuery::STATUS_NONSTUB);
$status = $saved->getParameter('status');
$status = idx($this->getStatusValues(), $status);
if ($status) {
$query->withStatus($status);
}
$order = $saved->getParameter('order');
$order = idx($this->getOrderValues(), $order);
if ($order) {
$query->setOrder($order);
}
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved_query) {
$form
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Status'))
->setName('status')
->setOptions($this->getStatusOptions())
->setValue($saved_query->getParameter('status')))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Order'))
->setName('order')
->setOptions($this->getOrderOptions())
->setValue($saved_query->getParameter('order')));
}
protected function getURI($path) {
return '/phriction/'.$path;
}
public function getBuiltinQueryNames() {
$names = array(
'active' => pht('Active'),
'updated' => pht('Updated'),
'all' => pht('All'),
);
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'active':
return $query->setParameter('status', 'active');
case 'all':
return $query;
case 'updated':
return $query->setParameter('order', 'updated');
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
private function getStatusOptions() {
return array(
'active' => pht('Show Active Documents'),
'all' => pht('Show All Documents'),
);
}
private function getStatusValues() {
return array(
'active' => PhrictionDocumentQuery::STATUS_OPEN,
'all' => PhrictionDocumentQuery::STATUS_NONSTUB,
);
}
private function getOrderOptions() {
return array(
'created' => pht('Date Created'),
'updated' => pht('Date Updated'),
);
}
private function getOrderValues() {
return array(
'created' => PhrictionDocumentQuery::ORDER_CREATED,
'updated' => PhrictionDocumentQuery::ORDER_UPDATED,
);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment