mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-11 15:21:03 +01:00
Modernize Releeph project create controller
Summary: Ref T3092. - Check for a duplicate key error; - do less single loading and use Query classes; - use responsive UI elements; - add crumbs. Test Plan: Created a new project, and hit error cases. Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T3092 Differential Revision: https://secure.phabricator.com/D6629
This commit is contained in:
parent
c6ae9c5672
commit
333e377488
3 changed files with 110 additions and 51 deletions
|
@ -8,15 +8,7 @@ final class ReleephProjectCreateController extends ReleephProjectController {
|
||||||
$trunk_branch = trim($request->getStr('trunkBranch'));
|
$trunk_branch = trim($request->getStr('trunkBranch'));
|
||||||
$arc_pr_id = $request->getInt('arcPrID');
|
$arc_pr_id = $request->getInt('arcPrID');
|
||||||
|
|
||||||
|
$arc_projects = $this->loadArcProjects();
|
||||||
// Only allow arc projects with repositories. Sort and re-key by ID.
|
|
||||||
$arc_projects = id(new PhabricatorRepositoryArcanistProject())->loadAll();
|
|
||||||
$arc_projects = mpull(
|
|
||||||
msort(
|
|
||||||
mfilter($arc_projects, 'getRepositoryID'),
|
|
||||||
'getName'),
|
|
||||||
null,
|
|
||||||
'getID');
|
|
||||||
|
|
||||||
$e_name = true;
|
$e_name = true;
|
||||||
$e_trunk_branch = true;
|
$e_trunk_branch = true;
|
||||||
|
@ -25,20 +17,14 @@ final class ReleephProjectCreateController extends ReleephProjectController {
|
||||||
if ($request->isFormPost()) {
|
if ($request->isFormPost()) {
|
||||||
if (!$name) {
|
if (!$name) {
|
||||||
$e_name = pht('Required');
|
$e_name = pht('Required');
|
||||||
$errors[] =
|
$errors[] = pht(
|
||||||
pht('Your Releeph project should have a simple descriptive name.');
|
'Your Releeph project should have a simple descriptive name.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$trunk_branch) {
|
if (!$trunk_branch) {
|
||||||
$e_trunk_branch = pht('Required');
|
$e_trunk_branch = pht('Required');
|
||||||
$errors[] =
|
$errors[] = pht(
|
||||||
pht('You must specify which branch you will be picking from.');
|
'You must specify which branch you will be picking from.');
|
||||||
}
|
|
||||||
|
|
||||||
$all_names = mpull(id(new ReleephProject())->loadAll(), 'getName');
|
|
||||||
|
|
||||||
if (in_array($name, $all_names)) {
|
|
||||||
$errors[] = pht('Releeph project name %s is already taken', $name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$arc_project = $arc_projects[$arc_pr_id];
|
$arc_project = $arc_projects[$arc_pr_id];
|
||||||
|
@ -52,10 +38,18 @@ final class ReleephProjectCreateController extends ReleephProjectController {
|
||||||
->setRepositoryPHID($pr_repository->getPHID())
|
->setRepositoryPHID($pr_repository->getPHID())
|
||||||
->setArcanistProjectID($arc_project->getID())
|
->setArcanistProjectID($arc_project->getID())
|
||||||
->setCreatedByUserPHID($request->getUser()->getPHID())
|
->setCreatedByUserPHID($request->getUser()->getPHID())
|
||||||
->setIsActive(1)
|
->setIsActive(1);
|
||||||
->save();
|
|
||||||
|
|
||||||
return id(new AphrontRedirectResponse())->setURI('/releeph/');
|
try {
|
||||||
|
$releeph_project->save();
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())
|
||||||
|
->setURI($releeph_project->getURI());
|
||||||
|
} catch (AphrontQueryDuplicateKeyException $ex) {
|
||||||
|
$e_name = pht('Not Unique');
|
||||||
|
$errors[] = pht(
|
||||||
|
'Another project already uses this name.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,29 +57,9 @@ final class ReleephProjectCreateController extends ReleephProjectController {
|
||||||
if ($errors) {
|
if ($errors) {
|
||||||
$error_view = new AphrontErrorView();
|
$error_view = new AphrontErrorView();
|
||||||
$error_view->setErrors($errors);
|
$error_view->setErrors($errors);
|
||||||
$error_view->setTitle(pht('Form Errors'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make our own optgroup select control
|
$arc_project_options = $this->getArcProjectSelectOptions($arc_projects);
|
||||||
$arc_project_choices = array();
|
|
||||||
$pr_repositories = mpull(
|
|
||||||
msort(
|
|
||||||
array_filter(
|
|
||||||
// Some arc-projects don't have repositories
|
|
||||||
mpull($arc_projects, 'loadRepository')),
|
|
||||||
'getName'),
|
|
||||||
null,
|
|
||||||
'getID');
|
|
||||||
|
|
||||||
foreach ($pr_repositories as $pr_repo_id => $pr_repository) {
|
|
||||||
$options = array();
|
|
||||||
foreach ($arc_projects as $arc_project) {
|
|
||||||
if ($arc_project->getRepositoryID() == $pr_repo_id) {
|
|
||||||
$options[$arc_project->getID()] = $arc_project->getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$arc_project_choices[$pr_repository->getName()] = $options;
|
|
||||||
}
|
|
||||||
|
|
||||||
$project_name_input = id(new AphrontFormTextControl())
|
$project_name_input = id(new AphrontFormTextControl())
|
||||||
->setLabel(pht('Name'))
|
->setLabel(pht('Name'))
|
||||||
|
@ -108,7 +82,7 @@ final class ReleephProjectCreateController extends ReleephProjectController {
|
||||||
'target' => '_blank',
|
'target' => '_blank',
|
||||||
),
|
),
|
||||||
'here')))
|
'here')))
|
||||||
->setOptions($arc_project_choices);
|
->setOptions($arc_project_options);
|
||||||
|
|
||||||
$branch_name_preview = id(new ReleephBranchPreviewView())
|
$branch_name_preview = id(new ReleephBranchPreviewView())
|
||||||
->setLabel(pht('Example Branch'))
|
->setLabel(pht('Example Branch'))
|
||||||
|
@ -119,6 +93,7 @@ final class ReleephProjectCreateController extends ReleephProjectController {
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
$form = id(new AphrontFormView())
|
||||||
->setUser($request->getUser())
|
->setUser($request->getUser())
|
||||||
|
->setFlexible(true)
|
||||||
->appendChild($project_name_input)
|
->appendChild($project_name_input)
|
||||||
->appendChild($arc_project_input)
|
->appendChild($arc_project_input)
|
||||||
->appendChild(
|
->appendChild(
|
||||||
|
@ -135,15 +110,62 @@ final class ReleephProjectCreateController extends ReleephProjectController {
|
||||||
->addCancelButton('/releeph/project/')
|
->addCancelButton('/releeph/project/')
|
||||||
->setValue(pht('Create')));
|
->setValue(pht('Create')));
|
||||||
|
|
||||||
$panel = id(new AphrontPanelView())
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
->setHeader(pht('Create Releeph Project'))
|
$crumbs->addCrumb(
|
||||||
->appendChild($form)
|
id(new PhabricatorCrumbView())
|
||||||
->setWidth(AphrontPanelView::WIDTH_FORM);
|
->setName(pht('New Project')));
|
||||||
|
|
||||||
return $this->buildStandardPageResponse(
|
return $this->buildApplicationPage(
|
||||||
array($error_view, $panel),
|
|
||||||
array(
|
array(
|
||||||
'title' => pht('Create New Releeph Project')
|
$crumbs,
|
||||||
|
$error_view,
|
||||||
|
$form,
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'title' => pht('Create New Project'),
|
||||||
|
'dust' => true,
|
||||||
|
'device' => true,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function loadArcProjects() {
|
||||||
|
$viewer = $this->getRequest()->getUser();
|
||||||
|
|
||||||
|
$projects = id(new PhabricatorRepositoryArcanistProjectQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->needRepositories(true)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
$projects = mfilter($projects, 'getRepository');
|
||||||
|
$projects = msort($projects, 'getName');
|
||||||
|
|
||||||
|
return $projects;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getArcProjectSelectOptions(array $arc_projects) {
|
||||||
|
assert_instances_of($arc_projects, 'PhabricatorRepositoryArcanistProject');
|
||||||
|
|
||||||
|
$repos = mpull($arc_projects, 'getRepository');
|
||||||
|
$repos = mpull($repos, null, 'getID');
|
||||||
|
|
||||||
|
$groups = array();
|
||||||
|
foreach ($arc_projects as $arc_project) {
|
||||||
|
$id = $arc_project->getID();
|
||||||
|
$repo_id = $arc_project->getRepository()->getID();
|
||||||
|
$groups[$repo_id][$id] = $arc_project->getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
$choices = array();
|
||||||
|
foreach ($groups as $repo_id => $group) {
|
||||||
|
$repo_name = $repos[$repo_id]->getName();
|
||||||
|
$callsign = $repos[$repo_id]->getCallsign();
|
||||||
|
$name = "r{$callsign} ({$repo_name})";
|
||||||
|
$choices[$name] = $group;
|
||||||
|
}
|
||||||
|
|
||||||
|
ksort($choices);
|
||||||
|
|
||||||
|
return $choices;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ final class PhabricatorRepositoryArcanistProjectQuery
|
||||||
private $ids;
|
private $ids;
|
||||||
private $phids;
|
private $phids;
|
||||||
|
|
||||||
|
private $needRepositories;
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
public function withIDs(array $ids) {
|
||||||
$this->ids = $ids;
|
$this->ids = $ids;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -19,6 +21,11 @@ final class PhabricatorRepositoryArcanistProjectQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function needRepositories($need_repositories) {
|
||||||
|
$this->needRepositories = $need_repositories;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$table = new PhabricatorRepositoryArcanistProject();
|
$table = new PhabricatorRepositoryArcanistProject();
|
||||||
$conn_r = $table->establishConnection('r');
|
$conn_r = $table->establishConnection('r');
|
||||||
|
@ -34,6 +41,24 @@ final class PhabricatorRepositoryArcanistProjectQuery
|
||||||
return $table->loadAllFromArray($data);
|
return $table->loadAllFromArray($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function willFilterPage(array $projects) {
|
||||||
|
assert_instances_of($projects, 'PhabricatorRepositoryArcanistProject');
|
||||||
|
|
||||||
|
if ($this->needRepositories) {
|
||||||
|
$repository_ids = mpull($projects, 'getRepositoryID');
|
||||||
|
$repositories = id(new PhabricatorRepositoryQuery())
|
||||||
|
->setViewer($this->getViewer())
|
||||||
|
->withIDs($repository_ids)
|
||||||
|
->execute();
|
||||||
|
foreach ($projects as $project) {
|
||||||
|
$repo = idx($repositories, $project->getRepositoryID());
|
||||||
|
$project->attachRepository($repo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $projects;
|
||||||
|
}
|
||||||
|
|
||||||
private function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
private function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
||||||
$where = array();
|
$where = array();
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ final class PhabricatorRepositoryArcanistProject
|
||||||
protected $symbolIndexLanguages = array();
|
protected $symbolIndexLanguages = array();
|
||||||
protected $symbolIndexProjects = array();
|
protected $symbolIndexProjects = array();
|
||||||
|
|
||||||
|
private $repository = self::ATTACHABLE;
|
||||||
|
|
||||||
public function getConfiguration() {
|
public function getConfiguration() {
|
||||||
return array(
|
return array(
|
||||||
self::CONFIG_AUX_PHID => true,
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
@ -30,6 +32,7 @@ final class PhabricatorRepositoryArcanistProject
|
||||||
PhabricatorRepositoryPHIDTypeArcanistProject::TYPECONST);
|
PhabricatorRepositoryPHIDTypeArcanistProject::TYPECONST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove.
|
||||||
public function loadRepository() {
|
public function loadRepository() {
|
||||||
if (!$this->getRepositoryID()) {
|
if (!$this->getRepositoryID()) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -51,6 +54,15 @@ final class PhabricatorRepositoryArcanistProject
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getRepository() {
|
||||||
|
return $this->assertAttached($this->repository);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function attachRepository(PhabricatorRepository $repository = null) {
|
||||||
|
$this->repository = $repository;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
Loading…
Reference in a new issue