Project list and profile view modifications

Summary: Added some change on the project's list view, to show information about
active tasks, population, etc. Also modified the "profile view", and added a class "PhabricatorProfileView" to render the profile, both on projects and users.

Test Plan: play around the project directory :)

Reviewers: epriestley ericfrenkiel

CC:

Differential Revision: 477
This commit is contained in:
Cristian Adamo
2011-06-18 05:13:56 -03:00
parent 565cc43f27
commit 7851b6573f
27 changed files with 664 additions and 263 deletions

View File

@@ -24,10 +24,50 @@ class PhabricatorProjectListController
$projects = id(new PhabricatorProject())->loadAllWhere(
'1 = 1 ORDER BY id DESC limit 100');
$author_phids = mpull($projects, 'getAuthorPHID');
$handles = id(new PhabricatorObjectHandleData($author_phids))
->loadHandles();
$rows = array();
foreach ($projects as $project) {
$documents = new PhabricatorProjectTransactionSearch($project->getPHID());
// search all open documents by default
$documents->setSearchOptions();
$documents = $documents->executeSearch();
$documents_types = igroup($documents,'documentType');
$tasks = idx(
$documents_types,
PhabricatorPHIDConstants::PHID_TYPE_TASK);
$tasks_amount = count($tasks);
// TODO: set up a relationship between the project and the arcanist's
// project, to be able get the revisions.
$revisions = idx(
$documents_types,
PhabricatorPHIDConstants::PHID_TYPE_DREV);
$revisions_amount = count($revisions);
$profile = $project->getProfile();
$affiliations = $project->loadAffiliations();
$population = count($affiliations);
$status = PhabricatorProjectStatus::getNameForStatus(
$project->getStatus());
$blurb = nonempty(
$profile->getBlurb(),
'Oops!, nothing is known about this elusive project.');
$blurb = $this->textWrap($blurb, $columns = 100);
$rows[] = array(
phutil_escape_html($project->getName()),
phutil_escape_html($blurb),
$handles[$project->getAuthorPHID()]->renderLink(),
phutil_escape_html($population),
phutil_escape_html($status),
phutil_escape_html($tasks_amount),
// phutil_escape_html($revisions_amount),
phutil_render_tag(
'a',
array(
@@ -42,11 +82,23 @@ class PhabricatorProjectListController
$table->setHeaders(
array(
'Project',
'Blurb',
'Mastermind',
'Population',
'Status',
'Open Tasks',
// 'Open Revisions',
'',
));
$table->setColumnClasses(
array(
'pri',
'wide',
'',
'right',
'pri',
'right',
// 'right',
'action',
));
@@ -62,4 +114,17 @@ class PhabricatorProjectListController
));
}
private function textWrap($text, $length) {
if (strlen($text) <= $length) {
return $text;
} else {
// TODO: perhaps this could be improved, adding the ability to get the
// last letter and suppress it, if it is one of [(,:; ,etc.
// making "blurb" looks a little bit better. :)
$wrapped = wordwrap($text, $length, '__#END#__');
$end_position = strpos($wrapped, '__#END#__');
$wrapped = substr($text, 0, $end_position).'...';
return $wrapped;
}
}
}

View File

@@ -6,8 +6,12 @@
phutil_require_module('phabricator', 'applications/phid/constants');
phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'applications/project/constants/status');
phutil_require_module('phabricator', 'applications/project/controller/base');
phutil_require_module('phabricator', 'applications/project/storage/project');
phutil_require_module('phabricator', 'applications/project/transactions/search');
phutil_require_module('phabricator', 'view/control/table');
phutil_require_module('phabricator', 'view/layout/panel');

View File

@@ -20,139 +20,168 @@ class PhabricatorProjectProfileController
extends PhabricatorProjectController {
private $id;
private $page;
public function willProcessRequest(array $data) {
$this->id = $data['id'];
$this->id = idx($data, 'id');
$this->page = idx($data, 'page');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$uri = $request->getRequestURI();
$project = id(new PhabricatorProject())->load($this->id);
if (!$project) {
return new Aphront404Response();
}
$profile = id(new PhabricatorProjectProfile())->loadOneWhere(
'projectPHID = %s',
$project->getPHID());
$profile = $project->getProfile();
if (!$profile) {
$profile = new PhabricatorProjectProfile();
}
require_celerity_resource('phabricator-profile-css');
$src_phid = $profile->getProfileImagePHID();
$src = PhabricatorFileURI::getViewURIForPHID($src_phid);
if (!$src_phid) {
$src_phid = $user->getProfileImagePHID();
}
$picture = PhabricatorFileURI::getViewURIForPHID($src_phid);
$picture = phutil_render_tag(
'img',
array(
'class' => 'profile-image',
'src' => $src,
));
$pages = array(
/*
'<h2>Active Documents</h2>',
'tasks' => 'Maniphest Tasks',
'revisions' => 'Differential Revisions',
'<hr />',
'<h2>Workflow</h2>',
'goals' => 'Goals',
'statistics' => 'Statistics',
'<hr />', */
'<h2>Information</h2>',
'edit' => 'Edit Profile',
'affiliation' => 'Edit Affiliation',
);
$links =
'<ul class="profile-nav-links">'.
'<li><a href="/project/edit/'.$project->getID().'/">'.
'Edit Project</a></li>'.
'<li><a href="/project/affiliation/'.$project->getID().'/">'.
'Edit Affiliation</a></li>'.
'</ul>';
if (empty($pages[$this->page])) {
$this->page = 'action'; // key($pages);
}
$blurb = nonempty(
$profile->getBlurb(),
'//Nothing is known about this elusive project.//');
switch ($this->page) {
default:
$content = $this->renderBasicInformation($project, $profile);
break;
}
$factory = new DifferentialMarkupEngineFactory();
$engine = $factory->newDifferentialCommentMarkupEngine();
$blurb = $engine->markupText($blurb);
$affiliations = id(new PhabricatorProjectAffiliation())->loadAllWhere(
'projectPHID = %s ORDER BY IF(status = "former", 1, 0), dateCreated',
$project->getPHID());
$phids = array_merge(
array($project->getAuthorPHID()),
mpull($affiliations, 'getUserPHID'));
$handles = id(new PhabricatorObjectHandleData($phids))
->loadHandles();
$affiliated = array();
foreach ($affiliations as $affiliation) {
$user = $handles[$affiliation->getUserPHID()]->renderLink();
$role = phutil_escape_html($affiliation->getRole());
$status = null;
if ($affiliation->getStatus() == 'former') {
$role = '<em>Former '.$role.'</em>';
$profile = new PhabricatorProfileView();
$profile->setProfilePicture($picture);
$profile->setProfileNames($project->getName());
foreach ($pages as $page => $name) {
if (is_integer($page)) {
$profile->addProfileItem(
phutil_render_tag(
'span',
array(),
$name));
} else {
$uri->setPath('/project/'.$page.'/'.$project->getID().'/');
$profile->addProfileItem(
phutil_render_tag(
'a',
array(
'href' => $uri,
'class' => ($this->page == $page)
? 'phabricator-profile-item-selected'
: null,
),
phutil_escape_html($name)));
}
$affiliated[] = '<li>'.$user.' &mdash; '.$role.$status.'</li>';
}
if ($affiliated) {
$affiliated = '<ul>'.implode("\n", $affiliated).'</ul>';
} else {
$affiliated = '<p><em>No one is affiliated with this project.</em></p>';
}
$timestamp = phabricator_format_timestamp($project->getDateCreated());
$content =
'<div class="phabricator-profile-info-group">
<h1 class="phabricator-profile-info-header">Basic Information</h1>
<div class="phabricator-profile-info-pane">
<table class="phabricator-profile-info-table">
<tr>
<th>Creator</th>
<td>'.$handles[$project->getAuthorPHID()]->renderLink().'</td>
</tr>
<tr>
<th>Created</th>
<td>'.$timestamp.'</td>
</tr>
<tr>
<th>PHID</th>
<td>'.phutil_escape_html($project->getPHID()).'</td>
</tr>
<tr>
<th>Blurb</th>
<td>'.$blurb.'</td>
</tr>
</table>
</div>
</div>';
$content .=
'<div class="phabricator-profile-info-group">
<h1 class="phabricator-profile-info-header">Resources</h1>
<div class="phabricator-profile-info-pane">'.
$affiliated.
'</div>
</div>';
$profile_markup =
'<table class="phabricator-profile-master-layout">
<tr>
<td class="phabricator-profile-navigation">'.
'<h1>'.phutil_escape_html($project->getName()).'</h1>'.
'<hr />'.
$picture.
'<hr />'.
$links.
'<hr />'.
'</td>
<td class="phabricator-profile-content">'.
$content.
'</td>
</tr>
</table>';
$profile->appendChild($content);
return $this->buildStandardPageResponse(
$profile_markup,
$profile,
array(
'title' => $project->getName(),
));
));
}
private function renderBasicInformation($project, $profile) {
$blurb = nonempty(
$profile->getBlurb(),
'//Nothing is known about this elusive project.//');
$factory = new DifferentialMarkupEngineFactory();
$engine = $factory->newDifferentialCommentMarkupEngine();
$blurb = $engine->markupText($blurb);
$affiliations = $project->loadAffiliations();
$phids = array_merge(
array($project->getAuthorPHID()),
mpull($affiliations, 'getUserPHID'));
$handles = id(new PhabricatorObjectHandleData($phids))
->loadHandles();
$affiliated = array();
foreach ($affiliations as $affiliation) {
$user = $handles[$affiliation->getUserPHID()]->renderLink();
$role = phutil_escape_html($affiliation->getRole());
$status = null;
if ($affiliation->getStatus() == 'former') {
$role = '<em>Former '.$role.'</em>';
}
$affiliated[] = '<li>'.$user.' &mdash; '.$role.$status.'</li>';
}
if ($affiliated) {
$affiliated = '<ul>'.implode("\n", $affiliated).'</ul>';
} else {
$affiliated = '<p><em>No one is affiliated with this project.</em></p>';
}
$timestamp = phabricator_format_timestamp($project->getDateCreated());
$status = PhabricatorProjectStatus::getNameForStatus(
$project->getStatus());
$content =
'<div class="phabricator-profile-info-group">
<h1 class="phabricator-profile-info-header">Basic Information</h1>
<div class="phabricator-profile-info-pane">
<table class="phabricator-profile-info-table">
<tr>
<th>Creator</th>
<td>'.$handles[$project->getAuthorPHID()]->renderLink().'</td>
</tr>
<tr>
<th>Status</th>
<td><strong>'.phutil_escape_html($status).'</strong></td>
</tr>
<tr>
<th>Created</th>
<td>'.$timestamp.'</td>
</tr>
<tr>
<th>PHID</th>
<td>'.phutil_escape_html($project->getPHID()).'</td>
</tr>
<tr>
<th>Blurb</th>
<td>'.$blurb.'</td>
</tr>
</table>
</div>
</div>';
$content .=
'<div class="phabricator-profile-info-group">
<h1 class="phabricator-profile-info-header">Resources</h1>
<div class="phabricator-profile-info-pane">'.
$affiliated.
'</div>
</div>';
return $content;
}
}

View File

@@ -10,11 +10,11 @@ phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'applications/differential/parser/markup');
phutil_require_module('phabricator', 'applications/files/uri');
phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'applications/project/constants/status');
phutil_require_module('phabricator', 'applications/project/controller/base');
phutil_require_module('phabricator', 'applications/project/storage/affiliation');
phutil_require_module('phabricator', 'applications/project/storage/profile');
phutil_require_module('phabricator', 'applications/project/storage/project');
phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'view/layout/profile');
phutil_require_module('phabricator', 'view/utils');
phutil_require_module('phutil', 'markup');

View File

@@ -16,7 +16,7 @@
* limitations under the License.
*/
class PhabricatorProjectEditController
class PhabricatorProjectProfileEditController
extends PhabricatorProjectController {
private $id;
@@ -35,9 +35,7 @@ class PhabricatorProjectEditController
if (!$project) {
return new Aphront404Response();
}
$profile = id(new PhabricatorProjectProfile())->loadOneWhere(
'projectPHID = %s',
$project->getPHID());
$profile = $project->getProfile();
} else {
$project = new PhabricatorProject();
$project->setAuthorPHID($user->getPHID());
@@ -47,12 +45,13 @@ class PhabricatorProjectEditController
$profile = new PhabricatorProjectProfile();
}
$options = PhabricatorProjectStatus::getStatusMap();
$e_name = true;
$errors = array();
if ($request->isFormPost()) {
$project->setName($request->getStr('name'));
$project->setStatus($request->getStr('status'));
$profile->setBlurb($request->getStr('blurb'));
if (!strlen($project->getName())) {
@@ -62,6 +61,21 @@ class PhabricatorProjectEditController
$e_name = null;
}
if (!empty($_FILES['image'])) {
$err = idx($_FILES['image'], 'error');
if ($err != UPLOAD_ERR_NO_FILE) {
$file = PhabricatorFile::newFromPHPUpload($_FILES['image']);
$okay = $file->isTransformableImage();
if ($okay) {
$profile->setProfileImagePHID($file->getPHID());
} else {
$errors[] =
'Only valid image files (jpg, jpeg, png or gif) '.
'will be accepted.';
}
}
}
if (!$errors) {
$project->save();
$profile->setProjectPHID($project->getPHID());
@@ -92,20 +106,32 @@ class PhabricatorProjectEditController
$form
->setUser($user)
->setAction($action)
->setEncType('multipart/form-data')
->appendChild(
id(new AphrontFormTextControl())
->setLabel('Name')
->setName('name')
->setValue($project->getName())
->setError($e_name))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel('Project Status')
->setName('status')
->setOptions($options)
->setValue($project->getStatus()))
->appendChild(
id(new AphrontFormTextAreaControl())
->setLabel('Blurb')
->setName('blurb')
->setValue($profile->getBlurb()))
->appendChild(
id(new AphrontFormFileControl())
->setLabel('Change Image')
->setName('image')
->setCaption('Upload a 280px-wide image.'))
->appendChild(
id(new AphrontFormSubmitControl())
->addCancelButton('/project/')
->addCancelButton('/project/view/'.$project->getID().'/')
->setValue('Save'));
$panel = new AphrontPanelView();
@@ -122,5 +148,4 @@ class PhabricatorProjectEditController
'title' => $title,
));
}
}

