@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+152 -9
+4
src/__phutil_library_map__.php
··· 1926 1926 'PhabricatorProjectBoardController' => 'applications/project/controller/PhabricatorProjectBoardController.php', 1927 1927 'PhabricatorProjectBoardDeleteController' => 'applications/project/controller/PhabricatorProjectBoardDeleteController.php', 1928 1928 'PhabricatorProjectBoardEditController' => 'applications/project/controller/PhabricatorProjectBoardEditController.php', 1929 + 'PhabricatorProjectBoardImportController' => 'applications/project/controller/PhabricatorProjectBoardImportController.php', 1929 1930 'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php', 1930 1931 'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php', 1931 1932 'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php', ··· 2620 2621 'PonderVoteSaveController' => 'applications/ponder/controller/PonderVoteSaveController.php', 2621 2622 'ProjectBoardTaskCard' => 'applications/project/view/ProjectBoardTaskCard.php', 2622 2623 'ProjectConduitAPIMethod' => 'applications/project/conduit/ProjectConduitAPIMethod.php', 2624 + 'ProjectCreateConduitAPIMethod' => 'applications/project/conduit/ProjectCreateConduitAPIMethod.php', 2623 2625 'ProjectCreateProjectsCapability' => 'applications/project/capability/ProjectCreateProjectsCapability.php', 2624 2626 'ProjectQueryConduitAPIMethod' => 'applications/project/conduit/ProjectQueryConduitAPIMethod.php', 2625 2627 'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php', ··· 4752 4754 'PhabricatorProjectBoardController' => 'PhabricatorProjectController', 4753 4755 'PhabricatorProjectBoardDeleteController' => 'PhabricatorProjectBoardController', 4754 4756 'PhabricatorProjectBoardEditController' => 'PhabricatorProjectBoardController', 4757 + 'PhabricatorProjectBoardImportController' => 'PhabricatorProjectBoardController', 4755 4758 'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController', 4756 4759 'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController', 4757 4760 'PhabricatorProjectColumn' => array( ··· 5561 5564 'PonderVoteEditor' => 'PhabricatorEditor', 5562 5565 'PonderVoteSaveController' => 'PonderController', 5563 5566 'ProjectConduitAPIMethod' => 'ConduitAPIMethod', 5567 + 'ProjectCreateConduitAPIMethod' => 'ProjectConduitAPIMethod', 5564 5568 'ProjectCreateProjectsCapability' => 'PhabricatorPolicyCapability', 5565 5569 'ProjectQueryConduitAPIMethod' => 'ProjectConduitAPIMethod', 5566 5570 'ProjectRemarkupRule' => 'PhabricatorObjectRemarkupRule',
+2
src/applications/project/application/PhabricatorProjectApplication.php
··· 71 71 => 'PhabricatorProjectBoardDeleteController', 72 72 'column/(?:(?P<id>\d+)/)?' 73 73 => 'PhabricatorProjectColumnDetailController', 74 + 'import/' 75 + => 'PhabricatorProjectBoardImportController', 74 76 'reorder/' 75 77 => 'PhabricatorProjectBoardReorderController', 76 78 ),
+85
src/applications/project/controller/PhabricatorProjectBoardImportController.php
··· 1 + <?php 2 + 3 + final class PhabricatorProjectBoardImportController 4 + extends PhabricatorProjectBoardController { 5 + 6 + private $projectID; 7 + 8 + public function willProcessRequest(array $data) { 9 + $this->projectID = $data['projectID']; 10 + } 11 + 12 + public function processRequest() { 13 + $request = $this->getRequest(); 14 + $viewer = $request->getUser(); 15 + 16 + $project = id(new PhabricatorProjectQuery()) 17 + ->setViewer($viewer) 18 + ->requireCapabilities( 19 + array( 20 + PhabricatorPolicyCapability::CAN_VIEW, 21 + PhabricatorPolicyCapability::CAN_EDIT, 22 + )) 23 + ->withIDs(array($this->projectID)) 24 + ->executeOne(); 25 + if (!$project) { 26 + return new Aphront404Response(); 27 + } 28 + $this->setProject($project); 29 + 30 + $columns = id(new PhabricatorProjectColumnQuery()) 31 + ->setViewer($viewer) 32 + ->withProjectPHIDs(array($project->getPHID())) 33 + ->execute(); 34 + if ($columns) { 35 + return new Aphront400Response(); 36 + } 37 + 38 + $project_id = $project->getID(); 39 + $board_uri = $this->getApplicationURI("board/{$project_id}/"); 40 + 41 + if ($request->isFormPost()) { 42 + $import_phid = $request->getArr('importProjectPHID'); 43 + $import_phid = reset($import_phid); 44 + 45 + $import_columns = id(new PhabricatorProjectColumnQuery()) 46 + ->setViewer($viewer) 47 + ->withProjectPHIDs(array($import_phid)) 48 + ->execute(); 49 + if (!$import_columns) { 50 + return new Aphront400Response(); 51 + } 52 + 53 + $table = id(new PhabricatorProjectColumn()) 54 + ->openTransaction(); 55 + foreach ($import_columns as $import_column) { 56 + if ($import_column->isHidden()) { 57 + continue; 58 + } 59 + $new_column = PhabricatorProjectColumn::initializeNewColumn($viewer) 60 + ->setSequence($import_column->getSequence()) 61 + ->setProjectPHID($project->getPHID()) 62 + ->setName($import_column->getName()) 63 + ->save(); 64 + } 65 + $table->saveTransaction(); 66 + 67 + return id(new AphrontRedirectResponse())->setURI($board_uri); 68 + } 69 + 70 + $proj_selector = id(new AphrontFormTokenizerControl()) 71 + ->setName('importProjectPHID') 72 + ->setUser($viewer) 73 + ->setDatasource(id(new PhabricatorProjectDatasource()) 74 + ->setParameters(array('mustHaveColumns' => true)) 75 + ->setLimit(1)); 76 + return $this->newDialog() 77 + ->setTitle(pht('Import Columns')) 78 + ->setWidth(AphrontDialogView::WIDTH_FORM) 79 + ->appendParagraph(pht('Choose a project to import columns from:')) 80 + ->appendChild($proj_selector) 81 + ->addCancelButton($board_uri) 82 + ->addSubmitButton(pht('Import')); 83 + } 84 + 85 + }
+46 -9
src/applications/project/controller/PhabricatorProjectBoardViewController.php
··· 54 54 $columns = $column_query->execute(); 55 55 $columns = mpull($columns, null, 'getSequence'); 56 56 57 - // If there's no default column, create one now. 58 57 if (empty($columns[0])) { 59 - $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); 60 - $column = PhabricatorProjectColumn::initializeNewColumn($viewer) 61 - ->setSequence(0) 62 - ->setProjectPHID($project->getPHID()) 63 - ->save(); 64 - $column->attachProject($project); 65 - $columns[0] = $column; 66 - unset($unguarded); 58 + switch ($request->getStr('initialize-type')) { 59 + case 'backlog-only': 60 + $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); 61 + $column = PhabricatorProjectColumn::initializeNewColumn($viewer) 62 + ->setSequence(0) 63 + ->setProjectPHID($project->getPHID()) 64 + ->save(); 65 + $column->attachProject($project); 66 + $columns[0] = $column; 67 + unset($unguarded); 68 + break; 69 + case 'import': 70 + return id(new AphrontRedirectResponse()) 71 + ->setURI( 72 + $this->getApplicationURI('board/'.$project->getID().'/import/')); 73 + break; 74 + default: 75 + return $this->initializeWorkboardDialog($project); 76 + break; 77 + } 67 78 } 68 79 69 80 ksort($columns); ··· 406 417 return $manage_button; 407 418 } 408 419 420 + private function initializeWorkboardDialog(PhabricatorProject $project) { 421 + 422 + $instructions = pht('This workboard has not been setup yet.'); 423 + $new_selector = id(new AphrontFormRadioButtonControl()) 424 + ->setName('initialize-type') 425 + ->setValue('backlog-only') 426 + ->addButton( 427 + 'backlog-only', 428 + pht('New Empty Board'), 429 + pht('Create a new board with just a backlog column.')) 430 + ->addButton( 431 + 'import', 432 + pht('Import Columns'), 433 + pht('Import board columns from another project.')); 434 + 435 + $dialog = id(new AphrontDialogView()) 436 + ->setUser($this->getRequest()->getUser()) 437 + ->setTitle(pht('New Workboard')) 438 + ->addSubmitButton('Continue') 439 + ->addCancelButton($this->getApplicationURI('view/'.$project->getID().'/')) 440 + ->appendParagraph($instructions) 441 + ->appendChild($new_selector); 442 + 443 + return id(new AphrontDialogResponse()) 444 + ->setDialog($dialog); 445 + } 409 446 410 447 }
+15
src/applications/project/typeahead/PhabricatorProjectDatasource.php
··· 29 29 ->needSlugs(true) 30 30 ->withDatasourceQuery($raw_query) 31 31 ->execute(); 32 + $projs = mpull($projs, null, 'getPHID'); 33 + 34 + $must_have_cols = $this->getParameter('mustHaveColumns', false); 35 + if ($must_have_cols) { 36 + $columns = id(new PhabricatorProjectColumnQuery()) 37 + ->setViewer($viewer) 38 + ->withProjectPHIDs(array_keys($projs)) 39 + ->execute(); 40 + $has_cols = mgroup($columns, 'getProjectPHID'); 41 + } else { 42 + $has_cols = array_fill_keys(array_keys($projs), true); 43 + } 32 44 33 45 $results = array(); 34 46 foreach ($projs as $proj) { 47 + if (!isset($has_cols[$proj->getPHID()])) { 48 + continue; 49 + } 35 50 $closed = null; 36 51 if ($proj->isArchived()) { 37 52 $closed = pht('Archived');