mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-23 07:12:41 +01:00
Make mobile navigation work properly by default in more cases
Summary: Fixes T5752. This obsoletes a bunch of old patterns and I'll follow up on those with a big "go do a bunch of mechanical code changes" task. Major goals are: - Don't load named queries multiple times on search pages. - Don't require extra code to get standard navigation right on mobile. - Reduce the amount of boilerplate in ListControllers. - Reduce the amount of boilerplate around navigation/menus in all controllers. Specifically, here's what this does: - The StandardPage is now a smarter/more structured object with `setNavigation()` and `setCrumbs()` methods. More rendering decisions are delayed until the last possible moment. - It uses this to automatically add crumb actions to the application menu. - It uses this to automatically reuse one SearchEngine instead of running queries multiple times. - The new preferred way to build responses is `$this->newPage()` (like `$this->newDialog()`), which has structured methods for adding stuff (`setTitle()`, etc). - SearchEngine exposes a new convenience method so you don't have to do all the controller delegation stuff. - Building menus is generally simpler. Test Plan: - Tested paste list, view, edit, comment, raw controllers for functionality, mobile menu, crumbs, navigation menu. - Edited saved queries. - Tested Differential, Maniphest (no changes). - Verified the paste pages don't run any duplicate NamedQuery queries. Reviewers: chad Reviewed By: chad Maniphest Tasks: T5752 Differential Revision: https://secure.phabricator.com/D14382
This commit is contained in:
parent
2ca269cb31
commit
300c74c49d
11 changed files with 430 additions and 201 deletions
|
@ -1403,6 +1403,7 @@ phutil_register_library_map(array(
|
||||||
'PHUI' => 'view/phui/PHUI.php',
|
'PHUI' => 'view/phui/PHUI.php',
|
||||||
'PHUIActionPanelExample' => 'applications/uiexample/examples/PHUIActionPanelExample.php',
|
'PHUIActionPanelExample' => 'applications/uiexample/examples/PHUIActionPanelExample.php',
|
||||||
'PHUIActionPanelView' => 'view/phui/PHUIActionPanelView.php',
|
'PHUIActionPanelView' => 'view/phui/PHUIActionPanelView.php',
|
||||||
|
'PHUIApplicationMenuView' => 'view/layout/PHUIApplicationMenuView.php',
|
||||||
'PHUIBadgeBoxView' => 'view/phui/PHUIBadgeBoxView.php',
|
'PHUIBadgeBoxView' => 'view/phui/PHUIBadgeBoxView.php',
|
||||||
'PHUIBadgeExample' => 'applications/uiexample/examples/PHUIBadgeExample.php',
|
'PHUIBadgeExample' => 'applications/uiexample/examples/PHUIBadgeExample.php',
|
||||||
'PHUIBadgeMiniView' => 'view/phui/PHUIBadgeMiniView.php',
|
'PHUIBadgeMiniView' => 'view/phui/PHUIBadgeMiniView.php',
|
||||||
|
@ -5310,6 +5311,7 @@ phutil_register_library_map(array(
|
||||||
'PHUI' => 'Phobject',
|
'PHUI' => 'Phobject',
|
||||||
'PHUIActionPanelExample' => 'PhabricatorUIExample',
|
'PHUIActionPanelExample' => 'PhabricatorUIExample',
|
||||||
'PHUIActionPanelView' => 'AphrontTagView',
|
'PHUIActionPanelView' => 'AphrontTagView',
|
||||||
|
'PHUIApplicationMenuView' => 'Phobject',
|
||||||
'PHUIBadgeBoxView' => 'AphrontTagView',
|
'PHUIBadgeBoxView' => 'AphrontTagView',
|
||||||
'PHUIBadgeExample' => 'PhabricatorUIExample',
|
'PHUIBadgeExample' => 'PhabricatorUIExample',
|
||||||
'PHUIBadgeMiniView' => 'AphrontTagView',
|
'PHUIBadgeMiniView' => 'AphrontTagView',
|
||||||
|
@ -7182,7 +7184,10 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorStandardCustomFieldText' => 'PhabricatorStandardCustomField',
|
'PhabricatorStandardCustomFieldText' => 'PhabricatorStandardCustomField',
|
||||||
'PhabricatorStandardCustomFieldTokenizer' => 'PhabricatorStandardCustomFieldPHIDs',
|
'PhabricatorStandardCustomFieldTokenizer' => 'PhabricatorStandardCustomFieldPHIDs',
|
||||||
'PhabricatorStandardCustomFieldUsers' => 'PhabricatorStandardCustomFieldTokenizer',
|
'PhabricatorStandardCustomFieldUsers' => 'PhabricatorStandardCustomFieldTokenizer',
|
||||||
'PhabricatorStandardPageView' => 'PhabricatorBarePageView',
|
'PhabricatorStandardPageView' => array(
|
||||||
|
'PhabricatorBarePageView',
|
||||||
|
'AphrontResponseProducerInterface',
|
||||||
|
),
|
||||||
'PhabricatorStandardSelectCustomFieldDatasource' => 'PhabricatorTypeaheadDatasource',
|
'PhabricatorStandardSelectCustomFieldDatasource' => 'PhabricatorTypeaheadDatasource',
|
||||||
'PhabricatorStatusController' => 'PhabricatorController',
|
'PhabricatorStatusController' => 'PhabricatorController',
|
||||||
'PhabricatorStatusUIExample' => 'PhabricatorUIExample',
|
'PhabricatorStatusUIExample' => 'PhabricatorUIExample',
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
abstract class PhabricatorController extends AphrontController {
|
abstract class PhabricatorController extends AphrontController {
|
||||||
|
|
||||||
private $handles;
|
private $handles;
|
||||||
private $extraQuicksandConfig = array();
|
|
||||||
|
|
||||||
public function shouldRequireLogin() {
|
public function shouldRequireLogin() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -62,15 +61,6 @@ abstract class PhabricatorController extends AphrontController {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addExtraQuicksandConfig($config) {
|
|
||||||
$this->extraQuicksandConfig += $config;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getExtraQuicksandConfig() {
|
|
||||||
return $this->extraQuicksandConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function willBeginExecution() {
|
public function willBeginExecution() {
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
|
|
||||||
|
@ -285,32 +275,6 @@ abstract class PhabricatorController extends AphrontController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildStandardPageView() {
|
|
||||||
$view = new PhabricatorStandardPageView();
|
|
||||||
$view->setRequest($this->getRequest());
|
|
||||||
$view->setController($this);
|
|
||||||
return $view;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function buildStandardPageResponse($view, array $data) {
|
|
||||||
$page = $this->buildStandardPageView();
|
|
||||||
$page->appendChild($view);
|
|
||||||
return $this->buildPageResponse($page);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function buildPageResponse($page) {
|
|
||||||
if ($this->getRequest()->isQuicksand()) {
|
|
||||||
$response = id(new AphrontAjaxResponse())
|
|
||||||
->setContent($page->renderForQuicksand(
|
|
||||||
$this->getExtraQuicksandConfig()));
|
|
||||||
} else {
|
|
||||||
$response = id(new AphrontWebpageResponse())
|
|
||||||
->setContent($page->render());
|
|
||||||
}
|
|
||||||
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getApplicationURI($path = '') {
|
public function getApplicationURI($path = '') {
|
||||||
if (!$this->getCurrentApplication()) {
|
if (!$this->getCurrentApplication()) {
|
||||||
throw new Exception(pht('No application!'));
|
throw new Exception(pht('No application!'));
|
||||||
|
@ -318,62 +282,6 @@ abstract class PhabricatorController extends AphrontController {
|
||||||
return $this->getCurrentApplication()->getApplicationURI($path);
|
return $this->getCurrentApplication()->getApplicationURI($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildApplicationPage($view, array $options) {
|
|
||||||
$page = $this->buildStandardPageView();
|
|
||||||
|
|
||||||
$title = PhabricatorEnv::getEnvConfig('phabricator.serious-business') ?
|
|
||||||
'Phabricator' :
|
|
||||||
pht('Bacon Ice Cream for Breakfast');
|
|
||||||
|
|
||||||
$application = $this->getCurrentApplication();
|
|
||||||
$page->setTitle(idx($options, 'title', $title));
|
|
||||||
if ($application) {
|
|
||||||
$page->setApplicationName($application->getName());
|
|
||||||
if ($application->getTitleGlyph()) {
|
|
||||||
$page->setGlyph($application->getTitleGlyph());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx($options, 'class')) {
|
|
||||||
$page->addClass($options['class']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!($view instanceof AphrontSideNavFilterView)) {
|
|
||||||
$nav = new AphrontSideNavFilterView();
|
|
||||||
$nav->appendChild($view);
|
|
||||||
$view = $nav;
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = $this->getRequest()->getUser();
|
|
||||||
$view->setUser($user);
|
|
||||||
|
|
||||||
$page->appendChild($view);
|
|
||||||
|
|
||||||
$object_phids = idx($options, 'pageObjects', array());
|
|
||||||
if ($object_phids) {
|
|
||||||
$page->appendPageObjects($object_phids);
|
|
||||||
foreach ($object_phids as $object_phid) {
|
|
||||||
PhabricatorFeedStoryNotification::updateObjectNotificationViews(
|
|
||||||
$user,
|
|
||||||
$object_phid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx($options, 'device', true)) {
|
|
||||||
$page->setDeviceReady(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$page->setShowFooter(idx($options, 'showFooter', true));
|
|
||||||
$page->setShowChrome(idx($options, 'chrome', true));
|
|
||||||
|
|
||||||
$application_menu = $this->buildApplicationMenu();
|
|
||||||
if ($application_menu) {
|
|
||||||
$page->setApplicationMenu($application_menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->buildPageResponse($page);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function willSendResponse(AphrontResponse $response) {
|
public function willSendResponse(AphrontResponse $response) {
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
|
|
||||||
|
@ -536,6 +444,35 @@ abstract class PhabricatorController extends AphrontController {
|
||||||
->setSubmitURI($submit_uri);
|
->setSubmitURI($submit_uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function newPage() {
|
||||||
|
$page = id(new PhabricatorStandardPageView())
|
||||||
|
->setRequest($this->getRequest())
|
||||||
|
->setController($this);
|
||||||
|
|
||||||
|
$application = $this->getCurrentApplication();
|
||||||
|
if ($application) {
|
||||||
|
$page->setApplicationName($application->getName());
|
||||||
|
if ($application->getTitleGlyph()) {
|
||||||
|
$page->setGlyph($application->getTitleGlyph());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$viewer = $this->getRequest()->getUser();
|
||||||
|
if ($viewer) {
|
||||||
|
$page->setUser($viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove after removing callsites to addExtraQuicksandConfig().
|
||||||
|
$page->addQuicksandConfig($this->extraQuicksandConfig);
|
||||||
|
|
||||||
|
return $page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newApplicationMenu() {
|
||||||
|
return id(new PHUIApplicationMenuView())
|
||||||
|
->setViewer($this->getRequest()->getUser());
|
||||||
|
}
|
||||||
|
|
||||||
protected function buildTransactionTimeline(
|
protected function buildTransactionTimeline(
|
||||||
PhabricatorApplicationTransactionInterface $object,
|
PhabricatorApplicationTransactionInterface $object,
|
||||||
PhabricatorApplicationTransactionQuery $query,
|
PhabricatorApplicationTransactionQuery $query,
|
||||||
|
@ -583,4 +520,81 @@ abstract class PhabricatorController extends AphrontController {
|
||||||
return $timeline;
|
return $timeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -( Deprecated )--------------------------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED.
|
||||||
|
*/
|
||||||
|
private $extraQuicksandConfig = array();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED. Use @{method:newPage} and call addQuicksandConfig().
|
||||||
|
*/
|
||||||
|
public function addExtraQuicksandConfig($config) {
|
||||||
|
// TODO: When this method is removed,
|
||||||
|
$this->extraQuicksandConfig += $config;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED. Use @{method:newPage}.
|
||||||
|
*/
|
||||||
|
public function buildStandardPageView() {
|
||||||
|
return $this->newPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED. Use @{method:newPage}.
|
||||||
|
*/
|
||||||
|
public function buildStandardPageResponse($view, array $data) {
|
||||||
|
$page = $this->buildStandardPageView();
|
||||||
|
$page->appendChild($view);
|
||||||
|
return $page->produceAphrontResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEPRECATED. Use @{method:newPage}.
|
||||||
|
*/
|
||||||
|
public function buildApplicationPage($view, array $options) {
|
||||||
|
$page = $this->newPage();
|
||||||
|
|
||||||
|
$title = PhabricatorEnv::getEnvConfig('phabricator.serious-business') ?
|
||||||
|
'Phabricator' :
|
||||||
|
pht('Bacon Ice Cream for Breakfast');
|
||||||
|
|
||||||
|
$page->setTitle(idx($options, 'title', $title));
|
||||||
|
|
||||||
|
if (idx($options, 'class')) {
|
||||||
|
$page->addClass($options['class']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($view instanceof AphrontSideNavFilterView)) {
|
||||||
|
$nav = new AphrontSideNavFilterView();
|
||||||
|
$nav->appendChild($view);
|
||||||
|
$view = $nav;
|
||||||
|
}
|
||||||
|
|
||||||
|
$page->appendChild($view);
|
||||||
|
|
||||||
|
$object_phids = idx($options, 'pageObjects', array());
|
||||||
|
if ($object_phids) {
|
||||||
|
$page->setPageObjectPHIDs($object_phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx($options, 'device', true)) {
|
||||||
|
$page->setDeviceReady(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
$page->setShowFooter(idx($options, 'showFooter', true));
|
||||||
|
$page->setShowChrome(idx($options, 'chrome', true));
|
||||||
|
|
||||||
|
return $page->produceAphrontResponse();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,39 +2,9 @@
|
||||||
|
|
||||||
abstract class PhabricatorPasteController extends PhabricatorController {
|
abstract class PhabricatorPasteController extends PhabricatorController {
|
||||||
|
|
||||||
public function buildSideNavView($for_app = false) {
|
|
||||||
$user = $this->getRequest()->getUser();
|
|
||||||
|
|
||||||
$nav = new AphrontSideNavFilterView();
|
|
||||||
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
|
||||||
|
|
||||||
if ($for_app) {
|
|
||||||
$nav->addFilter('create', pht('Create Paste'));
|
|
||||||
}
|
|
||||||
|
|
||||||
id(new PhabricatorPasteSearchEngine())
|
|
||||||
->setViewer($user)
|
|
||||||
->addNavigationItems($nav->getMenu());
|
|
||||||
|
|
||||||
$nav->selectFilter(null);
|
|
||||||
|
|
||||||
return $nav;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function buildApplicationMenu() {
|
public function buildApplicationMenu() {
|
||||||
return $this->buildSideNavView(true)->getMenu();
|
return $this->newApplicationMenu()
|
||||||
}
|
->setSearchEngine(new PhabricatorPasteSearchEngine());
|
||||||
|
|
||||||
protected function buildApplicationCrumbs() {
|
|
||||||
$crumbs = parent::buildApplicationCrumbs();
|
|
||||||
|
|
||||||
$crumbs->addAction(
|
|
||||||
id(new PHUIListItemView())
|
|
||||||
->setName(pht('Create Paste'))
|
|
||||||
->setHref($this->getApplicationURI('create/'))
|
|
||||||
->setIcon('fa-plus-square'));
|
|
||||||
|
|
||||||
return $crumbs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildSourceCodeView(
|
public function buildSourceCodeView(
|
||||||
|
|
|
@ -231,7 +231,7 @@ final class PhabricatorPasteEditController extends PhabricatorPasteController {
|
||||||
$form_box->setValidationException($validation_exception);
|
$form_box->setValidationException($validation_exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs($this->buildSideNavView());
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
if (!$is_create) {
|
if (!$is_create) {
|
||||||
$crumbs->addTextCrumb('P'.$paste->getID(), '/P'.$paste->getID());
|
$crumbs->addTextCrumb('P'.$paste->getID(), '/P'.$paste->getID());
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,21 @@ final class PhabricatorPasteListController extends PhabricatorPasteController {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequest(AphrontRequest $request) {
|
public function handleRequest(AphrontRequest $request) {
|
||||||
$querykey = $request->getURIData('queryKey');
|
return id(new PhabricatorPasteSearchEngine())
|
||||||
|
->setController($this)
|
||||||
$controller = id(new PhabricatorApplicationSearchController())
|
->buildResponse();
|
||||||
->setQueryKey($querykey)
|
|
||||||
->setSearchEngine(new PhabricatorPasteSearchEngine())
|
|
||||||
->setNavigation($this->buildSideNavView());
|
|
||||||
|
|
||||||
return $this->delegateToController($controller);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function buildApplicationCrumbs() {
|
||||||
|
$crumbs = parent::buildApplicationCrumbs();
|
||||||
|
|
||||||
|
$crumbs->addAction(
|
||||||
|
id(new PHUIListItemView())
|
||||||
|
->setName(pht('Create Paste'))
|
||||||
|
->setHref($this->getApplicationURI('create/'))
|
||||||
|
->setIcon('fa-plus-square'));
|
||||||
|
|
||||||
|
return $crumbs;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@ final class PhabricatorPasteViewController extends PhabricatorPasteController {
|
||||||
),
|
),
|
||||||
$source_code);
|
$source_code);
|
||||||
|
|
||||||
$crumbs = $this->buildApplicationCrumbs($this->buildSideNavView())
|
$crumbs = $this->buildApplicationCrumbs()
|
||||||
->addTextCrumb('P'.$paste->getID(), '/P'.$paste->getID());
|
->addTextCrumb('P'.$paste->getID(), '/P'.$paste->getID());
|
||||||
|
|
||||||
$timeline = $this->buildTransactionTimeline(
|
$timeline = $this->buildTransactionTimeline(
|
||||||
|
@ -89,18 +89,20 @@ final class PhabricatorPasteViewController extends PhabricatorPasteController {
|
||||||
->setAction($this->getApplicationURI('/comment/'.$paste->getID().'/'))
|
->setAction($this->getApplicationURI('/comment/'.$paste->getID().'/'))
|
||||||
->setSubmitButtonName(pht('Add Comment'));
|
->setSubmitButtonName(pht('Add Comment'));
|
||||||
|
|
||||||
return $this->buildApplicationPage(
|
return $this->newPage()
|
||||||
array(
|
->setTitle($paste->getFullName())
|
||||||
$crumbs,
|
->setCrumbs($crumbs)
|
||||||
$object_box,
|
->setPageObjectPHIDs(
|
||||||
$source_code,
|
array(
|
||||||
$timeline,
|
$paste->getPHID(),
|
||||||
$add_comment_form,
|
))
|
||||||
),
|
->appendChild(
|
||||||
array(
|
array(
|
||||||
'title' => $paste->getFullName(),
|
$object_box,
|
||||||
'pageObjects' => array($paste->getPHID()),
|
$source_code,
|
||||||
));
|
$timeline,
|
||||||
|
$add_comment_form,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildHeaderView(PhabricatorPaste $paste) {
|
private function buildHeaderView(PhabricatorPaste $paste) {
|
||||||
|
|
|
@ -58,11 +58,6 @@ final class PhabricatorApplicationSearchController
|
||||||
throw new PhutilInvalidStateException('setEngine');
|
throw new PhutilInvalidStateException('setEngine');
|
||||||
}
|
}
|
||||||
|
|
||||||
$nav = $this->getNavigation();
|
|
||||||
if (!$nav) {
|
|
||||||
throw new PhutilInvalidStateException('setNavigation');
|
|
||||||
}
|
|
||||||
|
|
||||||
$engine->setViewer($this->getRequest()->getUser());
|
$engine->setViewer($this->getRequest()->getUser());
|
||||||
|
|
||||||
$parent = $this->getDelegatingController();
|
$parent = $this->getDelegatingController();
|
||||||
|
@ -85,6 +80,9 @@ final class PhabricatorApplicationSearchController
|
||||||
$user = $request->getUser();
|
$user = $request->getUser();
|
||||||
$engine = $this->getSearchEngine();
|
$engine = $this->getSearchEngine();
|
||||||
$nav = $this->getNavigation();
|
$nav = $this->getNavigation();
|
||||||
|
if (!$nav) {
|
||||||
|
$nav = $this->buildNavigation();
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
$saved_query = $engine->buildSavedQueryFromRequest($request);
|
$saved_query = $engine->buildSavedQueryFromRequest($request);
|
||||||
|
@ -174,9 +172,10 @@ final class PhabricatorApplicationSearchController
|
||||||
// we sort out T5307.
|
// we sort out T5307.
|
||||||
|
|
||||||
$form->appendChild($submit);
|
$form->appendChild($submit);
|
||||||
|
$body = array();
|
||||||
|
|
||||||
if ($this->getPreface()) {
|
if ($this->getPreface()) {
|
||||||
$nav->appendChild($this->getPreface());
|
$body[] = $this->getPreface();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($named_query) {
|
if ($named_query) {
|
||||||
|
@ -202,7 +201,7 @@ final class PhabricatorApplicationSearchController
|
||||||
$box->setForm($form);
|
$box->setForm($form);
|
||||||
}
|
}
|
||||||
|
|
||||||
$nav->appendChild($box);
|
$body[] = $box;
|
||||||
|
|
||||||
if ($run_query) {
|
if ($run_query) {
|
||||||
$box->setAnchor(
|
$box->setAnchor(
|
||||||
|
@ -257,7 +256,7 @@ final class PhabricatorApplicationSearchController
|
||||||
->addMargin(PHUI::MARGIN_LARGE)
|
->addMargin(PHUI::MARGIN_LARGE)
|
||||||
->setBorder(true)
|
->setBorder(true)
|
||||||
->appendChild($pager);
|
->appendChild($pager);
|
||||||
$nav->appendChild($pager_box);
|
$body[] = $pager_box;
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (PhabricatorTypeaheadInvalidTokenException $ex) {
|
} catch (PhabricatorTypeaheadInvalidTokenException $ex) {
|
||||||
|
@ -275,13 +274,12 @@ final class PhabricatorApplicationSearchController
|
||||||
->buildApplicationCrumbs()
|
->buildApplicationCrumbs()
|
||||||
->addTextCrumb($title);
|
->addTextCrumb($title);
|
||||||
|
|
||||||
$nav->setCrumbs($crumbs);
|
return $this->newPage()
|
||||||
|
->setApplicationMenu($this->buildApplicationMenu())
|
||||||
return $this->buildApplicationPage(
|
->setTitle(pht('Query: %s', $title))
|
||||||
$nav,
|
->setCrumbs($crumbs)
|
||||||
array(
|
->setNavigation($nav)
|
||||||
'title' => pht('Query: %s', $title),
|
->appendChild($body);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function processEditRequest() {
|
private function processEditRequest() {
|
||||||
|
@ -289,7 +287,11 @@ final class PhabricatorApplicationSearchController
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$user = $request->getUser();
|
$user = $request->getUser();
|
||||||
$engine = $this->getSearchEngine();
|
$engine = $this->getSearchEngine();
|
||||||
|
|
||||||
$nav = $this->getNavigation();
|
$nav = $this->getNavigation();
|
||||||
|
if (!$nav) {
|
||||||
|
$nav = $this->buildNavigation();
|
||||||
|
}
|
||||||
|
|
||||||
$named_queries = $engine->loadAllNamedQueries();
|
$named_queries = $engine->loadAllNamedQueries();
|
||||||
|
|
||||||
|
@ -357,23 +359,41 @@ final class PhabricatorApplicationSearchController
|
||||||
->addTextCrumb(pht('Saved Queries'), $engine->getQueryManagementURI());
|
->addTextCrumb(pht('Saved Queries'), $engine->getQueryManagementURI());
|
||||||
|
|
||||||
$nav->selectFilter('query/edit');
|
$nav->selectFilter('query/edit');
|
||||||
$nav->setCrumbs($crumbs);
|
|
||||||
|
|
||||||
$box = id(new PHUIObjectBoxView())
|
$box = id(new PHUIObjectBoxView())
|
||||||
->setHeaderText(pht('Saved Queries'))
|
->setHeaderText(pht('Saved Queries'))
|
||||||
->setObjectList($list);
|
->setObjectList($list);
|
||||||
|
|
||||||
$nav->appendChild($box);
|
return $this->newPage()
|
||||||
|
->setApplicationMenu($this->buildApplicationMenu())
|
||||||
return $parent->buildApplicationPage(
|
->setTitle(pht('Saved Queries'))
|
||||||
$nav,
|
->setCrumbs($crumbs)
|
||||||
array(
|
->setNavigation($nav)
|
||||||
'title' => pht('Saved Queries'),
|
->appendChild($box);
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildApplicationMenu() {
|
public function buildApplicationMenu() {
|
||||||
return $this->getDelegatingController()->buildApplicationMenu();
|
$menu = $this->getDelegatingController()
|
||||||
|
->buildApplicationMenu();
|
||||||
|
|
||||||
|
if ($menu instanceof PHUIApplicationMenuView) {
|
||||||
|
$menu->setSearchEngine($this->getSearchEngine());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildNavigation() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$engine = $this->getSearchEngine();
|
||||||
|
|
||||||
|
$nav = id(new AphrontSideNavFilterView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
||||||
|
|
||||||
|
$engine->addNavigationItems($nav->getMenu());
|
||||||
|
|
||||||
|
return $nav;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,32 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
private $customFields = false;
|
private $customFields = false;
|
||||||
private $request;
|
private $request;
|
||||||
private $context;
|
private $context;
|
||||||
|
private $controller;
|
||||||
|
private $namedQueries;
|
||||||
|
|
||||||
const CONTEXT_LIST = 'list';
|
const CONTEXT_LIST = 'list';
|
||||||
const CONTEXT_PANEL = 'panel';
|
const CONTEXT_PANEL = 'panel';
|
||||||
|
|
||||||
|
public function setController(PhabricatorController $controller) {
|
||||||
|
$this->controller = $controller;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getController() {
|
||||||
|
return $this->controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildResponse() {
|
||||||
|
$controller = $this->getController();
|
||||||
|
$request = $controller->getRequest();
|
||||||
|
|
||||||
|
$search = id(new PhabricatorApplicationSearchController())
|
||||||
|
->setQueryKey($request->getURIData('queryKey'))
|
||||||
|
->setSearchEngine($this);
|
||||||
|
|
||||||
|
return $controller->delegateToController($search);
|
||||||
|
}
|
||||||
|
|
||||||
public function newResultObject() {
|
public function newResultObject() {
|
||||||
// We may be able to get this automatically if newQuery() is implemented.
|
// We may be able to get this automatically if newQuery() is implemented.
|
||||||
$query = $this->newQuery();
|
$query = $this->newQuery();
|
||||||
|
@ -459,33 +481,36 @@ abstract class PhabricatorApplicationSearchEngine extends Phobject {
|
||||||
|
|
||||||
public function loadAllNamedQueries() {
|
public function loadAllNamedQueries() {
|
||||||
$viewer = $this->requireViewer();
|
$viewer = $this->requireViewer();
|
||||||
|
|
||||||
$named_queries = id(new PhabricatorNamedQueryQuery())
|
|
||||||
->setViewer($viewer)
|
|
||||||
->withUserPHIDs(array($viewer->getPHID()))
|
|
||||||
->withEngineClassNames(array(get_class($this)))
|
|
||||||
->execute();
|
|
||||||
$named_queries = mpull($named_queries, null, 'getQueryKey');
|
|
||||||
|
|
||||||
$builtin = $this->getBuiltinQueries($viewer);
|
$builtin = $this->getBuiltinQueries($viewer);
|
||||||
$builtin = mpull($builtin, null, 'getQueryKey');
|
|
||||||
|
|
||||||
foreach ($named_queries as $key => $named_query) {
|
if ($this->namedQueries === null) {
|
||||||
if ($named_query->getIsBuiltin()) {
|
$named_queries = id(new PhabricatorNamedQueryQuery())
|
||||||
if (isset($builtin[$key])) {
|
->setViewer($viewer)
|
||||||
$named_queries[$key]->setQueryName($builtin[$key]->getQueryName());
|
->withUserPHIDs(array($viewer->getPHID()))
|
||||||
unset($builtin[$key]);
|
->withEngineClassNames(array(get_class($this)))
|
||||||
} else {
|
->execute();
|
||||||
unset($named_queries[$key]);
|
$named_queries = mpull($named_queries, null, 'getQueryKey');
|
||||||
|
|
||||||
|
$builtin = mpull($builtin, null, 'getQueryKey');
|
||||||
|
|
||||||
|
foreach ($named_queries as $key => $named_query) {
|
||||||
|
if ($named_query->getIsBuiltin()) {
|
||||||
|
if (isset($builtin[$key])) {
|
||||||
|
$named_queries[$key]->setQueryName($builtin[$key]->getQueryName());
|
||||||
|
unset($builtin[$key]);
|
||||||
|
} else {
|
||||||
|
unset($named_queries[$key]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unset($builtin[$key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
unset($builtin[$key]);
|
$named_queries = msort($named_queries, 'getSortKey');
|
||||||
|
$this->namedQueries = $named_queries;
|
||||||
}
|
}
|
||||||
|
|
||||||
$named_queries = msort($named_queries, 'getSortKey');
|
return $this->namedQueries + $builtin;
|
||||||
|
|
||||||
return $named_queries + $builtin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadEnabledNamedQueries() {
|
public function loadEnabledNamedQueries() {
|
||||||
|
|
89
src/view/layout/PHUIApplicationMenuView.php
Normal file
89
src/view/layout/PHUIApplicationMenuView.php
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PHUIApplicationMenuView extends Phobject {
|
||||||
|
|
||||||
|
private $viewer;
|
||||||
|
private $crumbs;
|
||||||
|
private $searchEngine;
|
||||||
|
|
||||||
|
private $items = array();
|
||||||
|
|
||||||
|
public function setViewer(PhabricatorUser $viewer) {
|
||||||
|
$this->viewer = $viewer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getViewer() {
|
||||||
|
return $this->viewer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addLabel($name) {
|
||||||
|
$item = id(new PHUIListItemView())
|
||||||
|
->setName($name);
|
||||||
|
|
||||||
|
return $this->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addLink($name, $href) {
|
||||||
|
$item = id(new PHUIListItemView())
|
||||||
|
->setName($name)
|
||||||
|
->setHref($href);
|
||||||
|
|
||||||
|
return $this->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addItem(PHUIListItemView $item) {
|
||||||
|
$this->items[] = $item;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setSearchEngine(PhabricatorApplicationSearchEngine $engine) {
|
||||||
|
$this->searchEngine = $engine;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSearchEngine() {
|
||||||
|
return $this->searchEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCrumbs(PHUICrumbsView $crumbs) {
|
||||||
|
$this->crumbs = $crumbs;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCrumbs() {
|
||||||
|
return $this->crumbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildListView() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$view = id(new PHUIListView())
|
||||||
|
->setUser($viewer);
|
||||||
|
|
||||||
|
$crumbs = $this->getCrumbs();
|
||||||
|
if ($crumbs) {
|
||||||
|
$actions = $crumbs->getActions();
|
||||||
|
if ($actions) {
|
||||||
|
$view->newLabel(pht('Create'));
|
||||||
|
foreach ($crumbs->getActions() as $action) {
|
||||||
|
$view->addMenuItem($action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$engine = $this->getSearchEngine();
|
||||||
|
if ($engine) {
|
||||||
|
$engine
|
||||||
|
->setViewer($viewer)
|
||||||
|
->addNavigationItems($view);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->items as $item) {
|
||||||
|
$view->addMenuItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -4,7 +4,8 @@
|
||||||
* This is a standard Phabricator page with menus, Javelin, DarkConsole, and
|
* This is a standard Phabricator page with menus, Javelin, DarkConsole, and
|
||||||
* basic styles.
|
* basic styles.
|
||||||
*/
|
*/
|
||||||
final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
final class PhabricatorStandardPageView extends PhabricatorBarePageView
|
||||||
|
implements AphrontResponseProducerInterface {
|
||||||
|
|
||||||
private $baseURI;
|
private $baseURI;
|
||||||
private $applicationName;
|
private $applicationName;
|
||||||
|
@ -17,6 +18,9 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
||||||
private $applicationMenu;
|
private $applicationMenu;
|
||||||
private $showFooter = true;
|
private $showFooter = true;
|
||||||
private $showDurableColumn = true;
|
private $showDurableColumn = true;
|
||||||
|
private $quicksandConfig = array();
|
||||||
|
private $crumbs;
|
||||||
|
private $navigation;
|
||||||
|
|
||||||
public function setShowFooter($show_footer) {
|
public function setShowFooter($show_footer) {
|
||||||
$this->showFooter = $show_footer;
|
$this->showFooter = $show_footer;
|
||||||
|
@ -27,7 +31,10 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
||||||
return $this->showFooter;
|
return $this->showFooter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setApplicationMenu(PHUIListView $application_menu) {
|
public function setApplicationMenu($application_menu) {
|
||||||
|
// NOTE: For now, this can either be a PHUIListView or a
|
||||||
|
// PHUIApplicationMenuView.
|
||||||
|
|
||||||
$this->applicationMenu = $application_menu;
|
$this->applicationMenu = $application_menu;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
@ -73,10 +80,9 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function appendPageObjects(array $objs) {
|
public function setPageObjectPHIDs(array $phids) {
|
||||||
foreach ($objs as $obj) {
|
$this->pageObjects = $phids;
|
||||||
$this->pageObjects[] = $obj;
|
return $this;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setShowDurableColumn($show) {
|
public function setShowDurableColumn($show) {
|
||||||
|
@ -130,6 +136,32 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
||||||
return (bool)$this->getUserPreference($column_key, 0);
|
return (bool)$this->getUserPreference($column_key, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addQuicksandConfig(array $config) {
|
||||||
|
$this->quicksandConfig = $config + $this->quicksandConfig;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getQuicksandConfig() {
|
||||||
|
return $this->quicksandConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCrumbs(PHUICrumbsView $crumbs) {
|
||||||
|
$this->crumbs = $crumbs;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCrumbs() {
|
||||||
|
return $this->crumbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setNavigation(AphrontSideNavFilterView $navigation) {
|
||||||
|
$this->navigation = $navigation;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNavigation() {
|
||||||
|
return $this->navigation;
|
||||||
|
}
|
||||||
|
|
||||||
public function getTitle() {
|
public function getTitle() {
|
||||||
$glyph_key = PhabricatorUserPreferences::PREFERENCE_TITLES;
|
$glyph_key = PhabricatorUserPreferences::PREFERENCE_TITLES;
|
||||||
|
@ -271,8 +303,18 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
||||||
$menu->setController($this->getController());
|
$menu->setController($this->getController());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->getApplicationMenu()) {
|
$application_menu = $this->getApplicationMenu();
|
||||||
$menu->setApplicationMenu($this->getApplicationMenu());
|
if ($application_menu) {
|
||||||
|
if ($application_menu instanceof PHUIApplicationMenuView) {
|
||||||
|
$crumbs = $this->getCrumbs();
|
||||||
|
if ($crumbs) {
|
||||||
|
$application_menu->setCrumbs($crumbs);
|
||||||
|
}
|
||||||
|
|
||||||
|
$application_menu = $application_menu->buildListView();
|
||||||
|
}
|
||||||
|
|
||||||
|
$menu->setApplicationMenu($application_menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->menuContent = $menu->render();
|
$this->menuContent = $menu->render();
|
||||||
|
@ -433,9 +475,26 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
||||||
private function renderPageBodyContent() {
|
private function renderPageBodyContent() {
|
||||||
$console = $this->getConsole();
|
$console = $this->getConsole();
|
||||||
|
|
||||||
|
$body = parent::getBody();
|
||||||
|
|
||||||
|
$nav = $this->getNavigation();
|
||||||
|
if ($nav) {
|
||||||
|
$crumbs = $this->getCrumbs();
|
||||||
|
if ($crumbs) {
|
||||||
|
$nav->setCrumbs($crumbs);
|
||||||
|
}
|
||||||
|
$nav->appendChild($body);
|
||||||
|
$body = phutil_implode_html('', array($nav->render()));
|
||||||
|
} else {
|
||||||
|
$crumbs = $this->getCrumbs();
|
||||||
|
if ($crumbs) {
|
||||||
|
$body = phutil_implode_html('', array($crumbs, $body));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
($console ? hsprintf('<darkconsole />') : null),
|
($console ? hsprintf('<darkconsole />') : null),
|
||||||
parent::getBody(),
|
$body,
|
||||||
$this->renderFooter(),
|
$this->renderFooter(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -619,11 +678,13 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
||||||
$foot);
|
$foot);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderForQuicksand(array $extra_config) {
|
public function renderForQuicksand() {
|
||||||
parent::willRenderPage();
|
parent::willRenderPage();
|
||||||
$response = $this->renderPageBodyContent();
|
$response = $this->renderPageBodyContent();
|
||||||
$response = $this->willSendResponse($response);
|
$response = $this->willSendResponse($response);
|
||||||
|
|
||||||
|
$extra_config = $this->getQuicksandConfig();
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'content' => hsprintf('%s', $response),
|
'content' => hsprintf('%s', $response),
|
||||||
) + $this->buildQuicksandConfig()
|
) + $this->buildQuicksandConfig()
|
||||||
|
@ -732,4 +793,37 @@ final class PhabricatorStandardPageView extends PhabricatorBarePageView {
|
||||||
return $user->loadPreferences()->getPreference($key, $default);
|
return $user->loadPreferences()->getPreference($key, $default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function produceAphrontResponse() {
|
||||||
|
$controller = $this->getController();
|
||||||
|
|
||||||
|
if (!$this->getApplicationMenu()) {
|
||||||
|
$application_menu = $controller->buildApplicationMenu();
|
||||||
|
if ($application_menu) {
|
||||||
|
$this->setApplicationMenu($application_menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$viewer = $this->getUser();
|
||||||
|
if ($viewer && $viewer->getPHID()) {
|
||||||
|
$object_phids = $this->pageObjects;
|
||||||
|
foreach ($object_phids as $object_phid) {
|
||||||
|
PhabricatorFeedStoryNotification::updateObjectNotificationViews(
|
||||||
|
$viewer,
|
||||||
|
$object_phid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getRequest()->isQuicksand()) {
|
||||||
|
$content = $this->renderForQuicksand();
|
||||||
|
$response = id(new AphrontAjaxResponse())
|
||||||
|
->setContent($content);
|
||||||
|
} else {
|
||||||
|
$content = $this->render();
|
||||||
|
$response = id(new AphrontWebpageResponse())
|
||||||
|
->setContent($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,10 @@ final class PHUICrumbsView extends AphrontView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getActions() {
|
||||||
|
return $this->actions;
|
||||||
|
}
|
||||||
|
|
||||||
public function render() {
|
public function render() {
|
||||||
require_celerity_resource('phui-crumbs-view-css');
|
require_celerity_resource('phui-crumbs-view-css');
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue