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

Workboards - add new "initialization" flow

Summary: Currently, we just create a default "backlog" column if / when you visit a workboard for the first time. Post this patch, instead you see a blocking dialog that lets you either create the default backlog column or import columns from another project. In the case of the latter, the user gets another dialog which lets them select any project of which they are a member that also has columns in it. Note that only not hidden columns get imported. Fixes T4431.

Test Plan:
- made a new workboard and got my new dialog. made a default backlog and it worked!
- made a new workboard again and tried the import flow - it also worked.
- verified projects with no columns do not show up in import dialog
- verified project with / without columns still all show up in maniphest project typeahead

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: epriestley, Korvin

Maniphest Tasks: T4431

Differential Revision: https://secure.phabricator.com/D10153
This commit is contained in:
Bob Trahan 2014-08-05 13:40:41 -07:00
parent e68b6deccb
commit 21dca29c5f
5 changed files with 152 additions and 9 deletions

View file

@ -1926,6 +1926,7 @@ phutil_register_library_map(array(
'PhabricatorProjectBoardController' => 'applications/project/controller/PhabricatorProjectBoardController.php', 'PhabricatorProjectBoardController' => 'applications/project/controller/PhabricatorProjectBoardController.php',
'PhabricatorProjectBoardDeleteController' => 'applications/project/controller/PhabricatorProjectBoardDeleteController.php', 'PhabricatorProjectBoardDeleteController' => 'applications/project/controller/PhabricatorProjectBoardDeleteController.php',
'PhabricatorProjectBoardEditController' => 'applications/project/controller/PhabricatorProjectBoardEditController.php', 'PhabricatorProjectBoardEditController' => 'applications/project/controller/PhabricatorProjectBoardEditController.php',
'PhabricatorProjectBoardImportController' => 'applications/project/controller/PhabricatorProjectBoardImportController.php',
'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php', 'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php',
'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php', 'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php',
'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php', 'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php',
@ -2620,6 +2621,7 @@ phutil_register_library_map(array(
'PonderVoteSaveController' => 'applications/ponder/controller/PonderVoteSaveController.php', 'PonderVoteSaveController' => 'applications/ponder/controller/PonderVoteSaveController.php',
'ProjectBoardTaskCard' => 'applications/project/view/ProjectBoardTaskCard.php', 'ProjectBoardTaskCard' => 'applications/project/view/ProjectBoardTaskCard.php',
'ProjectConduitAPIMethod' => 'applications/project/conduit/ProjectConduitAPIMethod.php', 'ProjectConduitAPIMethod' => 'applications/project/conduit/ProjectConduitAPIMethod.php',
'ProjectCreateConduitAPIMethod' => 'applications/project/conduit/ProjectCreateConduitAPIMethod.php',
'ProjectCreateProjectsCapability' => 'applications/project/capability/ProjectCreateProjectsCapability.php', 'ProjectCreateProjectsCapability' => 'applications/project/capability/ProjectCreateProjectsCapability.php',
'ProjectQueryConduitAPIMethod' => 'applications/project/conduit/ProjectQueryConduitAPIMethod.php', 'ProjectQueryConduitAPIMethod' => 'applications/project/conduit/ProjectQueryConduitAPIMethod.php',
'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php', 'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php',
@ -4752,6 +4754,7 @@ phutil_register_library_map(array(
'PhabricatorProjectBoardController' => 'PhabricatorProjectController', 'PhabricatorProjectBoardController' => 'PhabricatorProjectController',
'PhabricatorProjectBoardDeleteController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardDeleteController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBoardEditController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardEditController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBoardImportController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectColumn' => array( 'PhabricatorProjectColumn' => array(
@ -5561,6 +5564,7 @@ phutil_register_library_map(array(
'PonderVoteEditor' => 'PhabricatorEditor', 'PonderVoteEditor' => 'PhabricatorEditor',
'PonderVoteSaveController' => 'PonderController', 'PonderVoteSaveController' => 'PonderController',
'ProjectConduitAPIMethod' => 'ConduitAPIMethod', 'ProjectConduitAPIMethod' => 'ConduitAPIMethod',
'ProjectCreateConduitAPIMethod' => 'ProjectConduitAPIMethod',
'ProjectCreateProjectsCapability' => 'PhabricatorPolicyCapability', 'ProjectCreateProjectsCapability' => 'PhabricatorPolicyCapability',
'ProjectQueryConduitAPIMethod' => 'ProjectConduitAPIMethod', 'ProjectQueryConduitAPIMethod' => 'ProjectConduitAPIMethod',
'ProjectRemarkupRule' => 'PhabricatorObjectRemarkupRule', 'ProjectRemarkupRule' => 'PhabricatorObjectRemarkupRule',

View file

@ -71,6 +71,8 @@ final class PhabricatorProjectApplication extends PhabricatorApplication {
=> 'PhabricatorProjectBoardDeleteController', => 'PhabricatorProjectBoardDeleteController',
'column/(?:(?P<id>\d+)/)?' 'column/(?:(?P<id>\d+)/)?'
=> 'PhabricatorProjectColumnDetailController', => 'PhabricatorProjectColumnDetailController',
'import/'
=> 'PhabricatorProjectBoardImportController',
'reorder/' 'reorder/'
=> 'PhabricatorProjectBoardReorderController', => 'PhabricatorProjectBoardReorderController',
), ),

View file

@ -0,0 +1,85 @@
<?php
final class PhabricatorProjectBoardImportController
extends PhabricatorProjectBoardController {
private $projectID;
public function willProcessRequest(array $data) {
$this->projectID = $data['projectID'];
}
public function processRequest() {
$request = $this->getRequest();
$viewer = $request->getUser();
$project = id(new PhabricatorProjectQuery())
->setViewer($viewer)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->withIDs(array($this->projectID))
->executeOne();
if (!$project) {
return new Aphront404Response();
}
$this->setProject($project);
$columns = id(new PhabricatorProjectColumnQuery())
->setViewer($viewer)
->withProjectPHIDs(array($project->getPHID()))
->execute();
if ($columns) {
return new Aphront400Response();
}
$project_id = $project->getID();
$board_uri = $this->getApplicationURI("board/{$project_id}/");
if ($request->isFormPost()) {
$import_phid = $request->getArr('importProjectPHID');
$import_phid = reset($import_phid);
$import_columns = id(new PhabricatorProjectColumnQuery())
->setViewer($viewer)
->withProjectPHIDs(array($import_phid))
->execute();
if (!$import_columns) {
return new Aphront400Response();
}
$table = id(new PhabricatorProjectColumn())
->openTransaction();
foreach ($import_columns as $import_column) {
if ($import_column->isHidden()) {
continue;
}
$new_column = PhabricatorProjectColumn::initializeNewColumn($viewer)
->setSequence($import_column->getSequence())
->setProjectPHID($project->getPHID())
->setName($import_column->getName())
->save();
}
$table->saveTransaction();
return id(new AphrontRedirectResponse())->setURI($board_uri);
}
$proj_selector = id(new AphrontFormTokenizerControl())
->setName('importProjectPHID')
->setUser($viewer)
->setDatasource(id(new PhabricatorProjectDatasource())
->setParameters(array('mustHaveColumns' => true))
->setLimit(1));
return $this->newDialog()
->setTitle(pht('Import Columns'))
->setWidth(AphrontDialogView::WIDTH_FORM)
->appendParagraph(pht('Choose a project to import columns from:'))
->appendChild($proj_selector)
->addCancelButton($board_uri)
->addSubmitButton(pht('Import'));
}
}

View file

@ -54,16 +54,27 @@ final class PhabricatorProjectBoardViewController
$columns = $column_query->execute(); $columns = $column_query->execute();
$columns = mpull($columns, null, 'getSequence'); $columns = mpull($columns, null, 'getSequence');
// If there's no default column, create one now.
if (empty($columns[0])) { if (empty($columns[0])) {
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); switch ($request->getStr('initialize-type')) {
$column = PhabricatorProjectColumn::initializeNewColumn($viewer) case 'backlog-only':
->setSequence(0) $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
->setProjectPHID($project->getPHID()) $column = PhabricatorProjectColumn::initializeNewColumn($viewer)
->save(); ->setSequence(0)
$column->attachProject($project); ->setProjectPHID($project->getPHID())
$columns[0] = $column; ->save();
unset($unguarded); $column->attachProject($project);
$columns[0] = $column;
unset($unguarded);
break;
case 'import':
return id(new AphrontRedirectResponse())
->setURI(
$this->getApplicationURI('board/'.$project->getID().'/import/'));
break;
default:
return $this->initializeWorkboardDialog($project);
break;
}
} }
ksort($columns); ksort($columns);
@ -406,5 +417,31 @@ final class PhabricatorProjectBoardViewController
return $manage_button; return $manage_button;
} }
private function initializeWorkboardDialog(PhabricatorProject $project) {
$instructions = pht('This workboard has not been setup yet.');
$new_selector = id(new AphrontFormRadioButtonControl())
->setName('initialize-type')
->setValue('backlog-only')
->addButton(
'backlog-only',
pht('New Empty Board'),
pht('Create a new board with just a backlog column.'))
->addButton(
'import',
pht('Import Columns'),
pht('Import board columns from another project.'));
$dialog = id(new AphrontDialogView())
->setUser($this->getRequest()->getUser())
->setTitle(pht('New Workboard'))
->addSubmitButton('Continue')
->addCancelButton($this->getApplicationURI('view/'.$project->getID().'/'))
->appendParagraph($instructions)
->appendChild($new_selector);
return id(new AphrontDialogResponse())
->setDialog($dialog);
}
} }

View file

@ -29,9 +29,24 @@ final class PhabricatorProjectDatasource
->needSlugs(true) ->needSlugs(true)
->withDatasourceQuery($raw_query) ->withDatasourceQuery($raw_query)
->execute(); ->execute();
$projs = mpull($projs, null, 'getPHID');
$must_have_cols = $this->getParameter('mustHaveColumns', false);
if ($must_have_cols) {
$columns = id(new PhabricatorProjectColumnQuery())
->setViewer($viewer)
->withProjectPHIDs(array_keys($projs))
->execute();
$has_cols = mgroup($columns, 'getProjectPHID');
} else {
$has_cols = array_fill_keys(array_keys($projs), true);
}
$results = array(); $results = array();
foreach ($projs as $proj) { foreach ($projs as $proj) {
if (!isset($has_cols[$proj->getPHID()])) {
continue;
}
$closed = null; $closed = null;
if ($proj->isArchived()) { if ($proj->isArchived()) {
$closed = pht('Archived'); $closed = pht('Archived');