1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-12-23 14:00:56 +01:00

Use ApplicationSearch in Applications application

Summary: Ref T603. OMG SO META

Test Plan: See screenshot.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T603

Differential Revision: https://secure.phabricator.com/D7197
This commit is contained in:
epriestley 2013-10-02 13:13:07 -07:00
parent 691e73b576
commit f75c13b987
8 changed files with 329 additions and 36 deletions

View file

@ -807,6 +807,7 @@ phutil_register_library_map(array(
'PhabricatorAnchorView' => 'view/layout/PhabricatorAnchorView.php',
'PhabricatorAphrontBarExample' => 'applications/uiexample/examples/PhabricatorAphrontBarExample.php',
'PhabricatorAphrontViewTestCase' => 'view/__tests__/PhabricatorAphrontViewTestCase.php',
'PhabricatorAppSearchEngine' => 'applications/meta/query/PhabricatorAppSearchEngine.php',
'PhabricatorApplication' => 'applications/base/PhabricatorApplication.php',
'PhabricatorApplicationApplications' => 'applications/meta/application/PhabricatorApplicationApplications.php',
'PhabricatorApplicationAudit' => 'applications/audit/application/PhabricatorApplicationAudit.php',
@ -849,6 +850,7 @@ phutil_register_library_map(array(
'PhabricatorApplicationPolicy' => 'applications/policy/application/PhabricatorApplicationPolicy.php',
'PhabricatorApplicationPonder' => 'applications/ponder/application/PhabricatorApplicationPonder.php',
'PhabricatorApplicationProject' => 'applications/project/application/PhabricatorApplicationProject.php',
'PhabricatorApplicationQuery' => 'applications/meta/query/PhabricatorApplicationQuery.php',
'PhabricatorApplicationReleeph' => 'applications/releeph/application/PhabricatorApplicationReleeph.php',
'PhabricatorApplicationReleephConfigOptions' => 'applications/releeph/config/PhabricatorApplicationReleephConfigOptions.php',
'PhabricatorApplicationRepositories' => 'applications/repository/application/PhabricatorApplicationRepositories.php',
@ -2912,6 +2914,8 @@ phutil_register_library_map(array(
'PhabricatorAnchorView' => 'AphrontView',
'PhabricatorAphrontBarExample' => 'PhabricatorUIExample',
'PhabricatorAphrontViewTestCase' => 'PhabricatorTestCase',
'PhabricatorAppSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorApplication' => 'PhabricatorPolicyInterface',
'PhabricatorApplicationApplications' => 'PhabricatorApplication',
'PhabricatorApplicationAudit' => 'PhabricatorApplication',
'PhabricatorApplicationAuth' => 'PhabricatorApplication',
@ -2953,6 +2957,7 @@ phutil_register_library_map(array(
'PhabricatorApplicationPolicy' => 'PhabricatorApplication',
'PhabricatorApplicationPonder' => 'PhabricatorApplication',
'PhabricatorApplicationProject' => 'PhabricatorApplication',
'PhabricatorApplicationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorApplicationReleeph' => 'PhabricatorApplication',
'PhabricatorApplicationReleephConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorApplicationRepositories' => 'PhabricatorApplication',
@ -3669,7 +3674,7 @@ phutil_register_library_map(array(
'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController',
'PhabricatorRegistrationProfile' => 'Phobject',
'PhabricatorRemarkupControl' => 'AphrontFormTextAreaControl',
'PhabricatorRemarkupRuleEmbedFile' => 'PhutilRemarkupRule',
'PhabricatorRemarkupRuleEmbedFile' => 'PhabricatorRemarkupRuleObject',
'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule',
'PhabricatorRemarkupRuleMeme' => 'PhutilRemarkupRule',
'PhabricatorRemarkupRuleMention' => 'PhutilRemarkupRule',

View file

@ -8,7 +8,8 @@
* @task meta Application Management
* @group apps
*/
abstract class PhabricatorApplication {
abstract class PhabricatorApplication
implements PhabricatorPolicyInterface {
const GROUP_CORE = 'core';
const GROUP_COMMUNICATION = 'communication';
@ -49,7 +50,6 @@ abstract class PhabricatorApplication {
/* -( Application Information )-------------------------------------------- */
public function getName() {
return substr(get_class($this), strlen('PhabricatorApplication'));
}
@ -82,6 +82,25 @@ abstract class PhabricatorApplication {
return false;
}
/**
* Returns true if an application is first-party (developed by Phacility)
* and false otherwise.
*/
final public function isFirstParty() {
$where = id(new ReflectionClass($this))->getFileName();
$root = phutil_get_library_root('phabricator');
if (!Filesystem::isDescendant($where, $root)) {
return false;
}
if (Filesystem::isDescendant($where, $root.'/extensions')) {
return false;
}
return true;
}
public function canUninstall() {
return true;
}
@ -297,5 +316,33 @@ abstract class PhabricatorApplication {
return $apps;
}
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return PhabricatorPolicies::POLICY_USER;
case PhabricatorPolicyCapability::CAN_EDIT:
return PhabricatorPolicies::POLICY_ADMIN;
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return false;
}
public function describeAutomaticCapability($capability) {
return null;
}
}

View file

@ -29,7 +29,8 @@ final class PhabricatorApplicationApplications extends PhabricatorApplication {
public function getRoutes() {
return array(
'/applications/' => array(
'' => 'PhabricatorApplicationsListController',
'(?:query/(?P<queryKey>[^/]+)/)?' =>
'PhabricatorApplicationsListController',
'view/(?P<application>\w+)/' =>
'PhabricatorApplicationDetailViewController',
'(?P<application>\w+)/(?P<action>install|uninstall)/' =>

View file

@ -6,19 +6,23 @@ abstract class PhabricatorApplicationsController extends PhabricatorController {
return true;
}
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($this->getApplicationURI()));
$nav->addLabel(pht('Installed Applications'));
$nav->addFilter('/', pht('Applications'));
id(new PhabricatorAppSearchEngine())
->setViewer($user)
->addNavigationItems($nav->getMenu());
$nav->selectFilter(null);
return $nav;
}
public function buildApplicationMenu() {
return $this->buildSideNavView(null, true)->getMenu();
return $this->buildSideNavView(true)->getMenu();
}
}

View file

@ -1,40 +1,30 @@
<?php
final class PhabricatorApplicationsListController
extends PhabricatorApplicationsController {
extends PhabricatorApplicationsController
implements PhabricatorApplicationSearchResultsControllerInterface {
private $queryKey;
public function willProcessRequest(array $data) {
$this->queryKey = idx($data, 'queryKey');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$controller = id(new PhabricatorApplicationSearchController($request))
->setQueryKey($this->queryKey)
->setSearchEngine(new PhabricatorAppSearchEngine())
->setNavigation($this->buildSideNavView());
$nav = $this->buildSideNavView();
$nav->selectFilter('/');
$applications = PhabricatorApplication::getAllApplications();
$list = $this->buildInstalledApplicationsList($applications);
$title = pht('Installed Applications');
$nav->appendChild($list);
$crumbs = $this
->buildApplicationCrumbs()
->addCrumb(
id(new PhabricatorCrumbView())
->setName(pht('Applications'))
->setHref($this->getApplicationURI()));
$nav->setCrumbs($crumbs);
return $this->buildApplicationPage(
$nav,
array(
'title' => $title,
'device' => true,
));
return $this->delegateToController($controller);
}
public function renderResultsList(
array $applications,
PhabricatorSavedQuery $query) {
assert_instances_of($applications, 'PhabricatorApplication');
private function buildInstalledApplicationsList(array $applications) {
$list = new PHUIObjectItemListView();
$applications = msort($applications, 'getName');

View file

@ -0,0 +1,134 @@
<?php
final class PhabricatorAppSearchEngine
extends PhabricatorApplicationSearchEngine {
public function getPageSize(PhabricatorSavedQuery $saved) {
return INF;
}
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter('name', $request->getStr('name'));
$saved->setParameter('installed', $this->readBool($request, 'installed'));
$saved->setParameter('beta', $this->readBool($request, 'beta'));
$saved->setParameter('firstParty', $this->readBool($request, 'firstParty'));
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new PhabricatorApplicationQuery());
$name = $saved->getParameter('name');
if (strlen($name)) {
$query->withNameContains($name);
}
$installed = $saved->getParameter('installed');
if ($installed !== null) {
$query->withInstalled($installed);
}
$beta = $saved->getParameter('beta');
if ($beta !== null) {
$query->withBeta($beta);
}
$first_party = $saved->getParameter('firstParty');
if ($first_party !== null) {
$query->withFirstParty($first_party);
}
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved) {
$form
->appendChild(
id(new AphrontFormTextControl())
->setLabel(pht('Name Contains'))
->setName('name')
->setValue($saved->getParameter('name')))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Installed'))
->setName('installed')
->setValue($this->getBool($saved, 'installed'))
->setOptions(
array(
'' => pht('Show All Applications'),
'true' => pht('Show Installed Applications'),
'false' => pht('Show Uninstalled Applications'),
)))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Beta'))
->setName('beta')
->setValue($this->getBool($saved, 'beta'))
->setOptions(
array(
'' => pht('Show All Applications'),
'true' => pht('Show Beta Applications'),
'false' => pht('Show Released Applications'),
)))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Provenance'))
->setName('firstParty')
->setValue($this->getBool($saved, 'firstParty'))
->setOptions(
array(
'' => pht('Show All Applications'),
'true' => pht('Show First-Party Applications'),
'false' => pht('Show Third-Party Applications'),
)));
}
protected function getURI($path) {
return '/applications/'.$path;
}
public function getBuiltinQueryNames() {
$names = array(
'all' => pht('All Applications'),
);
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
private function readBool(AphrontRequest $request, $key) {
if (!strlen($request->getStr($key))) {
return null;
}
return $request->getBool($key);
}
private function getBool(PhabricatorSavedQuery $query, $key) {
$value = $query->getParameter($key);
if ($value === null) {
return $value;
}
return $value ? 'true' : 'false';
}
}

View file

@ -0,0 +1,84 @@
<?php
final class PhabricatorApplicationQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $installed;
private $beta;
private $firstParty;
private $nameContains;
private $classes;
public function withNameContains($name_contains) {
$this->nameContains = $name_contains;
return $this;
}
public function withInstalled($installed) {
$this->installed = $installed;
return $this;
}
public function withBeta($beta) {
$this->beta = $beta;
return $this;
}
public function withFirstParty($first_party) {
$this->firstParty = $first_party;
return $this;
}
public function withClasses(array $classes) {
$this->classes = $classes;
return $this;
}
public function loadPage() {
$apps = PhabricatorApplication::getAllApplications();
if ($this->classes) {
$classes = array_fuse($this->classes);
foreach ($apps as $key => $app) {
if (empty($classes[get_class($app)])) {
unset($apps[$key]);
}
}
}
if (strlen($this->nameContains)) {
foreach ($apps as $key => $app) {
if (stripos($app->getName(), $this->nameContains) === false) {
unset($apps[$key]);
}
}
}
if ($this->installed !== null) {
foreach ($apps as $key => $app) {
if ($app->isInstalled() != $this->installed) {
unset($apps[$key]);
}
}
}
if ($this->beta !== null) {
foreach ($apps as $key => $app) {
if ($app->isBeta() != $this->beta) {
unset($apps[$key]);
}
}
}
if ($this->firstParty !== null) {
foreach ($apps as $key => $app) {
if ($app->isFirstParty() != $this->firstParty) {
unset($apps[$key]);
}
}
}
return msort($apps, 'getName');
}
}

View file

@ -35,3 +35,31 @@ interface PhabricatorPolicyInterface {
public function describeAutomaticCapability($capability);
}
// TEMPLATE IMPLEMENTATION /////////////////////////////////////////////////////
/* -( PhabricatorPolicyInterface )----------------------------------------- */
/*
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
);
}
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return PhabricatorPolicies::POLICY_USER;
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return false;
}
public function describeAutomaticCapability($capability) {
return null;
}
*/