2013-05-30 14:09:02 -07:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
final class PhabricatorApplicationSearchController
|
|
|
|
|
extends PhabricatorSearchBaseController {
|
|
|
|
|
|
|
|
|
|
private $searchEngine;
|
|
|
|
|
private $navigation;
|
|
|
|
|
private $queryKey;
|
Move edit/deactivate operations onto project view page in Releeph
Summary:
Ref T3092.
Releeph's objects basically go like this:
- At the top level, we have Projects (like "www" or "libphutil")
- Each project has Branches (like "LATEST" or "v1.1.3")
- Each branch has Requests (like pull requests, e.g. "please merge commit X into branch Y (in project Z)")
Currently, there's no real "project detail" or "branch detail" page. Instead, we have a search results page for their contained objects. That is, the "project detail" page shows a list of branches in the project, using ApplicationSearch.
This means that operations like "edit" and "deactivate" are one level up, on the respective list pages.
Instead, move details onto the detail pages. This gives us more room for actions and information, and simplifies the list views.
Basically, these are "detail pages" where the object content is a search interface. We do something simliar to this in Phame right now, although it's messier there (no ApplicationSearch yet).
@chad, you might have some ideas here. Roughly, the design question is "How should we present an object's detail view when its content is really a search interface (Phame Blog for Posts, Releeph Project for Branches)?"
I think the simple approach I've taken here (see screenshot) gives us reasonable results, but overall it's something we haven't done much or done too much thinking about, I think.
Test Plan: {F54774}
Reviewers: btrahan
Reviewed By: btrahan
CC: chad, aran
Maniphest Tasks: T3092
Differential Revision: https://secure.phabricator.com/D6771
2013-08-19 18:30:30 -07:00
|
|
|
private $preface;
|
|
|
|
|
|
|
|
|
|
public function setPreface($preface) {
|
|
|
|
|
$this->preface = $preface;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getPreface() {
|
|
|
|
|
return $this->preface;
|
|
|
|
|
}
|
2013-05-30 14:09:02 -07:00
|
|
|
|
|
|
|
|
public function setQueryKey($query_key) {
|
|
|
|
|
$this->queryKey = $query_key;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function getQueryKey() {
|
|
|
|
|
return $this->queryKey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function setNavigation(AphrontSideNavFilterView $navigation) {
|
|
|
|
|
$this->navigation = $navigation;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function getNavigation() {
|
|
|
|
|
return $this->navigation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function setSearchEngine(
|
|
|
|
|
PhabricatorApplicationSearchEngine $search_engine) {
|
|
|
|
|
$this->searchEngine = $search_engine;
|
|
|
|
|
return $this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function getSearchEngine() {
|
|
|
|
|
return $this->searchEngine;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function validateDelegatingController() {
|
|
|
|
|
$parent = $this->getDelegatingController();
|
|
|
|
|
|
|
|
|
|
if (!$parent) {
|
|
|
|
|
throw new Exception(
|
2015-03-01 09:41:00 +11:00
|
|
|
pht('You must delegate to this controller, not invoke it directly.'));
|
2013-05-30 14:09:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$engine = $this->getSearchEngine();
|
|
|
|
|
if (!$engine) {
|
2015-05-14 07:53:52 +10:00
|
|
|
throw new PhutilInvalidStateException('setEngine');
|
2013-05-30 14:09:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$nav = $this->getNavigation();
|
|
|
|
|
if (!$nav) {
|
2015-05-14 07:53:52 +10:00
|
|
|
throw new PhutilInvalidStateException('setNavigation');
|
2013-05-30 14:09:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$engine->setViewer($this->getRequest()->getUser());
|
|
|
|
|
|
|
|
|
|
$parent = $this->getDelegatingController();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function processRequest() {
|
|
|
|
|
$this->validateDelegatingController();
|
|
|
|
|
|
|
|
|
|
$key = $this->getQueryKey();
|
|
|
|
|
if ($key == 'edit') {
|
|
|
|
|
return $this->processEditRequest();
|
|
|
|
|
} else {
|
|
|
|
|
return $this->processSearchRequest();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function processSearchRequest() {
|
|
|
|
|
$parent = $this->getDelegatingController();
|
|
|
|
|
$request = $this->getRequest();
|
|
|
|
|
$user = $request->getUser();
|
|
|
|
|
$engine = $this->getSearchEngine();
|
|
|
|
|
$nav = $this->getNavigation();
|
|
|
|
|
|
|
|
|
|
if ($request->isFormPost()) {
|
2013-05-30 14:09:37 -07:00
|
|
|
$saved_query = $engine->buildSavedQueryFromRequest($request);
|
2014-05-20 11:42:05 -07:00
|
|
|
$engine->saveQuery($saved_query);
|
2013-05-30 14:09:02 -07:00
|
|
|
return id(new AphrontRedirectResponse())->setURI(
|
2013-09-17 11:30:39 -07:00
|
|
|
$engine->getQueryResultsPageURI($saved_query->getQueryKey()).'#R');
|
2013-05-30 14:09:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$named_query = null;
|
|
|
|
|
$run_query = true;
|
|
|
|
|
$query_key = $this->queryKey;
|
|
|
|
|
if ($this->queryKey == 'advanced') {
|
|
|
|
|
$run_query = false;
|
|
|
|
|
$query_key = $request->getStr('query');
|
2013-06-05 18:58:50 -07:00
|
|
|
} else if (!strlen($this->queryKey)) {
|
2013-11-27 12:18:10 -08:00
|
|
|
$found_query_data = false;
|
|
|
|
|
|
|
|
|
|
if ($request->isHTTPGet()) {
|
Allow construction of ApplicationSearch queries with GET
Summary:
Ref T3775 (discussion here). Ref T2625.
T3775 presents two problems:
# Existing tools which linked to `/differential/active/epriestley/` (that is, put a username in the URL) can't generate search links now.
# Humans can't edit the URL anymore, either.
I think (1) is an actual issue, and this fixes it. I think (2) is pretty fluff, and this doesn't really try to fix it, although it probably improves it.
The fix for (1) is:
- Provide a helper to read a parameter containing either a list of user PHIDs or a list of usernames, so `/?users[]=PHID-USER-xyz` (from a tokenizer) and `/?users=alincoln,htaft` (from an external program) are equivalent inputs.
- Rename all the form parameters to be more digestable (`authorPHIDs` -> `authors`). Almost all of them were in this form already anyway. This just gives us `?users=alincoln` instead of `userPHIDs=alincoln`.
- Inside ApplicationSearch, if a request has no query associated with it but does have query parameters, build a query from the request instead of issuing the user's default query. Basically, this means that `/differential/` runs the default query, while `/differential/?users=x` runs a custom query.
Test Plan: {F56612}
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T2625, T3775
Differential Revision: https://secure.phabricator.com/D6840
2013-08-29 11:52:29 -07:00
|
|
|
// If this is a GET request and it has some query data, don't
|
2013-11-27 12:18:10 -08:00
|
|
|
// do anything unless it's only before= or after=. We'll build and
|
|
|
|
|
// execute a query from it below. This allows external tools to build
|
|
|
|
|
// URIs like "/query/?users=a,b".
|
|
|
|
|
$pt_data = $request->getPassthroughRequestData();
|
|
|
|
|
|
|
|
|
|
foreach ($pt_data as $pt_key => $pt_value) {
|
|
|
|
|
if ($pt_key != 'before' && $pt_key != 'after') {
|
|
|
|
|
$found_query_data = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!$found_query_data) {
|
Allow construction of ApplicationSearch queries with GET
Summary:
Ref T3775 (discussion here). Ref T2625.
T3775 presents two problems:
# Existing tools which linked to `/differential/active/epriestley/` (that is, put a username in the URL) can't generate search links now.
# Humans can't edit the URL anymore, either.
I think (1) is an actual issue, and this fixes it. I think (2) is pretty fluff, and this doesn't really try to fix it, although it probably improves it.
The fix for (1) is:
- Provide a helper to read a parameter containing either a list of user PHIDs or a list of usernames, so `/?users[]=PHID-USER-xyz` (from a tokenizer) and `/?users=alincoln,htaft` (from an external program) are equivalent inputs.
- Rename all the form parameters to be more digestable (`authorPHIDs` -> `authors`). Almost all of them were in this form already anyway. This just gives us `?users=alincoln` instead of `userPHIDs=alincoln`.
- Inside ApplicationSearch, if a request has no query associated with it but does have query parameters, build a query from the request instead of issuing the user's default query. Basically, this means that `/differential/` runs the default query, while `/differential/?users=x` runs a custom query.
Test Plan: {F56612}
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T2625, T3775
Differential Revision: https://secure.phabricator.com/D6840
2013-08-29 11:52:29 -07:00
|
|
|
// Otherwise, there's no query data so just run the user's default
|
|
|
|
|
// query for this application.
|
|
|
|
|
$query_key = head_key($engine->loadEnabledNamedQueries());
|
|
|
|
|
}
|
2013-05-30 14:09:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($engine->isBuiltinQuery($query_key)) {
|
|
|
|
|
$saved_query = $engine->buildSavedQueryFromBuiltin($query_key);
|
2013-06-05 18:58:50 -07:00
|
|
|
$named_query = idx($engine->loadEnabledNamedQueries(), $query_key);
|
2013-05-30 14:09:02 -07:00
|
|
|
} else if ($query_key) {
|
|
|
|
|
$saved_query = id(new PhabricatorSavedQueryQuery())
|
|
|
|
|
->setViewer($user)
|
|
|
|
|
->withQueryKeys(array($query_key))
|
|
|
|
|
->executeOne();
|
|
|
|
|
|
|
|
|
|
if (!$saved_query) {
|
|
|
|
|
return new Aphront404Response();
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-05 18:58:50 -07:00
|
|
|
$named_query = idx($engine->loadEnabledNamedQueries(), $query_key);
|
2013-05-30 14:09:02 -07:00
|
|
|
} else {
|
|
|
|
|
$saved_query = $engine->buildSavedQueryFromRequest($request);
|
2013-12-16 12:30:51 -08:00
|
|
|
|
|
|
|
|
// Save the query to generate a query key, so "Save Custom Query..." and
|
|
|
|
|
// other features like Maniphest's "Export..." work correctly.
|
2014-05-20 11:42:05 -07:00
|
|
|
$engine->saveQuery($saved_query);
|
2013-05-30 14:09:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$nav->selectFilter(
|
2013-12-26 12:30:36 -08:00
|
|
|
'query/'.$saved_query->getQueryKey(),
|
|
|
|
|
'query/advanced');
|
2013-05-30 14:09:02 -07:00
|
|
|
|
|
|
|
|
$form = id(new AphrontFormView())
|
2014-08-01 17:22:24 -07:00
|
|
|
->setUser($user)
|
|
|
|
|
->setAction($request->getPath());
|
2013-05-30 14:09:02 -07:00
|
|
|
|
|
|
|
|
$engine->buildSearchForm($form, $saved_query);
|
|
|
|
|
|
2013-05-30 17:32:12 -07:00
|
|
|
$errors = $engine->getErrors();
|
|
|
|
|
if ($errors) {
|
|
|
|
|
$run_query = false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-30 14:09:02 -07:00
|
|
|
$submit = id(new AphrontFormSubmitControl())
|
|
|
|
|
->setValue(pht('Execute Query'));
|
|
|
|
|
|
2013-05-31 10:51:20 -07:00
|
|
|
if ($run_query && !$named_query && $user->isLoggedIn()) {
|
2013-05-30 14:09:02 -07:00
|
|
|
$submit->addCancelButton(
|
|
|
|
|
'/search/edit/'.$saved_query->getQueryKey().'/',
|
|
|
|
|
pht('Save Custom Query...'));
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-16 12:27:12 -07:00
|
|
|
// TODO: A "Create Dashboard Panel" action goes here somewhere once
|
|
|
|
|
// we sort out T5307.
|
|
|
|
|
|
2013-05-30 14:09:02 -07:00
|
|
|
$form->appendChild($submit);
|
|
|
|
|
|
Move edit/deactivate operations onto project view page in Releeph
Summary:
Ref T3092.
Releeph's objects basically go like this:
- At the top level, we have Projects (like "www" or "libphutil")
- Each project has Branches (like "LATEST" or "v1.1.3")
- Each branch has Requests (like pull requests, e.g. "please merge commit X into branch Y (in project Z)")
Currently, there's no real "project detail" or "branch detail" page. Instead, we have a search results page for their contained objects. That is, the "project detail" page shows a list of branches in the project, using ApplicationSearch.
This means that operations like "edit" and "deactivate" are one level up, on the respective list pages.
Instead, move details onto the detail pages. This gives us more room for actions and information, and simplifies the list views.
Basically, these are "detail pages" where the object content is a search interface. We do something simliar to this in Phame right now, although it's messier there (no ApplicationSearch yet).
@chad, you might have some ideas here. Roughly, the design question is "How should we present an object's detail view when its content is really a search interface (Phame Blog for Posts, Releeph Project for Branches)?"
I think the simple approach I've taken here (see screenshot) gives us reasonable results, but overall it's something we haven't done much or done too much thinking about, I think.
Test Plan: {F54774}
Reviewers: btrahan
Reviewed By: btrahan
CC: chad, aran
Maniphest Tasks: T3092
Differential Revision: https://secure.phabricator.com/D6771
2013-08-19 18:30:30 -07:00
|
|
|
if ($this->getPreface()) {
|
|
|
|
|
$nav->appendChild($this->getPreface());
|
|
|
|
|
}
|
|
|
|
|
|
[Redesign] Put all ApplicationSearch results in an ObjectBox
Summary:
Ref T8099. In most cases we return either an ObjectList or AphrontTable, and can pretty up the UI in ApplicationSearch. There are a few edge cases, like PeopleUserLog, that can be cleanup up individually in the future, but look fine for now.
Also added 'setNotice' for AphrontTable for a few cases where we want to convey addtional information.
TODO: Seems we always pass a Pager Object, which tries to get displayed, I'll redesign that interaction in the future, probably by passing the Pager to the ObjectBox
Test Plan: Went throught most/all ApplicationSearch panels I could find, even edge cases look better.
Reviewers: btrahan, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T8099
Differential Revision: https://secure.phabricator.com/D12989
2015-05-24 09:13:58 -07:00
|
|
|
if ($named_query) {
|
|
|
|
|
$title = $named_query->getQueryName();
|
|
|
|
|
} else {
|
|
|
|
|
$title = pht('Advanced Search');
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-30 14:09:02 -07:00
|
|
|
if ($run_query) {
|
2015-05-26 17:35:18 -07:00
|
|
|
$anchor = id(new PhabricatorAnchorView())
|
|
|
|
|
->setAnchorName('R');
|
2013-09-17 11:30:39 -07:00
|
|
|
|
2015-04-16 15:30:41 -07:00
|
|
|
try {
|
|
|
|
|
$query = $engine->buildQueryFromSavedQuery($saved_query);
|
2013-11-22 12:34:52 -08:00
|
|
|
|
2015-04-16 15:30:41 -07:00
|
|
|
$pager = $engine->newPagerForSavedQuery($saved_query);
|
|
|
|
|
$pager->readFromRequest($request);
|
2014-02-03 12:52:19 -08:00
|
|
|
|
2015-04-16 15:30:41 -07:00
|
|
|
$objects = $engine->executeQuery($query, $pager);
|
2014-02-03 12:52:19 -08:00
|
|
|
|
2015-04-16 15:30:41 -07:00
|
|
|
// TODO: To support Dashboard panels, rendering is moving into
|
|
|
|
|
// SearchEngines. Move it all the way in and then get rid of this.
|
2014-05-08 10:08:37 -07:00
|
|
|
|
2015-04-16 15:30:41 -07:00
|
|
|
$interface = 'PhabricatorApplicationSearchResultsControllerInterface';
|
|
|
|
|
if ($parent instanceof $interface) {
|
|
|
|
|
$list = $parent->renderResultsList($objects, $saved_query);
|
|
|
|
|
} else {
|
|
|
|
|
$engine->setRequest($request);
|
2013-05-30 14:09:02 -07:00
|
|
|
|
2015-04-16 15:30:41 -07:00
|
|
|
$list = $engine->renderResults(
|
|
|
|
|
$objects,
|
|
|
|
|
$saved_query);
|
|
|
|
|
}
|
2013-05-30 14:09:37 -07:00
|
|
|
|
[Redesign] Put all ApplicationSearch results in an ObjectBox
Summary:
Ref T8099. In most cases we return either an ObjectList or AphrontTable, and can pretty up the UI in ApplicationSearch. There are a few edge cases, like PeopleUserLog, that can be cleanup up individually in the future, but look fine for now.
Also added 'setNotice' for AphrontTable for a few cases where we want to convey addtional information.
TODO: Seems we always pass a Pager Object, which tries to get displayed, I'll redesign that interaction in the future, probably by passing the Pager to the ObjectBox
Test Plan: Went throught most/all ApplicationSearch panels I could find, even edge cases look better.
Reviewers: btrahan, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T8099
Differential Revision: https://secure.phabricator.com/D12989
2015-05-24 09:13:58 -07:00
|
|
|
$box = id(new PHUIObjectBoxView())
|
2015-05-26 17:35:18 -07:00
|
|
|
->setHeaderText($title)
|
|
|
|
|
->setAnchor($anchor);
|
|
|
|
|
|
|
|
|
|
$box->setShowHide(
|
|
|
|
|
pht('Edit Query'),
|
|
|
|
|
pht('Hide Query'),
|
|
|
|
|
$form,
|
|
|
|
|
$this->getApplicationURI('query/advanced/?query='.$query_key));
|
[Redesign] Put all ApplicationSearch results in an ObjectBox
Summary:
Ref T8099. In most cases we return either an ObjectList or AphrontTable, and can pretty up the UI in ApplicationSearch. There are a few edge cases, like PeopleUserLog, that can be cleanup up individually in the future, but look fine for now.
Also added 'setNotice' for AphrontTable for a few cases where we want to convey addtional information.
TODO: Seems we always pass a Pager Object, which tries to get displayed, I'll redesign that interaction in the future, probably by passing the Pager to the ObjectBox
Test Plan: Went throught most/all ApplicationSearch panels I could find, even edge cases look better.
Reviewers: btrahan, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T8099
Differential Revision: https://secure.phabricator.com/D12989
2015-05-24 09:13:58 -07:00
|
|
|
|
|
|
|
|
if ($list instanceof AphrontTableView) {
|
|
|
|
|
$box->setTable($list);
|
|
|
|
|
} else {
|
|
|
|
|
$box->setObjectList($list);
|
|
|
|
|
}
|
|
|
|
|
$nav->appendChild($box);
|
2015-04-16 15:30:41 -07:00
|
|
|
|
|
|
|
|
// TODO: This is a bit hacky.
|
|
|
|
|
if ($list instanceof PHUIObjectItemListView) {
|
|
|
|
|
$list->setNoDataString(pht('No results found for this query.'));
|
|
|
|
|
} else {
|
|
|
|
|
if ($pager->willShowPagingControls()) {
|
|
|
|
|
$pager_box = id(new PHUIBoxView())
|
|
|
|
|
->addPadding(PHUI::PADDING_MEDIUM)
|
|
|
|
|
->addMargin(PHUI::MARGIN_LARGE)
|
|
|
|
|
->setBorder(true)
|
|
|
|
|
->appendChild($pager);
|
|
|
|
|
$nav->appendChild($pager_box);
|
|
|
|
|
}
|
2013-09-13 14:43:33 -07:00
|
|
|
}
|
2015-04-16 15:30:41 -07:00
|
|
|
} catch (PhabricatorTypeaheadInvalidTokenException $ex) {
|
|
|
|
|
$errors[] = pht(
|
|
|
|
|
'This query specifies an invalid parameter. Review the '.
|
|
|
|
|
'query parameters and correct errors.');
|
2013-05-30 14:09:37 -07:00
|
|
|
}
|
2013-05-30 14:09:02 -07:00
|
|
|
}
|
|
|
|
|
|
2015-04-16 15:30:41 -07:00
|
|
|
if ($errors) {
|
|
|
|
|
$errors = id(new PHUIInfoView())
|
|
|
|
|
->setTitle(pht('Query Errors'))
|
|
|
|
|
->setErrors($errors);
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-30 17:32:12 -07:00
|
|
|
if ($errors) {
|
|
|
|
|
$nav->appendChild($errors);
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-30 14:09:02 -07:00
|
|
|
$crumbs = $parent
|
|
|
|
|
->buildApplicationCrumbs()
|
2014-02-21 12:51:25 -08:00
|
|
|
->addTextCrumb($title);
|
2013-05-30 14:09:02 -07:00
|
|
|
|
|
|
|
|
$nav->setCrumbs($crumbs);
|
|
|
|
|
|
|
|
|
|
return $this->buildApplicationPage(
|
|
|
|
|
$nav,
|
|
|
|
|
array(
|
2015-03-02 08:50:36 -08:00
|
|
|
'title' => pht('Query: %s', $title),
|
2013-05-30 14:09:02 -07:00
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private function processEditRequest() {
|
|
|
|
|
$parent = $this->getDelegatingController();
|
|
|
|
|
$request = $this->getRequest();
|
|
|
|
|
$user = $request->getUser();
|
|
|
|
|
$engine = $this->getSearchEngine();
|
|
|
|
|
$nav = $this->getNavigation();
|
|
|
|
|
|
2013-06-05 05:28:25 -07:00
|
|
|
$named_queries = $engine->loadAllNamedQueries();
|
2013-05-30 14:09:02 -07:00
|
|
|
|
2013-06-05 16:22:27 -07:00
|
|
|
$list_id = celerity_generate_unique_node_id();
|
|
|
|
|
|
2013-09-09 14:14:34 -07:00
|
|
|
$list = new PHUIObjectItemListView();
|
2013-05-30 14:09:02 -07:00
|
|
|
$list->setUser($user);
|
2013-06-05 16:22:27 -07:00
|
|
|
$list->setID($list_id);
|
|
|
|
|
|
|
|
|
|
Javelin::initBehavior(
|
|
|
|
|
'search-reorder-queries',
|
|
|
|
|
array(
|
|
|
|
|
'listID' => $list_id,
|
|
|
|
|
'orderURI' => '/search/order/'.get_class($engine).'/',
|
|
|
|
|
));
|
2013-05-30 14:09:02 -07:00
|
|
|
|
|
|
|
|
foreach ($named_queries as $named_query) {
|
2013-06-05 05:28:25 -07:00
|
|
|
$class = get_class($engine);
|
|
|
|
|
$key = $named_query->getQueryKey();
|
|
|
|
|
|
2013-09-09 14:14:34 -07:00
|
|
|
$item = id(new PHUIObjectItemView())
|
2013-05-30 14:09:02 -07:00
|
|
|
->setHeader($named_query->getQueryName())
|
2013-06-05 05:28:25 -07:00
|
|
|
->setHref($engine->getQueryResultsPageURI($key));
|
|
|
|
|
|
|
|
|
|
if ($named_query->getIsBuiltin() && $named_query->getIsDisabled()) {
|
2014-05-12 10:08:32 -07:00
|
|
|
$icon = 'fa-plus';
|
2013-06-05 05:28:25 -07:00
|
|
|
} else {
|
2014-05-12 10:08:32 -07:00
|
|
|
$icon = 'fa-times';
|
2013-06-05 05:28:25 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$item->addAction(
|
2013-06-05 08:41:43 -07:00
|
|
|
id(new PHUIListItemView())
|
2013-06-05 05:28:25 -07:00
|
|
|
->setIcon($icon)
|
|
|
|
|
->setHref('/search/delete/'.$key.'/'.$class.'/')
|
|
|
|
|
->setWorkflow(true));
|
2013-05-30 14:09:02 -07:00
|
|
|
|
|
|
|
|
if ($named_query->getIsBuiltin()) {
|
2013-06-05 05:28:25 -07:00
|
|
|
if ($named_query->getIsDisabled()) {
|
2014-05-12 10:08:32 -07:00
|
|
|
$item->addIcon('fa-times lightgreytext', pht('Disabled'));
|
2013-07-12 11:31:20 -07:00
|
|
|
$item->setDisabled(true);
|
2013-06-05 05:28:25 -07:00
|
|
|
} else {
|
2014-05-12 10:08:32 -07:00
|
|
|
$item->addIcon('fa-lock lightgreytext', pht('Builtin'));
|
2013-06-05 05:28:25 -07:00
|
|
|
}
|
2013-05-30 14:09:02 -07:00
|
|
|
} else {
|
|
|
|
|
$item->addAction(
|
2013-06-05 08:41:43 -07:00
|
|
|
id(new PHUIListItemView())
|
2014-05-12 10:08:32 -07:00
|
|
|
->setIcon('fa-pencil')
|
2013-06-05 05:28:25 -07:00
|
|
|
->setHref('/search/edit/'.$key.'/'));
|
2013-05-30 14:09:02 -07:00
|
|
|
}
|
|
|
|
|
|
2013-06-05 16:22:27 -07:00
|
|
|
$item->setGrippable(true);
|
|
|
|
|
$item->addSigil('named-query');
|
|
|
|
|
$item->setMetadata(
|
|
|
|
|
array(
|
|
|
|
|
'queryKey' => $named_query->getQueryKey(),
|
|
|
|
|
));
|
|
|
|
|
|
2013-05-30 14:09:02 -07:00
|
|
|
$list->addItem($item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$list->setNoDataString(pht('No saved queries.'));
|
|
|
|
|
|
|
|
|
|
$crumbs = $parent
|
|
|
|
|
->buildApplicationCrumbs()
|
2014-06-09 11:36:49 -07:00
|
|
|
->addTextCrumb(pht('Saved Queries'), $engine->getQueryManagementURI());
|
2013-05-30 14:09:02 -07:00
|
|
|
|
|
|
|
|
$nav->selectFilter('query/edit');
|
|
|
|
|
$nav->setCrumbs($crumbs);
|
[Redesign] Put all ApplicationSearch results in an ObjectBox
Summary:
Ref T8099. In most cases we return either an ObjectList or AphrontTable, and can pretty up the UI in ApplicationSearch. There are a few edge cases, like PeopleUserLog, that can be cleanup up individually in the future, but look fine for now.
Also added 'setNotice' for AphrontTable for a few cases where we want to convey addtional information.
TODO: Seems we always pass a Pager Object, which tries to get displayed, I'll redesign that interaction in the future, probably by passing the Pager to the ObjectBox
Test Plan: Went throught most/all ApplicationSearch panels I could find, even edge cases look better.
Reviewers: btrahan, epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T8099
Differential Revision: https://secure.phabricator.com/D12989
2015-05-24 09:13:58 -07:00
|
|
|
|
|
|
|
|
$box = id(new PHUIObjectBoxView())
|
|
|
|
|
->setHeaderText(pht('Saved Queries'))
|
|
|
|
|
->setObjectList($list);
|
|
|
|
|
|
|
|
|
|
$nav->appendChild($box);
|
2013-05-30 14:09:02 -07:00
|
|
|
|
|
|
|
|
return $parent->buildApplicationPage(
|
|
|
|
|
$nav,
|
|
|
|
|
array(
|
2014-06-09 11:36:49 -07:00
|
|
|
'title' => pht('Saved Queries'),
|
2013-05-30 14:09:02 -07:00
|
|
|
));
|
|
|
|
|
}
|
2013-05-30 14:09:37 -07:00
|
|
|
|
2015-01-16 07:41:26 +11:00
|
|
|
public function buildApplicationMenu() {
|
2013-05-31 10:50:49 -07:00
|
|
|
return $this->getDelegatingController()->buildApplicationMenu();
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-30 14:09:02 -07:00
|
|
|
}
|