View File

@@ -8,10 +8,14 @@
phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/files/storage/file');
phutil_require_module('phabricator', 'applications/project/constants/status');
phutil_require_module('phabricator', 'applications/project/controller/base');
phutil_require_module('phabricator', 'applications/project/storage/profile');
phutil_require_module('phabricator', 'applications/project/storage/project');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/file');
phutil_require_module('phabricator', 'view/form/control/select');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/control/text');
phutil_require_module('phabricator', 'view/form/control/textarea');
@@ -21,4 +25,4 @@ phutil_require_module('phabricator', 'view/layout/panel');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorProjectEditController.php');
phutil_require_source('PhabricatorProjectProfileEditController.php');

View File

@@ -28,10 +28,10 @@ class PhabricatorProjectQuickCreateController
$project = new PhabricatorProject();
$project->setAuthorPHID($user->getPHID());
$profile = new PhabricatorProjectProfile();
$options = PhabricatorProjectStatus::getStatusMap();
$e_name = true;
$errors = array();
if ($request->isFormPost()) {
$project->setName($request->getStr('name'));
@@ -46,7 +46,6 @@ class PhabricatorProjectQuickCreateController
if (!$errors) {
$project->save();
$profile->setProjectPHID($project->getPHID());
$profile->save();
@@ -91,5 +90,4 @@ class PhabricatorProjectQuickCreateController
return id(new AphrontDialogResponse())->setDialog($dialog);
}
}

View File

@@ -8,6 +8,7 @@
phutil_require_module('phabricator', 'aphront/response/ajax');
phutil_require_module('phabricator', 'aphront/response/dialog');
phutil_require_module('phabricator', 'applications/project/constants/status');
phutil_require_module('phabricator', 'applications/project/controller/base');
phutil_require_module('phabricator', 'applications/project/storage/profile');
phutil_require_module('phabricator', 'applications/project/storage/project');