1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-30 10:42:41 +01:00

Use ApplicationSearch for Releeph branch lists

Summary:
Releeph branch lists in project views have a bunch of custom UI right now; give them more standard UI and ApplicationSearch.

This drops a small piece of functionality: we now show only a total open request count instead of a detailed enumeration of each request status. I assume this is reasonable (that is, the important piece is "is there something to do on this branch?"), but we can muck with it if the more detailed status is important.

Test Plan: {F54344}

Reviewers: btrahan

Reviewed By: btrahan

CC: LegNeato, aran

Maniphest Tasks: T3656

Differential Revision: https://secure.phabricator.com/D6764
This commit is contained in:
epriestley 2013-08-16 18:55:35 -07:00
parent f909a295f7
commit 210e30c257
8 changed files with 319 additions and 212 deletions

View file

@ -1946,6 +1946,7 @@ phutil_register_library_map(array(
'ReleephBranchNamePreviewController' => 'applications/releeph/controller/branch/ReleephBranchNamePreviewController.php', 'ReleephBranchNamePreviewController' => 'applications/releeph/controller/branch/ReleephBranchNamePreviewController.php',
'ReleephBranchPreviewView' => 'applications/releeph/view/branch/ReleephBranchPreviewView.php', 'ReleephBranchPreviewView' => 'applications/releeph/view/branch/ReleephBranchPreviewView.php',
'ReleephBranchQuery' => 'applications/releeph/query/ReleephBranchQuery.php', 'ReleephBranchQuery' => 'applications/releeph/query/ReleephBranchQuery.php',
'ReleephBranchSearchEngine' => 'applications/releeph/query/ReleephBranchSearchEngine.php',
'ReleephBranchTemplate' => 'applications/releeph/view/branch/ReleephBranchTemplate.php', 'ReleephBranchTemplate' => 'applications/releeph/view/branch/ReleephBranchTemplate.php',
'ReleephBranchViewController' => 'applications/releeph/controller/branch/ReleephBranchViewController.php', 'ReleephBranchViewController' => 'applications/releeph/controller/branch/ReleephBranchViewController.php',
'ReleephCommitFinder' => 'applications/releeph/commitfinder/ReleephCommitFinder.php', 'ReleephCommitFinder' => 'applications/releeph/commitfinder/ReleephCommitFinder.php',
@ -1979,7 +1980,6 @@ phutil_register_library_map(array(
'ReleephProjectListController' => 'applications/releeph/controller/project/ReleephProjectListController.php', 'ReleephProjectListController' => 'applications/releeph/controller/project/ReleephProjectListController.php',
'ReleephProjectQuery' => 'applications/releeph/query/ReleephProjectQuery.php', 'ReleephProjectQuery' => 'applications/releeph/query/ReleephProjectQuery.php',
'ReleephProjectSearchEngine' => 'applications/releeph/query/ReleephProjectSearchEngine.php', 'ReleephProjectSearchEngine' => 'applications/releeph/query/ReleephProjectSearchEngine.php',
'ReleephProjectView' => 'applications/releeph/view/ReleephProjectView.php',
'ReleephProjectViewController' => 'applications/releeph/controller/project/ReleephProjectViewController.php', 'ReleephProjectViewController' => 'applications/releeph/controller/project/ReleephProjectViewController.php',
'ReleephReasonFieldSpecification' => 'applications/releeph/field/specification/ReleephReasonFieldSpecification.php', 'ReleephReasonFieldSpecification' => 'applications/releeph/field/specification/ReleephReasonFieldSpecification.php',
'ReleephRequest' => 'applications/releeph/storage/ReleephRequest.php', 'ReleephRequest' => 'applications/releeph/storage/ReleephRequest.php',
@ -4128,6 +4128,7 @@ phutil_register_library_map(array(
'ReleephBranchNamePreviewController' => 'ReleephController', 'ReleephBranchNamePreviewController' => 'ReleephController',
'ReleephBranchPreviewView' => 'AphrontFormControl', 'ReleephBranchPreviewView' => 'AphrontFormControl',
'ReleephBranchQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ReleephBranchQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'ReleephBranchSearchEngine' => 'PhabricatorApplicationSearchEngine',
'ReleephBranchViewController' => 'ReleephBranchViewController' =>
array( array(
0 => 'ReleephProjectController', 0 => 'ReleephProjectController',
@ -4172,8 +4173,11 @@ phutil_register_library_map(array(
), ),
'ReleephProjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ReleephProjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'ReleephProjectSearchEngine' => 'PhabricatorApplicationSearchEngine', 'ReleephProjectSearchEngine' => 'PhabricatorApplicationSearchEngine',
'ReleephProjectView' => 'AphrontView', 'ReleephProjectViewController' =>
'ReleephProjectViewController' => 'ReleephProjectController', array(
0 => 'ReleephProjectController',
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
),
'ReleephReasonFieldSpecification' => 'ReleephFieldSpecification', 'ReleephReasonFieldSpecification' => 'ReleephFieldSpecification',
'ReleephRequest' => 'ReleephRequest' =>
array( array(

View file

@ -38,8 +38,7 @@ final class PhabricatorApplicationReleeph extends PhabricatorApplication {
'(?:query/(?P<queryKey>[^/]+)/)?' => 'ReleephProjectListController', '(?:query/(?P<queryKey>[^/]+)/)?' => 'ReleephProjectListController',
'create/' => 'ReleephProjectCreateController', 'create/' => 'ReleephProjectCreateController',
'(?P<projectID>[1-9]\d*)/' => array( '(?P<projectID>[1-9]\d*)/' => array(
'' => 'ReleephProjectViewController', '(?:query/(?P<queryKey>[^/]+)/)?' => 'ReleephProjectViewController',
'closedbranches/' => 'ReleephProjectViewController',
'edit/' => 'ReleephProjectEditController', 'edit/' => 'ReleephProjectEditController',
'cutbranch/' => 'ReleephBranchCreateController', 'cutbranch/' => 'ReleephBranchCreateController',
'action/(?P<action>.+)/' => 'ReleephProjectActionController', 'action/(?P<action>.+)/' => 'ReleephProjectActionController',

View file

@ -10,23 +10,28 @@ final class ReleephBranchAccessController extends ReleephProjectController {
} }
public function processRequest() { public function processRequest() {
$rph_branch = $this->getReleephBranch(); $branch = $this->getReleephBranch();
$request = $this->getRequest(); $request = $this->getRequest();
$active_uri = '/releeph/project/'.$rph_branch->getReleephProjectID().'/'; $done_uri = '/releeph/project/'.$branch->getReleephProjectID().'/';
$inactive_uri = $active_uri.'inactive/';
switch ($this->action) { switch ($this->action) {
case 'close': case 'close':
$is_active = false; $is_active = false;
$origin_uri = $active_uri; $title_text = pht('Close Branch');
$body_text = pht(
'Really close the branch "%s"?',
$branch->getBasename());
$button_text = pht('Close Branch');
break; break;
case 're-open': case 're-open':
$is_active = true; $is_active = true;
$origin_uri = $inactive_uri; $title_text = pht('Reopen Branch');
$body_text = pht(
'Really reopen the branch "%s"?',
$branch->getBasename());
$button_text = pht('Reopen Branch');
break; break;
default: default:
throw new Exception("Unknown action '{$this->action}'!"); throw new Exception("Unknown action '{$this->action}'!");
break; break;
@ -35,26 +40,19 @@ final class ReleephBranchAccessController extends ReleephProjectController {
if ($request->isDialogFormPost()) { if ($request->isDialogFormPost()) {
id(new ReleephBranchEditor()) id(new ReleephBranchEditor())
->setActor($request->getUser()) ->setActor($request->getUser())
->setReleephBranch($rph_branch) ->setReleephBranch($branch)
->changeBranchAccess($is_active ? 1 : 0); ->changeBranchAccess($is_active ? 1 : 0);
return id(new AphrontRedirectResponse())
->setURI($origin_uri); return id(new AphrontReloadResponse())->setURI($done_uri);
} }
$button_text = pht('%s Branch', $this->action);
$text = pht('Really %s the branch: %s?',
$this->action,
$rph_branch->getBasename());
$message = phutil_tag('p', array(), $text);
$dialog = new AphrontDialogView(); $dialog = new AphrontDialogView();
$dialog $dialog
->setUser($request->getUser()) ->setUser($request->getUser())
->setTitle(pht('Confirm')) ->setTitle($title_text)
->appendChild($message) ->appendChild($body_text)
->addSubmitButton($button_text) ->addSubmitButton($button_text)
->addCancelButton($origin_uri); ->addCancelButton($done_uri);
return id(new AphrontDialogResponse())->setDialog($dialog); return id(new AphrontDialogResponse())->setDialog($dialog);
} }

View file

@ -1,45 +1,172 @@
<?php <?php
final class ReleephProjectViewController extends ReleephProjectController { final class ReleephProjectViewController extends ReleephProjectController
implements PhabricatorApplicationSearchResultsControllerInterface {
private $queryKey;
public function shouldAllowPublic() {
return true;
}
public function willProcessRequest(array $data) {
parent::willProcessRequest($data);
$this->queryKey = idx($data, 'queryKey');
}
public function processRequest() { public function processRequest() {
// Load all branches $request = $this->getRequest();
$releeph_project = $this->getReleephProject(); $controller = id(new PhabricatorApplicationSearchController($request))
$releeph_branches = id(new ReleephBranch()) ->setQueryKey($this->queryKey)
->loadAllWhere('releephProjectID = %d', ->setSearchEngine(
$releeph_project->getID()); id(new ReleephBranchSearchEngine())
->setProjectID($this->getReleephProject()->getID()))
->setNavigation($this->buildSideNavView());
$path = $this->getRequest()->getRequestURI()->getPath(); return $this->delegateToController($controller);
$is_open_branches = strpos($path, 'closedbranches/') === false; }
$view = id(new ReleephProjectView()) public function renderResultsList(
->setShowOpenBranches($is_open_branches) array $branches,
->setUser($this->getRequest()->getUser()) PhabricatorSavedQuery $saved) {
->setReleephProject($releeph_project) assert_instances_of($branches, 'ReleephBranch');
->setBranches($releeph_branches);
$crumbs = $this->buildApplicationCrumbs() $viewer = $this->getRequest()->getUser();
->addCrumb(
id(new PhabricatorCrumbView())
->setName($releeph_project->getName())
->setHref($releeph_project->getURI()));
if ($releeph_project->getIsActive()) { $projects = mpull($branches, 'getProject');
$crumbs->addAction( $repo_phids = mpull($projects, 'getRepositoryPHID');
id(new PHUIListItemView())
->setHref($releeph_project->getURI('cutbranch')) $repos = id(new PhabricatorRepositoryQuery())
->setName(pht('Cut New Branch')) ->setViewer($viewer)
->setIcon('create')); ->withPHIDs($repo_phids)
->execute();
$repos = mpull($repos, null, 'getPHID');
$phids = mpull($branches, 'getCreatedByUserPHID');
$this->loadHandles($phids);
$requests = array();
if ($branches) {
$requests = id(new ReleephRequestQuery())
->setViewer($viewer)
->withBranchIDs(mpull($branches, 'getID'))
->withStatus(ReleephRequestQuery::STATUS_OPEN)
->execute();
$requests = mgroup($requests, 'getBranchID');
} }
return $this->buildStandardPageResponse( $list = id(new PhabricatorObjectItemListView())
array( ->setUser($viewer);
$crumbs, foreach ($branches as $branch) {
$view, $diffusion_href = null;
), $repo = idx($repos, $branch->getProject()->getRepositoryPHID());
array( if ($repo) {
'title' => $releeph_project->getName() $drequest = DiffusionRequest::newFromDictionary(
)); array(
'user' => $viewer,
'repository' => $repo,
));
$diffusion_href = $drequest->generateURI(
array(
'action' => 'branch',
'branch' => $branch->getName(),
));
}
$branch_link = $branch->getName();
if ($diffusion_href) {
$branch_link = phutil_tag(
'a',
array(
'href' => $diffusion_href,
),
$branch_link);
}
$item = id(new PhabricatorObjectItemView())
->setHeader($branch->getDisplayName())
->setHref($branch->getURI())
->addAttribute($branch_link);
$item->addAction(
id(new PHUIListItemView())
->setIcon('edit')
->setHref($branch->getURI('edit/')));
if ($branch->getIsActive()) {
$item->setBarColor('blue');
$item->addAction(
id(new PHUIListItemView())
->setIcon('delete')
->setWorkflow(true)
->setHref($branch->getURI('close/')));
} else {
$item->setDisabled(true);
$item->addAction(
id(new PHUIListItemView())
->setIcon('enable')
->setWorkflow(true)
->setHref($branch->getURI('re-open/')));
}
$commit = $branch->getCutPointCommit();
if ($commit) {
$item->addIcon(
'none',
phabricator_datetime($commit->getEpoch(), $viewer));
}
$open_count = count(idx($requests, $branch->getID(), array()));
if ($open_count) {
$item->setBarColor('orange');
$item->addIcon(
'fork',
pht('%d Open Pull Request(s)', new PhutilNumber($open_count)));
}
$list->addItem($item);
}
return $list;
}
public function buildSideNavView($for_app = false) {
$user = $this->getRequest()->getUser();
$nav = new AphrontSideNavFilterView();
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
if ($for_app) {
$nav->addFilter('project/create/', pht('Create Project'));
}
id(new ReleephBranchSearchEngine())
->setProjectID($this->getReleephProject()->getID())
->setViewer($user)
->addNavigationItems($nav->getMenu());
$nav->selectFilter(null);
return $nav;
}
public function buildApplicationCrumbs() {
$crumbs = parent::buildApplicationCrumbs();
$project = $this->getReleephProject();
$crumbs->addCrumb(
id(new PhabricatorCrumbView())
->setName($project->getName()));
$crumbs->addAction(
id(new PHUIListItemView())
->setHref($project->getURI('cutbranch'))
->setName(pht('Cut New Branch'))
->setIcon('create'));
return $crumbs;
} }
} }

View file

@ -5,6 +5,11 @@ final class ReleephBranchQuery
private $ids; private $ids;
private $phids; private $phids;
private $projectIDs;
const STATUS_ALL = 'status-all';
const STATUS_OPEN = 'status-open';
private $status = self::STATUS_ALL;
private $needCutPointCommits; private $needCutPointCommits;
@ -23,6 +28,16 @@ final class ReleephBranchQuery
return $this; return $this;
} }
public function withStatus($status) {
$this->status = $status;
return $this;
}
public function withProjectIDs(array $ids) {
$this->projectIDs = $ids;
return $this;
}
public function loadPage() { public function loadPage() {
$table = new ReleephBranch(); $table = new ReleephBranch();
$conn_r = $table->establishConnection('r'); $conn_r = $table->establishConnection('r');
@ -89,6 +104,26 @@ final class ReleephBranchQuery
$this->phids); $this->phids);
} }
if ($this->projectIDs) {
$where[] = qsprintf(
$conn_r,
'releephProjectID IN (%Ld)',
$this->projectIDs);
}
$status = $this->status;
switch ($status) {
case self::STATUS_ALL:
break;
case self::STATUS_OPEN:
$where[] = qsprintf(
$conn_r,
'isActive = 1');
break;
default:
throw new Exception("Unknown status constant '{$status}'!");
}
$where[] = $this->buildPagingClause($conn_r); $where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where); return $this->formatWhereClause($where);

View file

@ -0,0 +1,94 @@
<?php
final class ReleephBranchSearchEngine
extends PhabricatorApplicationSearchEngine {
private $projectID;
public function setProjectID($project_id) {
$this->projectID = $project_id;
return $this;
}
public function getProjectID() {
return $this->projectID;
}
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter('active', $request->getStr('active'));
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new ReleephBranchQuery())
->needCutPointCommits(true)
->withProjectIDs(array($this->getProjectID()));
$active = $saved->getParameter('active');
$value = idx($this->getActiveValues(), $active);
if ($value !== null) {
$query->withStatus($value);
}
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved_query) {
$form->appendChild(
id(new AphrontFormSelectControl())
->setName('active')
->setLabel(pht('Show Branches'))
->setValue($saved_query->getParameter('active'))
->setOptions($this->getActiveOptions()));
}
protected function getURI($path) {
return '/releeph/project/'.$this->getProjectID().'/'.$path;
}
public function getBuiltinQueryNames() {
$names = array(
'open' => pht('Open'),
'all' => pht('All'),
);
return $names;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'open':
return $query
->setParameter('active', 'open');
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
private function getActiveOptions() {
return array(
'open' => pht('Open Branches'),
'all' => pht('Open and Closed Branches'),
);
}
private function getActiveValues() {
return array(
'open' => ReleephBranchQuery::STATUS_OPEN,
'all' => ReleephBranchQuery::STATUS_ALL,
);
}
}

View file

@ -1,155 +0,0 @@
<?php
final class ReleephProjectView extends AphrontView {
private $showOpenBranches = true;
private $releephProject;
private $releephBranches;
public function setShowOpenBranches($active) {
$this->showOpenBranches = $active;
return $this;
}
public function setReleephProject($releeph_project) {
$this->releephProject = $releeph_project;
return $this;
}
public function setBranches($branches) {
$this->releephBranches = $branches;
return $this;
}
public function render() {
$releeph_project = $this->releephProject;
if ($this->showOpenBranches) {
$releeph_branches = mfilter($this->releephBranches, 'getIsActive');
} else {
$releeph_branches = mfilter($this->releephBranches, 'getIsActive', true);
}
// Load all relevant PHID handles
$phids = array_merge(
array(
$this->releephProject->getPHID(),
$this->releephProject->getRepositoryPHID(),
),
mpull($releeph_branches, 'getCreatedByUserPHID'),
mpull($releeph_branches, 'getCutPointCommitPHID'),
$releeph_project->getPushers());
$handles = id(new PhabricatorObjectHandleData($phids))
->setViewer($this->getUser())
->loadHandles();
// Sort branches, which requires the handles above
$releeph_branches = self::sortBranches($releeph_branches, $handles);
// The header
$repository_phid = $releeph_project->getRepositoryPHID();
$header = hsprintf(
'%s in %s repository',
$releeph_project->getName(),
$handles[$repository_phid]->renderLink());
if ($this->showOpenBranches) {
$view_other_link = phutil_tag(
'a',
array(
'href' => $releeph_project->getURI('closedbranches/'),
),
'View closed branches');
} else {
$view_other_link = phutil_tag(
'a',
array(
'href' => $releeph_project->getURI(),
),
'View open branches');
}
$header = hsprintf("%s &middot; %s", $header, $view_other_link);
// The "create branch" button
$create_branch_url = $releeph_project->getURI('cutbranch/');
// Pushers info
$pushers_info = array();
$pushers = $releeph_project->getPushers();
require_celerity_resource('releeph-project');
if ($pushers) {
$pushers_info[] = phutil_tag('h2', array(), 'Pushers');
foreach ($pushers as $user_phid) {
$handle = $handles[$user_phid];
$div = phutil_tag(
'div',
array(
'class' => 'releeph-pusher',
'style' => 'background-image: url('.$handle->getImageURI().');',
),
phutil_tag(
'div',
array(
'class' => 'releeph-pusher-body',
),
$handles[$user_phid]->renderLink()));
$pushers_info[] = $div;
}
$pushers_info[] = hsprintf('<div style="clear: both;"></div>');
}
// Put it all together
$panel = id(new AphrontPanelView())
->setHeader($header)
->appendChild(phutil_implode_html('', $pushers_info));
foreach ($releeph_branches as $ii => $releeph_branch) {
$box = id(new ReleephBranchBoxView())
->setUser($this->user)
->setHandles($handles)
->setReleephBranch($releeph_branch)
->setNamed();
if ($ii === 0) {
$box->setLatest();
}
$panel->appendChild($box);
}
return $panel->render();
}
/**
* Sort branches by the point at which they were cut, newest cut points
* first.
*
* If branches share a cut point, sort newest branch first.
*/
private static function sortBranches($branches, $handles) {
// Group by commit phid
$groups = mgroup($branches, 'getCutPointCommitPHID');
// Convert commit phid to a commit timestamp
$ar = array();
foreach ($groups as $cut_phid => $group) {
$handle = $handles[$cut_phid];
// Pack (timestamp, group-with-this-timestamp) pairs into $ar
$ar[] = array(
$handle->getTimestamp(),
msort($group, 'getDateCreated')
);
}
$branches = array();
// Sort by timestamp, pull groups, and flatten into one big group
foreach (ipull(isort($ar, 0), 1) as $group) {
$branches = array_merge($branches, $group);
}
return array_reverse($branches);
}
}

View file

@ -662,6 +662,11 @@ abstract class PhabricatorBaseEnglishTranslation
'configuration sources: %s.', 'configuration sources: %s.',
), ),
'%d Open Pull Request(s)' => array(
'%d Open Pull Request',
'%d Open Pull Requests',
),
); );
} }