mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-28 16:30:59 +01:00
Simplify Project status field
Summary: This was a sort of speculative feature added by a contributor some time ago and just serves as a label; for now, simplify it into "active" and "archived" and remove "archived" projects from the "active" list. - Fix a bug where we'd publish a "renamed from X to X" transaction that had no effect. - Publish stories about status changes. - Remove the "edit affiliation" controller, which has no links in the UI (effectively replaced by join/leave links). - Add query/conduit support. Test Plan: Edited the status of several projects. Reviewers: btrahan Reviewed By: btrahan CC: aran, epriestley Maniphest Tasks: T681 Differential Revision: https://secure.phabricator.com/D1573
This commit is contained in:
parent
a5f8846f47
commit
4caa684724
19 changed files with 135 additions and 158 deletions
1
resources/sql/patches/104.projectstatuses.sql
Normal file
1
resources/sql/patches/104.projectstatuses.sql
Normal file
|
@ -0,0 +1 @@
|
|||
UPDATE phabricator_project.project SET status = IF(status = 5, 100, 0);
|
|
@ -627,7 +627,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProfileHeaderView' => 'view/layout/profileheader',
|
||||
'PhabricatorProject' => 'applications/project/storage/project',
|
||||
'PhabricatorProjectAffiliation' => 'applications/project/storage/affiliation',
|
||||
'PhabricatorProjectAffiliationEditController' => 'applications/project/controller/editaffiliation',
|
||||
'PhabricatorProjectConstants' => 'applications/project/constants/base',
|
||||
'PhabricatorProjectController' => 'applications/project/controller/base',
|
||||
'PhabricatorProjectCreateController' => 'applications/project/controller/create',
|
||||
|
@ -1332,7 +1331,6 @@ phutil_register_library_map(array(
|
|||
'PhabricatorProfileHeaderView' => 'AphrontView',
|
||||
'PhabricatorProject' => 'PhabricatorProjectDAO',
|
||||
'PhabricatorProjectAffiliation' => 'PhabricatorProjectDAO',
|
||||
'PhabricatorProjectAffiliationEditController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectController' => 'PhabricatorController',
|
||||
'PhabricatorProjectCreateController' => 'PhabricatorProjectController',
|
||||
'PhabricatorProjectDAO' => 'PhabricatorLiskDAO',
|
||||
|
|
|
@ -206,8 +206,6 @@ class AphrontDefaultApplicationConfiguration
|
|||
'edit/(?P<id>\d+)/$' => 'PhabricatorProjectProfileEditController',
|
||||
'view/(?P<id>\d+)/(?:(?P<page>\w+)/)?$'
|
||||
=> 'PhabricatorProjectProfileController',
|
||||
'affiliation/(?P<id>\d+)/$'
|
||||
=> 'PhabricatorProjectAffiliationEditController',
|
||||
'create/$' => 'PhabricatorProjectCreateController',
|
||||
'update/(?P<id>\d+)/(?P<action>[^/]+)/$'
|
||||
=> 'PhabricatorProjectUpdateController',
|
||||
|
|
|
@ -26,9 +26,19 @@ final class ConduitAPI_project_query_Method extends ConduitAPI_project_Method {
|
|||
}
|
||||
|
||||
public function defineParamTypes() {
|
||||
|
||||
$statuses = array(
|
||||
PhabricatorProjectQuery::STATUS_ANY,
|
||||
PhabricatorProjectQuery::STATUS_OPEN,
|
||||
PhabricatorProjectQuery::STATUS_CLOSED,
|
||||
PhabricatorProjectQuery::STATUS_ACTIVE,
|
||||
PhabricatorProjectQuery::STATUS_ARCHIVED,
|
||||
);
|
||||
|
||||
return array(
|
||||
'ids' => 'optional list<int>',
|
||||
'phids' => 'optional list<phid>',
|
||||
'status' => 'optional enum<'.implode(', ', $statuses).'>',
|
||||
|
||||
'members' => 'optional list<phid>',
|
||||
|
||||
|
@ -55,6 +65,11 @@ final class ConduitAPI_project_query_Method extends ConduitAPI_project_Method {
|
|||
$query->withIDs($ids);
|
||||
}
|
||||
|
||||
$status = $request->getValue('status');
|
||||
if ($status) {
|
||||
$query->withStatus($status);
|
||||
}
|
||||
|
||||
$phids = $request->getValue('phids');
|
||||
if ($phids) {
|
||||
$query->withPHIDs($phids);
|
||||
|
|
|
@ -106,6 +106,10 @@ abstract class PhabricatorFeedStory {
|
|||
phutil_escape_html($handle->getLinkName()));
|
||||
}
|
||||
|
||||
final protected function renderString($str) {
|
||||
return '<strong>'.phutil_escape_html($str).'</strong>';
|
||||
}
|
||||
|
||||
final protected function renderSummary($text, $len = 128) {
|
||||
if ($len) {
|
||||
$text = phutil_utf8_shorten($text, $len);
|
||||
|
|
|
@ -49,16 +49,29 @@ class PhabricatorFeedStoryProject extends PhabricatorFeedStory {
|
|||
$action = 'renamed project '.
|
||||
$this->linkTo($proj_phid).
|
||||
' from '.
|
||||
'<strong>'.phutil_escape_html($old).'</strong>'.
|
||||
$this->renderString($old).
|
||||
' to '.
|
||||
'<strong>'.phutil_escape_html($new).'</strong>.';
|
||||
$this->renderString($new).
|
||||
'.';
|
||||
} else {
|
||||
$action = 'created project '.
|
||||
$this->linkTo($proj_phid).
|
||||
' (as '.
|
||||
'<strong>'.phutil_escape_html($new).'</strong>).';
|
||||
$this->renderString($new).
|
||||
').';
|
||||
}
|
||||
break;
|
||||
case PhabricatorProjectTransactionType::TYPE_STATUS:
|
||||
$action = 'changed project '.
|
||||
$this->linkTo($proj_phid).
|
||||
' status from '.
|
||||
$this->renderString(
|
||||
PhabricatorProjectStatus::getNameForStatus($old)).
|
||||
' to '.
|
||||
$this->renderString(
|
||||
PhabricatorProjectStatus::getNameForStatus($new)).
|
||||
'.';
|
||||
break;
|
||||
case PhabricatorProjectTransactionType::TYPE_MEMBERS:
|
||||
$add = array_diff($new, $old);
|
||||
$rem = array_diff($old, $new);
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
|
||||
phutil_require_module('phabricator', 'applications/feed/story/base');
|
||||
phutil_require_module('phabricator', 'applications/feed/view/story');
|
||||
phutil_require_module('phabricator', 'applications/project/constants/status');
|
||||
phutil_require_module('phabricator', 'applications/project/constants/transaction');
|
||||
|
||||
phutil_require_module('phutil', 'markup');
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,41 +18,23 @@
|
|||
|
||||
final class PhabricatorProjectStatus {
|
||||
|
||||
const UNKNOWN = 0;
|
||||
const NOT_STARTED = 1;
|
||||
const IN_PROGRESS = 2;
|
||||
const REVIEW_PROCESS = 3;
|
||||
const RELEASED = 4;
|
||||
const COMPLETED = 5;
|
||||
const DEFERRED = 6;
|
||||
const ONGOING = 7;
|
||||
|
||||
const STATUS_ACTIVE = 0;
|
||||
const STATUS_ARCHIVED = 100;
|
||||
|
||||
public static function getNameForStatus($status) {
|
||||
static $map = array(
|
||||
self::UNKNOWN => '',
|
||||
self::NOT_STARTED => 'Not started',
|
||||
self::IN_PROGRESS => 'In progress',
|
||||
self::ONGOING => 'Ongoing',
|
||||
self::REVIEW_PROCESS => 'Review process',
|
||||
self::RELEASED => 'Released',
|
||||
self::COMPLETED => 'Completed',
|
||||
self::DEFERRED => 'Deferred',
|
||||
self::STATUS_ACTIVE => 'Active',
|
||||
self::STATUS_ARCHIVED => 'Archived',
|
||||
);
|
||||
|
||||
return idx($map, coalesce($status, '?'), $map[self::UNKNOWN]);
|
||||
return idx($map, coalesce($status, '?'), 'Unknown');
|
||||
}
|
||||
|
||||
public static function getStatusMap() {
|
||||
return array(
|
||||
self::UNKNOWN => 'Who knows?',
|
||||
self::NOT_STARTED => 'Not started',
|
||||
self::IN_PROGRESS => 'In progress',
|
||||
self::ONGOING => 'Ongoing',
|
||||
self::REVIEW_PROCESS => 'Review process',
|
||||
self::RELEASED => 'Released',
|
||||
self::COMPLETED => 'Completed',
|
||||
self::DEFERRED => 'Deferred',
|
||||
self::STATUS_ACTIVE => 'Active',
|
||||
self::STATUS_ARCHIVED => 'Archived',
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,5 +21,6 @@ final class PhabricatorProjectTransactionType
|
|||
|
||||
const TYPE_NAME = 'name';
|
||||
const TYPE_MEMBERS = 'members';
|
||||
const TYPE_STATUS = 'status';
|
||||
|
||||
}
|
||||
|
|
|
@ -49,8 +49,6 @@ class PhabricatorProjectCreateController
|
|||
$errors[] = $ex->getMessage();
|
||||
}
|
||||
|
||||
$project->setStatus(PhabricatorProjectStatus::ONGOING);
|
||||
|
||||
$profile->setBlurb($request->getStr('blurb'));
|
||||
|
||||
if (!$errors) {
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class PhabricatorProjectAffiliationEditController
|
||||
extends PhabricatorProjectController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$project = id(new PhabricatorProject())->load($this->id);
|
||||
if (!$project) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$affiliation = id(new PhabricatorProjectAffiliation())->loadOneWhere(
|
||||
'projectPHID = %s AND userPHID = %s',
|
||||
$project->getPHID(),
|
||||
$user->getPHID());
|
||||
|
||||
if (!$affiliation) {
|
||||
$affiliation = new PhabricatorProjectAffiliation();
|
||||
$affiliation->setUserPHID($user->getPHID());
|
||||
$affiliation->setProjectPHID($project->getPHID());
|
||||
}
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$affiliation->setRole($request->getStr('role'));
|
||||
|
||||
if (!strlen($affiliation->getRole())) {
|
||||
if ($affiliation->getID()) {
|
||||
if ($affiliation->getIsOwner()) {
|
||||
$affiliation->setRole('Owner');
|
||||
$affiliation->save();
|
||||
} else {
|
||||
$affiliation->delete();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$affiliation->save();
|
||||
}
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI('/project/view/'.$project->getID().'/');
|
||||
}
|
||||
|
||||
$form = new AphrontFormView();
|
||||
$form
|
||||
->setUser($user)
|
||||
->setAction('/project/affiliation/'.$project->getID().'/')
|
||||
->appendChild(
|
||||
id(new AphrontFormTextControl())
|
||||
->setLabel('Role')
|
||||
->setName('role')
|
||||
->setValue($affiliation->getRole()))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->addCancelButton('/project/view/'.$project->getID().'/')
|
||||
->setValue('Save'));
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
$panel->setHeader('Edit Project Affiliation');
|
||||
$panel->setWidth(AphrontPanelView::WIDTH_FORM);
|
||||
$panel->appendChild($form);
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$panel,
|
||||
array(
|
||||
'title' => 'Edit Project Affiliation',
|
||||
));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/404');
|
||||
phutil_require_module('phabricator', 'aphront/response/redirect');
|
||||
phutil_require_module('phabricator', 'applications/project/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/project/storage/affiliation');
|
||||
phutil_require_module('phabricator', 'applications/project/storage/project');
|
||||
phutil_require_module('phabricator', 'view/form/base');
|
||||
phutil_require_module('phabricator', 'view/form/control/submit');
|
||||
phutil_require_module('phabricator', 'view/form/control/text');
|
||||
phutil_require_module('phabricator', 'view/layout/panel');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorProjectAffiliationEditController.php');
|
|
@ -50,17 +50,22 @@ class PhabricatorProjectListController
|
|||
|
||||
$view_phid = $request->getUser()->getPHID();
|
||||
|
||||
$status_filter = PhabricatorProjectQuery::STATUS_ANY;
|
||||
|
||||
switch ($this->filter) {
|
||||
case 'active':
|
||||
$table_header = 'Active Projects';
|
||||
$query->setMembers(array($view_phid));
|
||||
$query->withStatus(PhabricatorProjectQuery::STATUS_ACTIVE);
|
||||
break;
|
||||
case 'owned':
|
||||
$table_header = 'Owned Projects';
|
||||
$query->setOwners(array($view_phid));
|
||||
$query->withStatus($status_filter);
|
||||
break;
|
||||
case 'all':
|
||||
$table_header = 'All Projects';
|
||||
$query->withStatus($status_filter);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -128,6 +133,8 @@ class PhabricatorProjectListController
|
|||
'href' => '/project/view/'.$project->getID().'/',
|
||||
),
|
||||
phutil_escape_html($project->getName())),
|
||||
phutil_escape_html(
|
||||
PhabricatorProjectStatus::getNameForStatus($project->getStatus())),
|
||||
phutil_escape_html($blurb),
|
||||
phutil_escape_html($population),
|
||||
phutil_render_tag(
|
||||
|
@ -143,6 +150,7 @@ class PhabricatorProjectListController
|
|||
$table->setHeaders(
|
||||
array(
|
||||
'Project',
|
||||
'Status',
|
||||
'Description',
|
||||
'Population',
|
||||
'Open Tasks',
|
||||
|
@ -150,6 +158,7 @@ class PhabricatorProjectListController
|
|||
$table->setColumnClasses(
|
||||
array(
|
||||
'pri',
|
||||
'',
|
||||
'wide',
|
||||
'',
|
||||
''
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/maniphest/query');
|
||||
phutil_require_module('phabricator', 'applications/project/constants/status');
|
||||
phutil_require_module('phabricator', 'applications/project/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/project/query/project');
|
||||
phutil_require_module('phabricator', 'applications/project/storage/affiliation');
|
||||
|
|
|
@ -65,6 +65,12 @@ class PhabricatorProjectProfileEditController
|
|||
$xaction->setNewValue($request->getStr('name'));
|
||||
$xactions[] = $xaction;
|
||||
|
||||
$xaction = new PhabricatorProjectTransaction();
|
||||
$xaction->setTransactionType(
|
||||
PhabricatorProjectTransactionType::TYPE_STATUS);
|
||||
$xaction->setNewValue($request->getStr('status'));
|
||||
$xactions[] = $xaction;
|
||||
|
||||
$editor = new PhabricatorProjectEditor($project);
|
||||
$editor->setUser($user);
|
||||
$editor->applyTransactions($xactions);
|
||||
|
@ -73,7 +79,6 @@ class PhabricatorProjectProfileEditController
|
|||
$errors[] = $ex->getMessage();
|
||||
}
|
||||
|
||||
$project->setStatus($request->getStr('status'));
|
||||
$project->setSubprojectPHIDs($request->getArr('set_subprojects'));
|
||||
$profile->setBlurb($request->getStr('blurb'));
|
||||
|
||||
|
|
|
@ -48,12 +48,21 @@ final class PhabricatorProjectEditor {
|
|||
$project->setAuthorPHID($user->getPHID());
|
||||
}
|
||||
|
||||
foreach ($transactions as $xaction) {
|
||||
foreach ($transactions as $key => $xaction) {
|
||||
$type = $xaction->getTransactionType();
|
||||
|
||||
$this->setTransactionOldValue($project, $xaction);
|
||||
$this->applyTransactionEffect($project, $xaction);
|
||||
|
||||
if (!$this->transactionHasEffect($xaction)) {
|
||||
unset($transactions[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->applyTransactionEffect($project, $xaction);
|
||||
}
|
||||
|
||||
if (!$transactions) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -128,6 +137,9 @@ final class PhabricatorProjectEditor {
|
|||
case PhabricatorProjectTransactionType::TYPE_NAME:
|
||||
$xaction->setOldValue($project->getName());
|
||||
break;
|
||||
case PhabricatorProjectTransactionType::TYPE_STATUS:
|
||||
$xaction->setOldValue($project->getStatus());
|
||||
break;
|
||||
case PhabricatorProjectTransactionType::TYPE_MEMBERS:
|
||||
$affils = $project->loadAffiliations();
|
||||
$project->attachAffiliations($affils);
|
||||
|
@ -158,6 +170,9 @@ final class PhabricatorProjectEditor {
|
|||
$project->setPhrictionSlug($xaction->getNewValue());
|
||||
$this->validateName($project);
|
||||
break;
|
||||
case PhabricatorProjectTransactionType::TYPE_STATUS:
|
||||
$project->setStatus($xaction->getNewValue());
|
||||
break;
|
||||
case PhabricatorProjectTransactionType::TYPE_MEMBERS:
|
||||
$old = array_fill_keys($xaction->getOldValue(), true);
|
||||
$new = array_fill_keys($xaction->getNewValue(), true);
|
||||
|
@ -213,4 +228,9 @@ final class PhabricatorProjectEditor {
|
|||
->publish();
|
||||
}
|
||||
|
||||
private function transactionHasEffect(
|
||||
PhabricatorProjectTransaction $xaction) {
|
||||
return ($xaction->getOldValue() !== $xaction->getNewValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,6 +23,13 @@ final class PhabricatorProjectQuery {
|
|||
private $owners;
|
||||
private $members;
|
||||
|
||||
private $status = 'status-any';
|
||||
const STATUS_ANY = 'status-any';
|
||||
const STATUS_OPEN = 'status-open';
|
||||
const STATUS_CLOSED = 'status-closed';
|
||||
const STATUS_ACTIVE = 'status-active';
|
||||
const STATUS_ARCHIVED = 'status-archived';
|
||||
|
||||
private $limit;
|
||||
private $offset;
|
||||
|
||||
|
@ -38,6 +45,11 @@ final class PhabricatorProjectQuery {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function withStatus($status) {
|
||||
$this->status = $status;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setLimit($limit) {
|
||||
$this->limit = $limit;
|
||||
return $this;
|
||||
|
@ -113,6 +125,42 @@ final class PhabricatorProjectQuery {
|
|||
private function buildWhereClause($conn_r) {
|
||||
$where = array();
|
||||
|
||||
if ($this->status != self::STATUS_ANY) {
|
||||
switch ($this->status) {
|
||||
case self::STATUS_OPEN:
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'status IN (%Ld)',
|
||||
array(
|
||||
PhabricatorProjectStatus::STATUS_ACTIVE,
|
||||
));
|
||||
break;
|
||||
case self::STATUS_CLOSED:
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'status IN (%Ld)',
|
||||
array(
|
||||
PhabricatorProjectStatus::STATUS_ARCHIVED,
|
||||
));
|
||||
break;
|
||||
case self::STATUS_ACTIVE:
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'status = %d',
|
||||
PhabricatorProjectStatus::STATUS_ACTIVE);
|
||||
break;
|
||||
case self::STATUS_ARCHIVED:
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
'status = %d',
|
||||
PhabricatorProjectStatus::STATUS_ARCHIVED);
|
||||
break;
|
||||
default:
|
||||
throw new Exception(
|
||||
"Unknown project status '{$this->status}'!");
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->ids) {
|
||||
$where[] = qsprintf(
|
||||
$conn_r,
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/project/constants/status');
|
||||
phutil_require_module('phabricator', 'applications/project/storage/affiliation');
|
||||
phutil_require_module('phabricator', 'applications/project/storage/project');
|
||||
phutil_require_module('phabricator', 'storage/qsprintf');
|
||||
|
|
|
@ -20,7 +20,7 @@ class PhabricatorProject extends PhabricatorProjectDAO {
|
|||
|
||||
protected $name;
|
||||
protected $phid;
|
||||
protected $status = PhabricatorProjectStatus::UNKNOWN;
|
||||
protected $status = PhabricatorProjectStatus::STATUS_ACTIVE;
|
||||
protected $authorPHID;
|
||||
protected $subprojectPHIDs = array();
|
||||
protected $phrictionSlug;
|
||||
|
|
Loading…
Reference in a new issue