mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 16:22:43 +01:00
Workboards - add column detail page
Summary: followup to D8544. This ends up creating an editor + transactions to get the job done. Test Plan: made a column - saw a nice created transaction. edited the name - saw a nice name edit. deleted the column - saw a deleted transaction, updated "deleted" ui, and hte action change to activate. "Activated" the column and saw a transaction and updated UI. Tried to delete a column with tasks in it and got an error. Reviewers: epriestley Reviewed By: epriestley Subscribers: epriestley, Korvin Differential Revision: https://secure.phabricator.com/D8620
This commit is contained in:
parent
543a313387
commit
655ac9927f
12 changed files with 698 additions and 295 deletions
21
resources/sql/autopatches/20140326.project.1.colxaction.sql
Normal file
21
resources/sql/autopatches/20140326.project.1.colxaction.sql
Normal file
|
@ -0,0 +1,21 @@
|
|||
CREATE TABLE {$NAMESPACE}_project.project_columntransaction (
|
||||
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
phid VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
authorPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
objectPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
viewPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
editPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
commentPHID VARCHAR(64) COLLATE utf8_bin,
|
||||
commentVersion INT UNSIGNED NOT NULL,
|
||||
transactionType VARCHAR(32) NOT NULL COLLATE utf8_bin,
|
||||
oldValue LONGTEXT NOT NULL COLLATE utf8_bin,
|
||||
newValue LONGTEXT NOT NULL COLLATE utf8_bin,
|
||||
contentSource LONGTEXT NOT NULL COLLATE utf8_bin,
|
||||
metadata LONGTEXT NOT NULL COLLATE utf8_bin,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL,
|
||||
|
||||
UNIQUE KEY `key_phid` (phid),
|
||||
KEY `key_object` (objectPHID)
|
||||
|
||||
) ENGINE=InnoDB, COLLATE utf8_general_ci;
|
|
@ -1862,8 +1862,13 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProjectBoardController' => 'applications/project/controller/PhabricatorProjectBoardController.php',
|
||||
'PhabricatorProjectBoardDeleteController' => 'applications/project/controller/PhabricatorProjectBoardDeleteController.php',
|
||||
'PhabricatorProjectBoardEditController' => 'applications/project/controller/PhabricatorProjectBoardEditController.php',
|
||||
'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php',
|
||||
'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php',
|
||||
'PhabricatorProjectColumnDetailController' => 'applications/project/controller/PhabricatorProjectColumnDetailController.php',
|
||||
'PhabricatorProjectColumnQuery' => 'applications/project/query/PhabricatorProjectColumnQuery.php',
|
||||
'PhabricatorProjectColumnTransaction' => 'applications/project/storage/PhabricatorProjectColumnTransaction.php',
|
||||
'PhabricatorProjectColumnTransactionEditor' => 'applications/project/editor/PhabricatorProjectColumnTransactionEditor.php',
|
||||
'PhabricatorProjectColumnTransactionQuery' => 'applications/project/query/PhabricatorProjectColumnTransactionQuery.php',
|
||||
'PhabricatorProjectConfigOptions' => 'applications/project/config/PhabricatorProjectConfigOptions.php',
|
||||
'PhabricatorProjectConfiguredCustomField' => 'applications/project/customfield/PhabricatorProjectConfiguredCustomField.php',
|
||||
'PhabricatorProjectConstants' => 'applications/project/constants/PhabricatorProjectConstants.php',
|
||||
|
@ -4668,14 +4673,19 @@ phutil_register_library_map(array(
|
|||
),
|
||||
'PhabricatorProjectArchiveController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectBoardController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectBoardDeleteController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectBoardEditController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectBoardDeleteController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectBoardEditController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectColumn' =>
|
||||
array(
|
||||
0 => 'PhabricatorProjectDAO',
|
||||
1 => 'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhabricatorProjectColumnDetailController' => 'PhabricatorProjectBoardController',
|
||||
'PhabricatorProjectColumnQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorProjectColumnTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'PhabricatorProjectColumnTransactionEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorProjectColumnTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorProjectConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
'PhabricatorProjectConfiguredCustomField' =>
|
||||
array(
|
||||
|
|
|
@ -51,12 +51,14 @@ final class PhabricatorApplicationProject extends PhabricatorApplication {
|
|||
'picture/(?P<id>[1-9]\d*)/' =>
|
||||
'PhabricatorProjectEditPictureController',
|
||||
'create/' => 'PhabricatorProjectCreateController',
|
||||
'board/(?P<id>[1-9]\d*)/' => 'PhabricatorProjectBoardController',
|
||||
'board/(?P<id>[1-9]\d*)/' => 'PhabricatorProjectBoardViewController',
|
||||
'move/(?P<id>[1-9]\d*)/' => 'PhabricatorProjectMoveController',
|
||||
'board/(?P<projectID>[1-9]\d*)/edit/(?:(?P<id>\d+)/)?'
|
||||
=> 'PhabricatorProjectBoardEditController',
|
||||
'board/(?P<projectID>[1-9]\d*)/delete/(?:(?P<id>\d+)/)?'
|
||||
=> 'PhabricatorProjectBoardDeleteController',
|
||||
'board/(?P<projectID>[1-9]\d*)/column/(?:(?P<id>\d+)/)?'
|
||||
=> 'PhabricatorProjectColumnDetailController',
|
||||
'update/(?P<id>[1-9]\d*)/(?P<action>[^/]+)/'
|
||||
=> 'PhabricatorProjectUpdateController',
|
||||
'history/(?P<id>[1-9]\d*)/' => 'PhabricatorProjectHistoryController',
|
||||
|
|
|
@ -1,219 +1,24 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectBoardController
|
||||
abstract class PhabricatorProjectBoardController
|
||||
extends PhabricatorProjectController {
|
||||
|
||||
private $id;
|
||||
private $handles;
|
||||
private $project;
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
protected function setProject(PhabricatorProject $project) {
|
||||
$this->project = $project;
|
||||
return $this;
|
||||
}
|
||||
protected function getProject() {
|
||||
return $this->project;
|
||||
}
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$project = id(new PhabricatorProjectQuery())
|
||||
->setViewer($viewer)
|
||||
->needImages(true)
|
||||
->withIDs(array($this->id))
|
||||
->executeOne();
|
||||
if (!$project) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$columns = id(new PhabricatorProjectColumnQuery())
|
||||
->setViewer($viewer)
|
||||
->withProjectPHIDs(array($project->getPHID()))
|
||||
->withStatuses(array(PhabricatorProjectColumn::STATUS_ACTIVE))
|
||||
->execute();
|
||||
|
||||
$columns = mpull($columns, null, 'getSequence');
|
||||
|
||||
// If there's no default column, create one now.
|
||||
if (empty($columns[0])) {
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
$column = PhabricatorProjectColumn::initializeNewColumn($viewer)
|
||||
->setSequence(0)
|
||||
->setProjectPHID($project->getPHID())
|
||||
->save();
|
||||
$column->attachProject($project);
|
||||
$columns[0] = $column;
|
||||
unset($unguarded);
|
||||
}
|
||||
|
||||
ksort($columns);
|
||||
|
||||
$tasks = id(new ManiphestTaskQuery())
|
||||
->setViewer($viewer)
|
||||
->withAllProjects(array($project->getPHID()))
|
||||
->withStatuses(ManiphestTaskStatus::getOpenStatusConstants())
|
||||
->setOrderBy(ManiphestTaskQuery::ORDER_PRIORITY)
|
||||
->execute();
|
||||
$tasks = mpull($tasks, null, 'getPHID');
|
||||
$task_phids = array_keys($tasks);
|
||||
|
||||
if ($task_phids) {
|
||||
$edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_COLUMN;
|
||||
$edge_query = id(new PhabricatorEdgeQuery())
|
||||
->withSourcePHIDs($task_phids)
|
||||
->withEdgeTypes(array($edge_type))
|
||||
->withDestinationPHIDs(mpull($columns, 'getPHID'));
|
||||
$edge_query->execute();
|
||||
}
|
||||
|
||||
$task_map = array();
|
||||
$default_phid = $columns[0]->getPHID();
|
||||
foreach ($tasks as $task) {
|
||||
$task_phid = $task->getPHID();
|
||||
$column_phids = $edge_query->getDestinationPHIDs(array($task_phid));
|
||||
|
||||
$column_phid = head($column_phids);
|
||||
$column_phid = nonempty($column_phid, $default_phid);
|
||||
|
||||
$task_map[$column_phid][] = $task_phid;
|
||||
}
|
||||
|
||||
$task_can_edit_map = id(new PhabricatorPolicyFilter())
|
||||
->setViewer($viewer)
|
||||
->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT))
|
||||
->apply($tasks);
|
||||
|
||||
$board_id = celerity_generate_unique_node_id();
|
||||
|
||||
$board = id(new PHUIWorkboardView())
|
||||
->setUser($viewer)
|
||||
->setFluidishLayout(true)
|
||||
->setID($board_id);
|
||||
|
||||
$this->initBehavior(
|
||||
'project-boards',
|
||||
array(
|
||||
'boardID' => $board_id,
|
||||
'projectPHID' => $project->getPHID(),
|
||||
'moveURI' => $this->getApplicationURI('move/'.$project->getID().'/'),
|
||||
'createURI' => '/maniphest/task/create/',
|
||||
));
|
||||
|
||||
$this->handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks);
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$panel = id(new PHUIWorkpanelView())
|
||||
->setHeader($column->getDisplayName())
|
||||
->setHeaderColor($column->getHeaderColor());
|
||||
if (!$column->isDefaultColumn()) {
|
||||
$panel->setEditURI('edit/'.$column->getID().'/');
|
||||
}
|
||||
$panel->setHeaderAction(id(new PHUIIconView())
|
||||
->setSpriteSheet(PHUIIconView::SPRITE_ACTIONS)
|
||||
->setSpriteIcon('new-grey')
|
||||
->setHref('/maniphest/task/create/')
|
||||
->addSigil('column-add-task')
|
||||
->setMetadata(
|
||||
array('columnPHID' => $column->getPHID())));
|
||||
|
||||
$cards = id(new PHUIObjectItemListView())
|
||||
->setUser($viewer)
|
||||
->setCards(true)
|
||||
->setFlush(true)
|
||||
->setAllowEmptyList(true)
|
||||
->addSigil('project-column')
|
||||
->setMetadata(
|
||||
array(
|
||||
'columnPHID' => $column->getPHID(),
|
||||
));
|
||||
$task_phids = idx($task_map, $column->getPHID(), array());
|
||||
foreach (array_select_keys($tasks, $task_phids) as $task) {
|
||||
$owner = null;
|
||||
if ($task->getOwnerPHID()) {
|
||||
$owner = $this->handles[$task->getOwnerPHID()];
|
||||
}
|
||||
$can_edit = idx($task_can_edit_map, $task->getPHID(), false);
|
||||
$cards->addItem(id(new ProjectBoardTaskCard())
|
||||
->setViewer($viewer)
|
||||
->setTask($task)
|
||||
->setOwner($owner)
|
||||
->setCanEdit($can_edit)
|
||||
->getItem());
|
||||
}
|
||||
$panel->setCards($cards);
|
||||
|
||||
if (!$task_phids) {
|
||||
$cards->addClass('project-column-empty');
|
||||
}
|
||||
|
||||
$board->addPanel($panel);
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
protected function buildApplicationCrumbs() {
|
||||
$project = $this->getProject();
|
||||
$crumbs = parent::buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(
|
||||
$project->getName(),
|
||||
$this->getApplicationURI('view/'.$project->getID().'/'));
|
||||
$crumbs->addTextCrumb(pht('Board'));
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$project,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$actions = id(new PhabricatorActionListView())
|
||||
->setUser($viewer)
|
||||
->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Add Column'))
|
||||
->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());
|
||||
|
||||
// TODO: Need this to get actions to render.
|
||||
$plist->addProperty(
|
||||
pht('Project Boards'),
|
||||
phutil_tag(
|
||||
'em',
|
||||
array(),
|
||||
pht(
|
||||
'This feature is beta, but should mostly work.')));
|
||||
$plist->setActionList($actions);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($project->getName())
|
||||
->setUser($viewer)
|
||||
->setImage($project->getProfileImageURI())
|
||||
->setPolicyObject($project);
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->addPropertyList($plist);
|
||||
|
||||
$board_box = id(new PHUIBoxView())
|
||||
->appendChild($board)
|
||||
->addMargin(PHUI::MARGIN_LARGE);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$box,
|
||||
$board_box,
|
||||
),
|
||||
array(
|
||||
'title' => pht('%s Board', $project->getName()),
|
||||
'device' => true,
|
||||
));
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectBoardDeleteController
|
||||
extends PhabricatorProjectController {
|
||||
extends PhabricatorProjectBoardController {
|
||||
|
||||
private $id;
|
||||
private $projectID;
|
||||
|
@ -14,7 +14,6 @@ final class PhabricatorProjectBoardDeleteController
|
|||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$project = id(new PhabricatorProjectQuery())
|
||||
->setViewer($viewer)
|
||||
->requireCapabilities(
|
||||
|
@ -28,89 +27,89 @@ final class PhabricatorProjectBoardDeleteController
|
|||
if (!$project) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$this->setProject($project);
|
||||
|
||||
$columns = id(new PhabricatorProjectColumnQuery())
|
||||
$column = id(new PhabricatorProjectColumnQuery())
|
||||
->setViewer($viewer)
|
||||
->withProjectPHIDs(array($project->getPHID()))
|
||||
->withStatuses(array(PhabricatorProjectColumn::STATUS_ACTIVE))
|
||||
->withIDs(array($this->id))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT))
|
||||
->execute();
|
||||
|
||||
if (!$columns) {
|
||||
->executeOne();
|
||||
if (!$column) {
|
||||
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];
|
||||
$column_phid = $column->getPHID();
|
||||
$has_task_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||
$column_phid,
|
||||
PhabricatorEdgeConfig::TYPE_COLUMN_HAS_OBJECT);
|
||||
|
||||
$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.')));
|
||||
if ($has_task_phids) {
|
||||
$error_view = id(new AphrontErrorView())
|
||||
->setTitle(pht('Column has Tasks!'));
|
||||
if ($column->isDeleted()) {
|
||||
$error_view->setErrors(array(pht(
|
||||
'A column can not be activated 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);
|
||||
$error_view->setErrors(array(pht(
|
||||
'A column can not be deleted if it has tasks '.
|
||||
'in it. Please remove the tasks and try again.')));
|
||||
}
|
||||
}
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendChild($error_view)
|
||||
->appendChild(id(new AphrontFormSelectControl())
|
||||
->setName('columnPHID')
|
||||
->setValue(head_key($options))
|
||||
->setOptions($options)
|
||||
->setLabel(pht('Column')));
|
||||
$view_uri = $this->getApplicationURI(
|
||||
'/board/'.$this->projectID.'/column/'.$this->id.'/');
|
||||
|
||||
$title = pht('Delete Column');
|
||||
if ($request->isFormPost() && !$error_view) {
|
||||
if ($column->isDeleted()) {
|
||||
$new_status = PhabricatorProjectColumn::STATUS_ACTIVE;
|
||||
} else {
|
||||
$new_status = PhabricatorProjectColumn::STATUS_DELETED;
|
||||
}
|
||||
|
||||
$type_status = PhabricatorProjectColumnTransaction::TYPE_STATUS;
|
||||
$xactions = array(id(new PhabricatorProjectColumnTransaction())
|
||||
->setTransactionType($type_status)
|
||||
->setNewValue($new_status));
|
||||
|
||||
$editor = id(new PhabricatorProjectColumnTransactionEditor())
|
||||
->setActor($viewer)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->applyTransactions($column, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($view_uri);
|
||||
}
|
||||
|
||||
if ($column->isDeleted()) {
|
||||
$title = pht('Activate Column');
|
||||
} else {
|
||||
$title = pht('Delete Column');
|
||||
}
|
||||
$submit = $title;
|
||||
if ($error_view) {
|
||||
$body = $error_view;
|
||||
} else if ($column->isDeleted()) {
|
||||
$body = pht('Are you sure you want to activate this column?');
|
||||
} else {
|
||||
$body = pht('Are you sure you want to delete this column?');
|
||||
}
|
||||
|
||||
$form->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue($submit)
|
||||
->addCancelButton($view_uri));
|
||||
$dialog = id(new AphrontDialogView())
|
||||
->setUser($viewer)
|
||||
->setWidth(AphrontDialogView::WIDTH_FORM)
|
||||
->setTitle($title)
|
||||
->appendChild($body)
|
||||
->setDisableWorkflowOnCancel(true)
|
||||
->addSubmitButton($title)
|
||||
->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);
|
||||
return id(new AphrontDialogResponse())
|
||||
->setDialog($dialog);
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText($title)
|
||||
->setForm($form);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$form_box,
|
||||
),
|
||||
array(
|
||||
'title' => $title,
|
||||
'device' => true,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectBoardEditController
|
||||
extends PhabricatorProjectController {
|
||||
extends PhabricatorProjectBoardController {
|
||||
|
||||
private $id;
|
||||
private $projectID;
|
||||
|
@ -28,6 +28,7 @@ final class PhabricatorProjectBoardEditController
|
|||
if (!$project) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$this->setProject($project);
|
||||
|
||||
$is_new = ($this->id ? false : true);
|
||||
|
||||
|
@ -48,21 +49,18 @@ final class PhabricatorProjectBoardEditController
|
|||
$column = PhabricatorProjectColumn::initializeNewColumn($viewer);
|
||||
}
|
||||
|
||||
$errors = array();
|
||||
$e_name = true;
|
||||
$error_view = null;
|
||||
$view_uri = $this->getApplicationURI('/board/'.$this->projectID.'/');
|
||||
$e_name = null;
|
||||
$validation_exception = null;
|
||||
$base_uri = '/board/'.$this->projectID.'/';
|
||||
if ($is_new) {
|
||||
// we want to go back to the board
|
||||
$view_uri = $this->getApplicationURI($base_uri);
|
||||
} else {
|
||||
$view_uri = $this->getApplicationURI($base_uri.'column/'.$this->id.'/');
|
||||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$new_name = $request->getStr('name');
|
||||
$column->setName($new_name);
|
||||
|
||||
if (!strlen($column->getName())) {
|
||||
$errors[] = pht('Column name is required.');
|
||||
$e_name = pht('Required');
|
||||
} else {
|
||||
$e_name = null;
|
||||
}
|
||||
|
||||
if ($is_new) {
|
||||
$column->setProjectPHID($project->getPHID());
|
||||
|
@ -81,9 +79,21 @@ final class PhabricatorProjectBoardEditController
|
|||
$column->setSequence($new_sequence);
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$column->save();
|
||||
$type_name = PhabricatorProjectColumnTransaction::TYPE_NAME;
|
||||
$xactions = array(id(new PhabricatorProjectColumnTransaction())
|
||||
->setTransactionType($type_name)
|
||||
->setNewValue($new_name));
|
||||
|
||||
try {
|
||||
$editor = id(new PhabricatorProjectColumnTransactionEditor())
|
||||
->setActor($viewer)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setContentSourceFromRequest($request)
|
||||
->applyTransactions($column, $xactions);
|
||||
return id(new AphrontRedirectResponse())->setURI($view_uri);
|
||||
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
||||
$e_name = $ex->getShortMessage($type_name);
|
||||
$validation_exception = $ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -112,9 +122,6 @@ final class PhabricatorProjectBoardEditController
|
|||
->addCancelButton($view_uri));
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(
|
||||
$project->getName(),
|
||||
$this->getApplicationURI('view/'.$project->getID().'/'));
|
||||
$crumbs->addTextCrumb(
|
||||
pht('Board'),
|
||||
$this->getApplicationURI('board/'.$project->getID().'/'));
|
||||
|
@ -122,7 +129,7 @@ final class PhabricatorProjectBoardEditController
|
|||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText($title)
|
||||
->setFormErrors($errors)
|
||||
->setValidationException($validation_exception)
|
||||
->setForm($form);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectBoardViewController
|
||||
extends PhabricatorProjectBoardController {
|
||||
|
||||
private $id;
|
||||
private $handles;
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$viewer = $request->getUser();
|
||||
|
||||
$project = id(new PhabricatorProjectQuery())
|
||||
->setViewer($viewer)
|
||||
->needImages(true)
|
||||
->withIDs(array($this->id))
|
||||
->executeOne();
|
||||
if (!$project) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$this->setProject($project);
|
||||
|
||||
$columns = id(new PhabricatorProjectColumnQuery())
|
||||
->setViewer($viewer)
|
||||
->withProjectPHIDs(array($project->getPHID()))
|
||||
->withStatuses(array(PhabricatorProjectColumn::STATUS_ACTIVE))
|
||||
->execute();
|
||||
|
||||
$columns = mpull($columns, null, 'getSequence');
|
||||
|
||||
// If there's no default column, create one now.
|
||||
if (empty($columns[0])) {
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
$column = PhabricatorProjectColumn::initializeNewColumn($viewer)
|
||||
->setSequence(0)
|
||||
->setProjectPHID($project->getPHID())
|
||||
->save();
|
||||
$column->attachProject($project);
|
||||
$columns[0] = $column;
|
||||
unset($unguarded);
|
||||
}
|
||||
|
||||
ksort($columns);
|
||||
|
||||
$tasks = id(new ManiphestTaskQuery())
|
||||
->setViewer($viewer)
|
||||
->withAllProjects(array($project->getPHID()))
|
||||
->withStatuses(ManiphestTaskStatus::getOpenStatusConstants())
|
||||
->setOrderBy(ManiphestTaskQuery::ORDER_PRIORITY)
|
||||
->execute();
|
||||
$tasks = mpull($tasks, null, 'getPHID');
|
||||
$task_phids = array_keys($tasks);
|
||||
|
||||
if ($task_phids) {
|
||||
$edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_COLUMN;
|
||||
$edge_query = id(new PhabricatorEdgeQuery())
|
||||
->withSourcePHIDs($task_phids)
|
||||
->withEdgeTypes(array($edge_type))
|
||||
->withDestinationPHIDs(mpull($columns, 'getPHID'));
|
||||
$edge_query->execute();
|
||||
}
|
||||
|
||||
$task_map = array();
|
||||
$default_phid = $columns[0]->getPHID();
|
||||
foreach ($tasks as $task) {
|
||||
$task_phid = $task->getPHID();
|
||||
$column_phids = $edge_query->getDestinationPHIDs(array($task_phid));
|
||||
|
||||
$column_phid = head($column_phids);
|
||||
$column_phid = nonempty($column_phid, $default_phid);
|
||||
|
||||
$task_map[$column_phid][] = $task_phid;
|
||||
}
|
||||
|
||||
$task_can_edit_map = id(new PhabricatorPolicyFilter())
|
||||
->setViewer($viewer)
|
||||
->requireCapabilities(array(PhabricatorPolicyCapability::CAN_EDIT))
|
||||
->apply($tasks);
|
||||
|
||||
$board_id = celerity_generate_unique_node_id();
|
||||
|
||||
$board = id(new PHUIWorkboardView())
|
||||
->setUser($viewer)
|
||||
->setFluidishLayout(true)
|
||||
->setID($board_id);
|
||||
|
||||
$this->initBehavior(
|
||||
'project-boards',
|
||||
array(
|
||||
'boardID' => $board_id,
|
||||
'projectPHID' => $project->getPHID(),
|
||||
'moveURI' => $this->getApplicationURI('move/'.$project->getID().'/'),
|
||||
'createURI' => '/maniphest/task/create/',
|
||||
));
|
||||
|
||||
$this->handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks);
|
||||
|
||||
foreach ($columns as $column) {
|
||||
$panel = id(new PHUIWorkpanelView())
|
||||
->setHeader($column->getDisplayName())
|
||||
->setHeaderColor($column->getHeaderColor());
|
||||
if (!$column->isDefaultColumn()) {
|
||||
$panel->setEditURI('column/'.$column->getID().'/');
|
||||
}
|
||||
$panel->setHeaderAction(id(new PHUIIconView())
|
||||
->setSpriteSheet(PHUIIconView::SPRITE_ACTIONS)
|
||||
->setSpriteIcon('new-grey')
|
||||
->setHref('/maniphest/task/create/')
|
||||
->addSigil('column-add-task')
|
||||
->setMetadata(
|
||||
array('columnPHID' => $column->getPHID())));
|
||||
|
||||
$cards = id(new PHUIObjectItemListView())
|
||||
->setUser($viewer)
|
||||
->setCards(true)
|
||||
->setFlush(true)
|
||||
->setAllowEmptyList(true)
|
||||
->addSigil('project-column')
|
||||
->setMetadata(
|
||||
array(
|
||||
'columnPHID' => $column->getPHID(),
|
||||
));
|
||||
$task_phids = idx($task_map, $column->getPHID(), array());
|
||||
foreach (array_select_keys($tasks, $task_phids) as $task) {
|
||||
$owner = null;
|
||||
if ($task->getOwnerPHID()) {
|
||||
$owner = $this->handles[$task->getOwnerPHID()];
|
||||
}
|
||||
$can_edit = idx($task_can_edit_map, $task->getPHID(), false);
|
||||
$cards->addItem(id(new ProjectBoardTaskCard())
|
||||
->setViewer($viewer)
|
||||
->setTask($task)
|
||||
->setOwner($owner)
|
||||
->setCanEdit($can_edit)
|
||||
->getItem());
|
||||
}
|
||||
$panel->setCards($cards);
|
||||
|
||||
if (!$task_phids) {
|
||||
$cards->addClass('project-column-empty');
|
||||
}
|
||||
|
||||
$board->addPanel($panel);
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(pht('Board'));
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$project,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$actions = id(new PhabricatorActionListView())
|
||||
->setUser($viewer)
|
||||
->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Add Column'))
|
||||
->setHref($this->getApplicationURI('board/'.$this->id.'/edit/'))
|
||||
->setIcon('create')
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
$plist = id(new PHUIPropertyListView());
|
||||
|
||||
// TODO: Need this to get actions to render.
|
||||
$plist->addProperty(
|
||||
pht('Project Boards'),
|
||||
phutil_tag(
|
||||
'em',
|
||||
array(),
|
||||
pht(
|
||||
'This feature is beta, but should mostly work.')));
|
||||
$plist->setActionList($actions);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($project->getName())
|
||||
->setUser($viewer)
|
||||
->setImage($project->getProfileImageURI())
|
||||
->setPolicyObject($project);
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->addPropertyList($plist);
|
||||
|
||||
$board_box = id(new PHUIBoxView())
|
||||
->appendChild($board)
|
||||
->addMargin(PHUI::MARGIN_LARGE);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$box,
|
||||
$board_box,
|
||||
),
|
||||
array(
|
||||
'title' => pht('%s Board', $project->getName()),
|
||||
'device' => true,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectColumnDetailController
|
||||
extends PhabricatorProjectBoardController {
|
||||
|
||||
private $id;
|
||||
private $projectID;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->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,
|
||||
))
|
||||
->withIDs(array($this->projectID))
|
||||
->executeOne();
|
||||
|
||||
if (!$project) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
$this->setProject($project);
|
||||
|
||||
$column = id(new PhabricatorProjectColumnQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($this->id))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
))
|
||||
->executeOne();
|
||||
if (!$column) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$xactions = id(new PhabricatorProjectColumnTransactionQuery())
|
||||
->setViewer($viewer)
|
||||
->withObjectPHIDs(array($column->getPHID()))
|
||||
->execute();
|
||||
|
||||
$engine = id(new PhabricatorMarkupEngine())
|
||||
->setViewer($viewer);
|
||||
|
||||
$timeline = id(new PhabricatorApplicationTransactionView())
|
||||
->setUser($viewer)
|
||||
->setObjectPHID($column->getPHID())
|
||||
->setTransactions($xactions);
|
||||
|
||||
$title = pht('%s', $column->getName());
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addTextCrumb(
|
||||
pht('Board'),
|
||||
$this->getApplicationURI('board/'.$project->getID().'/'));
|
||||
$crumbs->addTextCrumb($title);
|
||||
|
||||
$header = $this->buildHeaderView($column);
|
||||
$actions = $this->buildActionView($column);
|
||||
$properties = $this->buildPropertyView($column, $actions);
|
||||
|
||||
$box = id(new PHUIObjectBoxView())
|
||||
->setHeader($header)
|
||||
->addPropertyList($properties);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$box,
|
||||
$timeline,
|
||||
),
|
||||
array(
|
||||
'title' => $title,
|
||||
'device' => true,
|
||||
));
|
||||
}
|
||||
|
||||
private function buildHeaderView(PhabricatorProjectColumn $column) {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setUser($viewer)
|
||||
->setHeader($column->getName())
|
||||
->setPolicyObject($column);
|
||||
|
||||
if ($column->isDeleted()) {
|
||||
$header->setStatus('reject', 'red', pht('Deleted'));
|
||||
}
|
||||
|
||||
return $header;
|
||||
}
|
||||
|
||||
private function buildActionView(PhabricatorProjectColumn $column) {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$id = $column->getID();
|
||||
$project_id = $this->getProject()->getID();
|
||||
$base_uri = '/board/'.$project_id.'/';
|
||||
|
||||
$actions = id(new PhabricatorActionListView())
|
||||
->setObjectURI($this->getApplicationURI($base_uri.'column/'.$id.'/'))
|
||||
->setUser($viewer);
|
||||
|
||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||
$viewer,
|
||||
$column,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Edit column'))
|
||||
->setIcon('edit')
|
||||
->setHref($this->getApplicationURI($base_uri.'edit/'.$id.'/'))
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(!$can_edit));
|
||||
|
||||
if (!$column->isDeleted()) {
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Delete column'))
|
||||
->setIcon('delete')
|
||||
->setHref($this->getApplicationURI($base_uri.'delete/'.$id.'/'))
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(true));
|
||||
} else {
|
||||
$actions->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName(pht('Activate column'))
|
||||
->setIcon('enable')
|
||||
->setHref($this->getApplicationURI($base_uri.'delete/'.$id.'/'))
|
||||
->setDisabled(!$can_edit)
|
||||
->setWorkflow(true));
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
private function buildPropertyView(
|
||||
PhabricatorProjectColumn $column,
|
||||
PhabricatorActionListView $actions) {
|
||||
$viewer = $this->getRequest()->getUser();
|
||||
|
||||
$properties = id(new PHUIPropertyListView())
|
||||
->setUser($viewer)
|
||||
->setObject($column)
|
||||
->setActionList($actions);
|
||||
|
||||
$descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
|
||||
$viewer,
|
||||
$column);
|
||||
|
||||
$properties->addProperty(
|
||||
pht('Editable By'),
|
||||
$descriptions[PhabricatorPolicyCapability::CAN_EDIT]);
|
||||
|
||||
return $properties;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectColumnTransactionEditor
|
||||
extends PhabricatorApplicationTransactionEditor {
|
||||
|
||||
public function getTransactionTypes() {
|
||||
$types = parent::getTransactionTypes();
|
||||
|
||||
$types[] = PhabricatorProjectColumnTransaction::TYPE_NAME;
|
||||
$types[] = PhabricatorProjectColumnTransaction::TYPE_STATUS;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
protected function getCustomTransactionOldValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorProjectColumnTransaction::TYPE_NAME:
|
||||
return $object->getName();
|
||||
case PhabricatorProjectColumnTransaction::TYPE_STATUS:
|
||||
return $object->getStatus();
|
||||
}
|
||||
|
||||
return parent::getCustomTransactionOldValue($object, $xaction);
|
||||
}
|
||||
|
||||
protected function getCustomTransactionNewValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorProjectColumnTransaction::TYPE_NAME:
|
||||
case PhabricatorProjectColumnTransaction::TYPE_STATUS:
|
||||
return $xaction->getNewValue();
|
||||
}
|
||||
|
||||
return parent::getCustomTransactionNewValue($object, $xaction);
|
||||
}
|
||||
|
||||
protected function applyCustomInternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorProjectColumnTransaction::TYPE_NAME:
|
||||
$object->setName($xaction->getNewValue());
|
||||
return;
|
||||
case PhabricatorProjectColumnTransaction::TYPE_STATUS:
|
||||
$object->setStatus($xaction->getNewValue());
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomInternalTransaction($object, $xaction);
|
||||
}
|
||||
|
||||
protected function applyCustomExternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorProjectColumnTransaction::TYPE_NAME:
|
||||
case PhabricatorProjectColumnTransaction::TYPE_STATUS:
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::applyCustomExternalTransaction($object, $xaction);
|
||||
}
|
||||
|
||||
protected function validateTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
$type,
|
||||
array $xactions) {
|
||||
|
||||
$errors = parent::validateTransaction($object, $type, $xactions);
|
||||
|
||||
switch ($type) {
|
||||
case PhabricatorProjectColumnTransaction::TYPE_NAME:
|
||||
$missing = $this->validateIsEmptyTextField(
|
||||
$object->getName(),
|
||||
$xactions);
|
||||
|
||||
if ($missing) {
|
||||
$error = new PhabricatorApplicationTransactionValidationError(
|
||||
$type,
|
||||
pht('Required'),
|
||||
pht('Column name is required.'),
|
||||
nonempty(last($xactions), null));
|
||||
|
||||
$error->setIsMissingFieldError(true);
|
||||
$errors[] = $error;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
|
||||
protected function requireCapabilities(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorProjectColumnTransaction::TYPE_NAME:
|
||||
case PhabricatorProjectColumnTransaction::TYPE_STATUS:
|
||||
PhabricatorPolicyFilter::requireCapability(
|
||||
$this->requireActor(),
|
||||
$object,
|
||||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::requireCapabilities($object, $xaction);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectColumnTransactionQuery
|
||||
extends PhabricatorApplicationTransactionQuery {
|
||||
|
||||
public function getTemplateApplicationTransaction() {
|
||||
return new PhabricatorProjectColumnTransaction();
|
||||
}
|
||||
|
||||
}
|
|
@ -44,6 +44,10 @@ final class PhabricatorProjectColumn
|
|||
return ($this->getSequence() == 0);
|
||||
}
|
||||
|
||||
public function isDeleted() {
|
||||
return ($this->getStatus() == self::STATUS_DELETED);
|
||||
}
|
||||
|
||||
public function getDisplayName() {
|
||||
if ($this->isDefaultColumn()) {
|
||||
return pht('Backlog');
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorProjectColumnTransaction
|
||||
extends PhabricatorApplicationTransaction {
|
||||
|
||||
const TYPE_NAME = 'project:col:name';
|
||||
const TYPE_STATUS = 'project:col:status';
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'project';
|
||||
}
|
||||
|
||||
public function getApplicationTransactionType() {
|
||||
return PhabricatorProjectPHIDTypeColumn::TYPECONST;
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
$author_handle = $this->renderHandleLink($this->getAuthorPHID());
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
case PhabricatorProjectColumnTransaction::TYPE_NAME:
|
||||
if (!strlen($old)) {
|
||||
return pht(
|
||||
'%s created this column.',
|
||||
$author_handle);
|
||||
} else {
|
||||
return pht(
|
||||
'%s renamed this column from "%s" to "%s".',
|
||||
$author_handle,
|
||||
$old,
|
||||
$new);
|
||||
}
|
||||
case PhabricatorProjectColumnTransaction::TYPE_STATUS:
|
||||
switch ($new) {
|
||||
case PhabricatorProjectColumn::STATUS_ACTIVE:
|
||||
return pht(
|
||||
'%s activated this column.',
|
||||
$author_handle);
|
||||
case PhabricatorProjectColumn::STATUS_DELETED:
|
||||
return pht(
|
||||
'%s deleted this column.',
|
||||
$author_handle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue