mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-23 15:22:41 +01:00
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
This commit is contained in:
parent
9ef0ea91c4
commit
dcec8e60cc
6 changed files with 133 additions and 63 deletions
|
@ -16,7 +16,10 @@ abstract class ReleephProjectController extends ReleephController {
|
||||||
$project_id = idx($data, 'projectID');
|
$project_id = idx($data, 'projectID');
|
||||||
$project_name = idx($data, 'projectName');
|
$project_name = idx($data, 'projectName');
|
||||||
if ($project_id) {
|
if ($project_id) {
|
||||||
$project = id(new ReleephProject())->load($project_id);
|
$project = id(new ReleephProjectQuery())
|
||||||
|
->setViewer($this->getRequest()->getUser())
|
||||||
|
->withIDs(array($project_id))
|
||||||
|
->executeOne();
|
||||||
if (!$project) {
|
if (!$project) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
"ReleephProject with id '{$project_id}' not found!");
|
"ReleephProject with id '{$project_id}' not found!");
|
||||||
|
|
|
@ -11,15 +11,31 @@ final class ReleephProjectActionController extends ReleephProjectController {
|
||||||
|
|
||||||
public function processRequest() {
|
public function processRequest() {
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
$action = $this->action;
|
$action = $this->action;
|
||||||
$rph_project = $this->getReleephProject();
|
|
||||||
|
$project = id(new ReleephProjectQuery())
|
||||||
|
->withIDs(array($this->getReleephProject()->getID()))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
|
->setViewer($viewer)
|
||||||
|
->executeOne();
|
||||||
|
if (!$project) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$project_id = $project->getID();
|
||||||
|
$project_uri = $this->getApplicationURI("project/{$project_id}/");
|
||||||
|
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
case 'deactivate':
|
case 'deactivate':
|
||||||
if ($request->isDialogFormPost()) {
|
if ($request->isDialogFormPost()) {
|
||||||
$rph_project->deactivate($request->getUser())->save();
|
$project->deactivate($viewer)->save();
|
||||||
return id(new AphrontRedirectResponse())->setURI('/releeph');
|
return id(new AphrontRedirectResponse())->setURI($project_uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
$dialog = id(new AphrontDialogView())
|
$dialog = id(new AphrontDialogView())
|
||||||
|
@ -29,42 +45,14 @@ final class ReleephProjectActionController extends ReleephProjectController {
|
||||||
'p',
|
'p',
|
||||||
array(),
|
array(),
|
||||||
pht('Really deactivate the Releeph project: %s?',
|
pht('Really deactivate the Releeph project: %s?',
|
||||||
$rph_project->getName())))
|
$project->getName())))
|
||||||
->appendChild(phutil_tag(
|
->addSubmitButton(pht('Deactivate Project'))
|
||||||
'p',
|
->addCancelButton($project_uri);
|
||||||
array(),
|
|
||||||
pht('It will still exist, but '.
|
|
||||||
'will be hidden from the list of active projects.')))
|
|
||||||
->addSubmitButton(pht('Deactivate Releeph Project'))
|
|
||||||
->addCancelButton($request->getRequestURI());
|
|
||||||
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||||
|
|
||||||
case 'activate':
|
case 'activate':
|
||||||
$rph_project->setIsActive(1)->save();
|
$project->setIsActive(1)->save();
|
||||||
return id(new AphrontRedirectResponse())->setURI('/releeph');
|
return id(new AphrontRedirectResponse())->setURI($project_uri);
|
||||||
|
|
||||||
case 'delete':
|
|
||||||
if ($request->isDialogFormPost()) {
|
|
||||||
$rph_project->delete();
|
|
||||||
return id(new AphrontRedirectResponse())
|
|
||||||
->setURI('/releeph/project/inactive');
|
|
||||||
}
|
|
||||||
|
|
||||||
$dialog = id(new AphrontDialogView())
|
|
||||||
->setUser($request->getUser())
|
|
||||||
->setTitle(pht('Really delete Releeph Project?'))
|
|
||||||
->appendChild(phutil_tag(
|
|
||||||
'p',
|
|
||||||
array(),
|
|
||||||
pht('Really delete the Releeph project: %s? '.
|
|
||||||
'This cannot be undone!'),
|
|
||||||
$rph_project->getName()))
|
|
||||||
->setHeaderColor(PhabricatorActionHeaderView::HEADER_RED)
|
|
||||||
->addSubmitButton(pht('Delete'))
|
|
||||||
->addCancelButton($request->getRequestURI());
|
|
||||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,34 +39,9 @@ final class ReleephProjectListController extends ReleephController
|
||||||
->setHeader($project->getName())
|
->setHeader($project->getName())
|
||||||
->setHref($this->getApplicationURI("project/{$id}/"));
|
->setHref($this->getApplicationURI("project/{$id}/"));
|
||||||
|
|
||||||
$edit_uri = $this->getApplicationURI("project/{$id}/edit/");
|
if (!$project->getIsActive()) {
|
||||||
$item->addAction(
|
|
||||||
id(new PHUIListItemView())
|
|
||||||
->setIcon('edit')
|
|
||||||
->setHref($edit_uri));
|
|
||||||
|
|
||||||
if ($project->getIsActive()) {
|
|
||||||
$disable_uri = $this->getApplicationURI(
|
|
||||||
"project/{$id}/action/deactivate/");
|
|
||||||
|
|
||||||
$item->addAction(
|
|
||||||
id(new PHUIListItemView())
|
|
||||||
->setIcon('delete')
|
|
||||||
->setName(pht('Deactivate'))
|
|
||||||
->setWorkflow(true)
|
|
||||||
->setHref($disable_uri));
|
|
||||||
} else {
|
|
||||||
$enable_uri = $this->getApplicationURI(
|
|
||||||
"project/{$id}/action/activate/");
|
|
||||||
|
|
||||||
$item->setDisabled(true);
|
$item->setDisabled(true);
|
||||||
$item->addIcon('none', pht('Inactive'));
|
$item->addIcon('none', pht('Inactive'));
|
||||||
$item->addAction(
|
|
||||||
id(new PHUIListItemView())
|
|
||||||
->setIcon('new')
|
|
||||||
->setName(pht('Reactivate'))
|
|
||||||
->setWorkflow(true)
|
|
||||||
->setHref($enable_uri));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$repo = $project->getRepository();
|
$repo = $project->getRepository();
|
||||||
|
|
|
@ -18,6 +18,7 @@ final class ReleephProjectViewController extends ReleephProjectController
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$controller = id(new PhabricatorApplicationSearchController($request))
|
$controller = id(new PhabricatorApplicationSearchController($request))
|
||||||
->setQueryKey($this->queryKey)
|
->setQueryKey($this->queryKey)
|
||||||
|
->setPreface($this->renderPreface())
|
||||||
->setSearchEngine(
|
->setSearchEngine(
|
||||||
id(new ReleephBranchSearchEngine())
|
id(new ReleephBranchSearchEngine())
|
||||||
->setProjectID($this->getReleephProject()->getID()))
|
->setProjectID($this->getReleephProject()->getID()))
|
||||||
|
@ -165,4 +166,92 @@ final class ReleephProjectViewController extends ReleephProjectController
|
||||||
return $crumbs;
|
return $crumbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function renderPreface() {
|
||||||
|
$project = $this->getReleephProject();
|
||||||
|
$viewer = $this->getRequest()->getUser();
|
||||||
|
|
||||||
|
$id = $project->getID();
|
||||||
|
|
||||||
|
$header = id(new PhabricatorHeaderView())
|
||||||
|
->setHeader($project->getName());
|
||||||
|
|
||||||
|
if (!$project->getIsActive()) {
|
||||||
|
$header->addTag(
|
||||||
|
id(new PhabricatorTagView())
|
||||||
|
->setType(PhabricatorTagView::TYPE_STATE)
|
||||||
|
->setBackgroundColor(PhabricatorTagView::COLOR_BLACK)
|
||||||
|
->setName(pht('Deactivated')));
|
||||||
|
}
|
||||||
|
|
||||||
|
$actions = id(new PhabricatorActionListView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setObject($project)
|
||||||
|
->setObjectURI($this->getRequest()->getRequestURI());
|
||||||
|
|
||||||
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$viewer,
|
||||||
|
$project,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$edit_uri = $this->getApplicationURI("project/{$id}/edit/");
|
||||||
|
|
||||||
|
$deactivate_uri = "project/{$id}/action/deactivate/";
|
||||||
|
$deactivate_uri = $this->getApplicationURI($deactivate_uri);
|
||||||
|
|
||||||
|
$reactivate_uri = "project/{$id}/action/activate/";
|
||||||
|
$reactivate_uri = $this->getApplicationURI($reactivate_uri);
|
||||||
|
|
||||||
|
$actions->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Edit Project'))
|
||||||
|
->setHref($edit_uri)
|
||||||
|
->setIcon('edit')
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(!$can_edit));
|
||||||
|
|
||||||
|
if ($project->getIsActive()) {
|
||||||
|
$actions->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Deactivate Project'))
|
||||||
|
->setHref($deactivate_uri)
|
||||||
|
->setIcon('delete')
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(true));
|
||||||
|
} else {
|
||||||
|
$actions->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setName(pht('Reactivate Project'))
|
||||||
|
->setHref($reactivate_uri)
|
||||||
|
->setIcon('new')
|
||||||
|
->setUser($viewer)
|
||||||
|
->setRenderAsForm(true)
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$properties = id(new PhabricatorPropertyListView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->setObject($project);
|
||||||
|
|
||||||
|
$properties->addProperty(
|
||||||
|
pht('Repository'),
|
||||||
|
$project->getRepository()->getName());
|
||||||
|
|
||||||
|
$pushers = $project->getPushers();
|
||||||
|
if ($pushers) {
|
||||||
|
$this->loadHandles($pushers);
|
||||||
|
$properties->addProperty(
|
||||||
|
pht('Pushers'),
|
||||||
|
$this->renderHandlesForPHIDs($pushers));
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
$header,
|
||||||
|
$actions,
|
||||||
|
$properties,
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,6 +181,7 @@ final class ReleephProject extends ReleephDAO
|
||||||
public function getCapabilities() {
|
public function getCapabilities() {
|
||||||
return array(
|
return array(
|
||||||
PhabricatorPolicyCapability::CAN_VIEW,
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,16 @@ final class PhabricatorApplicationSearchController
|
||||||
private $searchEngine;
|
private $searchEngine;
|
||||||
private $navigation;
|
private $navigation;
|
||||||
private $queryKey;
|
private $queryKey;
|
||||||
|
private $preface;
|
||||||
|
|
||||||
|
public function setPreface($preface) {
|
||||||
|
$this->preface = $preface;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPreface() {
|
||||||
|
return $this->preface;
|
||||||
|
}
|
||||||
|
|
||||||
public function setQueryKey($query_key) {
|
public function setQueryKey($query_key) {
|
||||||
$this->queryKey = $query_key;
|
$this->queryKey = $query_key;
|
||||||
|
@ -166,6 +176,10 @@ final class PhabricatorApplicationSearchController
|
||||||
$this->getApplicationURI('query/advanced/?query='.$query_key));
|
$this->getApplicationURI('query/advanced/?query='.$query_key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->getPreface()) {
|
||||||
|
$nav->appendChild($this->getPreface());
|
||||||
|
}
|
||||||
|
|
||||||
$nav->appendChild($filter_view);
|
$nav->appendChild($filter_view);
|
||||||
|
|
||||||
if ($run_query) {
|
if ($run_query) {
|
||||||
|
|
Loading…
Reference in a new issue