diff --git a/resources/sql/autopatches/20140314.projectcolumn.1.statuscol.sql b/resources/sql/autopatches/20140314.projectcolumn.1.statuscol.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20140314.projectcolumn.1.statuscol.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_project.project_column + ADD COLUMN status INT UNSIGNED NOT NULL AFTER name; diff --git a/resources/sql/autopatches/20140314.projectcolumn.2.statuskey.sql b/resources/sql/autopatches/20140314.projectcolumn.2.statuskey.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20140314.projectcolumn.2.statuskey.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_project.project_column + ADD KEY `key_status` (`projectPHID`,`status`,`sequence`); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1843,6 +1843,7 @@ 'PhabricatorProject' => 'applications/project/storage/PhabricatorProject.php', 'PhabricatorProjectArchiveController' => 'applications/project/controller/PhabricatorProjectArchiveController.php', 'PhabricatorProjectBoardController' => 'applications/project/controller/PhabricatorProjectBoardController.php', + 'PhabricatorProjectBoardDeleteController' => 'applications/project/controller/PhabricatorProjectBoardDeleteController.php', 'PhabricatorProjectBoardEditController' => 'applications/project/controller/PhabricatorProjectBoardEditController.php', 'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php', 'PhabricatorProjectColumnQuery' => 'applications/project/query/PhabricatorProjectColumnQuery.php', @@ -4609,6 +4610,7 @@ ), 'PhabricatorProjectArchiveController' => 'PhabricatorProjectController', 'PhabricatorProjectBoardController' => 'PhabricatorProjectController', + 'PhabricatorProjectBoardDeleteController' => 'PhabricatorProjectController', 'PhabricatorProjectBoardEditController' => 'PhabricatorProjectController', 'PhabricatorProjectColumn' => array( diff --git a/src/applications/project/application/PhabricatorApplicationProject.php b/src/applications/project/application/PhabricatorApplicationProject.php --- a/src/applications/project/application/PhabricatorApplicationProject.php +++ b/src/applications/project/application/PhabricatorApplicationProject.php @@ -53,6 +53,8 @@ 'move/(?P[1-9]\d*)/' => 'PhabricatorProjectMoveController', 'board/(?P[1-9]\d*)/edit/(?:(?P\d+)/)?' => 'PhabricatorProjectBoardEditController', + 'board/(?P[1-9]\d*)/delete/(?:(?P\d+)/)?' + => 'PhabricatorProjectBoardDeleteController', 'update/(?P[1-9]\d*)/(?P[^/]+)/' => 'PhabricatorProjectUpdateController', 'history/(?P[1-9]\d*)/' => 'PhabricatorProjectHistoryController', diff --git a/src/applications/project/controller/PhabricatorProjectBoardController.php b/src/applications/project/controller/PhabricatorProjectBoardController.php --- a/src/applications/project/controller/PhabricatorProjectBoardController.php +++ b/src/applications/project/controller/PhabricatorProjectBoardController.php @@ -30,6 +30,7 @@ $columns = id(new PhabricatorProjectColumnQuery()) ->setViewer($viewer) ->withProjectPHIDs(array($project->getPHID())) + ->withStatuses(array(PhabricatorProjectColumn::STATUS_ACTIVE)) ->execute(); $columns = mpull($columns, null, 'getSequence'); @@ -168,6 +169,13 @@ ->setHref($this->getApplicationURI('board/'.$this->id.'/edit/')) ->setIcon('create') ->setDisabled(!$can_edit) + ->setWorkflow(!$can_edit)) + ->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Delete Column')) + ->setHref($this->getApplicationURI('board/'.$this->id.'/delete/')) + ->setIcon('delete') + ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); $plist = id(new PHUIPropertyListView()); diff --git a/src/applications/project/controller/PhabricatorProjectBoardDeleteController.php b/src/applications/project/controller/PhabricatorProjectBoardDeleteController.php new file mode 100644 --- /dev/null +++ b/src/applications/project/controller/PhabricatorProjectBoardDeleteController.php @@ -0,0 +1,116 @@ +projectID = $data['projectID']; + $this->id = idx($data, 'id'); + } + + 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(); + } + + $columns = id(new PhabricatorProjectColumnQuery()) + ->setViewer($viewer) + ->withProjectPHIDs(array($project->getPHID())) + ->withStatuses(array(PhabricatorProjectColumn::STATUS_ACTIVE)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT)) + ->execute(); + + if (!$columns) { + return new Aphront404Response(); + } + + $columns = mpull($columns, null, 'getSequence'); + $columns = mfilter($columns, 'isDefaultColumn', true); + ksort($columns); + $options = mpull($columns, 'getName', 'getPHID'); + + $view_uri = $this->getApplicationURI('/board/'.$this->projectID.'/'); + $error_view = null; + if ($request->isFormPost()) { + $columns = mpull($columns, null, 'getPHID'); + $column_phid = $request->getStr('columnPHID'); + $column = $columns[$column_phid]; + + $has_task_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( + $column_phid, + PhabricatorEdgeConfig::TYPE_COLUMN_HAS_OBJECT); + + if ($has_task_phids) { + $error_view = id(new AphrontErrorView()) + ->setTitle(pht('Column has Tasks!')) + ->setErrors(array(pht('A column can not be deleted if it has tasks '. + 'in it. Please remove the tasks and try '. + 'again.'))); + } else { + $column->setStatus(PhabricatorProjectColumn::STATUS_DELETED); + $column->save(); + + return id(new AphrontRedirectResponse())->setURI($view_uri); + } + } + + $form = id(new AphrontFormView()) + ->setUser($viewer) + ->appendChild($error_view) + ->appendChild(id(new AphrontFormSelectControl()) + ->setName('columnPHID') + ->setValue(head_key($options)) + ->setOptions($options) + ->setLabel(pht('Column'))); + + $title = pht('Delete Column'); + $submit = $title; + + $form->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue($submit) + ->addCancelButton($view_uri)); + + $crumbs = $this->buildApplicationCrumbs(); + $crumbs->addTextCrumb( + $project->getName(), + $this->getApplicationURI('view/'.$project->getID().'/')); + $crumbs->addTextCrumb( + pht('Board'), + $this->getApplicationURI('board/'.$project->getID().'/')); + $crumbs->addTextCrumb($title); + + $form_box = id(new PHUIObjectBoxView()) + ->setHeaderText($title) + ->setForm($form); + + return $this->buildApplicationPage( + array( + $crumbs, + $form_box, + ), + array( + 'title' => $title, + 'device' => true, + )); + } +} diff --git a/src/applications/project/phid/PhabricatorProjectPHIDTypeColumn.php b/src/applications/project/phid/PhabricatorProjectPHIDTypeColumn.php --- a/src/applications/project/phid/PhabricatorProjectPHIDTypeColumn.php +++ b/src/applications/project/phid/PhabricatorProjectPHIDTypeColumn.php @@ -34,6 +34,8 @@ $handle->setName($column->getDisplayName()); $handle->setURI('/project/board/'.$column->getProject()->getID().'/'); + $handle->setDisabled( + $column->getStatus() == PhabricatorProjectColumn::STATUS_DELETED); } } diff --git a/src/applications/project/query/PhabricatorProjectColumnQuery.php b/src/applications/project/query/PhabricatorProjectColumnQuery.php --- a/src/applications/project/query/PhabricatorProjectColumnQuery.php +++ b/src/applications/project/query/PhabricatorProjectColumnQuery.php @@ -6,6 +6,7 @@ private $ids; private $phids; private $projectPHIDs; + private $statuses; public function withIDs(array $ids) { $this->ids = $ids; @@ -22,6 +23,11 @@ return $this; } + public function withStatuses(array $status) { + $this->statuses = $status; + return $this; + } + protected function loadPage() { $table = new PhabricatorProjectColumn(); $conn_r = $table->establishConnection('r'); @@ -87,6 +93,13 @@ $this->projectPHIDs); } + if ($this->statuses !== null) { + $where[] = qsprintf( + $conn_r, + 'status IN (%Ld)', + $this->statuses); + } + $where[] = $this->buildPagingClause($conn_r); return $this->formatWhereClause($where); diff --git a/src/applications/project/storage/PhabricatorProjectColumn.php b/src/applications/project/storage/PhabricatorProjectColumn.php --- a/src/applications/project/storage/PhabricatorProjectColumn.php +++ b/src/applications/project/storage/PhabricatorProjectColumn.php @@ -4,7 +4,11 @@ extends PhabricatorProjectDAO implements PhabricatorPolicyInterface { + const STATUS_ACTIVE = 0; + const STATUS_DELETED = 1; + protected $name; + protected $status; protected $projectPHID; protected $sequence; @@ -12,7 +16,8 @@ public static function initializeNewColumn(PhabricatorUser $user) { return id(new PhabricatorProjectColumn()) - ->setName(''); + ->setName('') + ->setStatus(self::STATUS_ACTIVE); } public function getConfiguration() {